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