コード例 #1
0
ファイル: secsign.c プロジェクト: Crawping/chromium_extract
/*
** Sign a block of data returning in result a bunch of bytes that are the
** signature. Returns zero on success, an error code on failure.
*/
SECStatus
SEC_SignData(SECItem *res, const unsigned char *buf, int len,
	     SECKEYPrivateKey *pk, SECOidTag algid)
{
    SECStatus rv;
    SGNContext *sgn;


    sgn = SGN_NewContext(algid, pk);

    if (sgn == NULL)
	return SECFailure;

    rv = SGN_Begin(sgn);
    if (rv != SECSuccess)
	goto loser;

    rv = SGN_Update(sgn, buf, len);
    if (rv != SECSuccess)
	goto loser;

    rv = SGN_End(sgn, res);

  loser:
    SGN_DestroyContext(sgn, PR_TRUE);
    return rv;
}
コード例 #2
0
ファイル: mar_sign.c プロジェクト: Flatta/LibreOffice-core
/**
 * Writes out a copy of the MAR at src but with embedded signatures.
 * The passed in MAR file must not already be signed or an error will
 * be returned.
 *
 * @param  NSSConfigDir  The NSS directory containing the private key for signing
 * @param  certNames     The nicknames of the certificate to use for signing
 * @param  certCount     The number of certificate names contained in certNames.
 *                       One signature will be produced for each certificate.
 * @param  src           The path of the source MAR file to sign
 * @param  dest          The path of the MAR file to write out that is signed
 * @return 0 on success
 *         -1 on error
*/
int
mar_repackage_and_sign(const char *NSSConfigDir,
                       const char * const *certNames,
                       uint32_t certCount,
                       const char *src,
                       const char *dest)
{
  uint32_t offsetToIndex, dstOffsetToIndex, indexLength,
    numSignatures = 0, leftOver,
    signatureAlgorithmID, signatureSectionLength = 0;
  uint32_t signatureLengths[MAX_SIGNATURES];
  int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR,
    signaturePlaceholderOffset, numBytesToCopy,
    numChunks, i;
  FILE *fpSrc = NULL, *fpDest = NULL;
  int rv = -1, hasSignatureBlock;
  SGNContext *ctxs[MAX_SIGNATURES];
  SECItem secItems[MAX_SIGNATURES];
  char buf[BLOCKSIZE];
  SECKEYPrivateKey *privKeys[MAX_SIGNATURES];
  CERTCertificate *certs[MAX_SIGNATURES];
  char *indexBuf = NULL;
  uint32_t k;

  memset(signatureLengths, 0, sizeof(signatureLengths));
  memset(ctxs, 0, sizeof(ctxs));
  memset(secItems, 0, sizeof(secItems));
  memset(privKeys, 0, sizeof(privKeys));
  memset(certs, 0, sizeof(certs));

  if (!NSSConfigDir || !certNames || certCount == 0 || !src || !dest) {
    fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
    return -1;
  }

  if (NSSInitCryptoContext(NSSConfigDir)) {
    fprintf(stderr, "ERROR: Could not init config dir: %s\n", NSSConfigDir);
    goto failure;
  }

  PK11_SetPasswordFunc(SECU_GetModulePassword);

  fpSrc = fopen(src, "rb");
  if (!fpSrc) {
    fprintf(stderr, "ERROR: could not open source file: %s\n", src);
    goto failure;
  }

  fpDest = fopen(dest, "wb");
  if (!fpDest) {
    fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
    goto failure;
  }

  /* Determine if the source MAR file has the new fields for signing or not */
  if (get_mar_file_info(src, &hasSignatureBlock, NULL, NULL, NULL, NULL)) {
    fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
    goto failure;
  }

  for (k = 0; k < certCount; k++) {
    if (NSSSignBegin(certNames[k], &ctxs[k], &privKeys[k],
                     &certs[k], &signatureLengths[k])) {
      fprintf(stderr, "ERROR: NSSSignBegin failed\n");
      goto failure;
    }
  }

  /* MAR ID */
  if (ReadWriteAndUpdateSignatures(fpSrc, fpDest,
                                   buf, MAR_ID_SIZE,
                                   ctxs, certCount, "MAR ID")) {
    goto failure;
  }

  /* Offset to index */
  if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
    fprintf(stderr, "ERROR: Could not read offset\n");
    goto failure;
  }
  offsetToIndex = ntohl(offsetToIndex);

  /* Get the real size of the MAR */
  oldPos = ftello(fpSrc);
  if (fseeko(fpSrc, 0, SEEK_END)) {
    fprintf(stderr, "ERROR: Could not seek to end of file.\n");
    goto failure;
  }
  realSizeOfSrcMAR = ftello(fpSrc);
  if (fseeko(fpSrc, oldPos, SEEK_SET)) {
    fprintf(stderr, "ERROR: Could not seek back to current location.\n");
    goto failure;
  }

  if (hasSignatureBlock) {
    /* Get the MAR length and adjust its size */
    if (fread(&sizeOfEntireMAR,
              sizeof(sizeOfEntireMAR), 1, fpSrc) != 1) {
      fprintf(stderr, "ERROR: Could read mar size\n");
      goto failure;
    }
    sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
    if (sizeOfEntireMAR != realSizeOfSrcMAR) {
      fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
      goto failure;
    }

    /* Get the num signatures in the source file */
    if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
      fprintf(stderr, "ERROR: Could read num signatures\n");
      goto failure;
    }
    numSignatures = ntohl(numSignatures);

    /* We do not support resigning, if you have multiple signatures,
       you must add them all at the same time. */
    if (numSignatures) {
      fprintf(stderr, "ERROR: MAR is already signed\n");
      goto failure;
    }
  } else {
    sizeOfEntireMAR = realSizeOfSrcMAR;
  }

  if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
    fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
    goto failure;
  }

  /* Calculate the total signature block length */
  for (k = 0; k < certCount; k++) {
    signatureSectionLength += sizeof(signatureAlgorithmID) +
                              sizeof(signatureLengths[k]) +
                              signatureLengths[k];
  }
  dstOffsetToIndex = offsetToIndex;
  if (!hasSignatureBlock) {
    dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
  }
  dstOffsetToIndex += signatureSectionLength;

  /* Write out the index offset */
  dstOffsetToIndex = htonl(dstOffsetToIndex);
  if (WriteAndUpdateSignatures(fpDest, &dstOffsetToIndex,
                               sizeof(dstOffsetToIndex), ctxs, certCount,
                               "index offset")) {
    goto failure;
  }
  dstOffsetToIndex = ntohl(dstOffsetToIndex);

  /* Write out the new MAR file size */
  sizeOfEntireMAR += signatureSectionLength;
  if (!hasSignatureBlock) {
    sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
  }

  /* Write out the MAR size */
  sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
  if (WriteAndUpdateSignatures(fpDest, &sizeOfEntireMAR,
                               sizeof(sizeOfEntireMAR), ctxs, certCount,
                               "size of MAR")) {
    goto failure;
  }
  sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);

  /* Write out the number of signatures */
  numSignatures = certCount;
  numSignatures = htonl(numSignatures);
  if (WriteAndUpdateSignatures(fpDest, &numSignatures,
                               sizeof(numSignatures), ctxs, certCount,
                               "num signatures")) {
    goto failure;
  }
  numSignatures = ntohl(numSignatures);

  signaturePlaceholderOffset = ftello(fpDest);

  for (k = 0; k < certCount; k++) {
    /* Write out the signature algorithm ID, Only an ID of 1 is supported */
    signatureAlgorithmID = htonl(1);
    if (WriteAndUpdateSignatures(fpDest, &signatureAlgorithmID,
                                 sizeof(signatureAlgorithmID),
                                 ctxs, certCount, "num signatures")) {
      goto failure;
    }
    signatureAlgorithmID = ntohl(signatureAlgorithmID);

    /* Write out the signature length */
    signatureLengths[k] = htonl(signatureLengths[k]);
    if (WriteAndUpdateSignatures(fpDest, &signatureLengths[k],
                                 sizeof(signatureLengths[k]),
                                 ctxs, certCount, "signature length")) {
      goto failure;
    }
    signatureLengths[k] = ntohl(signatureLengths[k]);

    /* Write out a placeholder for the signature, we'll come back to this later
      *** THIS IS NOT SIGNED because it is a placeholder that will be replaced
          below, plus it is going to be the signature itself. *** */
    memset(buf, 0, sizeof(buf));
    if (fwrite(buf, signatureLengths[k], 1, fpDest) != 1) {
      fprintf(stderr, "ERROR: Could not write signature length\n");
      goto failure;
    }
  }

  /* Write out the rest of the MAR excluding the index header and index
     offsetToIndex unfortunately has to remain 32-bit because for backwards
     compatibility with the old MAR file format. */
  if (ftello(fpSrc) > ((int64_t)offsetToIndex)) {
    fprintf(stderr, "ERROR: Index offset is too small.\n");
    goto failure;
  }
  numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
  numChunks = numBytesToCopy / BLOCKSIZE;
  leftOver = numBytesToCopy % BLOCKSIZE;

  /* Read each file and write it to the MAR file */
  for (i = 0; i < numChunks; ++i) {
    if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
                                     BLOCKSIZE, ctxs, certCount,
                                     "content block")) {
      goto failure;
    }
  }

  /* Write out the left over */
  if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
                                   leftOver, ctxs, certCount,
                                   "left over content block")) {
    goto failure;
  }

  /* Length of the index */
  if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, &indexLength,
                                   sizeof(indexLength), ctxs, certCount,
                                   "index length")) {
    goto failure;
  }
  indexLength = ntohl(indexLength);

  /* Consume the index and adjust each index by signatureSectionLength */
  indexBuf = malloc(indexLength);
  if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
    fprintf(stderr, "ERROR: Could not read index\n");
    goto failure;
  }

  /* Adjust each entry in the index */
  if (hasSignatureBlock) {
    AdjustIndexContentOffsets(indexBuf, indexLength, signatureSectionLength);
  } else {
    AdjustIndexContentOffsets(indexBuf, indexLength,
                              sizeof(sizeOfEntireMAR) +
                              sizeof(numSignatures) +
                              signatureSectionLength);
  }

  if (WriteAndUpdateSignatures(fpDest, indexBuf,
                               indexLength, ctxs, certCount, "index")) {
    goto failure;
  }

  /* Ensure that we don't sign a file that is too large to be accepted by
     the verification function. */
  if (ftello(fpDest) > MAX_SIZE_OF_MAR_FILE) {
    goto failure;
  }

  for (k = 0; k < certCount; k++) {
    /* Get the signature */
    if (SGN_End(ctxs[k], &secItems[k]) != SECSuccess) {
      fprintf(stderr, "ERROR: Could not end signature context\n");
      goto failure;
    }
    if (signatureLengths[k] != secItems[k].len) {
      fprintf(stderr, "ERROR: Signature is not the expected length\n");
      goto failure;
    }
  }

  /* Get back to the location of the signature placeholder */
  if (fseeko(fpDest, signaturePlaceholderOffset, SEEK_SET)) {
    fprintf(stderr, "ERROR: Could not seek to signature offset\n");
    goto failure;
  }

  for (k = 0; k < certCount; k++) {
    /* Skip to the position of the next signature */
    if (fseeko(fpDest, sizeof(signatureAlgorithmID) +
               sizeof(signatureLengths[k]), SEEK_CUR)) {
      fprintf(stderr, "ERROR: Could not seek to signature offset\n");
      goto failure;
    }

    /* Write out the calculated signature.
      *** THIS IS NOT SIGNED because it is the signature itself. *** */
    if (fwrite(secItems[k].data, secItems[k].len, 1, fpDest) != 1) {
      fprintf(stderr, "ERROR: Could not write signature\n");
      goto failure;
    }
  }

  rv = 0;
failure:
  if (fpSrc) {
    fclose(fpSrc);
  }

  if (fpDest) {
    fclose(fpDest);
  }

  if (rv) {
    remove(dest);
  }

  if (indexBuf) {
    free(indexBuf);
  }

  /* Cleanup */
  for (k = 0; k < certCount; k++) {
    if (ctxs[k]) {
      SGN_DestroyContext(ctxs[k], PR_TRUE);
    }

    if (certs[k]) {
      CERT_DestroyCertificate(certs[k]);
    }

    if (privKeys[k]) {
      SECKEY_DestroyPrivateKey(privKeys[k]);
    }

    SECITEM_FreeItem(&secItems[k], PR_FALSE);
  }

  if (rv) {
    remove(dest);
  }

  return rv;
}