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