modules/libmar/verify/mar_verify.c

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:12a8752ee1ab
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/. */
4
5 #ifdef XP_WIN
6 #ifndef WIN32_LEAN_AND_MEAN
7 #define WIN32_LEAN_AND_MEAN
8 #endif
9 #endif
10
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include "mar_private.h"
17 #include "mar.h"
18 #include "cryptox.h"
19
20 int mar_extract_and_verify_signatures_fp(FILE *fp,
21 CryptoX_ProviderHandle provider,
22 CryptoX_PublicKey *keys,
23 uint32_t keyCount);
24 int mar_verify_signatures_for_fp(FILE *fp,
25 CryptoX_ProviderHandle provider,
26 CryptoX_PublicKey *keys,
27 const uint8_t * const *extractedSignatures,
28 uint32_t keyCount,
29 uint32_t *numVerified);
30
31 /**
32 * Reads the specified number of bytes from the file pointer and
33 * stores them in the passed buffer.
34 *
35 * @param fp The file pointer to read from.
36 * @param buffer The buffer to store the read results.
37 * @param size The number of bytes to read, buffer must be
38 * at least of this size.
39 * @param ctxs Pointer to the first element in an array of verify context.
40 * @param count The number of elements in ctxs
41 * @param err The name of what is being written to in case of error.
42 * @return 0 on success
43 * -1 on read error
44 * -2 on verify update error
45 */
46 int
47 ReadAndUpdateVerifyContext(FILE *fp,
48 void *buffer,
49 uint32_t size,
50 CryptoX_SignatureHandle *ctxs,
51 uint32_t count,
52 const char *err)
53 {
54 uint32_t k;
55 if (!fp || !buffer || !ctxs || count == 0 || !err) {
56 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
57 return CryptoX_Error;
58 }
59
60 if (!size) {
61 return CryptoX_Success;
62 }
63
64 if (fread(buffer, size, 1, fp) != 1) {
65 fprintf(stderr, "ERROR: Could not read %s\n", err);
66 return CryptoX_Error;
67 }
68
69 for (k = 0; k < count; k++) {
70 if (CryptoX_Failed(CryptoX_VerifyUpdate(&ctxs[k], buffer, size))) {
71 fprintf(stderr, "ERROR: Could not update verify context for %s\n", err);
72 return -2;
73 }
74 }
75 return CryptoX_Success;
76 }
77
78 /**
79 * Verifies a MAR file by verifying each signature with the corresponding
80 * certificate. That is, the first signature will be verified using the first
81 * certificate given, the second signature will be verified using the second
82 * certificate given, etc. The signature count must exactly match the number of
83 * certificates given, and all signature verifications must succeed.
84 * This is only used by the signmar program when used with arguments to verify
85 * a MAR. This should not be used to verify a MAR that will be extracted in the
86 * same operation by updater code. This function prints the error message if
87 * verification fails.
88 *
89 * @param pathToMARFile The path of the MAR file to verify.
90 * @param certData Pointer to the first element in an array of certificate
91 * file data.
92 * @param certDataSizes Pointer to the first element in an array for size of the
93 * cert data.
94 * @param certNames Pointer to the first element in an array of certificate names.
95 * Used only if compiled as NSS, specifies the certificate names
96 * @param certCount The number of elements in certData, certDataSizes, and certNames
97 * @return 0 on success
98 * a negative number if there was an error
99 * a positive number if the signature does not verify
100 */
101 int
102 mar_verify_signatures(const char *pathToMARFile,
103 const uint8_t * const *certData,
104 const uint32_t *certDataSizes,
105 const char * const *certNames,
106 uint32_t certCount) {
107 int rv;
108 CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
109 CryptoX_Certificate certs[MAX_SIGNATURES];
110 CryptoX_PublicKey keys[MAX_SIGNATURES];
111 FILE *fp;
112 uint32_t k;
113
114 memset(certs, 0, sizeof(certs));
115 memset(keys, 0, sizeof(keys));
116
117 if (!pathToMARFile || certCount == 0) {
118 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
119 return CryptoX_Error;
120 }
121
122 fp = fopen(pathToMARFile, "rb");
123 if (!fp) {
124 fprintf(stderr, "ERROR: Could not open MAR file.\n");
125 return CryptoX_Error;
126 }
127
128 if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
129 fclose(fp);
130 fprintf(stderr, "ERROR: Could not init crytpo library.\n");
131 return CryptoX_Error;
132 }
133
134 /* Load the certs and keys */
135 for (k = 0; k < certCount; k++) {
136 if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
137 &keys[k], certNames[k], &certs[k]))) {
138 fclose(fp);
139 fprintf(stderr, "ERROR: Could not load public key.\n");
140 return CryptoX_Error;
141 }
142 }
143
144 rv = mar_extract_and_verify_signatures_fp(fp, provider, keys, certCount);
145 fclose(fp);
146
147 /* Cleanup the allocated keys and certs */
148 for (k = 0; k < certCount; k++) {
149 if (keys[k]) {
150 CryptoX_FreePublicKey(&keys[k]);
151 }
152
153 if (certs[k]) {
154 CryptoX_FreeCertificate(&certs[k]);
155 }
156 }
157 return rv;
158 }
159
160 #ifdef XP_WIN
161 /**
162 * Verifies a MAR file by verifying each signature with the corresponding
163 * certificate. That is, the first signature will be verified using the first
164 * certificate given, the second signature will be verified using the second
165 * certificate given, etc. The signature count must exactly match the number of
166 * certificates given, and all signature verifications must succeed.
167 *
168 * @param pathToMARFile The path of the MAR file who's signature
169 * should be calculated
170 * @param certData Pointer to the first element in an array of
171 * certificate data
172 * @param certDataSizes Pointer to the first element in an array for size of
173 * the data stored
174 * @param certCount The number of elements in certData and certDataSizes
175 * @return 0 on success
176 */
177 int
178 mar_verify_signaturesW(MarFile *mar,
179 const uint8_t * const *certData,
180 const uint32_t *certDataSizes,
181 uint32_t certCount) {
182 int rv = -1;
183 CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
184 CryptoX_Certificate certs[MAX_SIGNATURES];
185 CryptoX_PublicKey keys[MAX_SIGNATURES];
186 uint32_t k;
187
188 memset(certs, 0, sizeof(certs));
189 memset(keys, 0, sizeof(keys));
190
191 if (!mar || !certData || !certDataSizes || certCount == 0) {
192 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
193 goto failure;
194 }
195
196 if (!mar->fp) {
197 fprintf(stderr, "ERROR: MAR file is not open.\n");
198 goto failure;
199 }
200
201 if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
202 fprintf(stderr, "ERROR: Could not init crytpo library.\n");
203 goto failure;
204 }
205
206 for (k = 0; k < certCount; ++k) {
207 if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
208 &keys[k], "", &certs[k]))) {
209 fprintf(stderr, "ERROR: Could not load public key.\n");
210 goto failure;
211 }
212 }
213
214 rv = mar_extract_and_verify_signatures_fp(mar->fp, provider, keys, certCount);
215
216 failure:
217
218 for (k = 0; k < certCount; ++k) {
219 if (keys[k]) {
220 CryptoX_FreePublicKey(&keys[k]);
221 }
222
223 if (certs[k]) {
224 CryptoX_FreeCertificate(&certs[k]);
225 }
226 }
227
228 return rv;
229 }
230 #endif
231
232 /**
233 * Extracts each signature from the specified MAR file,
234 * then calls mar_verify_signatures_for_fp to verify each signature.
235 *
236 * @param fp An opened MAR file handle
237 * @param provider A library provider
238 * @param keys The public keys to use to verify the MAR
239 * @param keyCount The number of keys pointed to by keys
240 * @return 0 on success
241 */
242 int
243 mar_extract_and_verify_signatures_fp(FILE *fp,
244 CryptoX_ProviderHandle provider,
245 CryptoX_PublicKey *keys,
246 uint32_t keyCount) {
247 char buf[5] = {0};
248 uint32_t signatureCount, signatureLen, numVerified = 0;
249 uint32_t signatureAlgorithmIDs[MAX_SIGNATURES];
250 int rv = -1;
251 int64_t curPos;
252 uint8_t *extractedSignatures[MAX_SIGNATURES];
253 uint32_t i;
254
255 memset(signatureAlgorithmIDs, 0, sizeof(signatureAlgorithmIDs));
256 memset(extractedSignatures, 0, sizeof(extractedSignatures));
257
258 if (!fp) {
259 fprintf(stderr, "ERROR: Invalid file pointer passed.\n");
260 return CryptoX_Error;
261 }
262
263 /* To protect against invalid MAR files, we assumes that the MAR file
264 size is less than or equal to MAX_SIZE_OF_MAR_FILE. */
265 if (fseeko(fp, 0, SEEK_END)) {
266 fprintf(stderr, "ERROR: Could not seek to the end of the MAR file.\n");
267 return CryptoX_Error;
268 }
269 if (ftello(fp) > MAX_SIZE_OF_MAR_FILE) {
270 fprintf(stderr, "ERROR: MAR file is too large to be verified.\n");
271 return CryptoX_Error;
272 }
273
274 /* Skip to the start of the signature block */
275 if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
276 fprintf(stderr, "ERROR: Could not seek to the signature block.\n");
277 return CryptoX_Error;
278 }
279
280 /* Get the number of signatures */
281 if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
282 fprintf(stderr, "ERROR: Could not read number of signatures.\n");
283 return CryptoX_Error;
284 }
285 signatureCount = ntohl(signatureCount);
286
287 /* Check that we have less than the max amount of signatures so we don't
288 waste too much of either updater's or signmar's time. */
289 if (signatureCount > MAX_SIGNATURES) {
290 fprintf(stderr, "ERROR: At most %d signatures can be specified.\n",
291 MAX_SIGNATURES);
292 return CryptoX_Error;
293 }
294
295 for (i = 0; i < signatureCount; i++) {
296 /* Get the signature algorithm ID */
297 if (fread(&signatureAlgorithmIDs[i], sizeof(uint32_t), 1, fp) != 1) {
298 fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n");
299 return CryptoX_Error;
300 }
301 signatureAlgorithmIDs[i] = ntohl(signatureAlgorithmIDs[i]);
302
303 if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) {
304 fprintf(stderr, "ERROR: Could not read signatures length.\n");
305 return CryptoX_Error;
306 }
307 signatureLen = ntohl(signatureLen);
308
309 /* To protected against invalid input make sure the signature length
310 isn't too big. */
311 if (signatureLen > MAX_SIGNATURE_LENGTH) {
312 fprintf(stderr, "ERROR: Signature length is too large to verify.\n");
313 return CryptoX_Error;
314 }
315
316 extractedSignatures[i] = malloc(signatureLen);
317 if (!extractedSignatures[i]) {
318 fprintf(stderr, "ERROR: Could allocate buffer for signature.\n");
319 return CryptoX_Error;
320 }
321 if (fread(extractedSignatures[i], signatureLen, 1, fp) != 1) {
322 fprintf(stderr, "ERROR: Could not read extracted signature.\n");
323 for (i = 0; i < signatureCount; ++i) {
324 free(extractedSignatures[i]);
325 }
326 return CryptoX_Error;
327 }
328
329 /* We don't try to verify signatures we don't know about */
330 if (signatureAlgorithmIDs[i] != 1) {
331 fprintf(stderr, "ERROR: Unknown signature algorithm ID.\n");
332 for (i = 0; i < signatureCount; ++i) {
333 free(extractedSignatures[i]);
334 }
335 return CryptoX_Error;
336 }
337 }
338
339 curPos = ftello(fp);
340 rv = mar_verify_signatures_for_fp(fp,
341 provider,
342 keys,
343 (const uint8_t * const *)extractedSignatures,
344 signatureCount,
345 &numVerified);
346 for (i = 0; i < signatureCount; ++i) {
347 free(extractedSignatures[i]);
348 }
349
350 /* If we reached here and we verified every
351 signature, return success. */
352 if (numVerified == signatureCount && keyCount == numVerified) {
353 return CryptoX_Success;
354 }
355
356 if (numVerified == 0) {
357 fprintf(stderr, "ERROR: Not all signatures were verified.\n");
358 } else {
359 fprintf(stderr, "ERROR: Only %d of %d signatures were verified.\n",
360 numVerified, signatureCount);
361 }
362 return CryptoX_Error;
363 }
364
365 /**
366 * Verifies a MAR file by verifying each signature with the corresponding
367 * certificate. That is, the first signature will be verified using the first
368 * certificate given, the second signature will be verified using the second
369 * certificate given, etc. The signature count must exactly match the number of
370 * certificates given, and all signature verifications must succeed.
371 *
372 * @param fp An opened MAR file handle
373 * @param provider A library provider
374 * @param keys A pointer to the first element in an
375 * array of keys.
376 * @param extractedSignatures Pointer to the first element in an array
377 * of extracted signatures.
378 * @param signatureCount The number of signatures in the MAR file
379 * @param numVerified Out parameter which will be filled with
380 * the number of verified signatures.
381 * This information can be useful for printing
382 * error messages.
383 * @return 0 on success, *numVerified == signatureCount.
384 */
385 int
386 mar_verify_signatures_for_fp(FILE *fp,
387 CryptoX_ProviderHandle provider,
388 CryptoX_PublicKey *keys,
389 const uint8_t * const *extractedSignatures,
390 uint32_t signatureCount,
391 uint32_t *numVerified)
392 {
393 CryptoX_SignatureHandle signatureHandles[MAX_SIGNATURES];
394 char buf[BLOCKSIZE];
395 uint32_t signatureLengths[MAX_SIGNATURES];
396 uint32_t i;
397 int rv = CryptoX_Error;
398
399 memset(signatureHandles, 0, sizeof(signatureHandles));
400 memset(signatureLengths, 0, sizeof(signatureLengths));
401
402 if (!extractedSignatures || !numVerified) {
403 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
404 goto failure;
405 }
406
407 *numVerified = 0;
408
409 /* This function is only called when we have at least one signature,
410 but to protected against future people who call this function we
411 make sure a non zero value is passed in.
412 */
413 if (!signatureCount) {
414 fprintf(stderr, "ERROR: There must be at least one signature.\n");
415 goto failure;
416 }
417
418 for (i = 0; i < signatureCount; i++) {
419 if (CryptoX_Failed(CryptoX_VerifyBegin(provider,
420 &signatureHandles[i], &keys[i]))) {
421 fprintf(stderr, "ERROR: Could not initialize signature handle.\n");
422 goto failure;
423 }
424 }
425
426 /* Skip to the start of the file */
427 if (fseeko(fp, 0, SEEK_SET)) {
428 fprintf(stderr, "ERROR: Could not seek to start of the file\n");
429 goto failure;
430 }
431
432 /* Bytes 0-3: MAR1
433 Bytes 4-7: index offset
434 Bytes 8-15: size of entire MAR
435 */
436 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, buf,
437 SIGNATURE_BLOCK_OFFSET +
438 sizeof(uint32_t),
439 signatureHandles,
440 signatureCount,
441 "signature block"))) {
442 goto failure;
443 }
444
445 /* Read the signature block */
446 for (i = 0; i < signatureCount; i++) {
447 /* Get the signature algorithm ID */
448 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
449 &buf,
450 sizeof(uint32_t),
451 signatureHandles,
452 signatureCount,
453 "signature algorithm ID"))) {
454 goto failure;
455 }
456
457 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
458 &signatureLengths[i],
459 sizeof(uint32_t),
460 signatureHandles,
461 signatureCount,
462 "signature length"))) {
463 goto failure;
464 }
465 signatureLengths[i] = ntohl(signatureLengths[i]);
466 if (signatureLengths[i] > MAX_SIGNATURE_LENGTH) {
467 fprintf(stderr, "ERROR: Embedded signature length is too large.\n");
468 goto failure;
469 }
470
471 /* Skip past the signature itself as those are not included */
472 if (fseeko(fp, signatureLengths[i], SEEK_CUR)) {
473 fprintf(stderr, "ERROR: Could not seek past signature.\n");
474 goto failure;
475 }
476 }
477
478 /* Read the rest of the file after the signature block */
479 while (!feof(fp)) {
480 int numRead = fread(buf, 1, BLOCKSIZE , fp);
481 if (ferror(fp)) {
482 fprintf(stderr, "ERROR: Error reading data block.\n");
483 goto failure;
484 }
485
486 for (i = 0; i < signatureCount; i++) {
487 if (CryptoX_Failed(CryptoX_VerifyUpdate(&signatureHandles[i],
488 buf, numRead))) {
489 fprintf(stderr, "ERROR: Error updating verify context with"
490 " data block.\n");
491 goto failure;
492 }
493 }
494 }
495
496 /* Verify the signatures */
497 for (i = 0; i < signatureCount; i++) {
498 if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandles[i],
499 &keys[i],
500 extractedSignatures[i],
501 signatureLengths[i]))) {
502 fprintf(stderr, "ERROR: Error verifying signature.\n");
503 goto failure;
504 }
505 ++*numVerified;
506 }
507
508 rv = CryptoX_Success;
509 failure:
510 for (i = 0; i < signatureCount; i++) {
511 CryptoX_FreeSignatureHandle(&signatureHandles[i]);
512 }
513
514 return rv;
515 }

mercurial