LibreOffice Module onlineupdate (master) 1
mar_sign.c
Go to the documentation of this file.
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 _WIN32
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>
18#include <onlineupdate/mar.h>
19#include "cryptox.h"
20#ifndef _WIN32
21#include <unistd.h>
22#endif
23
24#include "nss_secutil.h"
25#include "base64.h"
26
34int
35NSSInitCryptoContext(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
54int
55NSSSignBegin(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",
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
126int
127WriteAndUpdateSignatures(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
159void
160AdjustIndexContentOffsets(char *indexBuf, uint32_t indexLength, uint32_t offsetAmount)
161{
162 char *indexBufLoc = indexBuf;
163
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;
174 }
175}
176
193int
194ReadWriteAndUpdateSignatures(FILE *fpSrc, FILE *fpDest, void *buffer,
195 uint32_t size, SGNContext **ctxs,
196 uint32_t ctxCount,
197 const char *err)
198{
199 if (!size) {
200 return 0;
201 }
202
203 if (fread(buffer, size, 1, fpSrc) != 1) {
204 fprintf(stderr, "ERROR: Could not read %s\n", err);
205 return -1;
206 }
207
208 return WriteAndUpdateSignatures(fpDest, buffer, size, ctxs, ctxCount, err);
209}
210
211
224int
225ReadAndWrite(FILE *fpSrc, FILE *fpDest, void *buffer,
226 uint32_t size, const char *err)
227{
228 if (!size) {
229 return 0;
230 }
231
232 if (fread(buffer, size, 1, fpSrc) != 1) {
233 fprintf(stderr, "ERROR: Could not read %s\n", err);
234 return -1;
235 }
236
237 if (fwrite(buffer, size, 1, fpDest) != 1) {
238 fprintf(stderr, "ERROR: Could not write %s\n", err);
239 return -2;
240 }
241
242 return 0;
243}
244
254int
255strip_signature_block(const char *src, const char * dest)
256{
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;
266
267 if (!src || !dest) {
268 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
269 return -1;
270 }
271
272 fpSrc = fopen(src, "rb");
273 if (!fpSrc) {
274 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
275 goto failure;
276 }
277
278 fpDest = fopen(dest, "wb");
279 if (!fpDest) {
280 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
281 goto failure;
282 }
283
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;
288 }
289
290 /* MAR ID */
291 if (ReadAndWrite(fpSrc, fpDest, buf, MAR_ID_SIZE, "MAR ID")) {
292 goto failure;
293 }
294
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;
299 }
300 offsetToIndex = ntohl(offsetToIndex);
301
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;
307 }
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;
312 }
313
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;
320 }
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;
325 }
326
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;
331 }
332 numSignatures = ntohl(numSignatures);
333
334 for (i = 0; i < numSignatures; i++) {
335 uint32_t signatureLen;
336
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");
340 }
341
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;
346 }
347 signatureLen = ntohl(signatureLen);
348
349 /* Skip past the signature */
350 if (fseeko(fpSrc, signatureLen, SEEK_CUR)) {
351 fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
352 }
353
354 stripAmount += sizeof(uint32_t) + sizeof(uint32_t) + signatureLen;
355 }
356
357 } else {
358 sizeOfEntireMAR = realSizeOfSrcMAR;
359 numSignatures = 0;
360 }
361
362 if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
363 fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
364 goto failure;
365 }
366
367 dstOffsetToIndex = offsetToIndex;
368 if (!hasSignatureBlock) {
369 dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
370 }
371 dstOffsetToIndex -= stripAmount;
372
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;
378 }
379 dstOffsetToIndex = ntohl(dstOffsetToIndex);
380
381 /* Write out the new MAR file size */
382 if (!hasSignatureBlock) {
383 sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
384 }
385 sizeOfEntireMAR -= stripAmount;
386
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;
392 }
393 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
394
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;
400 }
401
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;
408 }
409 numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
410 numChunks = numBytesToCopy / BLOCKSIZE;
411 leftOver = numBytesToCopy % BLOCKSIZE;
412
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;
417 }
418 }
419
420 /* Write out the left over */
421 if (ReadAndWrite(fpSrc, fpDest, buf,
422 leftOver, "left over content block")) {
423 goto failure;
424 }
425
426 /* Length of the index */
427 if (ReadAndWrite(fpSrc, fpDest, &indexLength,
428 sizeof(indexLength), "index length")) {
429 goto failure;
430 }
431 indexLength = ntohl(indexLength);
432
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;
438 }
439
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);
448 }
449
450 if (fwrite(indexBuf, indexLength, 1, fpDest) != 1) {
451 fprintf(stderr, "ERROR: Could not write index\n");
452 goto failure;
453 }
454
455 rv = 0;
456failure:
457 if (fpSrc) {
458 fclose(fpSrc);
459 }
460
461 if (fpDest) {
462 fclose(fpDest);
463 }
464
465 if (rv) {
466 remove(dest);
467 }
468
469 if (indexBuf) {
470 free(indexBuf);
471 }
472
473 if (rv) {
474 remove(dest);
475 }
476 return rv;
477}
478
488int
489extract_signature(const char *src, uint32_t sigIndex, const char * dest)
490{
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;
501 }
502
503 fpSrc = fopen(src, "rb");
504 if (!fpSrc) {
505 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
506 goto failure;
507 }
508
509 fpDest = fopen(dest, "wb");
510 if (!fpDest) {
511 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
512 goto failure;
513 }
514
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;
519 }
520
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;
525 }
526 signatureCount = ntohl(signatureCount);
527 if (sigIndex >= signatureCount) {
528 fprintf(stderr, "ERROR: Signature index was out of range\n");
529 goto failure;
530 }
531
532 /* Skip to the correct signature */
533 for (i = 0; i <= sigIndex; i++) {
534 /* Avoid leaking while skipping signatures */
535 free(extractedSignature);
536
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;
541 }
542
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;
547 }
548 signatureLen = ntohl(signatureLen);
549
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;
555 }
556 }
557
558 base64Encoded = BTOA_DataToAscii(extractedSignature, signatureLen);
559 if (!base64Encoded) {
560 fprintf(stderr, "ERROR: could not obtain base64 encoded data\n");
561 goto failure;
562 }
563
564 if (fwrite(base64Encoded, strlen(base64Encoded), 1, fpDest) != 1) {
565 fprintf(stderr, "ERROR: Could not write base64 encoded string\n");
566 goto failure;
567 }
568
569 rv = 0;
570failure:
571 if (base64Encoded) {
572 PORT_Free(base64Encoded);
573 }
574
575 if (extractedSignature) {
576 free(extractedSignature);
577 }
578
579 if (fpSrc) {
580 fclose(fpSrc);
581 }
582
583 if (fpDest) {
584 fclose(fpDest);
585 }
586
587 if (rv) {
588 remove(dest);
589 }
590
591 return rv;
592}
593
604int
605import_signature(const char *src, uint32_t sigIndex,
606 const char *base64SigFile, const char *dest)
607{
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;
621
622 if (!src || !dest) {
623 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
624 goto failure;
625 }
626
627 fpSrc = fopen(src, "rb");
628 if (!fpSrc) {
629 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
630 goto failure;
631 }
632
633 fpDest = fopen(dest, "wb");
634 if (!fpDest) {
635 fprintf(stderr, "ERROR: could not open dest file: %s\n", dest);
636 goto failure;
637 }
638
639 fpSigFile = fopen(base64SigFile , "rb");
640 if (!fpSigFile) {
641 fprintf(stderr, "ERROR: could not open sig file: %s\n", base64SigFile);
642 goto failure;
643 }
644
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;
649 }
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;
654 }
655
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;
660 }
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;
665 }
666
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;
673 }
674
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;
680 }
681
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;
686 }
687
688 /* Get the number of signatures */
689 if (ReadAndWrite(fpSrc, fpDest, &signatureCount,
690 sizeof(signatureCount), "signature count")) {
691 goto failure;
692 }
693 signatureCount = ntohl(signatureCount);
694 if (signatureCount > MAX_SIGNATURES) {
695 fprintf(stderr, "ERROR: Signature count was out of range\n");
696 goto failure;
697 }
698
699 if (sigIndex >= signatureCount) {
700 fprintf(stderr, "ERROR: Signature index was out of range\n");
701 goto failure;
702 }
703
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;
713 }
714
715 /* Read/Write the signature length */
716 if (ReadAndWrite(fpSrc, fpDest,
717 &signatureLen, sizeof(signatureLen), "sig length")) {
718 goto failure;
719 }
720 signatureLen = ntohl(signatureLen);
721
722 /* Get the signature */
723 if (extractedMARSignature) {
724 free(extractedMARSignature);
725 }
726 extractedMARSignature = malloc(signatureLen);
727
728 if (sigIndex == i) {
729 if (passedInSignatureLenRaw != signatureLen) {
730 fprintf(stderr, "ERROR: Signature length must be the same\n");
731 goto failure;
732 }
733
734 if (fread(extractedMARSignature, signatureLen, 1, fpSrc) != 1) {
735 fprintf(stderr, "ERROR: Could not read signature\n");
736 goto failure;
737 }
738
739 if (fwrite(passedInSignatureRaw, passedInSignatureLenRaw,
740 1, fpDest) != 1) {
741 fprintf(stderr, "ERROR: Could not write signature\n");
742 goto failure;
743 }
744 } else {
745 if (ReadAndWrite(fpSrc, fpDest,
746 extractedMARSignature, signatureLen, "signature")) {
747 goto failure;
748 }
749 }
750 }
751
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;
756
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;
761 }
762 }
763
764 if (ReadAndWrite(fpSrc, fpDest, buf, leftOver, "left over content block")) {
765 goto failure;
766 }
767
768 rv = 0;
769
770failure:
771
772 if (fpSrc) {
773 fclose(fpSrc);
774 }
775
776 if (fpDest) {
777 fclose(fpDest);
778 }
779
780 if (fpSigFile) {
781 fclose(fpSigFile);
782 }
783
784 if (rv) {
785 remove(dest);
786 }
787
788 if (extractedMARSignature) {
789 free(extractedMARSignature);
790 }
791
792 if (passedInSignatureB64) {
793 free(passedInSignatureB64);
794 }
795
796 if (passedInSignatureRaw) {
797 PORT_Free(passedInSignatureRaw);
798 }
799
800 return rv;
801}
802
817int
818mar_repackage_and_sign(const char *NSSConfigDir,
819 const char * const *certNames,
820 uint32_t certCount,
821 const char *src,
822 const char *dest)
823{
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;
840
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));
846
847 if (!NSSConfigDir || !certNames || certCount == 0 || !src || !dest) {
848 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
849 return -1;
850 }
851
852 if (NSSInitCryptoContext(NSSConfigDir)) {
853 fprintf(stderr, "ERROR: Could not init config dir: %s\n", NSSConfigDir);
854 goto failure;
855 }
856
857 PK11_SetPasswordFunc(SECU_GetModulePassword);
858
859 fpSrc = fopen(src, "rb");
860 if (!fpSrc) {
861 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
862 goto failure;
863 }
864
865 fpDest = fopen(dest, "wb");
866 if (!fpDest) {
867 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
868 goto failure;
869 }
870
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;
875 }
876
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;
882 }
883 }
884
885 /* MAR ID */
886 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest,
887 buf, MAR_ID_SIZE,
888 ctxs, certCount, "MAR ID")) {
889 goto failure;
890 }
891
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;
896 }
897 offsetToIndex = ntohl(offsetToIndex);
898
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;
904 }
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;
909 }
910
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;
917 }
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;
922 }
923
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;
928 }
929 numSignatures = ntohl(numSignatures);
930
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;
936 }
937 } else {
938 sizeOfEntireMAR = realSizeOfSrcMAR;
939 }
940
941 if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
942 fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
943 goto failure;
944 }
945
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];
951 }
952 dstOffsetToIndex = offsetToIndex;
953 if (!hasSignatureBlock) {
954 dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
955 }
956 dstOffsetToIndex += signatureSectionLength;
957
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;
964 }
965 dstOffsetToIndex = ntohl(dstOffsetToIndex);
966
967 /* Write out the new MAR file size */
968 sizeOfEntireMAR += signatureSectionLength;
969 if (!hasSignatureBlock) {
970 sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
971 }
972
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;
979 }
980 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
981
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;
989 }
990 numSignatures = ntohl(numSignatures);
991
992 signaturePlaceholderOffset = ftello(fpDest);
993
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;
1001 }
1002 signatureAlgorithmID = ntohl(signatureAlgorithmID);
1003
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;
1010 }
1011 signatureLengths[k] = ntohl(signatureLengths[k]);
1012
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;
1020 }
1021 }
1022
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;
1029 }
1030 numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
1031 numChunks = numBytesToCopy / BLOCKSIZE;
1032 leftOver = numBytesToCopy % BLOCKSIZE;
1033
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;
1040 }
1041 }
1042
1043 /* Write out the left over */
1044 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
1045 leftOver, ctxs, certCount,
1046 "left over content block")) {
1047 goto failure;
1048 }
1049
1050 /* Length of the index */
1051 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, &indexLength,
1052 sizeof(indexLength), ctxs, certCount,
1053 "index length")) {
1054 goto failure;
1055 }
1056 indexLength = ntohl(indexLength);
1057
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;
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;
1121failure:
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}
#define CryptoX_Error
Definition: cryptox.h:12
#define XP_MIN_SIGNATURE_LEN_IN_BYTES
Definition: cryptox.h:8
return NULL
#define MAX_SIGNATURES
Definition: mar.h:23
#define NETWORK_TO_HOST64
Definition: mar_private.h:77
#define MAX_SIZE_OF_MAR_FILE
Definition: mar_private.h:26
#define SIGNATURE_BLOCK_OFFSET
Definition: mar_private.h:22
#define MAR_ID_SIZE
Definition: mar_private.h:18
#define HOST_TO_NETWORK64(x)
Definition: mar_private.h:68
#define BLOCKSIZE
Definition: mar_private.h:14
int get_mar_file_info(const char *path, int *hasSignatureBlock, uint32_t *numSignatures, int *hasAdditionalBlocks, uint32_t *offsetAdditionalBlocks, uint32_t *numAdditionalBlocks)
Determines the MAR file information.
Definition: mar_read.c:551
void AdjustIndexContentOffsets(char *indexBuf, uint32_t indexLength, uint32_t offsetAmount)
Adjusts each entry's content offset in the passed in index by the specified amount.
Definition: mar_sign.c:160
int NSSSignBegin(const char *certName, SGNContext **ctx, SECKEYPrivateKey **privKey, CERTCertificate **cert, uint32_t *signatureLength)
Obtains a signing context.
Definition: mar_sign.c:55
int import_signature(const char *src, uint32_t sigIndex, const char *base64SigFile, const char *dest)
Imports a base64 encoded signature into a MAR file.
Definition: mar_sign.c:605
int NSSInitCryptoContext(const char *NSSConfigDir)
Initializes the NSS context.
Definition: mar_sign.c:35
int extract_signature(const char *src, uint32_t sigIndex, const char *dest)
Extracts a signature from a MAR file, base64 encodes it, and writes it out.
Definition: mar_sign.c:489
int WriteAndUpdateSignatures(FILE *fpDest, void *buffer, uint32_t size, SGNContext **ctxs, uint32_t ctxCount, const char *err)
Writes the passed buffer to the file fp and updates the signature contexts.
Definition: mar_sign.c:127
int ReadAndWrite(FILE *fpSrc, FILE *fpDest, void *buffer, uint32_t size, const char *err)
Reads from fpSrc, writes it to fpDest.
Definition: mar_sign.c:225
int ReadWriteAndUpdateSignatures(FILE *fpSrc, FILE *fpDest, void *buffer, uint32_t size, SGNContext **ctxs, uint32_t ctxCount, const char *err)
Reads from fpSrc, writes it to fpDest, and updates the signature contexts.
Definition: mar_sign.c:194
int mar_repackage_and_sign(const char *NSSConfigDir, const char *const *certNames, uint32_t certCount, const char *src, const char *dest)
Writes out a copy of the MAR at src but with embedded signatures.
Definition: mar_sign.c:818
int strip_signature_block(const char *src, const char *dest)
Writes out a copy of the MAR at src but with the signature block stripped.
Definition: mar_sign.c:255
err
size
OUStringBuffer & remove(OUStringBuffer &rIn, sal_Unicode c)
int i
ctx
sal_uInt32 htonl(sal_uInt32 h)
sal_uInt32 ntohl(sal_uInt32 n)
char * SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg)
Definition: nss_secutil.c:187