1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WIN32_LEAN_AND_MEAN
7 #define WIN32_LEAN_AND_MEAN
11 #include <sys/types.h>
17 #include <onlineupdate/mar_private.h>
18 #include <onlineupdate/mar.h>
22 mar_read_entire_file(const char * filePath
, uint32_t maxSize
,
23 /*out*/ const uint8_t * *data
,
24 /*out*/ uint32_t *size
)
29 if (!filePath
|| !data
|| !size
) {
33 f
= fopen(filePath
, "rb");
39 if (!fseeko(f
, 0, SEEK_END
)) {
40 int64_t fileSize
= ftello(f
);
41 if (fileSize
> 0 && fileSize
<= maxSize
&& !fseeko(f
, 0, SEEK_SET
)) {
42 unsigned char * fileData
;
44 *size
= (unsigned int) fileSize
;
45 fileData
= malloc(*size
);
47 if (fread(fileData
, *size
, 1, f
) == 1) {
62 int mar_extract_and_verify_signatures_fp(FILE *fp
,
63 CryptoX_ProviderHandle provider
,
64 CryptoX_PublicKey
*keys
,
66 int mar_verify_signatures_for_fp(FILE *fp
,
67 CryptoX_ProviderHandle provider
,
68 CryptoX_PublicKey
*keys
,
69 const uint8_t * const *extractedSignatures
,
71 uint32_t *numVerified
);
74 * Reads the specified number of bytes from the file pointer and
75 * stores them in the passed buffer.
77 * @param fp The file pointer to read from.
78 * @param buffer The buffer to store the read results.
79 * @param size The number of bytes to read, buffer must be
80 * at least of this size.
81 * @param ctxs Pointer to the first element in an array of verify context.
82 * @param count The number of elements in ctxs
83 * @param err The name of what is being written to in case of error.
84 * @return 0 on success
86 * -2 on verify update error
89 ReadAndUpdateVerifyContext(FILE *fp
,
92 CryptoX_SignatureHandle
*ctxs
,
97 if (!fp
|| !buffer
|| !ctxs
|| count
== 0 || !err
) {
98 fprintf(stderr
, "ERROR: Invalid parameter specified.\n");
103 return CryptoX_Success
;
106 if (fread(buffer
, size
, 1, fp
) != 1) {
107 fprintf(stderr
, "ERROR: Could not read %s\n", err
);
108 return CryptoX_Error
;
111 for (k
= 0; k
< count
; k
++) {
112 if (CryptoX_Failed(CryptoX_VerifyUpdate(&ctxs
[k
], buffer
, size
))) {
113 fprintf(stderr
, "ERROR: Could not update verify context for %s\n", err
);
117 return CryptoX_Success
;
121 * Verifies a MAR file by verifying each signature with the corresponding
122 * certificate. That is, the first signature will be verified using the first
123 * certificate given, the second signature will be verified using the second
124 * certificate given, etc. The signature count must exactly match the number of
125 * certificates given, and all signature verifications must succeed.
127 * @param mar The file who's signature should be calculated
128 * @param certData Pointer to the first element in an array of
130 * @param certDataSizes Pointer to the first element in an array for size of
132 * @param certCount The number of elements in certData and certDataSizes
133 * @return 0 on success
136 mar_verify_signatures(MarFile
*mar
,
137 const uint8_t * const *certData
,
138 const uint32_t *certDataSizes
,
139 uint32_t certCount
) {
141 CryptoX_ProviderHandle provider
= CryptoX_InvalidHandleValue
;
142 CryptoX_PublicKey keys
[MAX_SIGNATURES
];
145 memset(keys
, 0, sizeof(keys
));
147 if (!mar
|| !certData
|| !certDataSizes
|| certCount
== 0) {
148 fprintf(stderr
, "ERROR: Invalid parameter specified.\n");
153 fprintf(stderr
, "ERROR: MAR file is not open.\n");
157 if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider
))) {
158 fprintf(stderr
, "ERROR: Could not init crypto library.\n");
162 for (k
= 0; k
< certCount
; ++k
) {
163 if (CryptoX_Failed(CryptoX_LoadPublicKey(provider
, certData
[k
], certDataSizes
[k
],
165 fprintf(stderr
, "ERROR: Could not load public key.\n");
170 rv
= mar_extract_and_verify_signatures_fp(mar
->fp
, provider
, keys
, certCount
);
174 for (k
= 0; k
< certCount
; ++k
) {
176 CryptoX_FreePublicKey(&keys
[k
]);
184 * Extracts each signature from the specified MAR file,
185 * then calls mar_verify_signatures_for_fp to verify each signature.
187 * @param fp An opened MAR file handle
188 * @param provider A library provider
189 * @param keys The public keys to use to verify the MAR
190 * @param keyCount The number of keys pointed to by keys
191 * @return 0 on success
194 mar_extract_and_verify_signatures_fp(FILE *fp
,
195 CryptoX_ProviderHandle provider
,
196 CryptoX_PublicKey
*keys
,
198 uint32_t signatureCount
, signatureLen
, numVerified
= 0;
199 uint32_t signatureAlgorithmIDs
[MAX_SIGNATURES
];
201 uint8_t *extractedSignatures
[MAX_SIGNATURES
];
204 memset(signatureAlgorithmIDs
, 0, sizeof(signatureAlgorithmIDs
));
205 memset(extractedSignatures
, 0, sizeof(extractedSignatures
));
208 fprintf(stderr
, "ERROR: Invalid file pointer passed.\n");
209 return CryptoX_Error
;
212 /* To protect against invalid MAR files, we assume that the MAR file
213 size is less than or equal to MAX_SIZE_OF_MAR_FILE. */
214 if (fseeko(fp
, 0, SEEK_END
)) {
215 fprintf(stderr
, "ERROR: Could not seek to the end of the MAR file.\n");
216 return CryptoX_Error
;
218 if (ftello(fp
) > MAX_SIZE_OF_MAR_FILE
) {
219 fprintf(stderr
, "ERROR: MAR file is too large to be verified.\n");
220 return CryptoX_Error
;
223 /* Skip to the start of the signature block */
224 if (fseeko(fp
, SIGNATURE_BLOCK_OFFSET
, SEEK_SET
)) {
225 fprintf(stderr
, "ERROR: Could not seek to the signature block.\n");
226 return CryptoX_Error
;
229 /* Get the number of signatures */
230 if (fread(&signatureCount
, sizeof(signatureCount
), 1, fp
) != 1) {
231 fprintf(stderr
, "ERROR: Could not read number of signatures.\n");
232 return CryptoX_Error
;
234 signatureCount
= ntohl(signatureCount
);
236 /* Check that we have less than the max amount of signatures so we don't
237 waste too much of either updater's or signmar's time. */
238 if (signatureCount
> MAX_SIGNATURES
) {
239 fprintf(stderr
, "ERROR: At most %d signatures can be specified.\n",
241 return CryptoX_Error
;
244 for (i
= 0; i
< signatureCount
; i
++) {
245 /* Get the signature algorithm ID */
246 if (fread(&signatureAlgorithmIDs
[i
], sizeof(uint32_t), 1, fp
) != 1) {
247 fprintf(stderr
, "ERROR: Could not read signatures algorithm ID.\n");
248 return CryptoX_Error
;
250 signatureAlgorithmIDs
[i
] = ntohl(signatureAlgorithmIDs
[i
]);
252 if (fread(&signatureLen
, sizeof(uint32_t), 1, fp
) != 1) {
253 fprintf(stderr
, "ERROR: Could not read signatures length.\n");
254 return CryptoX_Error
;
256 signatureLen
= ntohl(signatureLen
);
258 /* To protected against invalid input make sure the signature length
260 if (signatureLen
> MAX_SIGNATURE_LENGTH
) {
261 fprintf(stderr
, "ERROR: Signature length is too large to verify.\n");
262 return CryptoX_Error
;
265 extractedSignatures
[i
] = malloc(signatureLen
);
266 if (!extractedSignatures
[i
]) {
267 fprintf(stderr
, "ERROR: Could allocate buffer for signature.\n");
268 return CryptoX_Error
;
270 if (fread(extractedSignatures
[i
], signatureLen
, 1, fp
) != 1) {
271 fprintf(stderr
, "ERROR: Could not read extracted signature.\n");
272 for (i
= 0; i
< signatureCount
; ++i
) {
273 free(extractedSignatures
[i
]);
275 return CryptoX_Error
;
278 /* We don't try to verify signatures we don't know about */
279 if (signatureAlgorithmIDs
[i
] != 1) {
280 fprintf(stderr
, "ERROR: Unknown signature algorithm ID.\n");
281 for (i
= 0; i
< signatureCount
; ++i
) {
282 free(extractedSignatures
[i
]);
284 return CryptoX_Error
;
288 rv
= mar_verify_signatures_for_fp(fp
,
291 (const uint8_t * const *)extractedSignatures
,
294 for (i
= 0; i
< signatureCount
; ++i
) {
295 free(extractedSignatures
[i
]);
298 /* If we reached here and we verified every
299 signature, return success. */
300 if (numVerified
== signatureCount
&& keyCount
== numVerified
) {
301 assert(rv
== 0); (void) rv
;
302 return CryptoX_Success
;
305 if (numVerified
== 0) {
306 fprintf(stderr
, "ERROR: Not all signatures were verified.\n");
308 fprintf(stderr
, "ERROR: Only %d of %d signatures were verified.\n",
309 numVerified
, signatureCount
);
311 return CryptoX_Error
;
315 * Verifies a MAR file by verifying each signature with the corresponding
316 * certificate. That is, the first signature will be verified using the first
317 * certificate given, the second signature will be verified using the second
318 * certificate given, etc. The signature count must exactly match the number of
319 * certificates given, and all signature verifications must succeed.
321 * @param fp An opened MAR file handle
322 * @param provider A library provider
323 * @param keys A pointer to the first element in an
325 * @param extractedSignatures Pointer to the first element in an array
326 * of extracted signatures.
327 * @param signatureCount The number of signatures in the MAR file
328 * @param numVerified Out parameter which will be filled with
329 * the number of verified signatures.
330 * This information can be useful for printing
332 * @return 0 on success, *numVerified == signatureCount.
335 mar_verify_signatures_for_fp(FILE *fp
,
336 CryptoX_ProviderHandle provider
,
337 CryptoX_PublicKey
*keys
,
338 const uint8_t * const *extractedSignatures
,
339 uint32_t signatureCount
,
340 uint32_t *numVerified
)
342 CryptoX_SignatureHandle signatureHandles
[MAX_SIGNATURES
];
344 uint32_t signatureLengths
[MAX_SIGNATURES
];
346 int rv
= CryptoX_Error
;
348 (void) provider
; (void) keys
; // avoid warnings
350 memset(signatureHandles
, 0, sizeof(signatureHandles
));
351 memset(signatureLengths
, 0, sizeof(signatureLengths
));
353 if (!extractedSignatures
|| !numVerified
) {
354 fprintf(stderr
, "ERROR: Invalid parameter specified.\n");
360 /* This function is only called when we have at least one signature,
361 but to protected against future people who call this function we
362 make sure a non zero value is passed in.
364 if (!signatureCount
) {
365 fprintf(stderr
, "ERROR: There must be at least one signature.\n");
369 for (i
= 0; i
< signatureCount
; i
++) {
370 if (CryptoX_Failed(CryptoX_VerifyBegin(provider
,
371 &signatureHandles
[i
], &keys
[i
]))) {
372 fprintf(stderr
, "ERROR: Could not initialize signature handle.\n");
377 /* Skip to the start of the file */
378 if (fseeko(fp
, 0, SEEK_SET
)) {
379 fprintf(stderr
, "ERROR: Could not seek to start of the file\n");
384 Bytes 4-7: index offset
385 Bytes 8-15: size of entire MAR
387 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp
, buf
,
388 SIGNATURE_BLOCK_OFFSET
+
392 "signature block"))) {
396 /* Read the signature block */
397 for (i
= 0; i
< signatureCount
; i
++) {
398 /* Get the signature algorithm ID */
399 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp
,
404 "signature algorithm ID"))) {
408 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp
,
409 &signatureLengths
[i
],
413 "signature length"))) {
416 signatureLengths
[i
] = ntohl(signatureLengths
[i
]);
417 if (signatureLengths
[i
] > MAX_SIGNATURE_LENGTH
) {
418 fprintf(stderr
, "ERROR: Embedded signature length is too large.\n");
422 /* Skip past the signature itself as those are not included */
423 if (fseeko(fp
, signatureLengths
[i
], SEEK_CUR
)) {
424 fprintf(stderr
, "ERROR: Could not seek past signature.\n");
429 /* Read the rest of the file after the signature block */
431 int numRead
= fread(buf
, 1, BLOCKSIZE
, fp
);
433 fprintf(stderr
, "ERROR: Error reading data block.\n");
437 for (i
= 0; i
< signatureCount
; i
++) {
438 if (CryptoX_Failed(CryptoX_VerifyUpdate(&signatureHandles
[i
],
440 fprintf(stderr
, "ERROR: Error updating verify context with"
447 /* Verify the signatures */
448 for (i
= 0; i
< signatureCount
; i
++) {
449 if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandles
[i
],
451 extractedSignatures
[i
],
452 signatureLengths
[i
]))) {
453 fprintf(stderr
, "ERROR: Error verifying signature.\n");
459 rv
= CryptoX_Success
;
461 for (i
= 0; i
< signatureCount
; i
++) {
462 CryptoX_FreeSignatureHandle(&signatureHandles
[i
]);