modules/libmar/sign/mar_sign.c

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:847db2632e33
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_cmdline.h"
18 #include "mar.h"
19 #include "cryptox.h"
20 #ifndef XP_WIN
21 #include <unistd.h>
22 #endif
23
24 #include "nss_secutil.h"
25 #include "base64.h"
26
27 /**
28 * Initializes the NSS context.
29 *
30 * @param NSSConfigDir The config dir containing the private key to use
31 * @return 0 on success
32 * -1 on error
33 */
34 int
35 NSSInitCryptoContext(const char *NSSConfigDir)
36 {
37 SECStatus status = NSS_Initialize(NSSConfigDir,
38 "", "", SECMOD_DB, NSS_INIT_READONLY);
39 if (SECSuccess != status) {
40 fprintf(stderr, "ERROR: Could not initialize NSS\n");
41 return -1;
42 }
43
44 return 0;
45 }
46
47 /**
48 * Obtains a signing context.
49 *
50 * @param ctx A pointer to the signing context to fill
51 * @return 0 on success
52 * -1 on error
53 */
54 int
55 NSSSignBegin(const char *certName,
56 SGNContext **ctx,
57 SECKEYPrivateKey **privKey,
58 CERTCertificate **cert,
59 uint32_t *signatureLength)
60 {
61 secuPWData pwdata = { PW_NONE, 0 };
62 if (!certName || !ctx || !privKey || !cert || !signatureLength) {
63 fprintf(stderr, "ERROR: Invalid parameter passed to NSSSignBegin\n");
64 return -1;
65 }
66
67 /* Get the cert and embedded public key out of the database */
68 *cert = PK11_FindCertFromNickname(certName, &pwdata);
69 if (!*cert) {
70 fprintf(stderr, "ERROR: Could not find cert from nickname\n");
71 return -1;
72 }
73
74 /* Get the private key out of the database */
75 *privKey = PK11_FindKeyByAnyCert(*cert, &pwdata);
76 if (!*privKey) {
77 fprintf(stderr, "ERROR: Could not find private key\n");
78 return -1;
79 }
80
81 *signatureLength = PK11_SignatureLen(*privKey);
82
83 if (*signatureLength > BLOCKSIZE) {
84 fprintf(stderr,
85 "ERROR: Program must be compiled with a larger block size"
86 " to support signing with signatures this large: %u.\n",
87 *signatureLength);
88 return -1;
89 }
90
91 /* Check that the key length is large enough for our requirements */
92 if (*signatureLength < XP_MIN_SIGNATURE_LEN_IN_BYTES) {
93 fprintf(stderr, "ERROR: Key length must be >= %d bytes\n",
94 XP_MIN_SIGNATURE_LEN_IN_BYTES);
95 return -1;
96 }
97
98 *ctx = SGN_NewContext (SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, *privKey);
99 if (!*ctx) {
100 fprintf(stderr, "ERROR: Could not create signature context\n");
101 return -1;
102 }
103
104 if (SGN_Begin(*ctx) != SECSuccess) {
105 fprintf(stderr, "ERROR: Could not begin signature\n");
106 return -1;
107 }
108
109 return 0;
110 }
111
112 /**
113 * Writes the passed buffer to the file fp and updates the signature contexts.
114 *
115 * @param fpDest The file pointer to write to.
116 * @param buffer The buffer to write.
117 * @param size The size of the buffer to write.
118 * @param ctxs Pointer to the first element in an array of signature
119 * contexts to update.
120 * @param ctxCount The number of signature contexts pointed to by ctxs
121 * @param err The name of what is being written to in case of error.
122 * @return 0 on success
123 * -2 on write error
124 * -3 on signature update error
125 */
126 int
127 WriteAndUpdateSignatures(FILE *fpDest, void *buffer,
128 uint32_t size, SGNContext **ctxs,
129 uint32_t ctxCount,
130 const char *err)
131 {
132 uint32_t k;
133 if (!size) {
134 return 0;
135 }
136
137 if (fwrite(buffer, size, 1, fpDest) != 1) {
138 fprintf(stderr, "ERROR: Could not write %s\n", err);
139 return -2;
140 }
141
142 for (k = 0; k < ctxCount; ++k) {
143 if (SGN_Update(ctxs[k], buffer, size) != SECSuccess) {
144 fprintf(stderr, "ERROR: Could not update signature context for %s\n", err);
145 return -3;
146 }
147 }
148 return 0;
149 }
150
151 /**
152 * Adjusts each entry's content offset in the the passed in index by the
153 * specified amount.
154 *
155 * @param indexBuf A buffer containing the MAR index
156 * @param indexLength The length of the MAR index
157 * @param offsetAmount The amount to adjust each index entry by
158 */
159 void
160 AdjustIndexContentOffsets(char *indexBuf, uint32_t indexLength, uint32_t offsetAmount)
161 {
162 uint32_t *offsetToContent;
163 char *indexBufLoc = indexBuf;
164
165 /* Consume the index and adjust each index by the specified amount */
166 while (indexBufLoc != (indexBuf + indexLength)) {
167 /* Adjust the offset */
168 offsetToContent = (uint32_t *)indexBufLoc;
169 *offsetToContent = ntohl(*offsetToContent);
170 *offsetToContent += offsetAmount;
171 *offsetToContent = htonl(*offsetToContent);
172 /* Skip past the offset, length, and flags */
173 indexBufLoc += 3 * sizeof(uint32_t);
174 indexBufLoc += strlen(indexBufLoc) + 1;
175 }
176 }
177
178 /**
179 * Reads from fpSrc, writes it to fpDest, and updates the signature contexts.
180 *
181 * @param fpSrc The file pointer to read from.
182 * @param fpDest The file pointer to write to.
183 * @param buffer The buffer to write.
184 * @param size The size of the buffer to write.
185 * @param ctxs Pointer to the first element in an array of signature
186 * contexts to update.
187 * @param ctxCount The number of signature contexts pointed to by ctxs
188 * @param err The name of what is being written to in case of error.
189 * @return 0 on success
190 * -1 on read error
191 * -2 on write error
192 * -3 on signature update error
193 */
194 int
195 ReadWriteAndUpdateSignatures(FILE *fpSrc, FILE *fpDest, void *buffer,
196 uint32_t size, SGNContext **ctxs,
197 uint32_t ctxCount,
198 const char *err)
199 {
200 if (!size) {
201 return 0;
202 }
203
204 if (fread(buffer, size, 1, fpSrc) != 1) {
205 fprintf(stderr, "ERROR: Could not read %s\n", err);
206 return -1;
207 }
208
209 return WriteAndUpdateSignatures(fpDest, buffer, size, ctxs, ctxCount, err);
210 }
211
212
213 /**
214 * Reads from fpSrc, writes it to fpDest.
215 *
216 * @param fpSrc The file pointer to read from.
217 * @param fpDest The file pointer to write to.
218 * @param buffer The buffer to write.
219 * @param size The size of the buffer to write.
220 * @param err The name of what is being written to in case of error.
221 * @return 0 on success
222 * -1 on read error
223 * -2 on write error
224 */
225 int
226 ReadAndWrite(FILE *fpSrc, FILE *fpDest, void *buffer,
227 uint32_t size, const char *err)
228 {
229 if (!size) {
230 return 0;
231 }
232
233 if (fread(buffer, size, 1, fpSrc) != 1) {
234 fprintf(stderr, "ERROR: Could not read %s\n", err);
235 return -1;
236 }
237
238 if (fwrite(buffer, size, 1, fpDest) != 1) {
239 fprintf(stderr, "ERROR: Could not write %s\n", err);
240 return -2;
241 }
242
243 return 0;
244 }
245
246 /**
247 * Writes out a copy of the MAR at src but with the signature block stripped.
248 *
249 * @param src The path of the source MAR file
250 * @param dest The path of the MAR file to write out that
251 has no signature block
252 * @return 0 on success
253 * -1 on error
254 */
255 int
256 strip_signature_block(const char *src, const char * dest)
257 {
258 uint32_t offsetToIndex, dstOffsetToIndex, indexLength,
259 numSignatures = 0, leftOver;
260 int32_t stripAmount = 0;
261 int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR, numBytesToCopy,
262 numChunks, i;
263 FILE *fpSrc = NULL, *fpDest = NULL;
264 int rv = -1, hasSignatureBlock;
265 char buf[BLOCKSIZE];
266 char *indexBuf = NULL, *indexBufLoc;
267
268 if (!src || !dest) {
269 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
270 return -1;
271 }
272
273 fpSrc = fopen(src, "rb");
274 if (!fpSrc) {
275 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
276 goto failure;
277 }
278
279 fpDest = fopen(dest, "wb");
280 if (!fpDest) {
281 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
282 goto failure;
283 }
284
285 /* Determine if the source MAR file has the new fields for signing or not */
286 if (get_mar_file_info(src, &hasSignatureBlock, NULL, NULL, NULL, NULL)) {
287 fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
288 goto failure;
289 }
290
291 /* MAR ID */
292 if (ReadAndWrite(fpSrc, fpDest, buf, MAR_ID_SIZE, "MAR ID")) {
293 goto failure;
294 }
295
296 /* Offset to index */
297 if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
298 fprintf(stderr, "ERROR: Could not read offset\n");
299 goto failure;
300 }
301 offsetToIndex = ntohl(offsetToIndex);
302
303 /* Get the real size of the MAR */
304 oldPos = ftello(fpSrc);
305 if (fseeko(fpSrc, 0, SEEK_END)) {
306 fprintf(stderr, "ERROR: Could not seek to end of file.\n");
307 goto failure;
308 }
309 realSizeOfSrcMAR = ftello(fpSrc);
310 if (fseeko(fpSrc, oldPos, SEEK_SET)) {
311 fprintf(stderr, "ERROR: Could not seek back to current location.\n");
312 goto failure;
313 }
314
315 if (hasSignatureBlock) {
316 /* Get the MAR length and adjust its size */
317 if (fread(&sizeOfEntireMAR,
318 sizeof(sizeOfEntireMAR), 1, fpSrc) != 1) {
319 fprintf(stderr, "ERROR: Could read mar size\n");
320 goto failure;
321 }
322 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
323 if (sizeOfEntireMAR != realSizeOfSrcMAR) {
324 fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
325 goto failure;
326 }
327
328 /* Get the num signatures in the source file so we know what to strip */
329 if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
330 fprintf(stderr, "ERROR: Could read num signatures\n");
331 goto failure;
332 }
333 numSignatures = ntohl(numSignatures);
334
335 for (i = 0; i < numSignatures; i++) {
336 uint32_t signatureLen;
337
338 /* Skip past the signature algorithm ID */
339 if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
340 fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
341 }
342
343 /* Read in the length of the signature so we know how far to skip */
344 if (fread(&signatureLen, sizeof(uint32_t), 1, fpSrc) != 1) {
345 fprintf(stderr, "ERROR: Could not read signatures length.\n");
346 return CryptoX_Error;
347 }
348 signatureLen = ntohl(signatureLen);
349
350 /* Skip past the signature */
351 if (fseeko(fpSrc, signatureLen, SEEK_CUR)) {
352 fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
353 }
354
355 stripAmount += sizeof(uint32_t) + sizeof(uint32_t) + signatureLen;
356 }
357
358 } else {
359 sizeOfEntireMAR = realSizeOfSrcMAR;
360 numSignatures = 0;
361 }
362
363 if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
364 fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
365 goto failure;
366 }
367
368 dstOffsetToIndex = offsetToIndex;
369 if (!hasSignatureBlock) {
370 dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
371 }
372 dstOffsetToIndex -= stripAmount;
373
374 /* Write out the index offset */
375 dstOffsetToIndex = htonl(dstOffsetToIndex);
376 if (fwrite(&dstOffsetToIndex, sizeof(dstOffsetToIndex), 1, fpDest) != 1) {
377 fprintf(stderr, "ERROR: Could not write offset to index\n");
378 goto failure;
379 }
380 dstOffsetToIndex = ntohl(dstOffsetToIndex);
381
382 /* Write out the new MAR file size */
383 if (!hasSignatureBlock) {
384 sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
385 }
386 sizeOfEntireMAR -= stripAmount;
387
388 /* Write out the MAR size */
389 sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
390 if (fwrite(&sizeOfEntireMAR, sizeof(sizeOfEntireMAR), 1, fpDest) != 1) {
391 fprintf(stderr, "ERROR: Could not write size of MAR\n");
392 goto failure;
393 }
394 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
395
396 /* Write out the number of signatures, which is 0 */
397 numSignatures = 0;
398 if (fwrite(&numSignatures, sizeof(numSignatures), 1, fpDest) != 1) {
399 fprintf(stderr, "ERROR: Could not write out num signatures\n");
400 goto failure;
401 }
402
403 /* Write out the rest of the MAR excluding the index header and index
404 offsetToIndex unfortunately has to remain 32-bit because for backwards
405 compatibility with the old MAR file format. */
406 if (ftello(fpSrc) > ((int64_t)offsetToIndex)) {
407 fprintf(stderr, "ERROR: Index offset is too small.\n");
408 goto failure;
409 }
410 numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
411 numChunks = numBytesToCopy / BLOCKSIZE;
412 leftOver = numBytesToCopy % BLOCKSIZE;
413
414 /* Read each file and write it to the MAR file */
415 for (i = 0; i < numChunks; ++i) {
416 if (ReadAndWrite(fpSrc, fpDest, buf, BLOCKSIZE, "content block")) {
417 goto failure;
418 }
419 }
420
421 /* Write out the left over */
422 if (ReadAndWrite(fpSrc, fpDest, buf,
423 leftOver, "left over content block")) {
424 goto failure;
425 }
426
427 /* Length of the index */
428 if (ReadAndWrite(fpSrc, fpDest, &indexLength,
429 sizeof(indexLength), "index length")) {
430 goto failure;
431 }
432 indexLength = ntohl(indexLength);
433
434 /* Consume the index and adjust each index by the difference */
435 indexBuf = malloc(indexLength);
436 indexBufLoc = indexBuf;
437 if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
438 fprintf(stderr, "ERROR: Could not read index\n");
439 goto failure;
440 }
441
442 /* Adjust each entry in the index */
443 if (hasSignatureBlock) {
444 AdjustIndexContentOffsets(indexBuf, indexLength, -stripAmount);
445 } else {
446 AdjustIndexContentOffsets(indexBuf, indexLength,
447 sizeof(sizeOfEntireMAR) +
448 sizeof(numSignatures) -
449 stripAmount);
450 }
451
452 if (fwrite(indexBuf, indexLength, 1, fpDest) != 1) {
453 fprintf(stderr, "ERROR: Could not write index\n");
454 goto failure;
455 }
456
457 rv = 0;
458 failure:
459 if (fpSrc) {
460 fclose(fpSrc);
461 }
462
463 if (fpDest) {
464 fclose(fpDest);
465 }
466
467 if (rv) {
468 remove(dest);
469 }
470
471 if (indexBuf) {
472 free(indexBuf);
473 }
474
475 if (rv) {
476 remove(dest);
477 }
478 return rv;
479 }
480
481 /**
482 * Extracts a signature from a MAR file, base64 encodes it, and writes it out
483 *
484 * @param src The path of the source MAR file
485 * @param sigIndex The index of the signature to extract
486 * @param dest The path of file to write the signature to
487 * @return 0 on success
488 * -1 on error
489 */
490 int
491 extract_signature(const char *src, uint32_t sigIndex, const char * dest)
492 {
493 FILE *fpSrc = NULL, *fpDest = NULL;
494 uint32_t i;
495 uint32_t signatureCount;
496 uint32_t signatureLen;
497 uint8_t *extractedSignature = NULL;
498 char *base64Encoded = NULL;
499 int rv = -1;
500 if (!src || !dest) {
501 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
502 goto failure;
503 }
504
505 fpSrc = fopen(src, "rb");
506 if (!fpSrc) {
507 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
508 goto failure;
509 }
510
511 fpDest = fopen(dest, "wb");
512 if (!fpDest) {
513 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
514 goto failure;
515 }
516
517 /* Skip to the start of the signature block */
518 if (fseeko(fpSrc, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
519 fprintf(stderr, "ERROR: could not seek to signature block\n");
520 goto failure;
521 }
522
523 /* Get the number of signatures */
524 if (fread(&signatureCount, sizeof(signatureCount), 1, fpSrc) != 1) {
525 fprintf(stderr, "ERROR: could not read signature count\n");
526 goto failure;
527 }
528 signatureCount = ntohl(signatureCount);
529 if (sigIndex >= signatureCount) {
530 fprintf(stderr, "ERROR: Signature index was out of range\n");
531 goto failure;
532 }
533
534 /* Skip to the correct signature */
535 for (i = 0; i <= sigIndex; i++) {
536 /* skip past the signature algorithm ID */
537 if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
538 fprintf(stderr, "ERROR: Could not seek past sig algorithm ID.\n");
539 goto failure;
540 }
541
542 /* Get the signature length */
543 if (fread(&signatureLen, sizeof(signatureLen), 1, fpSrc) != 1) {
544 fprintf(stderr, "ERROR: could not read signature length\n");
545 goto failure;
546 }
547 signatureLen = ntohl(signatureLen);
548
549 /* Get the signature */
550 extractedSignature = malloc(signatureLen);
551 if (fread(extractedSignature, signatureLen, 1, fpSrc) != 1) {
552 fprintf(stderr, "ERROR: could not read signature\n");
553 goto failure;
554 }
555 }
556
557 base64Encoded = BTOA_DataToAscii(extractedSignature, signatureLen);
558 if (!base64Encoded) {
559 fprintf(stderr, "ERROR: could not obtain base64 encoded data\n");
560 goto failure;
561 }
562
563 if (fwrite(base64Encoded, strlen(base64Encoded), 1, fpDest) != 1) {
564 fprintf(stderr, "ERROR: Could not write base64 encoded string\n");
565 goto failure;
566 }
567
568 rv = 0;
569 failure:
570 if (base64Encoded) {
571 PORT_Free(base64Encoded);
572 }
573
574 if (extractedSignature) {
575 free(extractedSignature);
576 }
577
578 if (fpSrc) {
579 fclose(fpSrc);
580 }
581
582 if (fpDest) {
583 fclose(fpDest);
584 }
585
586 if (rv) {
587 remove(dest);
588 }
589
590 return rv;
591 }
592
593 /**
594 * Imports a base64 encoded signature into a MAR file
595 *
596 * @param src The path of the source MAR file
597 * @param sigIndex The index of the signature to import
598 * @param base64SigFile A file which contains the signature to import
599 * @param dest The path of the destination MAR file with replaced signature
600 * @return 0 on success
601 * -1 on error
602 */
603 int
604 import_signature(const char *src, uint32_t sigIndex,
605 const char *base64SigFile, const char *dest)
606 {
607 int rv = -1;
608 FILE *fpSrc = NULL;
609 FILE *fpDest = NULL;
610 FILE *fpSigFile = NULL;
611 uint32_t i;
612 uint32_t signatureCount, signatureLen, signatureAlgorithmID,
613 numChunks, leftOver;
614 char buf[BLOCKSIZE];
615 uint64_t sizeOfSrcMAR, sizeOfBase64EncodedFile;
616 char *passedInSignatureB64 = NULL;
617 uint8_t *passedInSignatureRaw = NULL;
618 uint8_t *extractedMARSignature = NULL;
619 unsigned int passedInSignatureLenRaw;
620
621 if (!src || !dest) {
622 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
623 goto failure;
624 }
625
626 fpSrc = fopen(src, "rb");
627 if (!fpSrc) {
628 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
629 goto failure;
630 }
631
632 fpDest = fopen(dest, "wb");
633 if (!fpDest) {
634 fprintf(stderr, "ERROR: could not open dest file: %s\n", dest);
635 goto failure;
636 }
637
638 fpSigFile = fopen(base64SigFile , "rb");
639 if (!fpSigFile) {
640 fprintf(stderr, "ERROR: could not open sig file: %s\n", base64SigFile);
641 goto failure;
642 }
643
644 /* Get the src file size */
645 if (fseeko(fpSrc, 0, SEEK_END)) {
646 fprintf(stderr, "ERROR: Could not seek to end of src file.\n");
647 goto failure;
648 }
649 sizeOfSrcMAR = ftello(fpSrc);
650 if (fseeko(fpSrc, 0, SEEK_SET)) {
651 fprintf(stderr, "ERROR: Could not seek to start of src file.\n");
652 goto failure;
653 }
654
655 /* Get the sig file size */
656 if (fseeko(fpSigFile, 0, SEEK_END)) {
657 fprintf(stderr, "ERROR: Could not seek to end of sig file.\n");
658 goto failure;
659 }
660 sizeOfBase64EncodedFile= ftello(fpSigFile);
661 if (fseeko(fpSigFile, 0, SEEK_SET)) {
662 fprintf(stderr, "ERROR: Could not seek to start of sig file.\n");
663 goto failure;
664 }
665
666 /* Read in the base64 encoded signature to import */
667 passedInSignatureB64 = malloc(sizeOfBase64EncodedFile + 1);
668 passedInSignatureB64[sizeOfBase64EncodedFile] = '\0';
669 if (fread(passedInSignatureB64, sizeOfBase64EncodedFile, 1, fpSigFile) != 1) {
670 fprintf(stderr, "ERROR: Could read b64 sig file.\n");
671 goto failure;
672 }
673
674 /* Decode the base64 encoded data */
675 passedInSignatureRaw = ATOB_AsciiToData(passedInSignatureB64, &passedInSignatureLenRaw);
676 if (!passedInSignatureRaw) {
677 fprintf(stderr, "ERROR: could not obtain base64 decoded data\n");
678 goto failure;
679 }
680
681 /* Read everything up until the signature block offset and write it out */
682 if (ReadAndWrite(fpSrc, fpDest, buf,
683 SIGNATURE_BLOCK_OFFSET, "signature block offset")) {
684 goto failure;
685 }
686
687 /* Get the number of signatures */
688 if (ReadAndWrite(fpSrc, fpDest, &signatureCount,
689 sizeof(signatureCount), "signature count")) {
690 goto failure;
691 }
692 signatureCount = ntohl(signatureCount);
693 if (signatureCount > MAX_SIGNATURES) {
694 fprintf(stderr, "ERROR: Signature count was out of range\n");
695 goto failure;
696 }
697
698 if (sigIndex >= signatureCount) {
699 fprintf(stderr, "ERROR: Signature index was out of range\n");
700 goto failure;
701 }
702
703 /* Read and write the whole signature block, but if we reach the
704 signature offset, then we should replace it with the specified
705 base64 decoded signature */
706 for (i = 0; i < signatureCount; i++) {
707 /* Read/Write the signature algorithm ID */
708 if (ReadAndWrite(fpSrc, fpDest,
709 &signatureAlgorithmID,
710 sizeof(signatureAlgorithmID), "sig algorithm ID")) {
711 goto failure;
712 }
713
714 /* Read/Write the signature length */
715 if (ReadAndWrite(fpSrc, fpDest,
716 &signatureLen, sizeof(signatureLen), "sig length")) {
717 goto failure;
718 }
719 signatureLen = ntohl(signatureLen);
720
721 /* Get the signature */
722 if (extractedMARSignature) {
723 free(extractedMARSignature);
724 }
725 extractedMARSignature = malloc(signatureLen);
726
727 if (sigIndex == i) {
728 if (passedInSignatureLenRaw != signatureLen) {
729 fprintf(stderr, "ERROR: Signature length must be the same\n");
730 goto failure;
731 }
732
733 if (fread(extractedMARSignature, signatureLen, 1, fpSrc) != 1) {
734 fprintf(stderr, "ERROR: Could not read signature\n");
735 goto failure;
736 }
737
738 if (fwrite(passedInSignatureRaw, passedInSignatureLenRaw,
739 1, fpDest) != 1) {
740 fprintf(stderr, "ERROR: Could not write signature\n");
741 goto failure;
742 }
743 } else {
744 if (ReadAndWrite(fpSrc, fpDest,
745 extractedMARSignature, signatureLen, "signature")) {
746 goto failure;
747 }
748 }
749 }
750
751 /* We replaced the signature so let's just skip past the rest o the
752 file. */
753 numChunks = (sizeOfSrcMAR - ftello(fpSrc)) / BLOCKSIZE;
754 leftOver = (sizeOfSrcMAR - ftello(fpSrc)) % BLOCKSIZE;
755
756 /* Read each file and write it to the MAR file */
757 for (i = 0; i < numChunks; ++i) {
758 if (ReadAndWrite(fpSrc, fpDest, buf, BLOCKSIZE, "content block")) {
759 goto failure;
760 }
761 }
762
763 if (ReadAndWrite(fpSrc, fpDest, buf, leftOver, "left over content block")) {
764 goto failure;
765 }
766
767 rv = 0;
768
769 failure:
770
771 if (fpSrc) {
772 fclose(fpSrc);
773 }
774
775 if (fpDest) {
776 fclose(fpDest);
777 }
778
779 if (fpSigFile) {
780 fclose(fpSigFile);
781 }
782
783 if (rv) {
784 remove(dest);
785 }
786
787 if (extractedMARSignature) {
788 free(extractedMARSignature);
789 }
790
791 if (passedInSignatureB64) {
792 free(passedInSignatureB64);
793 }
794
795 if (passedInSignatureRaw) {
796 PORT_Free(passedInSignatureRaw);
797 }
798
799 return rv;
800 }
801
802 /**
803 * Writes out a copy of the MAR at src but with embedded signatures.
804 * The passed in MAR file must not already be signed or an error will
805 * be returned.
806 *
807 * @param NSSConfigDir The NSS directory containing the private key for signing
808 * @param certNames The nicknames of the certificate to use for signing
809 * @param certCount The number of certificate names contained in certNames.
810 * One signature will be produced for each certificate.
811 * @param src The path of the source MAR file to sign
812 * @param dest The path of the MAR file to write out that is signed
813 * @return 0 on success
814 * -1 on error
815 */
816 int
817 mar_repackage_and_sign(const char *NSSConfigDir,
818 const char * const *certNames,
819 uint32_t certCount,
820 const char *src,
821 const char *dest)
822 {
823 uint32_t offsetToIndex, dstOffsetToIndex, indexLength,
824 numSignatures = 0, leftOver,
825 signatureAlgorithmID, signatureSectionLength = 0;
826 uint32_t signatureLengths[MAX_SIGNATURES];
827 int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR,
828 signaturePlaceholderOffset, numBytesToCopy,
829 numChunks, i;
830 FILE *fpSrc = NULL, *fpDest = NULL;
831 int rv = -1, hasSignatureBlock;
832 SGNContext *ctxs[MAX_SIGNATURES];
833 SECItem secItems[MAX_SIGNATURES];
834 char buf[BLOCKSIZE];
835 SECKEYPrivateKey *privKeys[MAX_SIGNATURES];
836 CERTCertificate *certs[MAX_SIGNATURES];
837 char *indexBuf = NULL, *indexBufLoc;
838 uint32_t k;
839
840 memset(signatureLengths, 0, sizeof(signatureLengths));
841 memset(ctxs, 0, sizeof(ctxs));
842 memset(secItems, 0, sizeof(secItems));
843 memset(privKeys, 0, sizeof(privKeys));
844 memset(certs, 0, sizeof(certs));
845
846 if (!NSSConfigDir || !certNames || certCount == 0 || !src || !dest) {
847 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
848 return -1;
849 }
850
851 if (NSSInitCryptoContext(NSSConfigDir)) {
852 fprintf(stderr, "ERROR: Could not init config dir: %s\n", NSSConfigDir);
853 goto failure;
854 }
855
856 PK11_SetPasswordFunc(SECU_GetModulePassword);
857
858 fpSrc = fopen(src, "rb");
859 if (!fpSrc) {
860 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
861 goto failure;
862 }
863
864 fpDest = fopen(dest, "wb");
865 if (!fpDest) {
866 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
867 goto failure;
868 }
869
870 /* Determine if the source MAR file has the new fields for signing or not */
871 if (get_mar_file_info(src, &hasSignatureBlock, NULL, NULL, NULL, NULL)) {
872 fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
873 goto failure;
874 }
875
876 for (k = 0; k < certCount; k++) {
877 if (NSSSignBegin(certNames[k], &ctxs[k], &privKeys[k],
878 &certs[k], &signatureLengths[k])) {
879 fprintf(stderr, "ERROR: NSSSignBegin failed\n");
880 goto failure;
881 }
882 }
883
884 /* MAR ID */
885 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest,
886 buf, MAR_ID_SIZE,
887 ctxs, certCount, "MAR ID")) {
888 goto failure;
889 }
890
891 /* Offset to index */
892 if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
893 fprintf(stderr, "ERROR: Could not read offset\n");
894 goto failure;
895 }
896 offsetToIndex = ntohl(offsetToIndex);
897
898 /* Get the real size of the MAR */
899 oldPos = ftello(fpSrc);
900 if (fseeko(fpSrc, 0, SEEK_END)) {
901 fprintf(stderr, "ERROR: Could not seek to end of file.\n");
902 goto failure;
903 }
904 realSizeOfSrcMAR = ftello(fpSrc);
905 if (fseeko(fpSrc, oldPos, SEEK_SET)) {
906 fprintf(stderr, "ERROR: Could not seek back to current location.\n");
907 goto failure;
908 }
909
910 if (hasSignatureBlock) {
911 /* Get the MAR length and adjust its size */
912 if (fread(&sizeOfEntireMAR,
913 sizeof(sizeOfEntireMAR), 1, fpSrc) != 1) {
914 fprintf(stderr, "ERROR: Could read mar size\n");
915 goto failure;
916 }
917 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
918 if (sizeOfEntireMAR != realSizeOfSrcMAR) {
919 fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
920 goto failure;
921 }
922
923 /* Get the num signatures in the source file */
924 if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
925 fprintf(stderr, "ERROR: Could read num signatures\n");
926 goto failure;
927 }
928 numSignatures = ntohl(numSignatures);
929
930 /* We do not support resigning, if you have multiple signatures,
931 you must add them all at the same time. */
932 if (numSignatures) {
933 fprintf(stderr, "ERROR: MAR is already signed\n");
934 goto failure;
935 }
936 } else {
937 sizeOfEntireMAR = realSizeOfSrcMAR;
938 }
939
940 if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
941 fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
942 goto failure;
943 }
944
945 /* Calculate the total signature block length */
946 for (k = 0; k < certCount; k++) {
947 signatureSectionLength += sizeof(signatureAlgorithmID) +
948 sizeof(signatureLengths[k]) +
949 signatureLengths[k];
950 }
951 dstOffsetToIndex = offsetToIndex;
952 if (!hasSignatureBlock) {
953 dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
954 }
955 dstOffsetToIndex += signatureSectionLength;
956
957 /* Write out the index offset */
958 dstOffsetToIndex = htonl(dstOffsetToIndex);
959 if (WriteAndUpdateSignatures(fpDest, &dstOffsetToIndex,
960 sizeof(dstOffsetToIndex), ctxs, certCount,
961 "index offset")) {
962 goto failure;
963 }
964 dstOffsetToIndex = ntohl(dstOffsetToIndex);
965
966 /* Write out the new MAR file size */
967 sizeOfEntireMAR += signatureSectionLength;
968 if (!hasSignatureBlock) {
969 sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
970 }
971
972 /* Write out the MAR size */
973 sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
974 if (WriteAndUpdateSignatures(fpDest, &sizeOfEntireMAR,
975 sizeof(sizeOfEntireMAR), ctxs, certCount,
976 "size of MAR")) {
977 goto failure;
978 }
979 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
980
981 /* Write out the number of signatures */
982 numSignatures = certCount;
983 numSignatures = htonl(numSignatures);
984 if (WriteAndUpdateSignatures(fpDest, &numSignatures,
985 sizeof(numSignatures), ctxs, certCount,
986 "num signatures")) {
987 goto failure;
988 }
989 numSignatures = ntohl(numSignatures);
990
991 signaturePlaceholderOffset = ftello(fpDest);
992
993 for (k = 0; k < certCount; k++) {
994 /* Write out the signature algorithm ID, Only an ID of 1 is supported */
995 signatureAlgorithmID = htonl(1);
996 if (WriteAndUpdateSignatures(fpDest, &signatureAlgorithmID,
997 sizeof(signatureAlgorithmID),
998 ctxs, certCount, "num signatures")) {
999 goto failure;
1000 }
1001 signatureAlgorithmID = ntohl(signatureAlgorithmID);
1002
1003 /* Write out the signature length */
1004 signatureLengths[k] = htonl(signatureLengths[k]);
1005 if (WriteAndUpdateSignatures(fpDest, &signatureLengths[k],
1006 sizeof(signatureLengths[k]),
1007 ctxs, certCount, "signature length")) {
1008 goto failure;
1009 }
1010 signatureLengths[k] = ntohl(signatureLengths[k]);
1011
1012 /* Write out a placeholder for the signature, we'll come back to this later
1013 *** THIS IS NOT SIGNED because it is a placeholder that will be replaced
1014 below, plus it is going to be the signature itself. *** */
1015 memset(buf, 0, sizeof(buf));
1016 if (fwrite(buf, signatureLengths[k], 1, fpDest) != 1) {
1017 fprintf(stderr, "ERROR: Could not write signature length\n");
1018 goto failure;
1019 }
1020 }
1021
1022 /* Write out the rest of the MAR excluding the index header and index
1023 offsetToIndex unfortunately has to remain 32-bit because for backwards
1024 compatibility with the old MAR file format. */
1025 if (ftello(fpSrc) > ((int64_t)offsetToIndex)) {
1026 fprintf(stderr, "ERROR: Index offset is too small.\n");
1027 goto failure;
1028 }
1029 numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
1030 numChunks = numBytesToCopy / BLOCKSIZE;
1031 leftOver = numBytesToCopy % BLOCKSIZE;
1032
1033 /* Read each file and write it to the MAR file */
1034 for (i = 0; i < numChunks; ++i) {
1035 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
1036 BLOCKSIZE, ctxs, certCount,
1037 "content block")) {
1038 goto failure;
1039 }
1040 }
1041
1042 /* Write out the left over */
1043 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
1044 leftOver, ctxs, certCount,
1045 "left over content block")) {
1046 goto failure;
1047 }
1048
1049 /* Length of the index */
1050 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, &indexLength,
1051 sizeof(indexLength), ctxs, certCount,
1052 "index length")) {
1053 goto failure;
1054 }
1055 indexLength = ntohl(indexLength);
1056
1057 /* Consume the index and adjust each index by signatureSectionLength */
1058 indexBuf = malloc(indexLength);
1059 indexBufLoc = indexBuf;
1060 if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
1061 fprintf(stderr, "ERROR: Could not read index\n");
1062 goto failure;
1063 }
1064
1065 /* Adjust each entry in the index */
1066 if (hasSignatureBlock) {
1067 AdjustIndexContentOffsets(indexBuf, indexLength, signatureSectionLength);
1068 } else {
1069 AdjustIndexContentOffsets(indexBuf, indexLength,
1070 sizeof(sizeOfEntireMAR) +
1071 sizeof(numSignatures) +
1072 signatureSectionLength);
1073 }
1074
1075 if (WriteAndUpdateSignatures(fpDest, indexBuf,
1076 indexLength, ctxs, certCount, "index")) {
1077 goto failure;
1078 }
1079
1080 /* Ensure that we don't sign a file that is too large to be accepted by
1081 the verification function. */
1082 if (ftello(fpDest) > MAX_SIZE_OF_MAR_FILE) {
1083 goto failure;
1084 }
1085
1086 for (k = 0; k < certCount; k++) {
1087 /* Get the signature */
1088 if (SGN_End(ctxs[k], &secItems[k]) != SECSuccess) {
1089 fprintf(stderr, "ERROR: Could not end signature context\n");
1090 goto failure;
1091 }
1092 if (signatureLengths[k] != secItems[k].len) {
1093 fprintf(stderr, "ERROR: Signature is not the expected length\n");
1094 goto failure;
1095 }
1096 }
1097
1098 /* Get back to the location of the signature placeholder */
1099 if (fseeko(fpDest, signaturePlaceholderOffset, SEEK_SET)) {
1100 fprintf(stderr, "ERROR: Could not seek to signature offset\n");
1101 goto failure;
1102 }
1103
1104 for (k = 0; k < certCount; k++) {
1105 /* Skip to the position of the next signature */
1106 if (fseeko(fpDest, sizeof(signatureAlgorithmID) +
1107 sizeof(signatureLengths[k]), SEEK_CUR)) {
1108 fprintf(stderr, "ERROR: Could not seek to signature offset\n");
1109 goto failure;
1110 }
1111
1112 /* Write out the calculated signature.
1113 *** THIS IS NOT SIGNED because it is the signature itself. *** */
1114 if (fwrite(secItems[k].data, secItems[k].len, 1, fpDest) != 1) {
1115 fprintf(stderr, "ERROR: Could not write signature\n");
1116 goto failure;
1117 }
1118 }
1119
1120 rv = 0;
1121 failure:
1122 if (fpSrc) {
1123 fclose(fpSrc);
1124 }
1125
1126 if (fpDest) {
1127 fclose(fpDest);
1128 }
1129
1130 if (rv) {
1131 remove(dest);
1132 }
1133
1134 if (indexBuf) {
1135 free(indexBuf);
1136 }
1137
1138 /* Cleanup */
1139 for (k = 0; k < certCount; k++) {
1140 if (ctxs[k]) {
1141 SGN_DestroyContext(ctxs[k], PR_TRUE);
1142 }
1143
1144 if (certs[k]) {
1145 CERT_DestroyCertificate(certs[k]);
1146 }
1147
1148 if (privKeys[k]) {
1149 SECKEY_DestroyPrivateKey(privKeys[k]);
1150 }
1151
1152 SECITEM_FreeItem(&secItems[k], PR_FALSE);
1153 }
1154
1155 if (rv) {
1156 remove(dest);
1157 }
1158
1159 return rv;
1160 }

mercurial