modules/libmar/sign/mar_sign.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 XP_WIN
     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 "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
    24 #include "nss_secutil.h"
    25 #include "base64.h"
    27 /**
    28  * Initializes the NSS context.
    29  * 
    30  * @param NSSConfigDir The config dir containing the private key to use
    31  * @return 0 on success
    32  *         -1 on error
    33 */
    34 int
    35 NSSInitCryptoContext(const char *NSSConfigDir)
    36 {
    37   SECStatus status = NSS_Initialize(NSSConfigDir, 
    38                                     "", "", SECMOD_DB, NSS_INIT_READONLY);
    39   if (SECSuccess != status) {
    40     fprintf(stderr, "ERROR: Could not initialize NSS\n");
    41     return -1;
    42   }
    44   return 0;
    45 }
    47 /** 
    48  * Obtains a signing context.
    49  *
    50  * @param  ctx A pointer to the signing context to fill
    51  * @return 0 on success
    52  *         -1 on error
    53 */
    54 int
    55 NSSSignBegin(const char *certName, 
    56              SGNContext **ctx, 
    57              SECKEYPrivateKey **privKey, 
    58              CERTCertificate **cert,
    59              uint32_t *signatureLength) 
    60 {
    61   secuPWData pwdata = { PW_NONE, 0 };
    62   if (!certName || !ctx || !privKey || !cert || !signatureLength) {
    63     fprintf(stderr, "ERROR: Invalid parameter passed to NSSSignBegin\n");
    64     return -1;
    65   }
    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   }
    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   }
    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;
    89   }
    91   /* Check that the key length is large enough for our requirements */
    92   if (*signatureLength < XP_MIN_SIGNATURE_LEN_IN_BYTES) {
    93     fprintf(stderr, "ERROR: Key length must be >= %d bytes\n", 
    94             XP_MIN_SIGNATURE_LEN_IN_BYTES);
    95     return -1;
    96   }
    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   }
   104   if (SGN_Begin(*ctx) != SECSuccess) {
   105     fprintf(stderr, "ERROR: Could not begin signature\n");
   106     return -1;
   107   }
   109   return 0;
   110 }
   112 /**
   113  * Writes the passed buffer to the file fp and updates the signature contexts.
   114  *
   115  * @param  fpDest   The file pointer to write to.
   116  * @param  buffer   The buffer to write.
   117  * @param  size     The size of the buffer to write.
   118  * @param  ctxs     Pointer to the first element in an array of signature
   119  *                  contexts to update.
   120  * @param  ctxCount The number of signature contexts pointed to by ctxs
   121  * @param  err    The name of what is being written to in case of error.
   122  * @return  0 on success
   123  *         -2 on write error
   124  *         -3 on signature update error
   125 */
   126 int
   127 WriteAndUpdateSignatures(FILE *fpDest, void *buffer,
   128                          uint32_t size, SGNContext **ctxs,
   129                          uint32_t ctxCount,
   130                          const char *err)
   131 {
   132   uint32_t k;
   133   if (!size) { 
   134     return 0;
   135   }
   137   if (fwrite(buffer, size, 1, fpDest) != 1) {
   138     fprintf(stderr, "ERROR: Could not write %s\n", err);
   139     return -2;
   140   }
   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 }
   151 /** 
   152  * Adjusts each entry's content offset in the the passed in index by the 
   153  * specified amount.
   154  *
   155  * @param indexBuf     A buffer containing the MAR index
   156  * @param indexLength  The length of the MAR index
   157  * @param offsetAmount The amount to adjust each index entry by
   158 */
   159 void
   160 AdjustIndexContentOffsets(char *indexBuf, uint32_t indexLength, uint32_t offsetAmount) 
   161 {
   162   uint32_t *offsetToContent;
   163   char *indexBufLoc = indexBuf;
   165   /* Consume the index and adjust each index by the specified amount */
   166   while (indexBufLoc != (indexBuf + indexLength)) {
   167     /* Adjust the offset */
   168     offsetToContent = (uint32_t *)indexBufLoc; 
   169     *offsetToContent = ntohl(*offsetToContent);
   170     *offsetToContent += offsetAmount;
   171     *offsetToContent = htonl(*offsetToContent);
   172     /* Skip past the offset, length, and flags */
   173     indexBufLoc += 3 * sizeof(uint32_t);
   174     indexBufLoc += strlen(indexBufLoc) + 1;
   175   }
   176 }
   178 /**
   179  * Reads from fpSrc, writes it to fpDest, and updates the signature contexts.
   180  *
   181  * @param  fpSrc    The file pointer to read from.
   182  * @param  fpDest   The file pointer to write to.
   183  * @param  buffer   The buffer to write.
   184  * @param  size     The size of the buffer to write.
   185  * @param  ctxs     Pointer to the first element in an array of signature
   186  *                  contexts to update.
   187  * @param  ctxCount The number of signature contexts pointed to by ctxs
   188  * @param  err    The name of what is being written to in case of error.
   189  * @return  0 on success
   190  *         -1 on read error
   191  *         -2 on write error
   192  *         -3 on signature update error
   193 */
   194 int
   195 ReadWriteAndUpdateSignatures(FILE *fpSrc, FILE *fpDest, void *buffer,
   196                              uint32_t size, SGNContext **ctxs,
   197                              uint32_t ctxCount,
   198                              const char *err)
   199 {
   200   if (!size) { 
   201     return 0;
   202   }
   204   if (fread(buffer, size, 1, fpSrc) != 1) {
   205     fprintf(stderr, "ERROR: Could not read %s\n", err);
   206     return -1;
   207   }
   209   return WriteAndUpdateSignatures(fpDest, buffer, size, ctxs, ctxCount, err);
   210 }
   213 /**
   214  * Reads from fpSrc, writes it to fpDest.
   215  *
   216  * @param  fpSrc  The file pointer to read from.
   217  * @param  fpDest The file pointer to write to.
   218  * @param  buffer The buffer to write.
   219  * @param  size   The size of the buffer to write.
   220  * @param  err    The name of what is being written to in case of error.
   221  * @return  0 on success
   222  *         -1 on read error
   223  *         -2 on write error
   224 */
   225 int
   226 ReadAndWrite(FILE *fpSrc, FILE *fpDest, void *buffer, 
   227              uint32_t size, const char *err) 
   228 {
   229   if (!size) { 
   230     return 0;
   231   }
   233   if (fread(buffer, size, 1, fpSrc) != 1) {
   234     fprintf(stderr, "ERROR: Could not read %s\n", err);
   235     return -1;
   236   }
   238   if (fwrite(buffer, size, 1, fpDest) != 1) {
   239     fprintf(stderr, "ERROR: Could not write %s\n", err);
   240     return -2;
   241   }
   243   return 0;
   244 }
   246 /**
   247  * Writes out a copy of the MAR at src but with the signature block stripped.
   248  *
   249  * @param  src  The path of the source MAR file
   250  * @param  dest The path of the MAR file to write out that 
   251                 has no signature block
   252  * @return 0 on success
   253  *         -1 on error
   254 */
   255 int
   256 strip_signature_block(const char *src, const char * dest)
   257 {
   258   uint32_t offsetToIndex, dstOffsetToIndex, indexLength, 
   259     numSignatures = 0, leftOver;
   260   int32_t stripAmount = 0;
   261   int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR, numBytesToCopy,
   262     numChunks, i;
   263   FILE *fpSrc = NULL, *fpDest = NULL;
   264   int rv = -1, hasSignatureBlock;
   265   char buf[BLOCKSIZE];
   266   char *indexBuf = NULL, *indexBufLoc;
   268   if (!src || !dest) {
   269     fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
   270     return -1;
   271   }
   273   fpSrc = fopen(src, "rb");
   274   if (!fpSrc) {
   275     fprintf(stderr, "ERROR: could not open source file: %s\n", src);
   276     goto failure;
   277   }
   279   fpDest = fopen(dest, "wb");
   280   if (!fpDest) {
   281     fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
   282     goto failure;
   283   }
   285   /* Determine if the source MAR file has the new fields for signing or not */
   286   if (get_mar_file_info(src, &hasSignatureBlock, NULL, NULL, NULL, NULL)) {
   287     fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
   288     goto failure;
   289   }
   291   /* MAR ID */
   292   if (ReadAndWrite(fpSrc, fpDest, buf, MAR_ID_SIZE, "MAR ID")) {
   293     goto failure;
   294   }
   296   /* Offset to index */
   297   if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
   298     fprintf(stderr, "ERROR: Could not read offset\n");
   299     goto failure;
   300   }
   301   offsetToIndex = ntohl(offsetToIndex);
   303   /* Get the real size of the MAR */
   304   oldPos = ftello(fpSrc);
   305   if (fseeko(fpSrc, 0, SEEK_END)) {
   306     fprintf(stderr, "ERROR: Could not seek to end of file.\n");
   307     goto failure;
   308   }
   309   realSizeOfSrcMAR = ftello(fpSrc);
   310   if (fseeko(fpSrc, oldPos, SEEK_SET)) {
   311     fprintf(stderr, "ERROR: Could not seek back to current location.\n");
   312     goto failure;
   313   }
   315   if (hasSignatureBlock) {
   316     /* Get the MAR length and adjust its size */
   317     if (fread(&sizeOfEntireMAR, 
   318               sizeof(sizeOfEntireMAR), 1, fpSrc) != 1) {
   319       fprintf(stderr, "ERROR: Could read mar size\n");
   320       goto failure;
   321     }
   322     sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
   323     if (sizeOfEntireMAR != realSizeOfSrcMAR) {
   324       fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
   325       goto failure;
   326     }
   328     /* Get the num signatures in the source file so we know what to strip */
   329     if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
   330       fprintf(stderr, "ERROR: Could read num signatures\n");
   331       goto failure;
   332     }
   333     numSignatures = ntohl(numSignatures);
   335     for (i = 0; i < numSignatures; i++) {
   336       uint32_t signatureLen;
   338       /* Skip past the signature algorithm ID */
   339       if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
   340         fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
   341       }
   343       /* Read in the length of the signature so we know how far to skip */
   344       if (fread(&signatureLen, sizeof(uint32_t), 1, fpSrc) != 1) {
   345         fprintf(stderr, "ERROR: Could not read signatures length.\n");
   346         return CryptoX_Error;
   347       }
   348       signatureLen = ntohl(signatureLen);
   350       /* Skip past the signature */
   351       if (fseeko(fpSrc, signatureLen, SEEK_CUR)) {
   352         fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
   353       }
   355       stripAmount += sizeof(uint32_t) + sizeof(uint32_t) + signatureLen; 
   356     }
   358   } else {
   359     sizeOfEntireMAR = realSizeOfSrcMAR;
   360     numSignatures = 0;
   361   }
   363   if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
   364     fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
   365     goto failure;
   366   }
   368   dstOffsetToIndex = offsetToIndex;
   369   if (!hasSignatureBlock) {
   370     dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
   371   }
   372   dstOffsetToIndex -= stripAmount;
   374   /* Write out the index offset */
   375   dstOffsetToIndex = htonl(dstOffsetToIndex);
   376   if (fwrite(&dstOffsetToIndex, sizeof(dstOffsetToIndex), 1, fpDest) != 1) {
   377     fprintf(stderr, "ERROR: Could not write offset to index\n");
   378     goto failure;
   379   }
   380   dstOffsetToIndex = ntohl(dstOffsetToIndex);
   382   /* Write out the new MAR file size */
   383   if (!hasSignatureBlock) {
   384     sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
   385   }
   386   sizeOfEntireMAR -= stripAmount;
   388   /* Write out the MAR size */
   389   sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
   390   if (fwrite(&sizeOfEntireMAR, sizeof(sizeOfEntireMAR), 1, fpDest) != 1) {
   391     fprintf(stderr, "ERROR: Could not write size of MAR\n");
   392     goto failure;
   393   }
   394   sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
   396   /* Write out the number of signatures, which is 0 */
   397   numSignatures = 0;
   398   if (fwrite(&numSignatures, sizeof(numSignatures), 1, fpDest) != 1) {
   399     fprintf(stderr, "ERROR: Could not write out num signatures\n");
   400     goto failure;
   401   }
   403   /* Write out the rest of the MAR excluding the index header and index
   404      offsetToIndex unfortunately has to remain 32-bit because for backwards
   405      compatibility with the old MAR file format. */
   406   if (ftello(fpSrc) > ((int64_t)offsetToIndex)) {
   407     fprintf(stderr, "ERROR: Index offset is too small.\n");
   408     goto failure;
   409   }
   410   numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
   411   numChunks = numBytesToCopy / BLOCKSIZE;
   412   leftOver = numBytesToCopy % BLOCKSIZE;
   414   /* Read each file and write it to the MAR file */
   415   for (i = 0; i < numChunks; ++i) {
   416     if (ReadAndWrite(fpSrc, fpDest, buf, BLOCKSIZE, "content block")) {
   417       goto failure;
   418     }
   419   }
   421   /* Write out the left over */
   422   if (ReadAndWrite(fpSrc, fpDest, buf, 
   423                    leftOver, "left over content block")) {
   424     goto failure;
   425   }
   427   /* Length of the index */
   428   if (ReadAndWrite(fpSrc, fpDest, &indexLength, 
   429                    sizeof(indexLength), "index length")) {
   430     goto failure;
   431   }
   432   indexLength = ntohl(indexLength);
   434   /* Consume the index and adjust each index by the difference */
   435   indexBuf = malloc(indexLength);
   436   indexBufLoc = indexBuf;
   437   if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
   438     fprintf(stderr, "ERROR: Could not read index\n");
   439     goto failure;
   440   }
   442   /* Adjust each entry in the index */
   443   if (hasSignatureBlock) {
   444     AdjustIndexContentOffsets(indexBuf, indexLength, -stripAmount);
   445   } else {
   446     AdjustIndexContentOffsets(indexBuf, indexLength, 
   447                               sizeof(sizeOfEntireMAR) + 
   448                               sizeof(numSignatures) - 
   449                               stripAmount);
   450   }
   452   if (fwrite(indexBuf, indexLength, 1, fpDest) != 1) {
   453     fprintf(stderr, "ERROR: Could not write index\n");
   454     goto failure;
   455   }
   457   rv = 0;
   458 failure: 
   459   if (fpSrc) {
   460     fclose(fpSrc);
   461   }
   463   if (fpDest) {
   464     fclose(fpDest);
   465   }
   467   if (rv) {
   468     remove(dest);
   469   }
   471   if (indexBuf) { 
   472     free(indexBuf);
   473   }
   475   if (rv) {
   476     remove(dest);
   477   }
   478   return rv;
   479 }
   481 /**
   482  * Extracts a signature from a MAR file, base64 encodes it, and writes it out
   483  *
   484  * @param  src       The path of the source MAR file
   485  * @param  sigIndex  The index of the signature to extract
   486  * @param  dest      The path of file to write the signature to
   487  * @return 0 on success
   488  *         -1 on error
   489 */
   490 int
   491 extract_signature(const char *src, uint32_t sigIndex, const char * dest)
   492 {
   493   FILE *fpSrc = NULL, *fpDest = NULL;
   494   uint32_t i;
   495   uint32_t signatureCount;
   496   uint32_t signatureLen;
   497   uint8_t *extractedSignature = NULL;
   498   char *base64Encoded = NULL;
   499   int rv = -1;
   500   if (!src || !dest) {
   501     fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
   502     goto failure;
   503   }
   505   fpSrc = fopen(src, "rb");
   506   if (!fpSrc) {
   507     fprintf(stderr, "ERROR: could not open source file: %s\n", src);
   508     goto failure;
   509   }
   511   fpDest = fopen(dest, "wb");
   512   if (!fpDest) {
   513     fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
   514     goto failure;
   515   }
   517   /* Skip to the start of the signature block */
   518   if (fseeko(fpSrc, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
   519     fprintf(stderr, "ERROR: could not seek to signature block\n");
   520     goto failure;
   521   }
   523   /* Get the number of signatures */
   524   if (fread(&signatureCount, sizeof(signatureCount), 1, fpSrc) != 1) {
   525     fprintf(stderr, "ERROR: could not read signature count\n");
   526     goto failure;
   527   }
   528   signatureCount = ntohl(signatureCount);
   529   if (sigIndex >= signatureCount) {
   530     fprintf(stderr, "ERROR: Signature index was out of range\n");
   531     goto failure;
   532   }
   534   /* Skip to the correct signature */
   535   for (i = 0; i <= sigIndex; i++) {
   536     /* skip past the signature algorithm ID */
   537     if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
   538       fprintf(stderr, "ERROR: Could not seek past sig algorithm ID.\n");
   539       goto failure;
   540     }
   542     /* Get the signature length */
   543     if (fread(&signatureLen, sizeof(signatureLen), 1, fpSrc) != 1) {
   544       fprintf(stderr, "ERROR: could not read signature length\n");
   545       goto failure;
   546     }
   547     signatureLen = ntohl(signatureLen);
   549     /* Get the signature */
   550     extractedSignature = malloc(signatureLen);
   551     if (fread(extractedSignature, signatureLen, 1, fpSrc) != 1) {
   552       fprintf(stderr, "ERROR: could not read signature\n");
   553       goto failure;
   554     }
   555   }
   557   base64Encoded = BTOA_DataToAscii(extractedSignature, signatureLen);
   558   if (!base64Encoded) {
   559     fprintf(stderr, "ERROR: could not obtain base64 encoded data\n");
   560     goto failure;
   561   }
   563   if (fwrite(base64Encoded, strlen(base64Encoded), 1, fpDest) != 1) {
   564     fprintf(stderr, "ERROR: Could not write base64 encoded string\n");
   565     goto failure;
   566   }
   568   rv = 0;
   569 failure:
   570   if (base64Encoded) {
   571     PORT_Free(base64Encoded);
   572   }
   574   if (extractedSignature) {
   575     free(extractedSignature);
   576   }
   578   if (fpSrc) {
   579     fclose(fpSrc);
   580   }
   582   if (fpDest) {
   583     fclose(fpDest);
   584   }
   586   if (rv) {
   587     remove(dest);
   588   }
   590   return rv;
   591 }
   593 /**
   594  * Imports a base64 encoded signature into a MAR file
   595  *
   596  * @param  src           The path of the source MAR file
   597  * @param  sigIndex      The index of the signature to import
   598  * @param  base64SigFile A file which contains the signature to import
   599  * @param  dest          The path of the destination MAR file with replaced signature
   600  * @return 0 on success
   601  *         -1 on error
   602 */
   603 int
   604 import_signature(const char *src, uint32_t sigIndex,
   605                  const char *base64SigFile, const char *dest)
   606 {
   607   int rv = -1;
   608   FILE *fpSrc = NULL;
   609   FILE *fpDest = NULL;
   610   FILE *fpSigFile = NULL;
   611   uint32_t i;
   612   uint32_t signatureCount, signatureLen, signatureAlgorithmID,
   613            numChunks, leftOver;
   614   char buf[BLOCKSIZE];
   615   uint64_t sizeOfSrcMAR, sizeOfBase64EncodedFile;
   616   char *passedInSignatureB64 = NULL;
   617   uint8_t *passedInSignatureRaw = NULL;
   618   uint8_t *extractedMARSignature = NULL;
   619   unsigned int passedInSignatureLenRaw;
   621   if (!src || !dest) {
   622     fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
   623     goto failure;
   624   }
   626   fpSrc = fopen(src, "rb");
   627   if (!fpSrc) {
   628     fprintf(stderr, "ERROR: could not open source file: %s\n", src);
   629     goto failure;
   630   }
   632   fpDest = fopen(dest, "wb");
   633   if (!fpDest) {
   634     fprintf(stderr, "ERROR: could not open dest file: %s\n", dest);
   635     goto failure;
   636   }
   638   fpSigFile = fopen(base64SigFile , "rb");
   639   if (!fpSigFile) {
   640     fprintf(stderr, "ERROR: could not open sig file: %s\n", base64SigFile);
   641     goto failure;
   642   }
   644   /* Get the src file size */
   645   if (fseeko(fpSrc, 0, SEEK_END)) {
   646     fprintf(stderr, "ERROR: Could not seek to end of src file.\n");
   647     goto failure;
   648   }
   649   sizeOfSrcMAR = ftello(fpSrc);
   650   if (fseeko(fpSrc, 0, SEEK_SET)) {
   651     fprintf(stderr, "ERROR: Could not seek to start of src file.\n");
   652     goto failure;
   653   }
   655   /* Get the sig file size */
   656   if (fseeko(fpSigFile, 0, SEEK_END)) {
   657     fprintf(stderr, "ERROR: Could not seek to end of sig file.\n");
   658     goto failure;
   659   }
   660   sizeOfBase64EncodedFile= ftello(fpSigFile);
   661   if (fseeko(fpSigFile, 0, SEEK_SET)) {
   662     fprintf(stderr, "ERROR: Could not seek to start of sig file.\n");
   663     goto failure;
   664   }
   666   /* Read in the base64 encoded signature to import */
   667   passedInSignatureB64 = malloc(sizeOfBase64EncodedFile + 1);
   668   passedInSignatureB64[sizeOfBase64EncodedFile] = '\0';
   669   if (fread(passedInSignatureB64, sizeOfBase64EncodedFile, 1, fpSigFile) != 1) {
   670     fprintf(stderr, "ERROR: Could read b64 sig file.\n");
   671     goto failure;
   672   }
   674   /* Decode the base64 encoded data */
   675   passedInSignatureRaw = ATOB_AsciiToData(passedInSignatureB64, &passedInSignatureLenRaw);
   676   if (!passedInSignatureRaw) {
   677     fprintf(stderr, "ERROR: could not obtain base64 decoded data\n");
   678     goto failure;
   679   }
   681   /* Read everything up until the signature block offset and write it out */
   682   if (ReadAndWrite(fpSrc, fpDest, buf,
   683                    SIGNATURE_BLOCK_OFFSET, "signature block offset")) {
   684     goto failure;
   685   }
   687   /* Get the number of signatures */
   688   if (ReadAndWrite(fpSrc, fpDest, &signatureCount,
   689                    sizeof(signatureCount), "signature count")) {
   690     goto failure;
   691   }
   692   signatureCount = ntohl(signatureCount);
   693   if (signatureCount > MAX_SIGNATURES) {
   694     fprintf(stderr, "ERROR: Signature count was out of range\n");
   695     goto failure;
   696   }
   698   if (sigIndex >= signatureCount) {
   699     fprintf(stderr, "ERROR: Signature index was out of range\n");
   700     goto failure;
   701   }
   703   /* Read and write the whole signature block, but if we reach the
   704      signature offset, then we should replace it with the specified
   705      base64 decoded signature */
   706   for (i = 0; i < signatureCount; i++) {
   707     /* Read/Write the signature algorithm ID */
   708     if (ReadAndWrite(fpSrc, fpDest,
   709                      &signatureAlgorithmID,
   710                      sizeof(signatureAlgorithmID), "sig algorithm ID")) {
   711       goto failure;
   712     }
   714     /* Read/Write the signature length */
   715     if (ReadAndWrite(fpSrc, fpDest,
   716                      &signatureLen, sizeof(signatureLen), "sig length")) {
   717       goto failure;
   718     }
   719     signatureLen = ntohl(signatureLen);
   721     /* Get the signature */
   722     if (extractedMARSignature) {
   723       free(extractedMARSignature);
   724     }
   725     extractedMARSignature = malloc(signatureLen);
   727     if (sigIndex == i) {
   728       if (passedInSignatureLenRaw != signatureLen) {
   729         fprintf(stderr, "ERROR: Signature length must be the same\n");
   730         goto failure;
   731       }
   733       if (fread(extractedMARSignature, signatureLen, 1, fpSrc) != 1) {
   734         fprintf(stderr, "ERROR: Could not read signature\n");
   735         goto failure;
   736       }
   738       if (fwrite(passedInSignatureRaw, passedInSignatureLenRaw,
   739                  1, fpDest) != 1) {
   740         fprintf(stderr, "ERROR: Could not write signature\n");
   741         goto failure;
   742       }
   743     } else {
   744       if (ReadAndWrite(fpSrc, fpDest,
   745                        extractedMARSignature, signatureLen, "signature")) {
   746         goto failure;
   747       }
   748     }
   749   }
   751   /* We replaced the signature so let's just skip past the rest o the
   752      file. */
   753   numChunks = (sizeOfSrcMAR - ftello(fpSrc)) / BLOCKSIZE;
   754   leftOver = (sizeOfSrcMAR - ftello(fpSrc)) % BLOCKSIZE;
   756   /* Read each file and write it to the MAR file */
   757   for (i = 0; i < numChunks; ++i) {
   758     if (ReadAndWrite(fpSrc, fpDest, buf, BLOCKSIZE, "content block")) {
   759       goto failure;
   760     }
   761   }
   763   if (ReadAndWrite(fpSrc, fpDest, buf, leftOver, "left over content block")) {
   764     goto failure;
   765   }
   767   rv = 0;
   769 failure:
   771   if (fpSrc) {
   772     fclose(fpSrc);
   773   }
   775   if (fpDest) {
   776     fclose(fpDest);
   777   }
   779   if (fpSigFile) {
   780     fclose(fpSigFile);
   781   }
   783   if (rv) {
   784     remove(dest);
   785   }
   787   if (extractedMARSignature) {
   788     free(extractedMARSignature);
   789   }
   791   if (passedInSignatureB64) {
   792     free(passedInSignatureB64);
   793   }
   795   if (passedInSignatureRaw) {
   796     PORT_Free(passedInSignatureRaw);
   797   }
   799   return rv;
   800 }
   802 /**
   803  * Writes out a copy of the MAR at src but with embedded signatures.
   804  * The passed in MAR file must not already be signed or an error will 
   805  * be returned.
   806  *
   807  * @param  NSSConfigDir  The NSS directory containing the private key for signing
   808  * @param  certNames     The nicknames of the certificate to use for signing
   809  * @param  certCount     The number of certificate names contained in certNames.
   810  *                       One signature will be produced for each certificate.
   811  * @param  src           The path of the source MAR file to sign
   812  * @param  dest          The path of the MAR file to write out that is signed
   813  * @return 0 on success
   814  *         -1 on error
   815 */
   816 int
   817 mar_repackage_and_sign(const char *NSSConfigDir, 
   818                        const char * const *certNames,
   819                        uint32_t certCount,
   820                        const char *src, 
   821                        const char *dest) 
   822 {
   823   uint32_t offsetToIndex, dstOffsetToIndex, indexLength, 
   824     numSignatures = 0, leftOver,
   825     signatureAlgorithmID, signatureSectionLength = 0;
   826   uint32_t signatureLengths[MAX_SIGNATURES];
   827   int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR, 
   828     signaturePlaceholderOffset, numBytesToCopy, 
   829     numChunks, i;
   830   FILE *fpSrc = NULL, *fpDest = NULL;
   831   int rv = -1, hasSignatureBlock;
   832   SGNContext *ctxs[MAX_SIGNATURES];
   833   SECItem secItems[MAX_SIGNATURES];
   834   char buf[BLOCKSIZE];
   835   SECKEYPrivateKey *privKeys[MAX_SIGNATURES];
   836   CERTCertificate *certs[MAX_SIGNATURES];
   837   char *indexBuf = NULL, *indexBufLoc;
   838   uint32_t k;
   840   memset(signatureLengths, 0, sizeof(signatureLengths));
   841   memset(ctxs, 0, sizeof(ctxs));
   842   memset(secItems, 0, sizeof(secItems));
   843   memset(privKeys, 0, sizeof(privKeys));
   844   memset(certs, 0, sizeof(certs));
   846   if (!NSSConfigDir || !certNames || certCount == 0 || !src || !dest) {
   847     fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
   848     return -1;
   849   }
   851   if (NSSInitCryptoContext(NSSConfigDir)) {
   852     fprintf(stderr, "ERROR: Could not init config dir: %s\n", NSSConfigDir);
   853     goto failure;
   854   }
   856   PK11_SetPasswordFunc(SECU_GetModulePassword);
   858   fpSrc = fopen(src, "rb");
   859   if (!fpSrc) {
   860     fprintf(stderr, "ERROR: could not open source file: %s\n", src);
   861     goto failure;
   862   }
   864   fpDest = fopen(dest, "wb");
   865   if (!fpDest) {
   866     fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
   867     goto failure;
   868   }
   870   /* Determine if the source MAR file has the new fields for signing or not */
   871   if (get_mar_file_info(src, &hasSignatureBlock, NULL, NULL, NULL, NULL)) {
   872     fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
   873     goto failure;
   874   }
   876   for (k = 0; k < certCount; k++) {
   877     if (NSSSignBegin(certNames[k], &ctxs[k], &privKeys[k],
   878                      &certs[k], &signatureLengths[k])) {
   879       fprintf(stderr, "ERROR: NSSSignBegin failed\n");
   880       goto failure;
   881     }
   882   }
   884   /* MAR ID */
   885   if (ReadWriteAndUpdateSignatures(fpSrc, fpDest,
   886                                    buf, MAR_ID_SIZE,
   887                                    ctxs, certCount, "MAR ID")) {
   888     goto failure;
   889   }
   891   /* Offset to index */
   892   if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
   893     fprintf(stderr, "ERROR: Could not read offset\n");
   894     goto failure;
   895   }
   896   offsetToIndex = ntohl(offsetToIndex);
   898   /* Get the real size of the MAR */
   899   oldPos = ftello(fpSrc);
   900   if (fseeko(fpSrc, 0, SEEK_END)) {
   901     fprintf(stderr, "ERROR: Could not seek to end of file.\n");
   902     goto failure;
   903   }
   904   realSizeOfSrcMAR = ftello(fpSrc);
   905   if (fseeko(fpSrc, oldPos, SEEK_SET)) {
   906     fprintf(stderr, "ERROR: Could not seek back to current location.\n");
   907     goto failure;
   908   }
   910   if (hasSignatureBlock) {
   911     /* Get the MAR length and adjust its size */
   912     if (fread(&sizeOfEntireMAR, 
   913               sizeof(sizeOfEntireMAR), 1, fpSrc) != 1) {
   914       fprintf(stderr, "ERROR: Could read mar size\n");
   915       goto failure;
   916     }
   917     sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
   918     if (sizeOfEntireMAR != realSizeOfSrcMAR) {
   919       fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
   920       goto failure;
   921     }
   923     /* Get the num signatures in the source file */
   924     if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
   925       fprintf(stderr, "ERROR: Could read num signatures\n");
   926       goto failure;
   927     }
   928     numSignatures = ntohl(numSignatures);
   930     /* We do not support resigning, if you have multiple signatures,
   931        you must add them all at the same time. */
   932     if (numSignatures) {
   933       fprintf(stderr, "ERROR: MAR is already signed\n");
   934       goto failure;
   935     }
   936   } else {
   937     sizeOfEntireMAR = realSizeOfSrcMAR;
   938   }
   940   if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
   941     fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
   942     goto failure;
   943   }
   945   /* Calculate the total signature block length */
   946   for (k = 0; k < certCount; k++) {
   947     signatureSectionLength += sizeof(signatureAlgorithmID) +
   948                               sizeof(signatureLengths[k]) +
   949                               signatureLengths[k];
   950   }
   951   dstOffsetToIndex = offsetToIndex;
   952   if (!hasSignatureBlock) {
   953     dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
   954   }
   955   dstOffsetToIndex += signatureSectionLength;
   957   /* Write out the index offset */
   958   dstOffsetToIndex = htonl(dstOffsetToIndex);
   959   if (WriteAndUpdateSignatures(fpDest, &dstOffsetToIndex,
   960                                sizeof(dstOffsetToIndex), ctxs, certCount,
   961                                "index offset")) {
   962     goto failure;
   963   }
   964   dstOffsetToIndex = ntohl(dstOffsetToIndex);
   966   /* Write out the new MAR file size */
   967   sizeOfEntireMAR += signatureSectionLength;
   968   if (!hasSignatureBlock) {
   969     sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
   970   }
   972   /* Write out the MAR size */
   973   sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
   974   if (WriteAndUpdateSignatures(fpDest, &sizeOfEntireMAR,
   975                                sizeof(sizeOfEntireMAR), ctxs, certCount,
   976                                "size of MAR")) {
   977     goto failure;
   978   }
   979   sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
   981   /* Write out the number of signatures */
   982   numSignatures = certCount;
   983   numSignatures = htonl(numSignatures);
   984   if (WriteAndUpdateSignatures(fpDest, &numSignatures,
   985                                sizeof(numSignatures), ctxs, certCount,
   986                                "num signatures")) {
   987     goto failure;
   988   }
   989   numSignatures = ntohl(numSignatures);
   991   signaturePlaceholderOffset = ftello(fpDest);
   993   for (k = 0; k < certCount; k++) {
   994     /* Write out the signature algorithm ID, Only an ID of 1 is supported */
   995     signatureAlgorithmID = htonl(1);
   996     if (WriteAndUpdateSignatures(fpDest, &signatureAlgorithmID,
   997                                  sizeof(signatureAlgorithmID),
   998                                  ctxs, certCount, "num signatures")) {
   999       goto failure;
  1001     signatureAlgorithmID = ntohl(signatureAlgorithmID);
  1003     /* Write out the signature length */
  1004     signatureLengths[k] = htonl(signatureLengths[k]);
  1005     if (WriteAndUpdateSignatures(fpDest, &signatureLengths[k],
  1006                                  sizeof(signatureLengths[k]),
  1007                                  ctxs, certCount, "signature length")) {
  1008       goto failure;
  1010     signatureLengths[k] = ntohl(signatureLengths[k]);
  1012     /* Write out a placeholder for the signature, we'll come back to this later
  1013       *** THIS IS NOT SIGNED because it is a placeholder that will be replaced
  1014           below, plus it is going to be the signature itself. *** */
  1015     memset(buf, 0, sizeof(buf));
  1016     if (fwrite(buf, signatureLengths[k], 1, fpDest) != 1) {
  1017       fprintf(stderr, "ERROR: Could not write signature length\n");
  1018       goto failure;
  1022   /* Write out the rest of the MAR excluding the index header and index
  1023      offsetToIndex unfortunately has to remain 32-bit because for backwards
  1024      compatibility with the old MAR file format. */
  1025   if (ftello(fpSrc) > ((int64_t)offsetToIndex)) {
  1026     fprintf(stderr, "ERROR: Index offset is too small.\n");
  1027     goto failure;
  1029   numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
  1030   numChunks = numBytesToCopy / BLOCKSIZE;
  1031   leftOver = numBytesToCopy % BLOCKSIZE;
  1033   /* Read each file and write it to the MAR file */
  1034   for (i = 0; i < numChunks; ++i) {
  1035     if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
  1036                                      BLOCKSIZE, ctxs, certCount,
  1037                                      "content block")) {
  1038       goto failure;
  1042   /* Write out the left over */
  1043   if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
  1044                                    leftOver, ctxs, certCount,
  1045                                    "left over content block")) {
  1046     goto failure;
  1049   /* Length of the index */
  1050   if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, &indexLength,
  1051                                    sizeof(indexLength), ctxs, certCount,
  1052                                    "index length")) {
  1053     goto failure;
  1055   indexLength = ntohl(indexLength);
  1057   /* Consume the index and adjust each index by signatureSectionLength */
  1058   indexBuf = malloc(indexLength);
  1059   indexBufLoc = indexBuf;
  1060   if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
  1061     fprintf(stderr, "ERROR: Could not read index\n");
  1062     goto failure;
  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;

mercurial