tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }