tor-browser

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

mar_verify.c (14433B)


      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 <stdbool.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 #include "mar_private.h"
     18 #include "mar.h"
     19 #include "cryptox.h"
     20 
     21 static bool CryptoX_Failed(CryptoX_Result status) {
     22  return status != CryptoX_Success;
     23 }
     24 
     25 int mar_read_entire_file(const char* filePath, uint32_t maxSize,
     26                         /*out*/ const uint8_t** data,
     27                         /*out*/ uint32_t* size) {
     28  int result;
     29  FILE* f;
     30 
     31  if (!filePath || !data || !size) {
     32    return -1;
     33  }
     34 
     35  f = fopen(filePath, "rb");
     36  if (!f) {
     37    return -1;
     38  }
     39 
     40  result = -1;
     41  if (!fseeko(f, 0, SEEK_END)) {
     42    int64_t fileSize = ftello(f);
     43    if (fileSize > 0 && fileSize <= maxSize && !fseeko(f, 0, SEEK_SET)) {
     44      unsigned char* fileData;
     45 
     46      *size = (unsigned int)fileSize;
     47      fileData = malloc(*size);
     48      if (fileData) {
     49        if (fread(fileData, *size, 1, f) == 1) {
     50          *data = fileData;
     51          result = 0;
     52        } else {
     53          free(fileData);
     54        }
     55      }
     56    }
     57  }
     58 
     59  fclose(f);
     60 
     61  return result;
     62 }
     63 
     64 int mar_extract_and_verify_signatures(MarFile* mar,
     65                                      CryptoX_ProviderHandle provider,
     66                                      CryptoX_PublicKey* keys,
     67                                      uint32_t keyCount);
     68 int mar_verify_extracted_signatures(MarFile* mar,
     69                                    CryptoX_ProviderHandle provider,
     70                                    CryptoX_PublicKey* keys,
     71                                    const uint8_t* const* extractedSignatures,
     72                                    uint32_t keyCount, uint32_t* numVerified);
     73 
     74 /**
     75 * Reads the specified number of bytes from the MAR buffer and
     76 * stores them in the passed buffer.
     77 *
     78 * @param  mar    An opened MAR
     79 * @param  mar_position
     80 *                Our current position within the MAR file buffer.
     81 * @param  buffer The buffer to store the read results.
     82 * @param  size   The number of bytes to read, buffer must be
     83 *                at least of this size.
     84 * @param  ctxs   Pointer to the first element in an array of verify context.
     85 * @param  count  The number of elements in ctxs
     86 * @param  err    The name of what is being written to in case of error.
     87 * @return  CryptoX_Success on success
     88 *          CryptoX_Error   on error
     89 */
     90 CryptoX_Result ReadAndUpdateVerifyContext(MarFile* mar, size_t* mar_position,
     91                                          void* buffer, uint32_t size,
     92                                          CryptoX_SignatureHandle* ctxs,
     93                                          uint32_t count, const char* err) {
     94  uint32_t k;
     95  if (!mar || !mar_position || !buffer || !ctxs || count == 0 || !err) {
     96    fprintf(stderr, "ERROR: Invalid parameter specified.\n");
     97    return CryptoX_Error;
     98  }
     99 
    100  if (!size) {
    101    return CryptoX_Success;
    102  }
    103 
    104  if (mar_read_buffer(mar, buffer, mar_position, size) != 0) {
    105    fprintf(stderr, "ERROR: Could not read %s\n", err);
    106    return CryptoX_Error;
    107  }
    108 
    109  for (k = 0; k < count; k++) {
    110    if (CryptoX_Failed(CryptoX_VerifyUpdate(&ctxs[k], buffer, size))) {
    111      fprintf(stderr, "ERROR: Could not update verify context for %s\n", err);
    112      return CryptoX_Error;
    113    }
    114  }
    115  return CryptoX_Success;
    116 }
    117 
    118 /**
    119 * Verifies a MAR file by verifying each signature with the corresponding
    120 * certificate. That is, the first signature will be verified using the first
    121 * certificate given, the second signature will be verified using the second
    122 * certificate given, etc. The signature count must exactly match the number of
    123 * certificates given, and all signature verifications must succeed.
    124 *
    125 * @param  mar            The file who's signature should be calculated
    126 * @param  certData       Pointer to the first element in an array of
    127 *                        certificate data
    128 * @param  certDataSizes  Pointer to the first element in an array for size of
    129 *                        the data stored
    130 * @param  certCount      The number of elements in certData and certDataSizes
    131 * @return 0 on success
    132 */
    133 int mar_verify_signatures(MarFile* mar, const uint8_t* const* certData,
    134                          const uint32_t* certDataSizes, uint32_t certCount) {
    135  int rv = -1;
    136  CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
    137  CryptoX_PublicKey keys[MAX_SIGNATURES];
    138  uint32_t k;
    139 
    140  memset(keys, 0, sizeof(keys));
    141 
    142  if (!mar || !certData || !certDataSizes || certCount == 0) {
    143    fprintf(stderr, "ERROR: Invalid parameter specified.\n");
    144    goto failure;
    145  }
    146 
    147  if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
    148    fprintf(stderr, "ERROR: Could not init crypto library.\n");
    149    goto failure;
    150  }
    151 
    152  for (k = 0; k < certCount; ++k) {
    153    if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k],
    154                                             certDataSizes[k], &keys[k]))) {
    155      fprintf(stderr, "ERROR: Could not load public key.\n");
    156      goto failure;
    157    }
    158  }
    159 
    160  rv = mar_extract_and_verify_signatures(mar, provider, keys, certCount);
    161 
    162 failure:
    163 
    164  for (k = 0; k < certCount; ++k) {
    165    if (keys[k]) {
    166      CryptoX_FreePublicKey(&keys[k]);
    167    }
    168  }
    169 
    170  return rv;
    171 }
    172 
    173 /**
    174 * Extracts each signature from the specified MAR file,
    175 * then calls mar_verify_extracted_signatures to verify each signature.
    176 *
    177 * @param  mar      An opened MAR
    178 * @param  provider A library provider
    179 * @param  keys     The public keys to use to verify the MAR
    180 * @param  keyCount The number of keys pointed to by keys
    181 * @return 0 on success
    182 */
    183 int mar_extract_and_verify_signatures(MarFile* mar,
    184                                      CryptoX_ProviderHandle provider,
    185                                      CryptoX_PublicKey* keys,
    186                                      uint32_t keyCount) {
    187  uint32_t signatureCount, signatureLen, numVerified = 0;
    188  uint32_t signatureAlgorithmIDs[MAX_SIGNATURES];
    189  uint8_t* extractedSignatures[MAX_SIGNATURES];
    190  uint32_t i;
    191  size_t mar_position = 0;
    192 
    193  memset(signatureAlgorithmIDs, 0, sizeof(signatureAlgorithmIDs));
    194  memset(extractedSignatures, 0, sizeof(extractedSignatures));
    195 
    196  if (!mar) {
    197    fprintf(stderr, "ERROR: Invalid file pointer passed.\n");
    198    return CryptoX_Error;
    199  }
    200 
    201  /* Skip to the start of the signature block */
    202  if (mar_buffer_seek(mar, &mar_position, SIGNATURE_BLOCK_OFFSET) != 0) {
    203    fprintf(stderr, "ERROR: Could not seek to the signature block.\n");
    204    return CryptoX_Error;
    205  }
    206 
    207  /* Get the number of signatures */
    208  if (mar_read_buffer(mar, &signatureCount, &mar_position,
    209                      sizeof(signatureCount)) != 0) {
    210    fprintf(stderr, "ERROR: Could not read number of signatures.\n");
    211    return CryptoX_Error;
    212  }
    213  signatureCount = ntohl(signatureCount);
    214 
    215  /* Check that we have less than the max amount of signatures so we don't
    216     waste too much of either updater's or signmar's time. */
    217  if (signatureCount > MAX_SIGNATURES) {
    218    fprintf(stderr, "ERROR: At most %d signatures can be specified.\n",
    219            MAX_SIGNATURES);
    220    return CryptoX_Error;
    221  }
    222 
    223  for (i = 0; i < signatureCount; i++) {
    224    /* Get the signature algorithm ID */
    225    if (mar_read_buffer(mar, &signatureAlgorithmIDs[i], &mar_position,
    226                        sizeof(uint32_t)) != 0) {
    227      fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n");
    228      return CryptoX_Error;
    229    }
    230    signatureAlgorithmIDs[i] = ntohl(signatureAlgorithmIDs[i]);
    231 
    232    if (mar_read_buffer(mar, &signatureLen, &mar_position, sizeof(uint32_t)) !=
    233        0) {
    234      fprintf(stderr, "ERROR: Could not read signatures length.\n");
    235      return CryptoX_Error;
    236    }
    237    signatureLen = ntohl(signatureLen);
    238 
    239    /* To protect against invalid input make sure the signature length
    240       isn't too big. */
    241    if (signatureLen > MAX_SIGNATURE_LENGTH) {
    242      fprintf(stderr, "ERROR: Signature length is too large to verify.\n");
    243      return CryptoX_Error;
    244    }
    245 
    246    extractedSignatures[i] = malloc(signatureLen);
    247    if (!extractedSignatures[i]) {
    248      fprintf(stderr, "ERROR: Could not allocate buffer for signature.\n");
    249      return CryptoX_Error;
    250    }
    251    if (mar_read_buffer(mar, extractedSignatures[i], &mar_position,
    252                        signatureLen) != 0) {
    253      fprintf(stderr, "ERROR: Could not read extracted signature.\n");
    254      for (i = 0; i < signatureCount; ++i) {
    255        free(extractedSignatures[i]);
    256      }
    257      return CryptoX_Error;
    258    }
    259 
    260    /* We don't try to verify signatures we don't know about */
    261    if (signatureAlgorithmIDs[i] != 2) {
    262      fprintf(stderr, "ERROR: Unknown signature algorithm ID.\n");
    263      for (i = 0; i < signatureCount; ++i) {
    264        free(extractedSignatures[i]);
    265      }
    266      return CryptoX_Error;
    267    }
    268  }
    269 
    270  if (mar_verify_extracted_signatures(
    271          mar, provider, keys, (const uint8_t* const*)extractedSignatures,
    272          signatureCount, &numVerified) == CryptoX_Error) {
    273    return CryptoX_Error;
    274  }
    275  for (i = 0; i < signatureCount; ++i) {
    276    free(extractedSignatures[i]);
    277  }
    278 
    279  /* If we reached here and we verified every
    280     signature, return success. */
    281  if (numVerified == signatureCount && keyCount == numVerified) {
    282    return CryptoX_Success;
    283  }
    284 
    285  if (numVerified == 0) {
    286    fprintf(stderr, "ERROR: Not all signatures were verified.\n");
    287  } else {
    288    fprintf(stderr, "ERROR: Only %d of %d signatures were verified.\n",
    289            numVerified, signatureCount);
    290  }
    291  return CryptoX_Error;
    292 }
    293 
    294 /**
    295 * Verifies a MAR file by verifying each signature with the corresponding
    296 * certificate. That is, the first signature will be verified using the first
    297 * certificate given, the second signature will be verified using the second
    298 * certificate given, etc. The signature count must exactly match the number of
    299 * certificates given, and all signature verifications must succeed.
    300 *
    301 * @param  mar                  An opened MAR
    302 * @param  provider             A library provider
    303 * @param  keys                 A pointer to the first element in an
    304 *                              array of keys.
    305 * @param  extractedSignatures  Pointer to the first element in an array
    306 *                              of extracted signatures.
    307 * @param  signatureCount       The number of signatures in the MAR file
    308 * @param numVerified           Out parameter which will be filled with
    309 *                              the number of verified signatures.
    310 *                              This information can be useful for printing
    311 *                              error messages.
    312 * @return  CryptoX_Success on success, *numVerified == signatureCount.
    313 */
    314 CryptoX_Result mar_verify_extracted_signatures(
    315    MarFile* mar, CryptoX_ProviderHandle provider, CryptoX_PublicKey* keys,
    316    const uint8_t* const* extractedSignatures, uint32_t signatureCount,
    317    uint32_t* numVerified) {
    318  CryptoX_SignatureHandle signatureHandles[MAX_SIGNATURES];
    319  char buf[BLOCKSIZE];
    320  uint32_t signatureLengths[MAX_SIGNATURES];
    321  uint32_t i;
    322  int rv = CryptoX_Error;
    323  size_t mar_position = 0;
    324 
    325  memset(signatureHandles, 0, sizeof(signatureHandles));
    326  memset(signatureLengths, 0, sizeof(signatureLengths));
    327 
    328  if (!extractedSignatures || !numVerified) {
    329    fprintf(stderr, "ERROR: Invalid parameter specified.\n");
    330    goto failure;
    331  }
    332 
    333  *numVerified = 0;
    334 
    335  /* This function is only called when we have at least one signature,
    336     but to protected against future people who call this function we
    337     make sure a non zero value is passed in.
    338   */
    339  if (!signatureCount) {
    340    fprintf(stderr, "ERROR: There must be at least one signature.\n");
    341    goto failure;
    342  }
    343 
    344  for (i = 0; i < signatureCount; i++) {
    345    if (CryptoX_Failed(
    346            CryptoX_VerifyBegin(provider, &signatureHandles[i], &keys[i]))) {
    347      fprintf(stderr, "ERROR: Could not initialize signature handle.\n");
    348      goto failure;
    349    }
    350  }
    351 
    352  /* Bytes 0-3: MAR1
    353     Bytes 4-7: index offset
    354     Bytes 8-15: size of entire MAR
    355   */
    356  if (CryptoX_Failed(ReadAndUpdateVerifyContext(
    357          mar, &mar_position, buf, SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t),
    358          signatureHandles, signatureCount, "signature block"))) {
    359    goto failure;
    360  }
    361 
    362  /* Read the signature block */
    363  for (i = 0; i < signatureCount; i++) {
    364    /* Get the signature algorithm ID */
    365    if (CryptoX_Failed(ReadAndUpdateVerifyContext(
    366            mar, &mar_position, &buf, sizeof(uint32_t), signatureHandles,
    367            signatureCount, "signature algorithm ID"))) {
    368      goto failure;
    369    }
    370 
    371    if (CryptoX_Failed(ReadAndUpdateVerifyContext(
    372            mar, &mar_position, &signatureLengths[i], sizeof(uint32_t),
    373            signatureHandles, signatureCount, "signature length"))) {
    374      goto failure;
    375    }
    376    signatureLengths[i] = ntohl(signatureLengths[i]);
    377    if (signatureLengths[i] > MAX_SIGNATURE_LENGTH) {
    378      fprintf(stderr, "ERROR: Embedded signature length is too large.\n");
    379      goto failure;
    380    }
    381 
    382    /* Skip past the signature itself as those are not included */
    383    if (mar_buffer_seek(mar, &mar_position, signatureLengths[i]) != 0) {
    384      fprintf(stderr, "ERROR: Could not seek past signature.\n");
    385      goto failure;
    386    }
    387  }
    388 
    389  /* Read the rest of the file after the signature block */
    390  while (mar_position < mar->data_len) {
    391    int numRead = mar_read_buffer_max(mar, buf, &mar_position, BLOCKSIZE);
    392    for (i = 0; i < signatureCount; i++) {
    393      if (CryptoX_Failed(
    394              CryptoX_VerifyUpdate(&signatureHandles[i], buf, numRead))) {
    395        fprintf(stderr,
    396                "ERROR: Error updating verify context with"
    397                " data block.\n");
    398        goto failure;
    399      }
    400    }
    401  }
    402 
    403  /* Verify the signatures */
    404  for (i = 0; i < signatureCount; i++) {
    405    if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandles[i], &keys[i],
    406                                               extractedSignatures[i],
    407                                               signatureLengths[i]))) {
    408      fprintf(stderr, "ERROR: Error verifying signature.\n");
    409      goto failure;
    410    }
    411    ++*numVerified;
    412  }
    413 
    414  rv = CryptoX_Success;
    415 failure:
    416  for (i = 0; i < signatureCount; i++) {
    417    CryptoX_FreeSignatureHandle(&signatureHandles[i]);
    418  }
    419 
    420  return rv;
    421 }