Backed out changeset a5ff95602119 (bug 1905021) as requested for causing accessibilit...
[gecko.git] / dom / crypto / WebCryptoCommon.h
blob8bdaea07a5b994f60fb0422e0e80844d6ff6a43a
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/. */
7 #ifndef mozilla_dom_WebCryptoCommon_h
8 #define mozilla_dom_WebCryptoCommon_h
10 // XXX Several of these dependencies could be removed by moving implementations
11 // to the cpp file.
13 #include <cstdint>
14 #include <cstring>
15 #include "js/StructuredClone.h"
16 #include "mozilla/ArrayUtils.h"
17 #include "mozilla/Assertions.h"
18 #include "mozilla/dom/CryptoBuffer.h"
19 #include "mozilla/fallible.h"
20 #include "nsContentUtils.h"
21 #include "nsLiteralString.h"
22 #include "nsStringFwd.h"
23 #include "pkcs11t.h"
24 #include "plarena.h"
25 #include "secasn1t.h"
26 #include "seccomon.h"
27 #include "secitem.h"
28 #include "secoid.h"
29 #include "secoidt.h"
30 #include "ScopedNSSTypes.h"
32 struct JSStructuredCloneReader;
33 struct JSStructuredCloneWriter;
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"
54 // WebCrypto key formats
55 #define WEBCRYPTO_KEY_FORMAT_RAW "raw"
56 #define WEBCRYPTO_KEY_FORMAT_PKCS8 "pkcs8"
57 #define WEBCRYPTO_KEY_FORMAT_SPKI "spki"
58 #define WEBCRYPTO_KEY_FORMAT_JWK "jwk"
60 // WebCrypto key types
61 #define WEBCRYPTO_KEY_TYPE_PUBLIC "public"
62 #define WEBCRYPTO_KEY_TYPE_PRIVATE "private"
63 #define WEBCRYPTO_KEY_TYPE_SECRET "secret"
65 // WebCrypto key usages
66 #define WEBCRYPTO_KEY_USAGE_ENCRYPT "encrypt"
67 #define WEBCRYPTO_KEY_USAGE_DECRYPT "decrypt"
68 #define WEBCRYPTO_KEY_USAGE_SIGN "sign"
69 #define WEBCRYPTO_KEY_USAGE_VERIFY "verify"
70 #define WEBCRYPTO_KEY_USAGE_DERIVEKEY "deriveKey"
71 #define WEBCRYPTO_KEY_USAGE_DERIVEBITS "deriveBits"
72 #define WEBCRYPTO_KEY_USAGE_WRAPKEY "wrapKey"
73 #define WEBCRYPTO_KEY_USAGE_UNWRAPKEY "unwrapKey"
75 // WebCrypto named curves
76 #define WEBCRYPTO_NAMED_CURVE_P256 "P-256"
77 #define WEBCRYPTO_NAMED_CURVE_P384 "P-384"
78 #define WEBCRYPTO_NAMED_CURVE_P521 "P-521"
79 #define WEBCRYPTO_NAMED_CURVE_ED25519 "Ed25519"
81 // JWK key types
82 #define JWK_TYPE_SYMMETRIC "oct"
83 #define JWK_TYPE_RSA "RSA"
84 #define JWK_TYPE_EC "EC"
85 #define JWK_TYPE_OKP "OKP"
87 // JWK algorithms
88 #define JWK_ALG_A128CBC "A128CBC" // CBC
89 #define JWK_ALG_A192CBC "A192CBC"
90 #define JWK_ALG_A256CBC "A256CBC"
91 #define JWK_ALG_A128CTR "A128CTR" // CTR
92 #define JWK_ALG_A192CTR "A192CTR"
93 #define JWK_ALG_A256CTR "A256CTR"
94 #define JWK_ALG_A128GCM "A128GCM" // GCM
95 #define JWK_ALG_A192GCM "A192GCM"
96 #define JWK_ALG_A256GCM "A256GCM"
97 #define JWK_ALG_A128KW "A128KW" // KW
98 #define JWK_ALG_A192KW "A192KW"
99 #define JWK_ALG_A256KW "A256KW"
100 #define JWK_ALG_HS1 "HS1" // HMAC
101 #define JWK_ALG_HS256 "HS256"
102 #define JWK_ALG_HS384 "HS384"
103 #define JWK_ALG_HS512 "HS512"
104 #define JWK_ALG_RS1 "RS1" // RSASSA-PKCS1
105 #define JWK_ALG_RS256 "RS256"
106 #define JWK_ALG_RS384 "RS384"
107 #define JWK_ALG_RS512 "RS512"
108 #define JWK_ALG_RSA_OAEP "RSA-OAEP" // RSA-OAEP
109 #define JWK_ALG_RSA_OAEP_256 "RSA-OAEP-256"
110 #define JWK_ALG_RSA_OAEP_384 "RSA-OAEP-384"
111 #define JWK_ALG_RSA_OAEP_512 "RSA-OAEP-512"
112 #define JWK_ALG_PS1 "PS1" // RSA-PSS
113 #define JWK_ALG_PS256 "PS256"
114 #define JWK_ALG_PS384 "PS384"
115 #define JWK_ALG_PS512 "PS512"
116 // The JSON Web Algorithms spec (RFC 7518) uses the hash to identify these, not
117 // the curve.
118 #define JWK_ALG_ECDSA_P_256 "ES256"
119 #define JWK_ALG_ECDSA_P_384 "ES384"
120 #define JWK_ALG_ECDSA_P_521 "ES512"
122 // JWK usages
123 #define JWK_USE_ENC "enc"
124 #define JWK_USE_SIG "sig"
126 // Define an unknown mechanism type
127 #define UNKNOWN_CK_MECHANISM CKM_VENDOR_DEFINED + 1
129 // python security/pkix/tools/DottedOIDToCode.py id-ecDH 1.3.132.112
130 static const uint8_t id_ecDH[] = {0x2b, 0x81, 0x04, 0x70};
131 const SECItem SEC_OID_DATA_EC_DH = {
132 siBuffer, (unsigned char*)id_ecDH,
133 static_cast<unsigned int>(mozilla::ArrayLength(id_ecDH))};
135 namespace mozilla::dom {
137 inline bool ReadBuffer(JSStructuredCloneReader* aReader,
138 CryptoBuffer& aBuffer) {
139 uint32_t length, zero;
140 bool ret = JS_ReadUint32Pair(aReader, &length, &zero);
141 if (!ret) {
142 return false;
145 if (length > 0) {
146 if (!aBuffer.SetLength(length, fallible)) {
147 return false;
149 ret = JS_ReadBytes(aReader, aBuffer.Elements(), aBuffer.Length());
151 return ret;
154 inline bool WriteBuffer(JSStructuredCloneWriter* aWriter,
155 const uint8_t* aBuffer, size_t aLength) {
156 bool ret = JS_WriteUint32Pair(aWriter, aLength, 0);
157 if (ret && aLength > 0) {
158 ret = JS_WriteBytes(aWriter, aBuffer, aLength);
160 return ret;
163 inline bool WriteBuffer(JSStructuredCloneWriter* aWriter,
164 const CryptoBuffer& aBuffer) {
165 return WriteBuffer(aWriter, aBuffer.Elements(), aBuffer.Length());
168 inline CK_MECHANISM_TYPE MapAlgorithmNameToMechanism(const nsString& aName) {
169 CK_MECHANISM_TYPE mechanism(UNKNOWN_CK_MECHANISM);
171 // Set mechanism based on algorithm name
172 if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) {
173 mechanism = CKM_AES_CBC_PAD;
174 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) {
175 mechanism = CKM_AES_CTR;
176 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
177 mechanism = CKM_AES_GCM;
178 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
179 mechanism = CKM_NSS_AES_KEY_WRAP;
180 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
181 mechanism = CKM_SHA_1;
182 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
183 mechanism = CKM_SHA256;
184 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
185 mechanism = CKM_SHA384;
186 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
187 mechanism = CKM_SHA512;
188 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
189 mechanism = CKM_PKCS5_PBKD2;
190 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
191 mechanism = CKM_RSA_PKCS;
192 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
193 mechanism = CKM_RSA_PKCS_OAEP;
194 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
195 mechanism = CKM_RSA_PKCS_PSS;
196 } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
197 mechanism = CKM_ECDH1_DERIVE;
200 return mechanism;
203 #define NORMALIZED_EQUALS(aTest, aConst) \
204 nsContentUtils::EqualsIgnoreASCIICase( \
205 aTest, NS_LITERAL_STRING_FROM_CSTRING(aConst))
207 inline bool NormalizeToken(const nsString& aName, nsString& aDest) {
208 // Algorithm names
209 if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CBC)) {
210 aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CBC);
211 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CTR)) {
212 aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CTR);
213 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_GCM)) {
214 aDest.AssignLiteral(WEBCRYPTO_ALG_AES_GCM);
215 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_KW)) {
216 aDest.AssignLiteral(WEBCRYPTO_ALG_AES_KW);
217 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA1)) {
218 aDest.AssignLiteral(WEBCRYPTO_ALG_SHA1);
219 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA256)) {
220 aDest.AssignLiteral(WEBCRYPTO_ALG_SHA256);
221 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA384)) {
222 aDest.AssignLiteral(WEBCRYPTO_ALG_SHA384);
223 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA512)) {
224 aDest.AssignLiteral(WEBCRYPTO_ALG_SHA512);
225 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HMAC)) {
226 aDest.AssignLiteral(WEBCRYPTO_ALG_HMAC);
227 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HKDF)) {
228 aDest.AssignLiteral(WEBCRYPTO_ALG_HKDF);
229 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_PBKDF2)) {
230 aDest.AssignLiteral(WEBCRYPTO_ALG_PBKDF2);
231 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSASSA_PKCS1)) {
232 aDest.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1);
233 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_OAEP)) {
234 aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP);
235 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_PSS)) {
236 aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_PSS);
237 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) {
238 aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH);
239 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) {
240 aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA);
241 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ED25519)) {
242 aDest.AssignLiteral(WEBCRYPTO_ALG_ED25519);
243 // Named curve values
244 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) {
245 aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
246 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P384)) {
247 aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
248 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P521)) {
249 aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
250 } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_ED25519)) {
251 aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_ED25519);
253 } else {
254 return false;
257 return true;
260 inline bool CheckEncodedParameters(const SECItem* aParams) {
261 // Need at least two bytes for a valid ASN.1 encoding.
262 if (aParams->len < 2) {
263 return false;
266 // Check the ASN.1 tag.
267 if (aParams->data[0] != SEC_ASN1_OBJECT_ID) {
268 return false;
271 // OID tags are short, we never need more than one length byte.
272 if (aParams->data[1] >= 128) {
273 return false;
276 // Check that the SECItem's length is correct.
277 if (aParams->len != (unsigned)aParams->data[1] + 2) {
278 return false;
281 return true;
284 inline bool FindOIDTagForEncodedParameters(const SECItem* params,
285 SECOidTag* tag) {
286 // Check that the given EC parameters are valid.
287 if (!CheckEncodedParameters(params)) {
288 return false;
291 // Construct the OID tag.
292 SECItem oid = {siBuffer, nullptr, 0};
293 oid.len = params->data[1];
294 oid.data = params->data + 2;
296 *tag = SECOID_FindOIDTag(&oid);
297 return true;
300 inline SECItem* CreateECParamsForCurve(const nsAString& aNamedCurve,
301 PLArenaPool* aArena) {
302 MOZ_ASSERT(aArena);
303 SECOidTag curveOIDTag;
305 if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P256)) {
306 curveOIDTag = SEC_OID_SECG_EC_SECP256R1;
307 } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P384)) {
308 curveOIDTag = SEC_OID_SECG_EC_SECP384R1;
309 } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P521)) {
310 curveOIDTag = SEC_OID_SECG_EC_SECP521R1;
311 } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_ED25519)) {
312 curveOIDTag = SEC_OID_ED25519_PUBLIC_KEY;
313 } else {
314 return nullptr;
317 // Retrieve curve data by OID tag.
318 SECOidData* oidData = SECOID_FindOIDByTag(curveOIDTag);
319 if (!oidData) {
320 return nullptr;
323 // Create parameters.
324 SECItem* params = ::SECITEM_AllocItem(aArena, nullptr, 2 + oidData->oid.len);
325 if (!params) {
326 return nullptr;
329 // Set parameters.
330 params->data[0] = SEC_ASN1_OBJECT_ID;
331 params->data[1] = oidData->oid.len;
332 memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
334 // Sanity check the params we just created.
335 if (!CheckEncodedParameters(params)) {
336 return nullptr;
339 return params;
342 // Implemented in CryptoKey.cpp
343 UniqueSECKEYPublicKey CreateECPublicKey(const SECItem* aKeyData,
344 const nsAString& aNamedCurve);
346 } // namespace mozilla::dom
348 #endif // mozilla_dom_WebCryptoCommon_h