Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / onlineupdate / source / libmar / sign / mar_sign.c
blob161cadc0d2c7b6a6031682fe46f276a44ed140db
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/. */
5 #ifdef _WIN32
6 #ifndef WIN32_LEAN_AND_MEAN
7 #define WIN32_LEAN_AND_MEAN
8 #endif
9 #endif
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <onlineupdate/mar_private.h>
17 #include <onlineupdate/mar_cmdline.h>
18 #include <onlineupdate/mar.h>
19 #include "cryptox.h"
20 #ifndef _WIN32
21 #include <unistd.h>
22 #endif
24 #include "nss_secutil.h"
25 #include "base64.h"
27 /**
28 * Initializes the NSS context.
30 * @param NSSConfigDir The config dir containing the private key to use
31 * @return 0 on success
32 * -1 on error
34 int
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");
41 return -1;
44 return 0;
47 /**
48 * Obtains a signing context.
50 * @param ctx A pointer to the signing context to fill
51 * @return 0 on success
52 * -1 on error
54 int
55 NSSSignBegin(const char *certName,
56 SGNContext **ctx,
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");
64 return -1;
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;
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;
81 *signatureLength = PK11_SignatureLen(*privKey);
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;
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;
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;
104 if (SGN_Begin(*ctx) != SECSuccess) {
105 fprintf(stderr, "ERROR: Could not begin signature\n");
106 return -1;
109 return 0;
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
123 * -2 on write error
124 * -3 on signature update error
127 WriteAndUpdateSignatures(FILE *fpDest, void *buffer,
128 uint32_t size, SGNContext **ctxs,
129 uint32_t ctxCount,
130 const char *err)
132 uint32_t k;
133 if (!size) {
134 return 0;
137 if (fwrite(buffer, size, 1, fpDest) != 1) {
138 fprintf(stderr, "ERROR: Could not write %s\n", err);
139 return -2;
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;
148 return 0;
152 * Adjusts each entry's content offset in the passed in index by the
153 * specified amount.
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
159 void
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
189 * -1 on read error
190 * -2 on write error
191 * -3 on signature update error
194 ReadWriteAndUpdateSignatures(FILE *fpSrc, FILE *fpDest, void *buffer,
195 uint32_t size, SGNContext **ctxs,
196 uint32_t ctxCount,
197 const char *err)
199 if (!size) {
200 return 0;
203 if (fread(buffer, size, 1, fpSrc) != 1) {
204 fprintf(stderr, "ERROR: Could not read %s\n", err);
205 return -1;
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
221 * -1 on read error
222 * -2 on write error
225 ReadAndWrite(FILE *fpSrc, FILE *fpDest, void *buffer,
226 uint32_t size, const char *err)
228 if (!size) {
229 return 0;
232 if (fread(buffer, size, 1, fpSrc) != 1) {
233 fprintf(stderr, "ERROR: Could not read %s\n", err);
234 return -1;
237 if (fwrite(buffer, size, 1, fpDest) != 1) {
238 fprintf(stderr, "ERROR: Could not write %s\n", err);
239 return -2;
242 return 0;
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
252 * -1 on error
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,
261 numChunks, i;
262 FILE *fpSrc = NULL, *fpDest = NULL;
263 int rv = -1, hasSignatureBlock;
264 char buf[BLOCKSIZE];
265 char *indexBuf = NULL;
267 if (!src || !dest) {
268 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
269 return -1;
272 fpSrc = fopen(src, "rb");
273 if (!fpSrc) {
274 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
275 goto failure;
278 fpDest = fopen(dest, "wb");
279 if (!fpDest) {
280 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
281 goto failure;
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");
287 goto failure;
290 /* MAR ID */
291 if (ReadAndWrite(fpSrc, fpDest, buf, MAR_ID_SIZE, "MAR ID")) {
292 goto failure;
295 /* Offset to index */
296 if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
297 fprintf(stderr, "ERROR: Could not read offset\n");
298 goto failure;
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");
306 goto failure;
308 realSizeOfSrcMAR = ftello(fpSrc);
309 if (fseeko(fpSrc, oldPos, SEEK_SET)) {
310 fprintf(stderr, "ERROR: Could not seek back to current location.\n");
311 goto failure;
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");
319 goto failure;
321 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
322 if (sizeOfEntireMAR != realSizeOfSrcMAR) {
323 fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
324 goto failure;
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");
330 goto failure;
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;
357 } else {
358 sizeOfEntireMAR = realSizeOfSrcMAR;
359 numSignatures = 0;
362 if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
363 fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
364 goto failure;
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");
377 goto failure;
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");
391 goto failure;
393 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
395 /* Write out the number of signatures, which is 0 */
396 numSignatures = 0;
397 if (fwrite(&numSignatures, sizeof(numSignatures), 1, fpDest) != 1) {
398 fprintf(stderr, "ERROR: Could not write out num signatures\n");
399 goto failure;
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");
407 goto failure;
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")) {
416 goto failure;
420 /* Write out the left over */
421 if (ReadAndWrite(fpSrc, fpDest, buf,
422 leftOver, "left over content block")) {
423 goto failure;
426 /* Length of the index */
427 if (ReadAndWrite(fpSrc, fpDest, &indexLength,
428 sizeof(indexLength), "index length")) {
429 goto failure;
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");
437 goto failure;
440 /* Adjust each entry in the index */
441 if (hasSignatureBlock) {
442 AdjustIndexContentOffsets(indexBuf, indexLength, -stripAmount);
443 } else {
444 AdjustIndexContentOffsets(indexBuf, indexLength,
445 sizeof(sizeOfEntireMAR) +
446 sizeof(numSignatures) -
447 stripAmount);
450 if (fwrite(indexBuf, indexLength, 1, fpDest) != 1) {
451 fprintf(stderr, "ERROR: Could not write index\n");
452 goto failure;
455 rv = 0;
456 failure:
457 if (fpSrc) {
458 fclose(fpSrc);
461 if (fpDest) {
462 fclose(fpDest);
465 if (rv) {
466 remove(dest);
469 if (indexBuf) {
470 free(indexBuf);
473 if (rv) {
474 remove(dest);
476 return rv;
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
486 * -1 on error
489 extract_signature(const char *src, uint32_t sigIndex, const char * dest)
491 FILE *fpSrc = NULL, *fpDest = NULL;
492 uint32_t i;
493 uint32_t signatureCount;
494 uint32_t signatureLen = 0;
495 uint8_t *extractedSignature = NULL;
496 char *base64Encoded = NULL;
497 int rv = -1;
498 if (!src || !dest) {
499 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
500 goto failure;
503 fpSrc = fopen(src, "rb");
504 if (!fpSrc) {
505 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
506 goto failure;
509 fpDest = fopen(dest, "wb");
510 if (!fpDest) {
511 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
512 goto failure;
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");
518 goto failure;
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");
524 goto failure;
526 signatureCount = ntohl(signatureCount);
527 if (sigIndex >= signatureCount) {
528 fprintf(stderr, "ERROR: Signature index was out of range\n");
529 goto failure;
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");
540 goto failure;
543 /* Get the signature length */
544 if (fread(&signatureLen, sizeof(signatureLen), 1, fpSrc) != 1) {
545 fprintf(stderr, "ERROR: could not read signature length\n");
546 goto failure;
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");
554 goto failure;
558 base64Encoded = BTOA_DataToAscii(extractedSignature, signatureLen);
559 if (!base64Encoded) {
560 fprintf(stderr, "ERROR: could not obtain base64 encoded data\n");
561 goto failure;
564 if (fwrite(base64Encoded, strlen(base64Encoded), 1, fpDest) != 1) {
565 fprintf(stderr, "ERROR: Could not write base64 encoded string\n");
566 goto failure;
569 rv = 0;
570 failure:
571 if (base64Encoded) {
572 PORT_Free(base64Encoded);
575 if (extractedSignature) {
576 free(extractedSignature);
579 if (fpSrc) {
580 fclose(fpSrc);
583 if (fpDest) {
584 fclose(fpDest);
587 if (rv) {
588 remove(dest);
591 return rv;
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
602 * -1 on error
605 import_signature(const char *src, uint32_t sigIndex,
606 const char *base64SigFile, const char *dest)
608 int rv = -1;
609 FILE *fpSrc = NULL;
610 FILE *fpDest = NULL;
611 FILE *fpSigFile = NULL;
612 uint32_t i;
613 uint32_t signatureCount, signatureLen, signatureAlgorithmID,
614 numChunks, leftOver;
615 char buf[BLOCKSIZE];
616 uint64_t sizeOfSrcMAR, sizeOfBase64EncodedFile;
617 char *passedInSignatureB64 = NULL;
618 uint8_t *passedInSignatureRaw = NULL;
619 uint8_t *extractedMARSignature = NULL;
620 unsigned int passedInSignatureLenRaw;
622 if (!src || !dest) {
623 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
624 goto failure;
627 fpSrc = fopen(src, "rb");
628 if (!fpSrc) {
629 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
630 goto failure;
633 fpDest = fopen(dest, "wb");
634 if (!fpDest) {
635 fprintf(stderr, "ERROR: could not open dest file: %s\n", dest);
636 goto failure;
639 fpSigFile = fopen(base64SigFile , "rb");
640 if (!fpSigFile) {
641 fprintf(stderr, "ERROR: could not open sig file: %s\n", base64SigFile);
642 goto failure;
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");
648 goto failure;
650 sizeOfSrcMAR = ftello(fpSrc);
651 if (fseeko(fpSrc, 0, SEEK_SET)) {
652 fprintf(stderr, "ERROR: Could not seek to start of src file.\n");
653 goto failure;
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");
659 goto failure;
661 sizeOfBase64EncodedFile= ftello(fpSigFile);
662 if (fseeko(fpSigFile, 0, SEEK_SET)) {
663 fprintf(stderr, "ERROR: Could not seek to start of sig file.\n");
664 goto failure;
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");
672 goto failure;
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");
679 goto failure;
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")) {
685 goto failure;
688 /* Get the number of signatures */
689 if (ReadAndWrite(fpSrc, fpDest, &signatureCount,
690 sizeof(signatureCount), "signature count")) {
691 goto failure;
693 signatureCount = ntohl(signatureCount);
694 if (signatureCount > MAX_SIGNATURES) {
695 fprintf(stderr, "ERROR: Signature count was out of range\n");
696 goto failure;
699 if (sigIndex >= signatureCount) {
700 fprintf(stderr, "ERROR: Signature index was out of range\n");
701 goto failure;
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")) {
712 goto failure;
715 /* Read/Write the signature length */
716 if (ReadAndWrite(fpSrc, fpDest,
717 &signatureLen, sizeof(signatureLen), "sig length")) {
718 goto failure;
720 signatureLen = ntohl(signatureLen);
722 /* Get the signature */
723 if (extractedMARSignature) {
724 free(extractedMARSignature);
726 extractedMARSignature = malloc(signatureLen);
728 if (sigIndex == i) {
729 if (passedInSignatureLenRaw != signatureLen) {
730 fprintf(stderr, "ERROR: Signature length must be the same\n");
731 goto failure;
734 if (fread(extractedMARSignature, signatureLen, 1, fpSrc) != 1) {
735 fprintf(stderr, "ERROR: Could not read signature\n");
736 goto failure;
739 if (fwrite(passedInSignatureRaw, passedInSignatureLenRaw,
740 1, fpDest) != 1) {
741 fprintf(stderr, "ERROR: Could not write signature\n");
742 goto failure;
744 } else {
745 if (ReadAndWrite(fpSrc, fpDest,
746 extractedMARSignature, signatureLen, "signature")) {
747 goto failure;
752 /* We replaced the signature so let's just skip past the rest o the
753 file. */
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")) {
760 goto failure;
764 if (ReadAndWrite(fpSrc, fpDest, buf, leftOver, "left over content block")) {
765 goto failure;
768 rv = 0;
770 failure:
772 if (fpSrc) {
773 fclose(fpSrc);
776 if (fpDest) {
777 fclose(fpDest);
780 if (fpSigFile) {
781 fclose(fpSigFile);
784 if (rv) {
785 remove(dest);
788 if (extractedMARSignature) {
789 free(extractedMARSignature);
792 if (passedInSignatureB64) {
793 free(passedInSignatureB64);
796 if (passedInSignatureRaw) {
797 PORT_Free(passedInSignatureRaw);
800 return rv;
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
806 * be returned.
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
815 * -1 on error
818 mar_repackage_and_sign(const char *NSSConfigDir,
819 const char * const *certNames,
820 uint32_t certCount,
821 const char *src,
822 const char *dest)
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,
830 numChunks, i;
831 FILE *fpSrc = NULL, *fpDest = NULL;
832 int rv = -1, hasSignatureBlock;
833 SGNContext *ctxs[MAX_SIGNATURES];
834 SECItem secItems[MAX_SIGNATURES];
835 char buf[BLOCKSIZE];
836 SECKEYPrivateKey *privKeys[MAX_SIGNATURES];
837 CERTCertificate *certs[MAX_SIGNATURES];
838 char *indexBuf = NULL;
839 uint32_t k;
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");
849 return -1;
852 if (NSSInitCryptoContext(NSSConfigDir)) {
853 fprintf(stderr, "ERROR: Could not init config dir: %s\n", NSSConfigDir);
854 goto failure;
857 PK11_SetPasswordFunc(SECU_GetModulePassword);
859 fpSrc = fopen(src, "rb");
860 if (!fpSrc) {
861 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
862 goto failure;
865 fpDest = fopen(dest, "wb");
866 if (!fpDest) {
867 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
868 goto failure;
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");
874 goto failure;
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");
881 goto failure;
885 /* MAR ID */
886 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest,
887 buf, MAR_ID_SIZE,
888 ctxs, certCount, "MAR ID")) {
889 goto failure;
892 /* Offset to index */
893 if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
894 fprintf(stderr, "ERROR: Could not read offset\n");
895 goto failure;
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");
903 goto failure;
905 realSizeOfSrcMAR = ftello(fpSrc);
906 if (fseeko(fpSrc, oldPos, SEEK_SET)) {
907 fprintf(stderr, "ERROR: Could not seek back to current location.\n");
908 goto failure;
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");
916 goto failure;
918 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
919 if (sizeOfEntireMAR != realSizeOfSrcMAR) {
920 fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
921 goto failure;
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");
927 goto failure;
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. */
933 if (numSignatures) {
934 fprintf(stderr, "ERROR: MAR is already signed\n");
935 goto failure;
937 } else {
938 sizeOfEntireMAR = realSizeOfSrcMAR;
941 if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
942 fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
943 goto failure;
946 /* Calculate the total signature block length */
947 for (k = 0; k < certCount; k++) {
948 signatureSectionLength += sizeof(signatureAlgorithmID) +
949 sizeof(signatureLengths[k]) +
950 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,
962 "index offset")) {
963 goto failure;
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,
977 "size of MAR")) {
978 goto failure;
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,
987 "num signatures")) {
988 goto failure;
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")) {
1000 goto failure;
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")) {
1009 goto failure;
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");
1019 goto failure;
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");
1028 goto failure;
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,
1038 "content block")) {
1039 goto failure;
1043 /* Write out the left over */
1044 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
1045 leftOver, ctxs, certCount,
1046 "left over content block")) {
1047 goto failure;
1050 /* Length of the index */
1051 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, &indexLength,
1052 sizeof(indexLength), ctxs, certCount,
1053 "index length")) {
1054 goto failure;
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");
1062 goto failure;
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);
1075 if (WriteAndUpdateSignatures(fpDest, indexBuf,
1076 indexLength, ctxs, certCount, "index")) {
1077 goto failure;
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;
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;
1092 if (signatureLengths[k] != secItems[k].len) {
1093 fprintf(stderr, "ERROR: Signature is not the expected length\n");
1094 goto failure;
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;
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;
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;
1120 rv = 0;
1121 failure:
1122 if (fpSrc) {
1123 fclose(fpSrc);
1126 if (fpDest) {
1127 fclose(fpDest);
1130 if (rv) {
1131 remove(dest);
1134 if (indexBuf) {
1135 free(indexBuf);
1138 /* Cleanup */
1139 for (k = 0; k < certCount; k++) {
1140 if (ctxs[k]) {
1141 SGN_DestroyContext(ctxs[k], PR_TRUE);
1144 if (certs[k]) {
1145 CERT_DestroyCertificate(certs[k]);
1148 if (privKeys[k]) {
1149 SECKEY_DestroyPrivateKey(privKeys[k]);
1152 SECITEM_FreeItem(&secItems[k], PR_FALSE);
1155 if (rv) {
1156 remove(dest);
1159 return rv;