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
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"
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"
53 // WebCrypto key formats
54 #define WEBCRYPTO_KEY_FORMAT_RAW "raw"
55 #define WEBCRYPTO_KEY_FORMAT_PKCS8 "pkcs8"
56 #define WEBCRYPTO_KEY_FORMAT_SPKI "spki"
57 #define WEBCRYPTO_KEY_FORMAT_JWK "jwk"
59 // WebCrypto key types
60 #define WEBCRYPTO_KEY_TYPE_PUBLIC "public"
61 #define WEBCRYPTO_KEY_TYPE_PRIVATE "private"
62 #define WEBCRYPTO_KEY_TYPE_SECRET "secret"
64 // WebCrypto key usages
65 #define WEBCRYPTO_KEY_USAGE_ENCRYPT "encrypt"
66 #define WEBCRYPTO_KEY_USAGE_DECRYPT "decrypt"
67 #define WEBCRYPTO_KEY_USAGE_SIGN "sign"
68 #define WEBCRYPTO_KEY_USAGE_VERIFY "verify"
69 #define WEBCRYPTO_KEY_USAGE_DERIVEKEY "deriveKey"
70 #define WEBCRYPTO_KEY_USAGE_DERIVEBITS "deriveBits"
71 #define WEBCRYPTO_KEY_USAGE_WRAPKEY "wrapKey"
72 #define WEBCRYPTO_KEY_USAGE_UNWRAPKEY "unwrapKey"
74 // WebCrypto named curves
75 #define WEBCRYPTO_NAMED_CURVE_P256 "P-256"
76 #define WEBCRYPTO_NAMED_CURVE_P384 "P-384"
77 #define WEBCRYPTO_NAMED_CURVE_P521 "P-521"
80 #define JWK_TYPE_SYMMETRIC "oct"
81 #define JWK_TYPE_RSA "RSA"
82 #define JWK_TYPE_EC "EC"
85 #define JWK_ALG_A128CBC "A128CBC" // CBC
86 #define JWK_ALG_A192CBC "A192CBC"
87 #define JWK_ALG_A256CBC "A256CBC"
88 #define JWK_ALG_A128CTR "A128CTR" // CTR
89 #define JWK_ALG_A192CTR "A192CTR"
90 #define JWK_ALG_A256CTR "A256CTR"
91 #define JWK_ALG_A128GCM "A128GCM" // GCM
92 #define JWK_ALG_A192GCM "A192GCM"
93 #define JWK_ALG_A256GCM "A256GCM"
94 #define JWK_ALG_A128KW "A128KW" // KW
95 #define JWK_ALG_A192KW "A192KW"
96 #define JWK_ALG_A256KW "A256KW"
97 #define JWK_ALG_HS1 "HS1" // HMAC
98 #define JWK_ALG_HS256 "HS256"
99 #define JWK_ALG_HS384 "HS384"
100 #define JWK_ALG_HS512 "HS512"
101 #define JWK_ALG_RS1 "RS1" // RSASSA-PKCS1
102 #define JWK_ALG_RS256 "RS256"
103 #define JWK_ALG_RS384 "RS384"
104 #define JWK_ALG_RS512 "RS512"
105 #define JWK_ALG_RSA_OAEP "RSA-OAEP" // RSA-OAEP
106 #define JWK_ALG_RSA_OAEP_256 "RSA-OAEP-256"
107 #define JWK_ALG_RSA_OAEP_384 "RSA-OAEP-384"
108 #define JWK_ALG_RSA_OAEP_512 "RSA-OAEP-512"
109 #define JWK_ALG_PS1 "PS1" // RSA-PSS
110 #define JWK_ALG_PS256 "PS256"
111 #define JWK_ALG_PS384 "PS384"
112 #define JWK_ALG_PS512 "PS512"
113 // The JSON Web Algorithms spec (RFC 7518) uses the hash to identify these, not
115 #define JWK_ALG_ECDSA_P_256 "ES256"
116 #define JWK_ALG_ECDSA_P_384 "ES384"
117 #define JWK_ALG_ECDSA_P_521 "ES512"
120 #define JWK_USE_ENC "enc"
121 #define JWK_USE_SIG "sig"
123 // Define an unknown mechanism type
124 #define UNKNOWN_CK_MECHANISM CKM_VENDOR_DEFINED + 1
126 // python security/pkix/tools/DottedOIDToCode.py id-ecDH 1.3.132.112
127 static const uint8_t id_ecDH
[] = {0x2b, 0x81, 0x04, 0x70};
128 const SECItem SEC_OID_DATA_EC_DH
= {
129 siBuffer
, (unsigned char*)id_ecDH
,
130 static_cast<unsigned int>(mozilla::ArrayLength(id_ecDH
))};
132 namespace mozilla::dom
{
134 inline bool ReadBuffer(JSStructuredCloneReader
* aReader
,
135 CryptoBuffer
& aBuffer
) {
136 uint32_t length
, zero
;
137 bool ret
= JS_ReadUint32Pair(aReader
, &length
, &zero
);
143 if (!aBuffer
.SetLength(length
, fallible
)) {
146 ret
= JS_ReadBytes(aReader
, aBuffer
.Elements(), aBuffer
.Length());
151 inline bool WriteBuffer(JSStructuredCloneWriter
* aWriter
,
152 const uint8_t* aBuffer
, size_t aLength
) {
153 bool ret
= JS_WriteUint32Pair(aWriter
, aLength
, 0);
154 if (ret
&& aLength
> 0) {
155 ret
= JS_WriteBytes(aWriter
, aBuffer
, aLength
);
160 inline bool WriteBuffer(JSStructuredCloneWriter
* aWriter
,
161 const CryptoBuffer
& aBuffer
) {
162 return WriteBuffer(aWriter
, aBuffer
.Elements(), aBuffer
.Length());
165 inline CK_MECHANISM_TYPE
MapAlgorithmNameToMechanism(const nsString
& aName
) {
166 CK_MECHANISM_TYPE
mechanism(UNKNOWN_CK_MECHANISM
);
168 // Set mechanism based on algorithm name
169 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
)) {
170 mechanism
= CKM_AES_CBC_PAD
;
171 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
)) {
172 mechanism
= CKM_AES_CTR
;
173 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
174 mechanism
= CKM_AES_GCM
;
175 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
176 mechanism
= CKM_NSS_AES_KEY_WRAP
;
177 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
178 mechanism
= CKM_SHA_1
;
179 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
180 mechanism
= CKM_SHA256
;
181 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
182 mechanism
= CKM_SHA384
;
183 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
184 mechanism
= CKM_SHA512
;
185 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
)) {
186 mechanism
= CKM_PKCS5_PBKD2
;
187 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
)) {
188 mechanism
= CKM_RSA_PKCS
;
189 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
190 mechanism
= CKM_RSA_PKCS_OAEP
;
191 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
192 mechanism
= CKM_RSA_PKCS_PSS
;
193 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
)) {
194 mechanism
= CKM_ECDH1_DERIVE
;
200 #define NORMALIZED_EQUALS(aTest, aConst) \
201 nsContentUtils::EqualsIgnoreASCIICase( \
202 aTest, NS_LITERAL_STRING_FROM_CSTRING(aConst))
204 inline bool NormalizeToken(const nsString
& aName
, nsString
& aDest
) {
206 if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_AES_CBC
)) {
207 aDest
.AssignLiteral(WEBCRYPTO_ALG_AES_CBC
);
208 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_AES_CTR
)) {
209 aDest
.AssignLiteral(WEBCRYPTO_ALG_AES_CTR
);
210 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_AES_GCM
)) {
211 aDest
.AssignLiteral(WEBCRYPTO_ALG_AES_GCM
);
212 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_AES_KW
)) {
213 aDest
.AssignLiteral(WEBCRYPTO_ALG_AES_KW
);
214 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_SHA1
)) {
215 aDest
.AssignLiteral(WEBCRYPTO_ALG_SHA1
);
216 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_SHA256
)) {
217 aDest
.AssignLiteral(WEBCRYPTO_ALG_SHA256
);
218 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_SHA384
)) {
219 aDest
.AssignLiteral(WEBCRYPTO_ALG_SHA384
);
220 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_SHA512
)) {
221 aDest
.AssignLiteral(WEBCRYPTO_ALG_SHA512
);
222 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_HMAC
)) {
223 aDest
.AssignLiteral(WEBCRYPTO_ALG_HMAC
);
224 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_HKDF
)) {
225 aDest
.AssignLiteral(WEBCRYPTO_ALG_HKDF
);
226 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_PBKDF2
)) {
227 aDest
.AssignLiteral(WEBCRYPTO_ALG_PBKDF2
);
228 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_RSASSA_PKCS1
)) {
229 aDest
.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
);
230 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_RSA_OAEP
)) {
231 aDest
.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP
);
232 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_RSA_PSS
)) {
233 aDest
.AssignLiteral(WEBCRYPTO_ALG_RSA_PSS
);
234 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_ECDH
)) {
235 aDest
.AssignLiteral(WEBCRYPTO_ALG_ECDH
);
236 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_ALG_ECDSA
)) {
237 aDest
.AssignLiteral(WEBCRYPTO_ALG_ECDSA
);
238 // Named curve values
239 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_NAMED_CURVE_P256
)) {
240 aDest
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256
);
241 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_NAMED_CURVE_P384
)) {
242 aDest
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384
);
243 } else if (NORMALIZED_EQUALS(aName
, WEBCRYPTO_NAMED_CURVE_P521
)) {
244 aDest
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521
);
252 inline bool CheckEncodedECParameters(const SECItem
* aEcParams
) {
253 // Need at least two bytes for a valid ASN.1 encoding.
254 if (aEcParams
->len
< 2) {
258 // Check the ASN.1 tag.
259 if (aEcParams
->data
[0] != SEC_ASN1_OBJECT_ID
) {
263 // OID tags are short, we never need more than one length byte.
264 if (aEcParams
->data
[1] >= 128) {
268 // Check that the SECItem's length is correct.
269 if (aEcParams
->len
!= (unsigned)aEcParams
->data
[1] + 2) {
276 inline SECItem
* CreateECParamsForCurve(const nsAString
& aNamedCurve
,
277 PLArenaPool
* aArena
) {
279 SECOidTag curveOIDTag
;
281 if (aNamedCurve
.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P256
)) {
282 curveOIDTag
= SEC_OID_SECG_EC_SECP256R1
;
283 } else if (aNamedCurve
.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P384
)) {
284 curveOIDTag
= SEC_OID_SECG_EC_SECP384R1
;
285 } else if (aNamedCurve
.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P521
)) {
286 curveOIDTag
= SEC_OID_SECG_EC_SECP521R1
;
291 // Retrieve curve data by OID tag.
292 SECOidData
* oidData
= SECOID_FindOIDByTag(curveOIDTag
);
297 // Create parameters.
298 SECItem
* params
= ::SECITEM_AllocItem(aArena
, nullptr, 2 + oidData
->oid
.len
);
304 params
->data
[0] = SEC_ASN1_OBJECT_ID
;
305 params
->data
[1] = oidData
->oid
.len
;
306 memcpy(params
->data
+ 2, oidData
->oid
.data
, oidData
->oid
.len
);
308 // Sanity check the params we just created.
309 if (!CheckEncodedECParameters(params
)) {
316 // Implemented in CryptoKey.cpp
317 UniqueSECKEYPublicKey
CreateECPublicKey(const SECItem
* aKeyData
,
318 const nsAString
& aNamedCurve
);
320 } // namespace mozilla::dom
322 #endif // mozilla_dom_WebCryptoCommon_h