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>
16 #include <onlineupdate/mar_private.h>
17 #include <onlineupdate/mar_cmdline.h>
18 #include <onlineupdate/mar.h>
24 #include "nss_secutil.h"
28 * Initializes the NSS context.
30 * @param NSSConfigDir The config dir containing the private key to use
31 * @return 0 on success
35 NSSInitCryptoContext(const char *NSSConfigDir
)
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");
48 * Obtains a signing context.
50 * @param ctx A pointer to the signing context to fill
51 * @return 0 on success
55 NSSSignBegin(const char *certName
,
57 SECKEYPrivateKey
**privKey
,
58 CERTCertificate
**cert
,
59 uint32_t *signatureLength
)
61 secuPWData pwdata
= { PW_NONE
, 0 };
62 if (!certName
|| !ctx
|| !privKey
|| !cert
|| !signatureLength
) {
63 fprintf(stderr
, "ERROR: Invalid parameter passed to NSSSignBegin\n");
67 /* Get the cert and embedded public key out of the database */
68 *cert
= PK11_FindCertFromNickname(certName
, &pwdata
);
70 fprintf(stderr
, "ERROR: Could not find cert from nickname\n");
74 /* Get the private key out of the database */
75 *privKey
= PK11_FindKeyByAnyCert(*cert
, &pwdata
);
77 fprintf(stderr
, "ERROR: Could not find private key\n");
81 *signatureLength
= PK11_SignatureLen(*privKey
);
83 if (*signatureLength
> BLOCKSIZE
) {
85 "ERROR: Program must be compiled with a larger block size"
86 " to support signing with signatures this large: %u.\n",
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
);
98 *ctx
= SGN_NewContext (SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE
, *privKey
);
100 fprintf(stderr
, "ERROR: Could not create signature context\n");
104 if (SGN_Begin(*ctx
) != SECSuccess
) {
105 fprintf(stderr
, "ERROR: Could not begin signature\n");
113 * Writes the passed buffer to the file fp and updates the signature contexts.
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
124 * -3 on signature update error
127 WriteAndUpdateSignatures(FILE *fpDest
, void *buffer
,
128 uint32_t size
, SGNContext
**ctxs
,
137 if (fwrite(buffer
, size
, 1, fpDest
) != 1) {
138 fprintf(stderr
, "ERROR: Could not write %s\n", err
);
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
);
152 * Adjusts each entry's content offset in the passed in index by the
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
160 AdjustIndexContentOffsets(char *indexBuf
, uint32_t indexLength
, uint32_t offsetAmount
)
162 char *indexBufLoc
= indexBuf
;
164 /* Consume the index and adjust each index by the specified amount */
165 while (indexBufLoc
!= (indexBuf
+ indexLength
)) {
166 /* Adjust the offset */
167 uint32_t* offsetToContent
= (uint32_t *)indexBufLoc
;
168 *offsetToContent
= ntohl(*offsetToContent
);
169 *offsetToContent
+= offsetAmount
;
170 *offsetToContent
= htonl(*offsetToContent
);
171 /* Skip past the offset, length, and flags */
172 indexBufLoc
+= 3 * sizeof(uint32_t);
173 indexBufLoc
+= strlen(indexBufLoc
) + 1;
178 * Reads from fpSrc, writes it to fpDest, and updates the signature contexts.
180 * @param fpSrc The file pointer to read from.
181 * @param fpDest The file pointer to write to.
182 * @param buffer The buffer to write.
183 * @param size The size of the buffer to write.
184 * @param ctxs Pointer to the first element in an array of signature
185 * contexts to update.
186 * @param ctxCount The number of signature contexts pointed to by ctxs
187 * @param err The name of what is being written to in case of error.
188 * @return 0 on success
191 * -3 on signature update error
194 ReadWriteAndUpdateSignatures(FILE *fpSrc
, FILE *fpDest
, void *buffer
,
195 uint32_t size
, SGNContext
**ctxs
,
203 if (fread(buffer
, size
, 1, fpSrc
) != 1) {
204 fprintf(stderr
, "ERROR: Could not read %s\n", err
);
208 return WriteAndUpdateSignatures(fpDest
, buffer
, size
, ctxs
, ctxCount
, err
);
213 * Reads from fpSrc, writes it to fpDest.
215 * @param fpSrc The file pointer to read from.
216 * @param fpDest The file pointer to write to.
217 * @param buffer The buffer to write.
218 * @param size The size of the buffer to write.
219 * @param err The name of what is being written to in case of error.
220 * @return 0 on success
225 ReadAndWrite(FILE *fpSrc
, FILE *fpDest
, void *buffer
,
226 uint32_t size
, const char *err
)
232 if (fread(buffer
, size
, 1, fpSrc
) != 1) {
233 fprintf(stderr
, "ERROR: Could not read %s\n", err
);
237 if (fwrite(buffer
, size
, 1, fpDest
) != 1) {
238 fprintf(stderr
, "ERROR: Could not write %s\n", err
);
246 * Writes out a copy of the MAR at src but with the signature block stripped.
248 * @param src The path of the source MAR file
249 * @param dest The path of the MAR file to write out that
250 has no signature block
251 * @return 0 on success
255 strip_signature_block(const char *src
, const char * dest
)
257 uint32_t offsetToIndex
, dstOffsetToIndex
, indexLength
,
258 numSignatures
= 0, leftOver
;
259 int32_t stripAmount
= 0;
260 int64_t oldPos
, sizeOfEntireMAR
= 0, realSizeOfSrcMAR
, numBytesToCopy
,
262 FILE *fpSrc
= NULL
, *fpDest
= NULL
;
263 int rv
= -1, hasSignatureBlock
;
265 char *indexBuf
= NULL
;
268 fprintf(stderr
, "ERROR: Invalid parameter passed in.\n");
272 fpSrc
= fopen(src
, "rb");
274 fprintf(stderr
, "ERROR: could not open source file: %s\n", src
);
278 fpDest
= fopen(dest
, "wb");
280 fprintf(stderr
, "ERROR: could not create target file: %s\n", dest
);
284 /* Determine if the source MAR file has the new fields for signing or not */
285 if (get_mar_file_info(src
, &hasSignatureBlock
, NULL
, NULL
, NULL
, NULL
)) {
286 fprintf(stderr
, "ERROR: could not determine if MAR is old or new.\n");
291 if (ReadAndWrite(fpSrc
, fpDest
, buf
, MAR_ID_SIZE
, "MAR ID")) {
295 /* Offset to index */
296 if (fread(&offsetToIndex
, sizeof(offsetToIndex
), 1, fpSrc
) != 1) {
297 fprintf(stderr
, "ERROR: Could not read offset\n");
300 offsetToIndex
= ntohl(offsetToIndex
);
302 /* Get the real size of the MAR */
303 oldPos
= ftello(fpSrc
);
304 if (fseeko(fpSrc
, 0, SEEK_END
)) {
305 fprintf(stderr
, "ERROR: Could not seek to end of file.\n");
308 realSizeOfSrcMAR
= ftello(fpSrc
);
309 if (fseeko(fpSrc
, oldPos
, SEEK_SET
)) {
310 fprintf(stderr
, "ERROR: Could not seek back to current location.\n");
314 if (hasSignatureBlock
) {
315 /* Get the MAR length and adjust its size */
316 if (fread(&sizeOfEntireMAR
,
317 sizeof(sizeOfEntireMAR
), 1, fpSrc
) != 1) {
318 fprintf(stderr
, "ERROR: Could read mar size\n");
321 sizeOfEntireMAR
= NETWORK_TO_HOST64(sizeOfEntireMAR
);
322 if (sizeOfEntireMAR
!= realSizeOfSrcMAR
) {
323 fprintf(stderr
, "ERROR: Source MAR is not of the right size\n");
327 /* Get the num signatures in the source file so we know what to strip */
328 if (fread(&numSignatures
, sizeof(numSignatures
), 1, fpSrc
) != 1) {
329 fprintf(stderr
, "ERROR: Could read num signatures\n");
332 numSignatures
= ntohl(numSignatures
);
334 for (i
= 0; i
< numSignatures
; i
++) {
335 uint32_t signatureLen
;
337 /* Skip past the signature algorithm ID */
338 if (fseeko(fpSrc
, sizeof(uint32_t), SEEK_CUR
)) {
339 fprintf(stderr
, "ERROR: Could not skip past signature algorithm ID\n");
342 /* Read in the length of the signature so we know how far to skip */
343 if (fread(&signatureLen
, sizeof(uint32_t), 1, fpSrc
) != 1) {
344 fprintf(stderr
, "ERROR: Could not read signatures length.\n");
345 return CryptoX_Error
;
347 signatureLen
= ntohl(signatureLen
);
349 /* Skip past the signature */
350 if (fseeko(fpSrc
, signatureLen
, SEEK_CUR
)) {
351 fprintf(stderr
, "ERROR: Could not skip past signature algorithm ID\n");
354 stripAmount
+= sizeof(uint32_t) + sizeof(uint32_t) + signatureLen
;
358 sizeOfEntireMAR
= realSizeOfSrcMAR
;
362 if (((int64_t)offsetToIndex
) > sizeOfEntireMAR
) {
363 fprintf(stderr
, "ERROR: Offset to index is larger than the file size.\n");
367 dstOffsetToIndex
= offsetToIndex
;
368 if (!hasSignatureBlock
) {
369 dstOffsetToIndex
+= sizeof(sizeOfEntireMAR
) + sizeof(numSignatures
);
371 dstOffsetToIndex
-= stripAmount
;
373 /* Write out the index offset */
374 dstOffsetToIndex
= htonl(dstOffsetToIndex
);
375 if (fwrite(&dstOffsetToIndex
, sizeof(dstOffsetToIndex
), 1, fpDest
) != 1) {
376 fprintf(stderr
, "ERROR: Could not write offset to index\n");
379 dstOffsetToIndex
= ntohl(dstOffsetToIndex
);
381 /* Write out the new MAR file size */
382 if (!hasSignatureBlock
) {
383 sizeOfEntireMAR
+= sizeof(sizeOfEntireMAR
) + sizeof(numSignatures
);
385 sizeOfEntireMAR
-= stripAmount
;
387 /* Write out the MAR size */
388 sizeOfEntireMAR
= HOST_TO_NETWORK64(sizeOfEntireMAR
);
389 if (fwrite(&sizeOfEntireMAR
, sizeof(sizeOfEntireMAR
), 1, fpDest
) != 1) {
390 fprintf(stderr
, "ERROR: Could not write size of MAR\n");
393 sizeOfEntireMAR
= NETWORK_TO_HOST64(sizeOfEntireMAR
);
395 /* Write out the number of signatures, which is 0 */
397 if (fwrite(&numSignatures
, sizeof(numSignatures
), 1, fpDest
) != 1) {
398 fprintf(stderr
, "ERROR: Could not write out num signatures\n");
402 /* Write out the rest of the MAR excluding the index header and index
403 offsetToIndex unfortunately has to remain 32-bit because for backwards
404 compatibility with the old MAR file format. */
405 if (ftello(fpSrc
) > ((int64_t)offsetToIndex
)) {
406 fprintf(stderr
, "ERROR: Index offset is too small.\n");
409 numBytesToCopy
= ((int64_t)offsetToIndex
) - ftello(fpSrc
);
410 numChunks
= numBytesToCopy
/ BLOCKSIZE
;
411 leftOver
= numBytesToCopy
% BLOCKSIZE
;
413 /* Read each file and write it to the MAR file */
414 for (i
= 0; i
< numChunks
; ++i
) {
415 if (ReadAndWrite(fpSrc
, fpDest
, buf
, BLOCKSIZE
, "content block")) {
420 /* Write out the left over */
421 if (ReadAndWrite(fpSrc
, fpDest
, buf
,
422 leftOver
, "left over content block")) {
426 /* Length of the index */
427 if (ReadAndWrite(fpSrc
, fpDest
, &indexLength
,
428 sizeof(indexLength
), "index length")) {
431 indexLength
= ntohl(indexLength
);
433 /* Consume the index and adjust each index by the difference */
434 indexBuf
= malloc(indexLength
);
435 if (fread(indexBuf
, indexLength
, 1, fpSrc
) != 1) {
436 fprintf(stderr
, "ERROR: Could not read index\n");
440 /* Adjust each entry in the index */
441 if (hasSignatureBlock
) {
442 AdjustIndexContentOffsets(indexBuf
, indexLength
, -stripAmount
);
444 AdjustIndexContentOffsets(indexBuf
, indexLength
,
445 sizeof(sizeOfEntireMAR
) +
446 sizeof(numSignatures
) -
450 if (fwrite(indexBuf
, indexLength
, 1, fpDest
) != 1) {
451 fprintf(stderr
, "ERROR: Could not write index\n");
480 * Extracts a signature from a MAR file, base64 encodes it, and writes it out
482 * @param src The path of the source MAR file
483 * @param sigIndex The index of the signature to extract
484 * @param dest The path of file to write the signature to
485 * @return 0 on success
489 extract_signature(const char *src
, uint32_t sigIndex
, const char * dest
)
491 FILE *fpSrc
= NULL
, *fpDest
= NULL
;
493 uint32_t signatureCount
;
494 uint32_t signatureLen
= 0;
495 uint8_t *extractedSignature
= NULL
;
496 char *base64Encoded
= NULL
;
499 fprintf(stderr
, "ERROR: Invalid parameter passed in.\n");
503 fpSrc
= fopen(src
, "rb");
505 fprintf(stderr
, "ERROR: could not open source file: %s\n", src
);
509 fpDest
= fopen(dest
, "wb");
511 fprintf(stderr
, "ERROR: could not create target file: %s\n", dest
);
515 /* Skip to the start of the signature block */
516 if (fseeko(fpSrc
, SIGNATURE_BLOCK_OFFSET
, SEEK_SET
)) {
517 fprintf(stderr
, "ERROR: could not seek to signature block\n");
521 /* Get the number of signatures */
522 if (fread(&signatureCount
, sizeof(signatureCount
), 1, fpSrc
) != 1) {
523 fprintf(stderr
, "ERROR: could not read signature count\n");
526 signatureCount
= ntohl(signatureCount
);
527 if (sigIndex
>= signatureCount
) {
528 fprintf(stderr
, "ERROR: Signature index was out of range\n");
532 /* Skip to the correct signature */
533 for (i
= 0; i
<= sigIndex
; i
++) {
534 /* Avoid leaking while skipping signatures */
535 free(extractedSignature
);
537 /* skip past the signature algorithm ID */
538 if (fseeko(fpSrc
, sizeof(uint32_t), SEEK_CUR
)) {
539 fprintf(stderr
, "ERROR: Could not seek past sig algorithm ID.\n");
543 /* Get the signature length */
544 if (fread(&signatureLen
, sizeof(signatureLen
), 1, fpSrc
) != 1) {
545 fprintf(stderr
, "ERROR: could not read signature length\n");
548 signatureLen
= ntohl(signatureLen
);
550 /* Get the signature */
551 extractedSignature
= malloc(signatureLen
);
552 if (fread(extractedSignature
, signatureLen
, 1, fpSrc
) != 1) {
553 fprintf(stderr
, "ERROR: could not read signature\n");
558 base64Encoded
= BTOA_DataToAscii(extractedSignature
, signatureLen
);
559 if (!base64Encoded
) {
560 fprintf(stderr
, "ERROR: could not obtain base64 encoded data\n");
564 if (fwrite(base64Encoded
, strlen(base64Encoded
), 1, fpDest
) != 1) {
565 fprintf(stderr
, "ERROR: Could not write base64 encoded string\n");
572 PORT_Free(base64Encoded
);
575 if (extractedSignature
) {
576 free(extractedSignature
);
595 * Imports a base64 encoded signature into a MAR file
597 * @param src The path of the source MAR file
598 * @param sigIndex The index of the signature to import
599 * @param base64SigFile A file which contains the signature to import
600 * @param dest The path of the destination MAR file with replaced signature
601 * @return 0 on success
605 import_signature(const char *src
, uint32_t sigIndex
,
606 const char *base64SigFile
, const char *dest
)
611 FILE *fpSigFile
= NULL
;
613 uint32_t signatureCount
, signatureLen
, signatureAlgorithmID
,
616 uint64_t sizeOfSrcMAR
, sizeOfBase64EncodedFile
;
617 char *passedInSignatureB64
= NULL
;
618 uint8_t *passedInSignatureRaw
= NULL
;
619 uint8_t *extractedMARSignature
= NULL
;
620 unsigned int passedInSignatureLenRaw
;
623 fprintf(stderr
, "ERROR: Invalid parameter passed in.\n");
627 fpSrc
= fopen(src
, "rb");
629 fprintf(stderr
, "ERROR: could not open source file: %s\n", src
);
633 fpDest
= fopen(dest
, "wb");
635 fprintf(stderr
, "ERROR: could not open dest file: %s\n", dest
);
639 fpSigFile
= fopen(base64SigFile
, "rb");
641 fprintf(stderr
, "ERROR: could not open sig file: %s\n", base64SigFile
);
645 /* Get the src file size */
646 if (fseeko(fpSrc
, 0, SEEK_END
)) {
647 fprintf(stderr
, "ERROR: Could not seek to end of src file.\n");
650 sizeOfSrcMAR
= ftello(fpSrc
);
651 if (fseeko(fpSrc
, 0, SEEK_SET
)) {
652 fprintf(stderr
, "ERROR: Could not seek to start of src file.\n");
656 /* Get the sig file size */
657 if (fseeko(fpSigFile
, 0, SEEK_END
)) {
658 fprintf(stderr
, "ERROR: Could not seek to end of sig file.\n");
661 sizeOfBase64EncodedFile
= ftello(fpSigFile
);
662 if (fseeko(fpSigFile
, 0, SEEK_SET
)) {
663 fprintf(stderr
, "ERROR: Could not seek to start of sig file.\n");
667 /* Read in the base64 encoded signature to import */
668 passedInSignatureB64
= malloc(sizeOfBase64EncodedFile
+ 1);
669 passedInSignatureB64
[sizeOfBase64EncodedFile
] = '\0';
670 if (fread(passedInSignatureB64
, sizeOfBase64EncodedFile
, 1, fpSigFile
) != 1) {
671 fprintf(stderr
, "ERROR: Could read b64 sig file.\n");
675 /* Decode the base64 encoded data */
676 passedInSignatureRaw
= ATOB_AsciiToData(passedInSignatureB64
, &passedInSignatureLenRaw
);
677 if (!passedInSignatureRaw
) {
678 fprintf(stderr
, "ERROR: could not obtain base64 decoded data\n");
682 /* Read everything up until the signature block offset and write it out */
683 if (ReadAndWrite(fpSrc
, fpDest
, buf
,
684 SIGNATURE_BLOCK_OFFSET
, "signature block offset")) {
688 /* Get the number of signatures */
689 if (ReadAndWrite(fpSrc
, fpDest
, &signatureCount
,
690 sizeof(signatureCount
), "signature count")) {
693 signatureCount
= ntohl(signatureCount
);
694 if (signatureCount
> MAX_SIGNATURES
) {
695 fprintf(stderr
, "ERROR: Signature count was out of range\n");
699 if (sigIndex
>= signatureCount
) {
700 fprintf(stderr
, "ERROR: Signature index was out of range\n");
704 /* Read and write the whole signature block, but if we reach the
705 signature offset, then we should replace it with the specified
706 base64 decoded signature */
707 for (i
= 0; i
< signatureCount
; i
++) {
708 /* Read/Write the signature algorithm ID */
709 if (ReadAndWrite(fpSrc
, fpDest
,
710 &signatureAlgorithmID
,
711 sizeof(signatureAlgorithmID
), "sig algorithm ID")) {
715 /* Read/Write the signature length */
716 if (ReadAndWrite(fpSrc
, fpDest
,
717 &signatureLen
, sizeof(signatureLen
), "sig length")) {
720 signatureLen
= ntohl(signatureLen
);
722 /* Get the signature */
723 if (extractedMARSignature
) {
724 free(extractedMARSignature
);
726 extractedMARSignature
= malloc(signatureLen
);
729 if (passedInSignatureLenRaw
!= signatureLen
) {
730 fprintf(stderr
, "ERROR: Signature length must be the same\n");
734 if (fread(extractedMARSignature
, signatureLen
, 1, fpSrc
) != 1) {
735 fprintf(stderr
, "ERROR: Could not read signature\n");
739 if (fwrite(passedInSignatureRaw
, passedInSignatureLenRaw
,
741 fprintf(stderr
, "ERROR: Could not write signature\n");
745 if (ReadAndWrite(fpSrc
, fpDest
,
746 extractedMARSignature
, signatureLen
, "signature")) {
752 /* We replaced the signature so let's just skip past the rest o the
754 numChunks
= (sizeOfSrcMAR
- ftello(fpSrc
)) / BLOCKSIZE
;
755 leftOver
= (sizeOfSrcMAR
- ftello(fpSrc
)) % BLOCKSIZE
;
757 /* Read each file and write it to the MAR file */
758 for (i
= 0; i
< numChunks
; ++i
) {
759 if (ReadAndWrite(fpSrc
, fpDest
, buf
, BLOCKSIZE
, "content block")) {
764 if (ReadAndWrite(fpSrc
, fpDest
, buf
, leftOver
, "left over content block")) {
788 if (extractedMARSignature
) {
789 free(extractedMARSignature
);
792 if (passedInSignatureB64
) {
793 free(passedInSignatureB64
);
796 if (passedInSignatureRaw
) {
797 PORT_Free(passedInSignatureRaw
);
804 * Writes out a copy of the MAR at src but with embedded signatures.
805 * The passed in MAR file must not already be signed or an error will
808 * @param NSSConfigDir The NSS directory containing the private key for signing
809 * @param certNames The nicknames of the certificate to use for signing
810 * @param certCount The number of certificate names contained in certNames.
811 * One signature will be produced for each certificate.
812 * @param src The path of the source MAR file to sign
813 * @param dest The path of the MAR file to write out that is signed
814 * @return 0 on success
818 mar_repackage_and_sign(const char *NSSConfigDir
,
819 const char * const *certNames
,
824 uint32_t offsetToIndex
, dstOffsetToIndex
, indexLength
,
825 numSignatures
= 0, leftOver
,
826 signatureAlgorithmID
, signatureSectionLength
= 0;
827 uint32_t signatureLengths
[MAX_SIGNATURES
];
828 int64_t oldPos
, sizeOfEntireMAR
= 0, realSizeOfSrcMAR
,
829 signaturePlaceholderOffset
, numBytesToCopy
,
831 FILE *fpSrc
= NULL
, *fpDest
= NULL
;
832 int rv
= -1, hasSignatureBlock
;
833 SGNContext
*ctxs
[MAX_SIGNATURES
];
834 SECItem secItems
[MAX_SIGNATURES
];
836 SECKEYPrivateKey
*privKeys
[MAX_SIGNATURES
];
837 CERTCertificate
*certs
[MAX_SIGNATURES
];
838 char *indexBuf
= NULL
;
841 memset(signatureLengths
, 0, sizeof(signatureLengths
));
842 memset(ctxs
, 0, sizeof(ctxs
));
843 memset(secItems
, 0, sizeof(secItems
));
844 memset(privKeys
, 0, sizeof(privKeys
));
845 memset(certs
, 0, sizeof(certs
));
847 if (!NSSConfigDir
|| !certNames
|| certCount
== 0 || !src
|| !dest
) {
848 fprintf(stderr
, "ERROR: Invalid parameter passed in.\n");
852 if (NSSInitCryptoContext(NSSConfigDir
)) {
853 fprintf(stderr
, "ERROR: Could not init config dir: %s\n", NSSConfigDir
);
857 PK11_SetPasswordFunc(SECU_GetModulePassword
);
859 fpSrc
= fopen(src
, "rb");
861 fprintf(stderr
, "ERROR: could not open source file: %s\n", src
);
865 fpDest
= fopen(dest
, "wb");
867 fprintf(stderr
, "ERROR: could not create target file: %s\n", dest
);
871 /* Determine if the source MAR file has the new fields for signing or not */
872 if (get_mar_file_info(src
, &hasSignatureBlock
, NULL
, NULL
, NULL
, NULL
)) {
873 fprintf(stderr
, "ERROR: could not determine if MAR is old or new.\n");
877 for (k
= 0; k
< certCount
; k
++) {
878 if (NSSSignBegin(certNames
[k
], &ctxs
[k
], &privKeys
[k
],
879 &certs
[k
], &signatureLengths
[k
])) {
880 fprintf(stderr
, "ERROR: NSSSignBegin failed\n");
886 if (ReadWriteAndUpdateSignatures(fpSrc
, fpDest
,
888 ctxs
, certCount
, "MAR ID")) {
892 /* Offset to index */
893 if (fread(&offsetToIndex
, sizeof(offsetToIndex
), 1, fpSrc
) != 1) {
894 fprintf(stderr
, "ERROR: Could not read offset\n");
897 offsetToIndex
= ntohl(offsetToIndex
);
899 /* Get the real size of the MAR */
900 oldPos
= ftello(fpSrc
);
901 if (fseeko(fpSrc
, 0, SEEK_END
)) {
902 fprintf(stderr
, "ERROR: Could not seek to end of file.\n");
905 realSizeOfSrcMAR
= ftello(fpSrc
);
906 if (fseeko(fpSrc
, oldPos
, SEEK_SET
)) {
907 fprintf(stderr
, "ERROR: Could not seek back to current location.\n");
911 if (hasSignatureBlock
) {
912 /* Get the MAR length and adjust its size */
913 if (fread(&sizeOfEntireMAR
,
914 sizeof(sizeOfEntireMAR
), 1, fpSrc
) != 1) {
915 fprintf(stderr
, "ERROR: Could read mar size\n");
918 sizeOfEntireMAR
= NETWORK_TO_HOST64(sizeOfEntireMAR
);
919 if (sizeOfEntireMAR
!= realSizeOfSrcMAR
) {
920 fprintf(stderr
, "ERROR: Source MAR is not of the right size\n");
924 /* Get the num signatures in the source file */
925 if (fread(&numSignatures
, sizeof(numSignatures
), 1, fpSrc
) != 1) {
926 fprintf(stderr
, "ERROR: Could read num signatures\n");
929 numSignatures
= ntohl(numSignatures
);
931 /* We do not support resigning, if you have multiple signatures,
932 you must add them all at the same time. */
934 fprintf(stderr
, "ERROR: MAR is already signed\n");
938 sizeOfEntireMAR
= realSizeOfSrcMAR
;
941 if (((int64_t)offsetToIndex
) > sizeOfEntireMAR
) {
942 fprintf(stderr
, "ERROR: Offset to index is larger than the file size.\n");
946 /* Calculate the total signature block length */
947 for (k
= 0; k
< certCount
; k
++) {
948 signatureSectionLength
+= sizeof(signatureAlgorithmID
) +
949 sizeof(signatureLengths
[k
]) +
952 dstOffsetToIndex
= offsetToIndex
;
953 if (!hasSignatureBlock
) {
954 dstOffsetToIndex
+= sizeof(sizeOfEntireMAR
) + sizeof(numSignatures
);
956 dstOffsetToIndex
+= signatureSectionLength
;
958 /* Write out the index offset */
959 dstOffsetToIndex
= htonl(dstOffsetToIndex
);
960 if (WriteAndUpdateSignatures(fpDest
, &dstOffsetToIndex
,
961 sizeof(dstOffsetToIndex
), ctxs
, certCount
,
965 dstOffsetToIndex
= ntohl(dstOffsetToIndex
);
967 /* Write out the new MAR file size */
968 sizeOfEntireMAR
+= signatureSectionLength
;
969 if (!hasSignatureBlock
) {
970 sizeOfEntireMAR
+= sizeof(sizeOfEntireMAR
) + sizeof(numSignatures
);
973 /* Write out the MAR size */
974 sizeOfEntireMAR
= HOST_TO_NETWORK64(sizeOfEntireMAR
);
975 if (WriteAndUpdateSignatures(fpDest
, &sizeOfEntireMAR
,
976 sizeof(sizeOfEntireMAR
), ctxs
, certCount
,
980 sizeOfEntireMAR
= NETWORK_TO_HOST64(sizeOfEntireMAR
);
982 /* Write out the number of signatures */
983 numSignatures
= certCount
;
984 numSignatures
= htonl(numSignatures
);
985 if (WriteAndUpdateSignatures(fpDest
, &numSignatures
,
986 sizeof(numSignatures
), ctxs
, certCount
,
990 numSignatures
= ntohl(numSignatures
);
992 signaturePlaceholderOffset
= ftello(fpDest
);
994 for (k
= 0; k
< certCount
; k
++) {
995 /* Write out the signature algorithm ID, Only an ID of 1 is supported */
996 signatureAlgorithmID
= htonl(1);
997 if (WriteAndUpdateSignatures(fpDest
, &signatureAlgorithmID
,
998 sizeof(signatureAlgorithmID
),
999 ctxs
, certCount
, "num signatures")) {
1002 signatureAlgorithmID
= ntohl(signatureAlgorithmID
);
1004 /* Write out the signature length */
1005 signatureLengths
[k
] = htonl(signatureLengths
[k
]);
1006 if (WriteAndUpdateSignatures(fpDest
, &signatureLengths
[k
],
1007 sizeof(signatureLengths
[k
]),
1008 ctxs
, certCount
, "signature length")) {
1011 signatureLengths
[k
] = ntohl(signatureLengths
[k
]);
1013 /* Write out a placeholder for the signature, we'll come back to this later
1014 *** THIS IS NOT SIGNED because it is a placeholder that will be replaced
1015 below, plus it is going to be the signature itself. *** */
1016 memset(buf
, 0, sizeof(buf
));
1017 if (fwrite(buf
, signatureLengths
[k
], 1, fpDest
) != 1) {
1018 fprintf(stderr
, "ERROR: Could not write signature length\n");
1023 /* Write out the rest of the MAR excluding the index header and index
1024 offsetToIndex unfortunately has to remain 32-bit because for backwards
1025 compatibility with the old MAR file format. */
1026 if (ftello(fpSrc
) > ((int64_t)offsetToIndex
)) {
1027 fprintf(stderr
, "ERROR: Index offset is too small.\n");
1030 numBytesToCopy
= ((int64_t)offsetToIndex
) - ftello(fpSrc
);
1031 numChunks
= numBytesToCopy
/ BLOCKSIZE
;
1032 leftOver
= numBytesToCopy
% BLOCKSIZE
;
1034 /* Read each file and write it to the MAR file */
1035 for (i
= 0; i
< numChunks
; ++i
) {
1036 if (ReadWriteAndUpdateSignatures(fpSrc
, fpDest
, buf
,
1037 BLOCKSIZE
, ctxs
, certCount
,
1043 /* Write out the left over */
1044 if (ReadWriteAndUpdateSignatures(fpSrc
, fpDest
, buf
,
1045 leftOver
, ctxs
, certCount
,
1046 "left over content block")) {
1050 /* Length of the index */
1051 if (ReadWriteAndUpdateSignatures(fpSrc
, fpDest
, &indexLength
,
1052 sizeof(indexLength
), ctxs
, certCount
,
1056 indexLength
= ntohl(indexLength
);
1058 /* Consume the index and adjust each index by signatureSectionLength */
1059 indexBuf
= malloc(indexLength
);
1060 if (fread(indexBuf
, indexLength
, 1, fpSrc
) != 1) {
1061 fprintf(stderr
, "ERROR: Could not read index\n");
1065 /* Adjust each entry in the index */
1066 if (hasSignatureBlock
) {
1067 AdjustIndexContentOffsets(indexBuf
, indexLength
, signatureSectionLength
);
1069 AdjustIndexContentOffsets(indexBuf
, indexLength
,
1070 sizeof(sizeOfEntireMAR
) +
1071 sizeof(numSignatures
) +
1072 signatureSectionLength
);
1075 if (WriteAndUpdateSignatures(fpDest
, indexBuf
,
1076 indexLength
, ctxs
, certCount
, "index")) {
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
) {
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");
1092 if (signatureLengths
[k
] != secItems
[k
].len
) {
1093 fprintf(stderr
, "ERROR: Signature is not the expected length\n");
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");
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");
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");
1139 for (k
= 0; k
< certCount
; k
++) {
1141 SGN_DestroyContext(ctxs
[k
], PR_TRUE
);
1145 CERT_DestroyCertificate(certs
[k
]);
1149 SECKEY_DestroyPrivateKey(privKeys
[k
]);
1152 SECITEM_FreeItem(&secItems
[k
], PR_FALSE
);