modules/libmar/verify/mar_verify.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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.h"
    18 #include "cryptox.h"
    20 int mar_extract_and_verify_signatures_fp(FILE *fp,
    21                                          CryptoX_ProviderHandle provider,
    22                                          CryptoX_PublicKey *keys,
    23                                          uint32_t keyCount);
    24 int mar_verify_signatures_for_fp(FILE *fp,
    25                                  CryptoX_ProviderHandle provider,
    26                                  CryptoX_PublicKey *keys,
    27                                  const uint8_t * const *extractedSignatures,
    28                                  uint32_t keyCount,
    29                                  uint32_t *numVerified);
    31 /**
    32  * Reads the specified number of bytes from the file pointer and
    33  * stores them in the passed buffer.
    34  *
    35  * @param  fp     The file pointer to read from.
    36  * @param  buffer The buffer to store the read results.
    37  * @param  size   The number of bytes to read, buffer must be 
    38  *                at least of this size.
    39  * @param  ctxs   Pointer to the first element in an array of verify context.
    40  * @param  count  The number of elements in ctxs
    41  * @param  err    The name of what is being written to in case of error.
    42  * @return  0 on success
    43  *         -1 on read error
    44  *         -2 on verify update error
    45 */
    46 int
    47 ReadAndUpdateVerifyContext(FILE *fp, 
    48                            void *buffer,
    49                            uint32_t size, 
    50                            CryptoX_SignatureHandle *ctxs,
    51                            uint32_t count,
    52                            const char *err) 
    53 {
    54   uint32_t k;
    55   if (!fp || !buffer || !ctxs || count == 0 || !err) {
    56     fprintf(stderr, "ERROR: Invalid parameter specified.\n");
    57     return CryptoX_Error;
    58   }
    60   if (!size) { 
    61     return CryptoX_Success;
    62   }
    64   if (fread(buffer, size, 1, fp) != 1) {
    65     fprintf(stderr, "ERROR: Could not read %s\n", err);
    66     return CryptoX_Error;
    67   }
    69   for (k = 0; k < count; k++) {
    70     if (CryptoX_Failed(CryptoX_VerifyUpdate(&ctxs[k], buffer, size))) {
    71       fprintf(stderr, "ERROR: Could not update verify context for %s\n", err);
    72       return -2;
    73     }
    74   }
    75   return CryptoX_Success;
    76 }
    78 /**
    79  * Verifies a MAR file by verifying each signature with the corresponding
    80  * certificate. That is, the first signature will be verified using the first
    81  * certificate given, the second signature will be verified using the second
    82  * certificate given, etc. The signature count must exactly match the number of
    83  * certificates given, and all signature verifications must succeed.
    84  * This is only used by the signmar program when used with arguments to verify 
    85  * a MAR. This should not be used to verify a MAR that will be extracted in the 
    86  * same operation by updater code. This function prints the error message if 
    87  * verification fails.
    88  * 
    89  * @param pathToMARFile The path of the MAR file to verify.
    90  * @param certData      Pointer to the first element in an array of certificate
    91  *                      file data.
    92  * @param certDataSizes Pointer to the first element in an array for size of the
    93  *                      cert data.
    94  * @param certNames     Pointer to the first element in an array of certificate names.
    95  *                      Used only if compiled as NSS, specifies the certificate names
    96  * @param certCount     The number of elements in certData, certDataSizes, and certNames
    97  * @return 0 on success
    98  *         a negative number if there was an error
    99  *         a positive number if the signature does not verify
   100  */
   101 int
   102 mar_verify_signatures(const char *pathToMARFile,
   103                       const uint8_t * const *certData,
   104                       const uint32_t *certDataSizes,
   105                       const char * const *certNames,
   106                       uint32_t certCount) {
   107   int rv;
   108   CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
   109   CryptoX_Certificate certs[MAX_SIGNATURES];
   110   CryptoX_PublicKey keys[MAX_SIGNATURES];
   111   FILE *fp;
   112   uint32_t k;
   114   memset(certs, 0, sizeof(certs));
   115   memset(keys, 0, sizeof(keys));
   117   if (!pathToMARFile || certCount == 0) {
   118     fprintf(stderr, "ERROR: Invalid parameter specified.\n");
   119     return CryptoX_Error;
   120   }
   122   fp = fopen(pathToMARFile, "rb");
   123   if (!fp) {
   124     fprintf(stderr, "ERROR: Could not open MAR file.\n");
   125     return CryptoX_Error;
   126   }
   128   if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
   129     fclose(fp);
   130     fprintf(stderr, "ERROR: Could not init crytpo library.\n");
   131     return CryptoX_Error;
   132   }
   134   /* Load the certs and keys */
   135   for (k = 0; k < certCount; k++) {
   136     if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
   137                                              &keys[k], certNames[k], &certs[k]))) {
   138       fclose(fp);
   139       fprintf(stderr, "ERROR: Could not load public key.\n");
   140       return CryptoX_Error;
   141     }
   142   }
   144   rv = mar_extract_and_verify_signatures_fp(fp, provider, keys, certCount);
   145   fclose(fp);
   147   /* Cleanup the allocated keys and certs */
   148   for (k = 0; k < certCount; k++) {
   149     if (keys[k]) {
   150       CryptoX_FreePublicKey(&keys[k]);
   151     }
   153     if (certs[k]) {
   154       CryptoX_FreeCertificate(&certs[k]);
   155     }
   156   }
   157   return rv;
   158 }
   160 #ifdef XP_WIN
   161 /**
   162  * Verifies a MAR file by verifying each signature with the corresponding
   163  * certificate. That is, the first signature will be verified using the first
   164  * certificate given, the second signature will be verified using the second
   165  * certificate given, etc. The signature count must exactly match the number of
   166  * certificates given, and all signature verifications must succeed.
   167  * 
   168  * @param  pathToMARFile  The path of the MAR file who's signature
   169  *                        should be calculated
   170  * @param  certData       Pointer to the first element in an array of
   171  *                        certificate data
   172  * @param  certDataSizes  Pointer to the first element in an array for size of
   173  *                        the data stored
   174  * @param  certCount      The number of elements in certData and certDataSizes
   175  * @return 0 on success
   176 */
   177 int
   178 mar_verify_signaturesW(MarFile *mar,
   179                        const uint8_t * const *certData,
   180                        const uint32_t *certDataSizes,
   181                        uint32_t certCount) {
   182   int rv = -1;
   183   CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
   184   CryptoX_Certificate certs[MAX_SIGNATURES];
   185   CryptoX_PublicKey keys[MAX_SIGNATURES];
   186   uint32_t k;
   188   memset(certs, 0, sizeof(certs));
   189   memset(keys, 0, sizeof(keys));
   191   if (!mar || !certData || !certDataSizes || certCount == 0) {
   192     fprintf(stderr, "ERROR: Invalid parameter specified.\n");
   193     goto failure;
   194   }
   196   if (!mar->fp) {
   197     fprintf(stderr, "ERROR: MAR file is not open.\n");
   198     goto failure;
   199   }
   201   if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) { 
   202     fprintf(stderr, "ERROR: Could not init crytpo library.\n");
   203     goto failure;
   204   }
   206   for (k = 0; k < certCount; ++k) {
   207     if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
   208                                              &keys[k], "", &certs[k]))) {
   209       fprintf(stderr, "ERROR: Could not load public key.\n");
   210       goto failure;
   211     }
   212   }
   214   rv = mar_extract_and_verify_signatures_fp(mar->fp, provider, keys, certCount);
   216 failure:
   218   for (k = 0; k < certCount; ++k) {
   219     if (keys[k]) {
   220       CryptoX_FreePublicKey(&keys[k]);
   221     }
   223     if (certs[k]) {
   224       CryptoX_FreeCertificate(&certs[k]);
   225     }
   226   }
   228   return rv;
   229 }
   230 #endif
   232 /**
   233  * Extracts each signature from the specified MAR file,
   234  * then calls mar_verify_signatures_for_fp to verify each signature.
   235  *
   236  * @param  fp       An opened MAR file handle
   237  * @param  provider A library provider
   238  * @param  keys     The public keys to use to verify the MAR
   239  * @param  keyCount The number of keys pointed to by keys
   240  * @return 0 on success
   241 */
   242 int
   243 mar_extract_and_verify_signatures_fp(FILE *fp,
   244                                      CryptoX_ProviderHandle provider,
   245                                      CryptoX_PublicKey *keys,
   246                                      uint32_t keyCount) {
   247   char buf[5] = {0};
   248   uint32_t signatureCount, signatureLen, numVerified = 0;
   249   uint32_t signatureAlgorithmIDs[MAX_SIGNATURES];
   250   int rv = -1;
   251   int64_t curPos;
   252   uint8_t *extractedSignatures[MAX_SIGNATURES];
   253   uint32_t i;
   255   memset(signatureAlgorithmIDs, 0, sizeof(signatureAlgorithmIDs));
   256   memset(extractedSignatures, 0, sizeof(extractedSignatures));
   258   if (!fp) {
   259     fprintf(stderr, "ERROR: Invalid file pointer passed.\n");
   260     return CryptoX_Error;
   261   }
   263   /* To protect against invalid MAR files, we assumes that the MAR file 
   264      size is less than or equal to MAX_SIZE_OF_MAR_FILE. */
   265   if (fseeko(fp, 0, SEEK_END)) {
   266     fprintf(stderr, "ERROR: Could not seek to the end of the MAR file.\n");
   267     return CryptoX_Error;
   268   }
   269   if (ftello(fp) > MAX_SIZE_OF_MAR_FILE) {
   270     fprintf(stderr, "ERROR: MAR file is too large to be verified.\n");
   271     return CryptoX_Error;
   272   }
   274   /* Skip to the start of the signature block */
   275   if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
   276     fprintf(stderr, "ERROR: Could not seek to the signature block.\n");
   277     return CryptoX_Error;
   278   }
   280   /* Get the number of signatures */
   281   if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
   282     fprintf(stderr, "ERROR: Could not read number of signatures.\n");
   283     return CryptoX_Error;
   284   }
   285   signatureCount = ntohl(signatureCount);
   287   /* Check that we have less than the max amount of signatures so we don't
   288      waste too much of either updater's or signmar's time. */
   289   if (signatureCount > MAX_SIGNATURES) {
   290     fprintf(stderr, "ERROR: At most %d signatures can be specified.\n",
   291             MAX_SIGNATURES);
   292     return CryptoX_Error;
   293   }
   295   for (i = 0; i < signatureCount; i++) {
   296     /* Get the signature algorithm ID */
   297     if (fread(&signatureAlgorithmIDs[i], sizeof(uint32_t), 1, fp) != 1) {
   298       fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n");
   299       return CryptoX_Error;
   300     }
   301     signatureAlgorithmIDs[i] = ntohl(signatureAlgorithmIDs[i]);
   303     if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) {
   304       fprintf(stderr, "ERROR: Could not read signatures length.\n");
   305       return CryptoX_Error;
   306     }
   307     signatureLen = ntohl(signatureLen);
   309     /* To protected against invalid input make sure the signature length
   310        isn't too big. */
   311     if (signatureLen > MAX_SIGNATURE_LENGTH) {
   312       fprintf(stderr, "ERROR: Signature length is too large to verify.\n");
   313       return CryptoX_Error;
   314     }
   316     extractedSignatures[i] = malloc(signatureLen);
   317     if (!extractedSignatures[i]) {
   318       fprintf(stderr, "ERROR: Could allocate buffer for signature.\n");
   319       return CryptoX_Error;
   320     }
   321     if (fread(extractedSignatures[i], signatureLen, 1, fp) != 1) {
   322       fprintf(stderr, "ERROR: Could not read extracted signature.\n");
   323       for (i = 0; i < signatureCount; ++i) {
   324         free(extractedSignatures[i]);
   325       }
   326       return CryptoX_Error;
   327     }
   329     /* We don't try to verify signatures we don't know about */
   330     if (signatureAlgorithmIDs[i] != 1) {
   331       fprintf(stderr, "ERROR: Unknown signature algorithm ID.\n");
   332       for (i = 0; i < signatureCount; ++i) {
   333         free(extractedSignatures[i]);
   334       }
   335       return CryptoX_Error;
   336     }
   337   }
   339   curPos = ftello(fp);
   340   rv = mar_verify_signatures_for_fp(fp,
   341                                     provider,
   342                                     keys,
   343                                     (const uint8_t * const *)extractedSignatures,
   344                                     signatureCount,
   345                                     &numVerified);
   346   for (i = 0; i < signatureCount; ++i) {
   347     free(extractedSignatures[i]);
   348   }
   350   /* If we reached here and we verified every
   351      signature, return success. */
   352   if (numVerified == signatureCount && keyCount == numVerified) {
   353     return CryptoX_Success;
   354   }
   356   if (numVerified == 0) {
   357     fprintf(stderr, "ERROR: Not all signatures were verified.\n");
   358   } else {
   359     fprintf(stderr, "ERROR: Only %d of %d signatures were verified.\n",
   360             numVerified, signatureCount);
   361   }
   362   return CryptoX_Error;
   363 }
   365 /**
   366  * Verifies a MAR file by verifying each signature with the corresponding
   367  * certificate. That is, the first signature will be verified using the first
   368  * certificate given, the second signature will be verified using the second
   369  * certificate given, etc. The signature count must exactly match the number of
   370  * certificates given, and all signature verifications must succeed.
   371  * 
   372  * @param  fp                   An opened MAR file handle
   373  * @param  provider             A library provider
   374  * @param  keys                 A pointer to the first element in an
   375  *                              array of keys.
   376  * @param  extractedSignatures  Pointer to the first element in an array
   377  *                              of extracted signatures.
   378  * @param  signatureCount       The number of signatures in the MAR file
   379  * @param numVerified           Out parameter which will be filled with
   380  *                              the number of verified signatures.
   381  *                              This information can be useful for printing
   382  *                              error messages.
   383  * @return 0 on success, *numVerified == signatureCount.
   384 */
   385 int
   386 mar_verify_signatures_for_fp(FILE *fp,
   387                              CryptoX_ProviderHandle provider,
   388                              CryptoX_PublicKey *keys,
   389                              const uint8_t * const *extractedSignatures,
   390                              uint32_t signatureCount,
   391                              uint32_t *numVerified)
   392 {
   393   CryptoX_SignatureHandle signatureHandles[MAX_SIGNATURES];
   394   char buf[BLOCKSIZE];
   395   uint32_t signatureLengths[MAX_SIGNATURES];
   396   uint32_t i;
   397   int rv = CryptoX_Error;
   399   memset(signatureHandles, 0, sizeof(signatureHandles));
   400   memset(signatureLengths, 0, sizeof(signatureLengths));
   402   if (!extractedSignatures || !numVerified) {
   403     fprintf(stderr, "ERROR: Invalid parameter specified.\n");
   404     goto failure;
   405   }
   407   *numVerified = 0;
   409   /* This function is only called when we have at least one signature,
   410      but to protected against future people who call this function we
   411      make sure a non zero value is passed in. 
   412    */
   413   if (!signatureCount) {
   414     fprintf(stderr, "ERROR: There must be at least one signature.\n");
   415     goto failure;
   416   }
   418   for (i = 0; i < signatureCount; i++) {
   419     if (CryptoX_Failed(CryptoX_VerifyBegin(provider,
   420                                            &signatureHandles[i], &keys[i]))) {
   421       fprintf(stderr, "ERROR: Could not initialize signature handle.\n");
   422       goto failure;
   423     }
   424   }
   426   /* Skip to the start of the file */
   427   if (fseeko(fp, 0, SEEK_SET)) {
   428     fprintf(stderr, "ERROR: Could not seek to start of the file\n");
   429     goto failure;
   430   }
   432   /* Bytes 0-3: MAR1
   433      Bytes 4-7: index offset 
   434      Bytes 8-15: size of entire MAR
   435    */
   436   if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, buf, 
   437                                                 SIGNATURE_BLOCK_OFFSET +
   438                                                 sizeof(uint32_t),
   439                                                 signatureHandles,
   440                                                 signatureCount,
   441                                                 "signature block"))) {
   442     goto failure;
   443   }
   445   /* Read the signature block */
   446   for (i = 0; i < signatureCount; i++) {
   447     /* Get the signature algorithm ID */
   448     if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
   449                                                   &buf, 
   450                                                   sizeof(uint32_t),
   451                                                   signatureHandles,
   452                                                   signatureCount,
   453                                                   "signature algorithm ID"))) {
   454       goto failure;
   455     }
   457     if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, 
   458                                                   &signatureLengths[i],
   459                                                   sizeof(uint32_t), 
   460                                                   signatureHandles,
   461                                                   signatureCount,
   462                                                   "signature length"))) {
   463       goto failure;
   464     }
   465     signatureLengths[i] = ntohl(signatureLengths[i]);
   466     if (signatureLengths[i] > MAX_SIGNATURE_LENGTH) {
   467       fprintf(stderr, "ERROR: Embedded signature length is too large.\n");
   468       goto failure;
   469     }
   471     /* Skip past the signature itself as those are not included */
   472     if (fseeko(fp, signatureLengths[i], SEEK_CUR)) {
   473       fprintf(stderr, "ERROR: Could not seek past signature.\n");
   474       goto failure;
   475     }
   476   }
   478   /* Read the rest of the file after the signature block */
   479   while (!feof(fp)) {
   480     int numRead = fread(buf, 1, BLOCKSIZE , fp);
   481     if (ferror(fp)) {
   482       fprintf(stderr, "ERROR: Error reading data block.\n");
   483       goto failure;
   484     }
   486     for (i = 0; i < signatureCount; i++) {
   487       if (CryptoX_Failed(CryptoX_VerifyUpdate(&signatureHandles[i],
   488                                               buf, numRead))) {
   489         fprintf(stderr, "ERROR: Error updating verify context with"
   490                         " data block.\n");
   491         goto failure;
   492       }
   493     }
   494   }
   496   /* Verify the signatures */
   497   for (i = 0; i < signatureCount; i++) {
   498     if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandles[i],
   499                                                &keys[i],
   500                                                extractedSignatures[i],
   501                                                signatureLengths[i]))) {
   502       fprintf(stderr, "ERROR: Error verifying signature.\n");
   503       goto failure;
   504     }
   505     ++*numVerified;
   506   }
   508   rv = CryptoX_Success;
   509 failure:
   510   for (i = 0; i < signatureCount; i++) {
   511     CryptoX_FreeSignatureHandle(&signatureHandles[i]);
   512   }
   514   return rv;
   515 }

mercurial