Commit 1582f105 authored by Brian Smith's avatar Brian Smith Committed by Georg Koppen
Browse files

Bug 903135 - Updates to libmar needed to support B2G MAR signature verification. r=bbondy

parent a27b3400
Loading
Loading
Loading
Loading
+24 −6
Original line number Diff line number Diff line
@@ -134,6 +134,26 @@ int mar_create(const char *dest,
 */
int mar_extract(const char *path);

#define MAR_MAX_CERT_SIZE (16*1024) // Way larger than necessary

/* Read the entire file (not a MAR file) into a newly-allocated buffer.
 * This function does not write to stderr. Instead, the caller should
 * write whatever error messages it sees fit. The caller must free the returned
 * buffer using free().
 *
 * @param filePath The path to the file that should be read.
 * @param maxSize  The maximum valid file size.
 * @param data     On success, *data will point to a newly-allocated buffer
 *                 with the file's contents in it.
 * @param size     On success, *size will be the size of the created buffer.
 * 
 * @return 0 on success, -1 on error
 */
int mar_read_entire_file(const char * filePath,
                         uint32_t maxSize,
                         /*out*/ const uint8_t * *data,
                         /*out*/ uint32_t *size);

/**
 * Verifies a MAR file by verifying each signature with the corresponding
 * certificate. That is, the first signature will be verified using the first
@@ -154,12 +174,10 @@ int mar_extract(const char *path);
 *         a negative number if there was an error
 *         a positive number if the signature does not verify
 */
#ifdef XP_WIN
int mar_verify_signaturesW(MarFile *mar,
int mar_verify_signatures(MarFile *mar,
                          const uint8_t * const *certData,
                          const uint32_t *certDataSizes,
                          uint32_t certCount);
#endif

/** 
 * Reads the product info block from the MAR file's additional block section.
+0 −32
Original line number Diff line number Diff line
@@ -38,38 +38,6 @@ int get_mar_file_info(const char *path,
                      uint32_t *offsetAdditionalBlocks,
                      uint32_t *numAdditionalBlocks);

/**
 * Verifies a MAR file by verifying each signature with the corresponding
 * certificate. That is, the first signature will be verified using the first
 * certificate given, the second signature will be verified using the second
 * certificate given, etc. The signature count must exactly match the number of
 * certificates given, and all signature verifications must succeed.
 * This is only used by the signmar program when used with arguments to verify 
 * a MAR. This should not be used to verify a MAR that will be extracted in the 
 * same operation by updater code. This function prints the error message if 
 * verification fails.
 * 
 * @param pathToMAR     The path of the MAR file whose signature should be
 *                      checked
 * @param certData      Pointer to the first element in an array of certificate
 *                      file data.
 * @param certDataSizes Pointer to the first element in an array for size of
 *                      the cert data.
 * @param certNames     Pointer to the first element in an array of certificate
 *                      names.
 *                      Used only if compiled with NSS support
 * @param certCount     The number of elements in certData, certDataSizes,
 *                      and certNames
 * @return 0 on success
 *         a negative number if there was an error
 *         a positive number if the signature does not verify
 */
int mar_verify_signatures(const char *pathToMAR,
                          const uint8_t * const *certData,
                          const uint32_t *certDataSizes,
                          const char * const *certNames,
                          uint32_t certCount);

/** 
 * Reads the product info block from the MAR file's additional block section.
 * The caller is responsible for freeing the fields in infoBlock
+58 −51
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#endif

#if !defined(NO_SIGN_VERIFY) && (!defined(XP_WIN) || defined(MAR_NSS))
#include "cert.h"
#include "pk11pub.h"
int NSSInitCryptoContext(const char *NSSConfigDir);
#endif

@@ -120,15 +122,13 @@ int main(int argc, char **argv) {
  uint32_t certCount = 0;
  int32_t sigIndex = -1;

#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
  HANDLE certFile;
#if !defined(NO_SIGN_VERIFY)
  uint32_t fileSizes[MAX_SIGNATURES];
  uint8_t* certBuffers[MAX_SIGNATURES];
#endif
#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
                                 defined(XP_MACOSX))
  char* DERFilePaths[MAX_SIGNATURES];
  uint32_t fileSizes[MAX_SIGNATURES];
  uint32_t read;
#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS)
  CERTCertificate* certs[MAX_SIGNATURES];
#endif
#endif

  memset(certNames, 0, sizeof(certNames));
@@ -319,43 +319,68 @@ int main(int argc, char **argv) {
    return import_signature(argv[2], sigIndex, argv[3], argv[4]);

  case 'v':

#if defined(XP_WIN) && !defined(MAR_NSS)
    if (certCount == 0) {
      print_usage();
      return -1;
    }

    for (k = 0; k < certCount; ++k) {
      /* If the mar program was built using CryptoAPI, then read in the buffer
        containing the cert from disk. */
      certFile = CreateFileA(DERFilePaths[k], GENERIC_READ,
                             FILE_SHARE_READ |
                             FILE_SHARE_WRITE |
                             FILE_SHARE_DELETE,
                             NULL,
                             OPEN_EXISTING,
                             0, NULL);
      if (INVALID_HANDLE_VALUE == certFile) {
#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS)
    if (!NSSConfigDir || certCount == 0) {
      print_usage();
      return -1;
    }
      fileSizes[k] = GetFileSize(certFile, NULL);
      certBuffers[k] = malloc(fileSizes[k]);
      if (!ReadFile(certFile, certBuffers[k], fileSizes[k], &read, NULL) ||
          fileSizes[k] != read) {
        CloseHandle(certFile);
        for (i = 0; i <= k; i++) {
          free(certBuffers[i]);
        }

    if (NSSInitCryptoContext(NSSConfigDir)) {
      fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
      return -1;
    }
      CloseHandle(certFile);
#endif

    rv = 0;
    for (k = 0; k < certCount; ++k) {
#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS)
      rv = mar_read_entire_file(DERFilePaths[k], MAR_MAX_CERT_SIZE,
                                &certBuffers[k], &fileSizes[k]);
#else
      /* It is somewhat circuitous to look up a CERTCertificate and then pass
       * in its DER encoding just so we can later re-create that
       * CERTCertificate to extract the public key out of it. However, by doing
       * things this way, we maximize the reuse of the mar_verify_signatures
       * function and also we keep the control flow as similar as possible
       * between programs and operating systems, at least for the functions
       * that are critically important to security.
       */
      certs[k] = PK11_FindCertFromNickname(certNames[k], NULL);
      if (certs[k]) {
        certBuffers[k] = certs[k]->derCert.data;
        fileSizes[k] = certs[k]->derCert.len;
      } else {
        rv = -1;
      }
#endif
      if (rv) {
        fprintf(stderr, "ERROR: could not read file %s", DERFilePaths[k]);
        break;
      }
    }

    rv = mar_verify_signatures(argv[2], certBuffers, fileSizes,
                               NULL, certCount);
    if (!rv) {
      MarFile *mar = mar_open(argv[2]);
      if (mar) {
        rv = mar_verify_signatures(mar, certBuffers, fileSizes, certCount);
        mar_close(mar);
      } else {
        fprintf(stderr, "ERROR: Could not open MAR file.\n");
        rv = -1;
      }
    }
    for (k = 0; k < certCount; ++k) {
#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS)
      free(certBuffers[k]);
#else
      /* certBuffers[k] is owned by certs[k] so don't free it */
      CERT_DestroyCertificate(certs[k]);
#endif
    }
    if (rv) {
      /* Determine if the source MAR file has the new fields for signing */
@@ -369,26 +394,8 @@ int main(int argc, char **argv) {
      }
      return -1;
    }

    return 0;

#elif defined(XP_MACOSX)
    return mar_verify_signatures(argv[2], (const uint8_t* const*)DERFilePaths,
                                 0, NULL, certCount);
#else
    if (!NSSConfigDir || certCount == 0) {
      print_usage();
      return -1;
    }

    if (NSSInitCryptoContext(NSSConfigDir)) {
      fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
      return -1;
    }

    return mar_verify_signatures(argv[2], NULL, 0, certNames, certCount);

#endif /* defined(XP_WIN) && !defined(MAR_NSS) */
  case 's':
    if (!NSSConfigDir || certCount == 0 || argc < 4) {
      print_usage();
+17 −15
Original line number Diff line number Diff line
@@ -16,29 +16,32 @@
/** 
 * Loads the public key for the specified cert name from the NSS store.
 * 
 * @param certName The cert name to find.
 * @param certData  The DER-encoded X509 certificate to extract the key from.
 * @param certDataSize The size of certData.
 * @param publicKey Out parameter for the public key to use.
 * @param cert      Out parameter for the certificate to use.
 * @return CryptoX_Success on success, CryptoX_Error on error.
*/
CryptoX_Result
NSS_LoadPublicKey(const char *certNickname, 
                  SECKEYPublicKey **publicKey, 
                  CERTCertificate **cert)
NSS_LoadPublicKey(const unsigned char *certData, unsigned int certDataSize,
                  SECKEYPublicKey **publicKey)
{
  secuPWData pwdata = { PW_NONE, 0 };
  if (!cert || !publicKey || !cert) {
  CERTCertificate * cert;
  SECItem certDataItem = { siBuffer, (unsigned char*) certData, certDataSize };

  if (!certData || !publicKey) {
    return CryptoX_Error;
  }

  cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certDataItem, NULL,
                                 PR_FALSE, PR_TRUE);
  /* Get the cert and embedded public key out of the database */
  *cert = PK11_FindCertFromNickname(certNickname, &pwdata);
  if (!*cert) {
  if (!cert) {
    return CryptoX_Error;
  }
  *publicKey = CERT_ExtractPublicKey(*cert);
  *publicKey = CERT_ExtractPublicKey(cert);
  CERT_DestroyCertificate(cert);

  if (!*publicKey) {
    CERT_DestroyCertificate(*cert);
    return CryptoX_Error;
  }
  return CryptoX_Success;
@@ -150,12 +153,11 @@ CryptoX_Result
CryptoAPI_LoadPublicKey(HCRYPTPROV provider, 
                        BYTE *certData,
                        DWORD sizeOfCertData,
                        HCRYPTKEY *publicKey,
                        HCERTSTORE *certStore)
                        HCRYPTKEY *publicKey)
{
  CRYPT_DATA_BLOB blob;
  CERT_CONTEXT *context;
  if (!provider || !certData || !publicKey || !certStore) {
  if (!provider || !certData || !publicKey) {
    return CryptoX_Error;
  }

@@ -165,7 +167,7 @@ CryptoAPI_LoadPublicKey(HCRYPTPROV provider,
                        CERT_QUERY_CONTENT_FLAG_CERT, 
                        CERT_QUERY_FORMAT_FLAG_BINARY, 
                        0, NULL, NULL, NULL, 
                        certStore, NULL, (const void **)&context)) {
                        NULL, NULL, (const void **)&context)) {
    return CryptoX_Error;
  }

+13 −16
Original line number Diff line number Diff line
@@ -15,7 +15,9 @@

#if defined(MAR_NSS)

#include "nss_secutil.h"
#include "cert.h"
#include "keyhi.h"
#include "cryptohi.h"

#define CryptoX_InvalidHandleValue NULL
#define CryptoX_ProviderHandle void*
@@ -26,9 +28,9 @@
#ifdef __cplusplus
extern "C" {
#endif
CryptoX_Result NSS_LoadPublicKey(const char *certNickname,
                                 SECKEYPublicKey **publicKey,
                                 CERTCertificate **cert);
CryptoX_Result NSS_LoadPublicKey(const unsigned char* certData,
                                 unsigned int certDataSize,
                                 SECKEYPublicKey** publicKey);
CryptoX_Result NSS_VerifyBegin(VFYContext **ctx,
                               SECKEYPublicKey * const *publicKey);
CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
@@ -46,9 +48,8 @@ CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
  VFY_DestroyContext(*SignatureHandle, PR_TRUE)
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
  VFY_Update(*SignatureHandle, (const unsigned char*)(buf), len)
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
                              publicKey, certName, cert) \
  NSS_LoadPublicKey(certName, publicKey, cert)
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
  NSS_LoadPublicKey(certData, dataSize, publicKey)
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
  NSS_VerifySignature(hash, (const unsigned char *)(signedData), len)
#define CryptoX_FreePublicKey(key) \
@@ -91,7 +92,7 @@ void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey);
#define CryptoX_VerifyUpdate(aInputData, aBuf, aLen) \
  CryptoMac_VerifyUpdate(aInputData, aBuf, aLen)
#define CryptoX_LoadPublicKey(aProviderHandle, aCertData, aDataSize, \
                              aPublicKey, aCertName, aCert) \
                              aPublicKey) \
  CryptoMac_LoadPublicKey(aCertData, aPublicKey)
#define CryptoX_VerifySignature(aInputData, aPublicKey, aSignature, \
                                aSignatureLen) \
@@ -111,8 +112,7 @@ CryptoX_Result CryptoAPI_InitCryptoContext(HCRYPTPROV *provider);
CryptoX_Result CryptoAPI_LoadPublicKey(HCRYPTPROV hProv, 
                                       BYTE *certData,
                                       DWORD sizeOfCertData,
                                       HCRYPTKEY *publicKey,
                                       HCERTSTORE *cert);
                                       HCRYPTKEY *publicKey);
CryptoX_Result CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash);
CryptoX_Result CryptoAPI_VerifyUpdate(HCRYPTHASH* hash, 
                                      BYTE *buf, DWORD len);
@@ -133,10 +133,8 @@ CryptoX_Result CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
#define CryptoX_FreeSignatureHandle(SignatureHandle)
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
  CryptoAPI_VerifyUpdate(SignatureHandle, (BYTE *)(buf), len)
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
                              publicKey, certName, cert) \
  CryptoAPI_LoadPublicKey(CryptoHandle, (BYTE*)(certData), \
                          dataSize, publicKey, cert)
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
  CryptoAPI_LoadPublicKey(CryptoHandle, (BYTE*)(certData), dataSize, publicKey)
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
  CyprtoAPI_VerifySignature(hash, publicKey, signedData, len)
#define CryptoX_FreePublicKey(key) \
@@ -163,8 +161,7 @@ CryptoX_Result CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
  CryptoX_Error
#define CryptoX_FreeSignatureHandle(SignatureHandle)
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) CryptoX_Error
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
                              publicKey, certName, cert) \
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
  CryptoX_Error
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) CryptoX_Error
#define CryptoX_FreePublicKey(key) CryptoX_Error
Loading