tor-browser

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

cryptox.c (8034B)


      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 <stdlib.h>
     12 #include <stdio.h>
     13 #include "cryptox.h"
     14 
     15 #if defined(MAR_NSS)
     16 
     17 /**
     18 * Loads the public key for the specified cert name from the NSS store.
     19 *
     20 * @param certData  The DER-encoded X509 certificate to extract the key from.
     21 * @param certDataSize The size of certData.
     22 * @param publicKey Out parameter for the public key to use.
     23 * @return CryptoX_Success on success, CryptoX_Error on error.
     24 */
     25 CryptoX_Result NSS_LoadPublicKey(const unsigned char* certData,
     26                                 unsigned int certDataSize,
     27                                 SECKEYPublicKey** publicKey) {
     28  CERTCertificate* cert;
     29  SECItem certDataItem = {siBuffer, (unsigned char*)certData, certDataSize};
     30 
     31  if (!certData || !publicKey) {
     32    return CryptoX_Error;
     33  }
     34 
     35  cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certDataItem, NULL,
     36                                 PR_FALSE, PR_TRUE);
     37  /* Get the cert and embedded public key out of the database */
     38  if (!cert) {
     39    return CryptoX_Error;
     40  }
     41  *publicKey = CERT_ExtractPublicKey(cert);
     42  CERT_DestroyCertificate(cert);
     43 
     44  if (!*publicKey) {
     45    return CryptoX_Error;
     46  }
     47  return CryptoX_Success;
     48 }
     49 
     50 CryptoX_Result NSS_VerifyBegin(VFYContext** ctx,
     51                               SECKEYPublicKey* const* publicKey) {
     52  SECStatus status;
     53  if (!ctx || !publicKey || !*publicKey) {
     54    return CryptoX_Error;
     55  }
     56 
     57  /* Check that the key length is large enough for our requirements */
     58  if ((SECKEY_PublicKeyStrength(*publicKey) * 8) <
     59      XP_MIN_SIGNATURE_LEN_IN_BYTES) {
     60    fprintf(stderr, "ERROR: Key length must be >= %d bytes\n",
     61            XP_MIN_SIGNATURE_LEN_IN_BYTES);
     62    return CryptoX_Error;
     63  }
     64 
     65  *ctx = VFY_CreateContext(*publicKey, NULL,
     66                           SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION, NULL);
     67  if (*ctx == NULL) {
     68    return CryptoX_Error;
     69  }
     70 
     71  status = VFY_Begin(*ctx);
     72  return SECSuccess == status ? CryptoX_Success : CryptoX_Error;
     73 }
     74 
     75 /**
     76 * Verifies if a verify context matches the passed in signature.
     77 *
     78 * @param ctx          The verify context that the signature should match.
     79 * @param signature    The signature to match.
     80 * @param signatureLen The length of the signature.
     81 * @return CryptoX_Success on success, CryptoX_Error on error.
     82 */
     83 CryptoX_Result NSS_VerifySignature(VFYContext* const* ctx,
     84                                   const unsigned char* signature,
     85                                   unsigned int signatureLen) {
     86  SECItem signedItem;
     87  SECStatus status;
     88  if (!ctx || !signature || !*ctx) {
     89    return CryptoX_Error;
     90  }
     91 
     92  signedItem.len = signatureLen;
     93  signedItem.data = (unsigned char*)signature;
     94  status = VFY_EndWithSignature(*ctx, &signedItem);
     95  return SECSuccess == status ? CryptoX_Success : CryptoX_Error;
     96 }
     97 
     98 #elif defined(XP_WIN)
     99 /**
    100 * Verifies if a signature + public key matches a hash context.
    101 *
    102 * @param hash      The hash context that the signature should match.
    103 * @param pubKey    The public key to use on the signature.
    104 * @param signature The signature to check.
    105 * @param signatureLen The length of the signature.
    106 * @return CryptoX_Success on success, CryptoX_Error on error.
    107 */
    108 CryptoX_Result CryptoAPI_VerifySignature(HCRYPTHASH* hash, HCRYPTKEY* pubKey,
    109                                         const BYTE* signature,
    110                                         DWORD signatureLen) {
    111  DWORD i;
    112  BOOL result;
    113  /* Windows APIs expect the bytes in the signature to be in little-endian
    114   * order, but we write the signature in big-endian order.  Other APIs like
    115   * NSS and OpenSSL expect big-endian order.
    116   */
    117  BYTE* signatureReversed;
    118  if (!hash || !pubKey || !signature || signatureLen < 1) {
    119    return CryptoX_Error;
    120  }
    121 
    122  signatureReversed = malloc(signatureLen);
    123  if (!signatureReversed) {
    124    return CryptoX_Error;
    125  }
    126 
    127  for (i = 0; i < signatureLen; i++) {
    128    signatureReversed[i] = signature[signatureLen - 1 - i];
    129  }
    130  result = CryptVerifySignature(*hash, signatureReversed, signatureLen, *pubKey,
    131                                NULL, 0);
    132  free(signatureReversed);
    133  return result ? CryptoX_Success : CryptoX_Error;
    134 }
    135 
    136 /**
    137 * Obtains the public key for the passed in cert data
    138 *
    139 * @param provider       The cyrto provider
    140 * @param certData       Data of the certificate to extract the public key from
    141 * @param sizeOfCertData The size of the certData buffer
    142 * @param certStore      Pointer to the handle of the certificate store to use
    143 * @param CryptoX_Success on success
    144 */
    145 CryptoX_Result CryptoAPI_LoadPublicKey(HCRYPTPROV provider, BYTE* certData,
    146                                       DWORD sizeOfCertData,
    147                                       HCRYPTKEY* publicKey) {
    148  CRYPT_DATA_BLOB blob;
    149  CERT_CONTEXT* context;
    150  if (!provider || !certData || !publicKey) {
    151    return CryptoX_Error;
    152  }
    153 
    154  blob.cbData = sizeOfCertData;
    155  blob.pbData = certData;
    156  if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob,
    157                        CERT_QUERY_CONTENT_FLAG_CERT,
    158                        CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL,
    159                        NULL, NULL, (const void**)&context)) {
    160    return CryptoX_Error;
    161  }
    162 
    163  if (!CryptImportPublicKeyInfo(
    164          provider, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
    165          &context->pCertInfo->SubjectPublicKeyInfo, publicKey)) {
    166    CertFreeCertificateContext(context);
    167    return CryptoX_Error;
    168  }
    169 
    170  CertFreeCertificateContext(context);
    171  return CryptoX_Success;
    172 }
    173 
    174 /* Try to acquire context in this way:
    175 * 1. Enhanced provider without creating a new key set
    176 * 2. Enhanced provider with creating a new key set
    177 * 3. Default provider without creating a new key set
    178 * 4. Default provider without creating a new key set
    179 * #2 and #4 should not be needed because of the CRYPT_VERIFYCONTEXT,
    180 * but we add it just in case.
    181 *
    182 * @param provider Out parameter containing the provider handle.
    183 * @return CryptoX_Success on success, CryptoX_Error on error.
    184 */
    185 CryptoX_Result CryptoAPI_InitCryptoContext(HCRYPTPROV* provider) {
    186  if (!CryptAcquireContext(provider, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
    187                           CRYPT_VERIFYCONTEXT)) {
    188    if (!CryptAcquireContext(provider, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
    189                             CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) {
    190      if (!CryptAcquireContext(provider, NULL, NULL, PROV_RSA_AES,
    191                               CRYPT_VERIFYCONTEXT)) {
    192        if (!CryptAcquireContext(provider, NULL, NULL, PROV_RSA_AES,
    193                                 CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) {
    194          *provider = CryptoX_InvalidHandleValue;
    195          return CryptoX_Error;
    196        }
    197      }
    198    }
    199  }
    200  return CryptoX_Success;
    201 }
    202 
    203 /**
    204 * Begins a signature verification hash context
    205 *
    206 * @param provider The crypt provider to use
    207 * @param hash     Out parameter for a handle to the hash context
    208 * @return CryptoX_Success on success, CryptoX_Error on error.
    209 */
    210 CryptoX_Result CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash) {
    211  BOOL result;
    212  if (!provider || !hash) {
    213    return CryptoX_Error;
    214  }
    215 
    216  *hash = (HCRYPTHASH)NULL;
    217  result = CryptCreateHash(provider, CALG_SHA_384, 0, 0, hash);
    218  return result ? CryptoX_Success : CryptoX_Error;
    219 }
    220 
    221 /**
    222 * Updates a signature verification hash context
    223 *
    224 * @param hash The hash context to udpate
    225 * @param buf  The buffer to update the hash context with
    226 * @param len The size of the passed in buffer
    227 * @return CryptoX_Success on success, CryptoX_Error on error.
    228 */
    229 CryptoX_Result CryptoAPI_VerifyUpdate(HCRYPTHASH* hash, BYTE* buf, DWORD len) {
    230  BOOL result;
    231  if (!hash || !buf) {
    232    return CryptoX_Error;
    233  }
    234 
    235  result = CryptHashData(*hash, buf, len, 0);
    236  return result ? CryptoX_Success : CryptoX_Error;
    237 }
    238 
    239 #endif