tor-browser

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

WebCryptoCommon.h (12506B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_WebCryptoCommon_h
      8 #define mozilla_dom_WebCryptoCommon_h
      9 
     10 // XXX Several of these dependencies could be removed by moving implementations
     11 // to the cpp file.
     12 
     13 #include <cstdint>
     14 #include <cstring>
     15 
     16 #include "ScopedNSSTypes.h"
     17 #include "js/StructuredClone.h"
     18 #include "mozilla/Assertions.h"
     19 #include "mozilla/dom/CryptoBuffer.h"
     20 #include "mozilla/fallible.h"
     21 #include "nsContentUtils.h"
     22 #include "nsLiteralString.h"
     23 #include "nsStringFwd.h"
     24 #include "pkcs11t.h"
     25 #include "plarena.h"
     26 #include "secasn1t.h"
     27 #include "seccomon.h"
     28 #include "secitem.h"
     29 #include "secoid.h"
     30 #include "secoidt.h"
     31 
     32 struct JSStructuredCloneReader;
     33 struct JSStructuredCloneWriter;
     34 
     35 // WebCrypto algorithm names
     36 #define WEBCRYPTO_ALG_AES_CBC "AES-CBC"
     37 #define WEBCRYPTO_ALG_AES_CTR "AES-CTR"
     38 #define WEBCRYPTO_ALG_AES_GCM "AES-GCM"
     39 #define WEBCRYPTO_ALG_AES_KW "AES-KW"
     40 #define WEBCRYPTO_ALG_SHA1 "SHA-1"
     41 #define WEBCRYPTO_ALG_SHA256 "SHA-256"
     42 #define WEBCRYPTO_ALG_SHA384 "SHA-384"
     43 #define WEBCRYPTO_ALG_SHA512 "SHA-512"
     44 #define WEBCRYPTO_ALG_HMAC "HMAC"
     45 #define WEBCRYPTO_ALG_HKDF "HKDF"
     46 #define WEBCRYPTO_ALG_PBKDF2 "PBKDF2"
     47 #define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5"
     48 #define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP"
     49 #define WEBCRYPTO_ALG_RSA_PSS "RSA-PSS"
     50 #define WEBCRYPTO_ALG_ECDH "ECDH"
     51 #define WEBCRYPTO_ALG_ECDSA "ECDSA"
     52 #define WEBCRYPTO_ALG_ED25519 "Ed25519"
     53 #define WEBCRYPTO_ALG_X25519 "X25519"
     54 
     55 // WebCrypto key formats
     56 #define WEBCRYPTO_KEY_FORMAT_RAW "raw"
     57 #define WEBCRYPTO_KEY_FORMAT_PKCS8 "pkcs8"
     58 #define WEBCRYPTO_KEY_FORMAT_SPKI "spki"
     59 #define WEBCRYPTO_KEY_FORMAT_JWK "jwk"
     60 
     61 // WebCrypto key types
     62 #define WEBCRYPTO_KEY_TYPE_PUBLIC "public"
     63 #define WEBCRYPTO_KEY_TYPE_PRIVATE "private"
     64 #define WEBCRYPTO_KEY_TYPE_SECRET "secret"
     65 
     66 // WebCrypto key usages
     67 #define WEBCRYPTO_KEY_USAGE_ENCRYPT "encrypt"
     68 #define WEBCRYPTO_KEY_USAGE_DECRYPT "decrypt"
     69 #define WEBCRYPTO_KEY_USAGE_SIGN "sign"
     70 #define WEBCRYPTO_KEY_USAGE_VERIFY "verify"
     71 #define WEBCRYPTO_KEY_USAGE_DERIVEKEY "deriveKey"
     72 #define WEBCRYPTO_KEY_USAGE_DERIVEBITS "deriveBits"
     73 #define WEBCRYPTO_KEY_USAGE_WRAPKEY "wrapKey"
     74 #define WEBCRYPTO_KEY_USAGE_UNWRAPKEY "unwrapKey"
     75 
     76 // WebCrypto named curves
     77 #define WEBCRYPTO_NAMED_CURVE_P256 "P-256"
     78 #define WEBCRYPTO_NAMED_CURVE_P384 "P-384"
     79 #define WEBCRYPTO_NAMED_CURVE_P521 "P-521"
     80 #define WEBCRYPTO_NAMED_CURVE_ED25519 "Ed25519"
     81 #define WEBCRYPTO_NAMED_CURVE_CURVE25519 "X25519"
     82 
     83 // JWK key types
     84 #define JWK_TYPE_SYMMETRIC "oct"
     85 #define JWK_TYPE_RSA "RSA"
     86 #define JWK_TYPE_EC "EC"
     87 #define JWK_TYPE_OKP "OKP"
     88 
     89 // JWK algorithms
     90 #define JWK_ALG_A128CBC "A128CBC"  // CBC
     91 #define JWK_ALG_A192CBC "A192CBC"
     92 #define JWK_ALG_A256CBC "A256CBC"
     93 #define JWK_ALG_A128CTR "A128CTR"  // CTR
     94 #define JWK_ALG_A192CTR "A192CTR"
     95 #define JWK_ALG_A256CTR "A256CTR"
     96 #define JWK_ALG_A128GCM "A128GCM"  // GCM
     97 #define JWK_ALG_A192GCM "A192GCM"
     98 #define JWK_ALG_A256GCM "A256GCM"
     99 #define JWK_ALG_A128KW "A128KW"  // KW
    100 #define JWK_ALG_A192KW "A192KW"
    101 #define JWK_ALG_A256KW "A256KW"
    102 #define JWK_ALG_HS1 "HS1"  // HMAC
    103 #define JWK_ALG_HS256 "HS256"
    104 #define JWK_ALG_HS384 "HS384"
    105 #define JWK_ALG_HS512 "HS512"
    106 #define JWK_ALG_RS1 "RS1"  // RSASSA-PKCS1
    107 #define JWK_ALG_RS256 "RS256"
    108 #define JWK_ALG_RS384 "RS384"
    109 #define JWK_ALG_RS512 "RS512"
    110 #define JWK_ALG_RSA_OAEP "RSA-OAEP"  // RSA-OAEP
    111 #define JWK_ALG_RSA_OAEP_256 "RSA-OAEP-256"
    112 #define JWK_ALG_RSA_OAEP_384 "RSA-OAEP-384"
    113 #define JWK_ALG_RSA_OAEP_512 "RSA-OAEP-512"
    114 #define JWK_ALG_PS1 "PS1"  // RSA-PSS
    115 #define JWK_ALG_PS256 "PS256"
    116 #define JWK_ALG_PS384 "PS384"
    117 #define JWK_ALG_PS512 "PS512"
    118 // The JSON Web Algorithms spec (RFC 7518) uses the hash to identify these, not
    119 // the curve.
    120 #define JWK_ALG_ECDSA_P_256 "ES256"
    121 #define JWK_ALG_ECDSA_P_384 "ES384"
    122 #define JWK_ALG_ECDSA_P_521 "ES512"
    123 // The Fully-Specified Algorithms for JOSE and COSE identifies both EdDSA and
    124 // Ed25519 as valid values for the "alg" JWK member.
    125 // https://datatracker.ietf.org/doc/draft-ietf-jose-fully-specified-algorithms/
    126 #define JWK_ALG_EDDSA "EdDSA"
    127 #define JWK_ALG_ED25519 "Ed25519"
    128 
    129 // JWK usages
    130 #define JWK_USE_ENC "enc"
    131 #define JWK_USE_SIG "sig"
    132 
    133 // Define an unknown mechanism type
    134 #define UNKNOWN_CK_MECHANISM CKM_VENDOR_DEFINED + 1
    135 
    136 // python security/pkix/tools/DottedOIDToCode.py id-ecDH 1.3.132.112
    137 static const uint8_t id_ecDH[] = {0x2b, 0x81, 0x04, 0x70};
    138 const SECItem SEC_OID_DATA_EC_DH = {
    139    siBuffer, (unsigned char*)id_ecDH,
    140    static_cast<unsigned int>(std::size(id_ecDH))};
    141 
    142 namespace mozilla::dom {
    143 
    144 inline bool ReadBuffer(JSStructuredCloneReader* aReader,
    145                       CryptoBuffer& aBuffer) {
    146  uint32_t length, zero;
    147  bool ret = JS_ReadUint32Pair(aReader, &length, &zero);
    148  if (!ret) {
    149    return false;
    150  }
    151 
    152  if (length > 0) {
    153    if (!aBuffer.SetLength(length, fallible)) {
    154      return false;
    155    }
    156    ret = JS_ReadBytes(aReader, aBuffer.Elements(), aBuffer.Length());
    157  }
    158  return ret;
    159 }
    160 
    161 inline bool WriteBuffer(JSStructuredCloneWriter* aWriter,
    162                        const uint8_t* aBuffer, size_t aLength) {
    163  bool ret = JS_WriteUint32Pair(aWriter, aLength, 0);
    164  if (ret && aLength > 0) {
    165    ret = JS_WriteBytes(aWriter, aBuffer, aLength);
    166  }
    167  return ret;
    168 }
    169 
    170 inline bool WriteBuffer(JSStructuredCloneWriter* aWriter,
    171                        const CryptoBuffer& aBuffer) {
    172  return WriteBuffer(aWriter, aBuffer.Elements(), aBuffer.Length());
    173 }
    174 
    175 inline CK_MECHANISM_TYPE MapAlgorithmNameToMechanism(const nsString& aName) {
    176  CK_MECHANISM_TYPE mechanism(UNKNOWN_CK_MECHANISM);
    177 
    178  // Set mechanism based on algorithm name
    179  if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) {
    180    mechanism = CKM_AES_CBC_PAD;
    181  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) {
    182    mechanism = CKM_AES_CTR;
    183  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
    184    mechanism = CKM_AES_GCM;
    185  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
    186    mechanism = CKM_NSS_AES_KEY_WRAP;
    187  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
    188    mechanism = CKM_SHA_1;
    189  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
    190    mechanism = CKM_SHA256;
    191  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
    192    mechanism = CKM_SHA384;
    193  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
    194    mechanism = CKM_SHA512;
    195  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
    196    mechanism = CKM_PKCS5_PBKD2;
    197  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
    198    mechanism = CKM_RSA_PKCS;
    199  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
    200    mechanism = CKM_RSA_PKCS_OAEP;
    201  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
    202    mechanism = CKM_RSA_PKCS_PSS;
    203  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
    204    mechanism = CKM_ECDH1_DERIVE;
    205  }
    206 
    207  return mechanism;
    208 }
    209 
    210 #define NORMALIZED_EQUALS(aTest, aConst) \
    211  nsContentUtils::EqualsIgnoreASCIICase( \
    212      aTest, NS_LITERAL_STRING_FROM_CSTRING(aConst))
    213 
    214 inline bool NormalizeToken(const nsString& aName, nsString& aDest) {
    215  // Algorithm names
    216  if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CBC)) {
    217    aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CBC);
    218  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CTR)) {
    219    aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CTR);
    220  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_GCM)) {
    221    aDest.AssignLiteral(WEBCRYPTO_ALG_AES_GCM);
    222  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_KW)) {
    223    aDest.AssignLiteral(WEBCRYPTO_ALG_AES_KW);
    224  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA1)) {
    225    aDest.AssignLiteral(WEBCRYPTO_ALG_SHA1);
    226  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA256)) {
    227    aDest.AssignLiteral(WEBCRYPTO_ALG_SHA256);
    228  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA384)) {
    229    aDest.AssignLiteral(WEBCRYPTO_ALG_SHA384);
    230  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA512)) {
    231    aDest.AssignLiteral(WEBCRYPTO_ALG_SHA512);
    232  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HMAC)) {
    233    aDest.AssignLiteral(WEBCRYPTO_ALG_HMAC);
    234  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HKDF)) {
    235    aDest.AssignLiteral(WEBCRYPTO_ALG_HKDF);
    236  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_PBKDF2)) {
    237    aDest.AssignLiteral(WEBCRYPTO_ALG_PBKDF2);
    238  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSASSA_PKCS1)) {
    239    aDest.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1);
    240  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_OAEP)) {
    241    aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP);
    242  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_PSS)) {
    243    aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_PSS);
    244  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) {
    245    aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH);
    246  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) {
    247    aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA);
    248  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ED25519)) {
    249    aDest.AssignLiteral(WEBCRYPTO_ALG_ED25519);
    250  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_X25519)) {
    251    aDest.AssignLiteral(WEBCRYPTO_ALG_X25519);
    252    // Named curve values
    253  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) {
    254    aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
    255  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P384)) {
    256    aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
    257  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P521)) {
    258    aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
    259  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_ED25519)) {
    260    aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_ED25519);
    261  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_CURVE25519)) {
    262    aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_CURVE25519);
    263 
    264  } else {
    265    return false;
    266  }
    267 
    268  return true;
    269 }
    270 
    271 inline bool CheckEncodedParameters(const SECItem* aParams) {
    272  // Need at least two bytes for a valid ASN.1 encoding.
    273  if (aParams->len < 2) {
    274    return false;
    275  }
    276 
    277  // Check the ASN.1 tag.
    278  if (aParams->data[0] != SEC_ASN1_OBJECT_ID) {
    279    return false;
    280  }
    281 
    282  // OID tags are short, we never need more than one length byte.
    283  if (aParams->data[1] >= 128) {
    284    return false;
    285  }
    286 
    287  // Check that the SECItem's length is correct.
    288  if (aParams->len != (unsigned)aParams->data[1] + 2) {
    289    return false;
    290  }
    291 
    292  return true;
    293 }
    294 
    295 inline bool FindOIDTagForEncodedParameters(const SECItem* params,
    296                                           SECOidTag* tag) {
    297  // Check that the given EC parameters are valid.
    298  if (!CheckEncodedParameters(params)) {
    299    return false;
    300  }
    301 
    302  // Construct the OID tag.
    303  SECItem oid = {siBuffer, nullptr, 0};
    304  oid.len = params->data[1];
    305  oid.data = params->data + 2;
    306 
    307  *tag = SECOID_FindOIDTag(&oid);
    308  return true;
    309 }
    310 
    311 inline SECItem* CreateECParamsForCurve(const nsAString& aNamedCurve,
    312                                       PLArenaPool* aArena) {
    313  MOZ_ASSERT(aArena);
    314  SECOidTag curveOIDTag;
    315 
    316  if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P256)) {
    317    curveOIDTag = SEC_OID_SECG_EC_SECP256R1;
    318  } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P384)) {
    319    curveOIDTag = SEC_OID_SECG_EC_SECP384R1;
    320  } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P521)) {
    321    curveOIDTag = SEC_OID_SECG_EC_SECP521R1;
    322  } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_ED25519)) {
    323    curveOIDTag = SEC_OID_ED25519_PUBLIC_KEY;
    324  } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_CURVE25519)) {
    325    curveOIDTag = SEC_OID_X25519;
    326  } else {
    327    return nullptr;
    328  }
    329 
    330  // Retrieve curve data by OID tag.
    331  SECOidData* oidData = SECOID_FindOIDByTag(curveOIDTag);
    332  if (!oidData) {
    333    return nullptr;
    334  }
    335 
    336  // Create parameters.
    337  SECItem* params = ::SECITEM_AllocItem(aArena, nullptr, 2 + oidData->oid.len);
    338  if (!params) {
    339    return nullptr;
    340  }
    341 
    342  // Set parameters.
    343  params->data[0] = SEC_ASN1_OBJECT_ID;
    344  params->data[1] = oidData->oid.len;
    345  memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
    346 
    347  // Sanity check the params we just created.
    348  if (!CheckEncodedParameters(params)) {
    349    return nullptr;
    350  }
    351 
    352  return params;
    353 }
    354 
    355 // Implemented in CryptoKey.cpp
    356 UniqueSECKEYPublicKey CreateECPublicKey(const SECItem* aKeyData,
    357                                        const nsAString& aNamedCurve);
    358 
    359 }  // namespace mozilla::dom
    360 
    361 #endif  // mozilla_dom_WebCryptoCommon_h