Line data Source code
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 : #include "js/StructuredClone.h"
11 : #include "mozilla/ArrayUtils.h"
12 : #include "mozilla/dom/CryptoBuffer.h"
13 : #include "nsContentUtils.h"
14 : #include "nsString.h"
15 : #include "pk11pub.h"
16 :
17 : // WebCrypto algorithm names
18 : #define WEBCRYPTO_ALG_AES_CBC "AES-CBC"
19 : #define WEBCRYPTO_ALG_AES_CTR "AES-CTR"
20 : #define WEBCRYPTO_ALG_AES_GCM "AES-GCM"
21 : #define WEBCRYPTO_ALG_AES_KW "AES-KW"
22 : #define WEBCRYPTO_ALG_SHA1 "SHA-1"
23 : #define WEBCRYPTO_ALG_SHA256 "SHA-256"
24 : #define WEBCRYPTO_ALG_SHA384 "SHA-384"
25 : #define WEBCRYPTO_ALG_SHA512 "SHA-512"
26 : #define WEBCRYPTO_ALG_HMAC "HMAC"
27 : #define WEBCRYPTO_ALG_HKDF "HKDF"
28 : #define WEBCRYPTO_ALG_PBKDF2 "PBKDF2"
29 : #define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5"
30 : #define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP"
31 : #define WEBCRYPTO_ALG_RSA_PSS "RSA-PSS"
32 : #define WEBCRYPTO_ALG_ECDH "ECDH"
33 : #define WEBCRYPTO_ALG_ECDSA "ECDSA"
34 : #define WEBCRYPTO_ALG_DH "DH"
35 :
36 : // WebCrypto key formats
37 : #define WEBCRYPTO_KEY_FORMAT_RAW "raw"
38 : #define WEBCRYPTO_KEY_FORMAT_PKCS8 "pkcs8"
39 : #define WEBCRYPTO_KEY_FORMAT_SPKI "spki"
40 : #define WEBCRYPTO_KEY_FORMAT_JWK "jwk"
41 :
42 : // WebCrypto key types
43 : #define WEBCRYPTO_KEY_TYPE_PUBLIC "public"
44 : #define WEBCRYPTO_KEY_TYPE_PRIVATE "private"
45 : #define WEBCRYPTO_KEY_TYPE_SECRET "secret"
46 :
47 : // WebCrypto key usages
48 : #define WEBCRYPTO_KEY_USAGE_ENCRYPT "encrypt"
49 : #define WEBCRYPTO_KEY_USAGE_DECRYPT "decrypt"
50 : #define WEBCRYPTO_KEY_USAGE_SIGN "sign"
51 : #define WEBCRYPTO_KEY_USAGE_VERIFY "verify"
52 : #define WEBCRYPTO_KEY_USAGE_DERIVEKEY "deriveKey"
53 : #define WEBCRYPTO_KEY_USAGE_DERIVEBITS "deriveBits"
54 : #define WEBCRYPTO_KEY_USAGE_WRAPKEY "wrapKey"
55 : #define WEBCRYPTO_KEY_USAGE_UNWRAPKEY "unwrapKey"
56 :
57 : // WebCrypto named curves
58 : #define WEBCRYPTO_NAMED_CURVE_P256 "P-256"
59 : #define WEBCRYPTO_NAMED_CURVE_P384 "P-384"
60 : #define WEBCRYPTO_NAMED_CURVE_P521 "P-521"
61 :
62 : // JWK key types
63 : #define JWK_TYPE_SYMMETRIC "oct"
64 : #define JWK_TYPE_RSA "RSA"
65 : #define JWK_TYPE_EC "EC"
66 :
67 : // JWK algorithms
68 : #define JWK_ALG_A128CBC "A128CBC" // CBC
69 : #define JWK_ALG_A192CBC "A192CBC"
70 : #define JWK_ALG_A256CBC "A256CBC"
71 : #define JWK_ALG_A128CTR "A128CTR" // CTR
72 : #define JWK_ALG_A192CTR "A192CTR"
73 : #define JWK_ALG_A256CTR "A256CTR"
74 : #define JWK_ALG_A128GCM "A128GCM" // GCM
75 : #define JWK_ALG_A192GCM "A192GCM"
76 : #define JWK_ALG_A256GCM "A256GCM"
77 : #define JWK_ALG_A128KW "A128KW" // KW
78 : #define JWK_ALG_A192KW "A192KW"
79 : #define JWK_ALG_A256KW "A256KW"
80 : #define JWK_ALG_HS1 "HS1" // HMAC
81 : #define JWK_ALG_HS256 "HS256"
82 : #define JWK_ALG_HS384 "HS384"
83 : #define JWK_ALG_HS512 "HS512"
84 : #define JWK_ALG_RS1 "RS1" // RSASSA-PKCS1
85 : #define JWK_ALG_RS256 "RS256"
86 : #define JWK_ALG_RS384 "RS384"
87 : #define JWK_ALG_RS512 "RS512"
88 : #define JWK_ALG_RSA_OAEP "RSA-OAEP" // RSA-OAEP
89 : #define JWK_ALG_RSA_OAEP_256 "RSA-OAEP-256"
90 : #define JWK_ALG_RSA_OAEP_384 "RSA-OAEP-384"
91 : #define JWK_ALG_RSA_OAEP_512 "RSA-OAEP-512"
92 : #define JWK_ALG_PS1 "PS1" // RSA-PSS
93 : #define JWK_ALG_PS256 "PS256"
94 : #define JWK_ALG_PS384 "PS384"
95 : #define JWK_ALG_PS512 "PS512"
96 : #define JWK_ALG_ECDSA_P_256 "ES256"
97 : #define JWK_ALG_ECDSA_P_384 "ES384"
98 : #define JWK_ALG_ECDSA_P_521 "ES521"
99 :
100 : // JWK usages
101 : #define JWK_USE_ENC "enc"
102 : #define JWK_USE_SIG "sig"
103 :
104 : // Define an unknown mechanism type
105 : #define UNKNOWN_CK_MECHANISM CKM_VENDOR_DEFINED+1
106 :
107 : // python security/pkix/tools/DottedOIDToCode.py id-ecDH 1.3.132.112
108 : static const uint8_t id_ecDH[] = { 0x2b, 0x81, 0x04, 0x70 };
109 : const SECItem SEC_OID_DATA_EC_DH = { siBuffer, (unsigned char*)id_ecDH,
110 : static_cast<unsigned int>(
111 : mozilla::ArrayLength(id_ecDH)) };
112 :
113 : // python security/pkix/tools/DottedOIDToCode.py dhKeyAgreement 1.2.840.113549.1.3.1
114 : static const uint8_t dhKeyAgreement[] = {
115 : 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x03, 0x01
116 : };
117 : const SECItem SEC_OID_DATA_DH_KEY_AGREEMENT = { siBuffer,
118 : (unsigned char*)dhKeyAgreement,
119 : static_cast<unsigned int>(
120 : mozilla::ArrayLength(dhKeyAgreement)) };
121 :
122 : namespace mozilla {
123 : namespace dom {
124 :
125 : // Helper functions for structured cloning
126 : inline bool
127 0 : ReadString(JSStructuredCloneReader* aReader, nsString& aString)
128 : {
129 : bool read;
130 : uint32_t nameLength, zero;
131 0 : read = JS_ReadUint32Pair(aReader, &nameLength, &zero);
132 0 : if (!read) {
133 0 : return false;
134 : }
135 :
136 0 : aString.SetLength(nameLength);
137 0 : size_t charSize = sizeof(nsString::char_type);
138 0 : read = JS_ReadBytes(aReader, (void*) aString.BeginWriting(), nameLength * charSize);
139 0 : if (!read) {
140 0 : return false;
141 : }
142 :
143 0 : return true;
144 : }
145 :
146 : inline bool
147 0 : WriteString(JSStructuredCloneWriter* aWriter, const nsString& aString)
148 : {
149 0 : size_t charSize = sizeof(nsString::char_type);
150 0 : return JS_WriteUint32Pair(aWriter, aString.Length(), 0) &&
151 0 : JS_WriteBytes(aWriter, aString.get(), aString.Length() * charSize);
152 : }
153 :
154 : inline bool
155 0 : ReadBuffer(JSStructuredCloneReader* aReader, CryptoBuffer& aBuffer)
156 : {
157 : uint32_t length, zero;
158 0 : bool ret = JS_ReadUint32Pair(aReader, &length, &zero);
159 0 : if (!ret) {
160 0 : return false;
161 : }
162 :
163 0 : if (length > 0) {
164 0 : if (!aBuffer.SetLength(length, fallible)) {
165 0 : return false;
166 : }
167 0 : ret = JS_ReadBytes(aReader, aBuffer.Elements(), aBuffer.Length());
168 : }
169 0 : return ret;
170 : }
171 :
172 : inline bool
173 0 : WriteBuffer(JSStructuredCloneWriter* aWriter, const uint8_t* aBuffer, size_t aLength)
174 : {
175 0 : bool ret = JS_WriteUint32Pair(aWriter, aLength, 0);
176 0 : if (ret && aLength > 0) {
177 0 : ret = JS_WriteBytes(aWriter, aBuffer, aLength);
178 : }
179 0 : return ret;
180 : }
181 :
182 : inline bool
183 0 : WriteBuffer(JSStructuredCloneWriter* aWriter, const CryptoBuffer& aBuffer)
184 : {
185 0 : return WriteBuffer(aWriter, aBuffer.Elements(), aBuffer.Length());
186 : }
187 :
188 : inline CK_MECHANISM_TYPE
189 0 : MapAlgorithmNameToMechanism(const nsString& aName)
190 : {
191 0 : CK_MECHANISM_TYPE mechanism(UNKNOWN_CK_MECHANISM);
192 :
193 : // Set mechanism based on algorithm name
194 0 : if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) {
195 0 : mechanism = CKM_AES_CBC_PAD;
196 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) {
197 0 : mechanism = CKM_AES_CTR;
198 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
199 0 : mechanism = CKM_AES_GCM;
200 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
201 0 : mechanism = CKM_NSS_AES_KEY_WRAP;
202 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
203 0 : mechanism = CKM_SHA_1;
204 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
205 0 : mechanism = CKM_SHA256;
206 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
207 0 : mechanism = CKM_SHA384;
208 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
209 0 : mechanism = CKM_SHA512;
210 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
211 0 : mechanism = CKM_PKCS5_PBKD2;
212 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
213 0 : mechanism = CKM_RSA_PKCS;
214 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
215 0 : mechanism = CKM_RSA_PKCS_OAEP;
216 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
217 0 : mechanism = CKM_RSA_PKCS_PSS;
218 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
219 0 : mechanism = CKM_ECDH1_DERIVE;
220 0 : } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
221 0 : mechanism = CKM_DH_PKCS_DERIVE;
222 : }
223 :
224 0 : return mechanism;
225 : }
226 :
227 : #define NORMALIZED_EQUALS(aTest, aConst) \
228 : nsContentUtils::EqualsIgnoreASCIICase(aTest, NS_LITERAL_STRING(aConst))
229 :
230 : inline bool
231 0 : NormalizeToken(const nsString& aName, nsString& aDest)
232 : {
233 : // Algorithm names
234 0 : if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CBC)) {
235 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CBC);
236 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CTR)) {
237 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CTR);
238 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_GCM)) {
239 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_AES_GCM);
240 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_KW)) {
241 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_AES_KW);
242 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA1)) {
243 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_SHA1);
244 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA256)) {
245 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_SHA256);
246 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA384)) {
247 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_SHA384);
248 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA512)) {
249 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_SHA512);
250 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HMAC)) {
251 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_HMAC);
252 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HKDF)) {
253 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_HKDF);
254 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_PBKDF2)) {
255 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_PBKDF2);
256 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSASSA_PKCS1)) {
257 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1);
258 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_OAEP)) {
259 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP);
260 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_PSS)) {
261 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_PSS);
262 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) {
263 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH);
264 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) {
265 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA);
266 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_DH)) {
267 0 : aDest.AssignLiteral(WEBCRYPTO_ALG_DH);
268 : // Named curve values
269 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) {
270 0 : aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
271 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P384)) {
272 0 : aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
273 0 : } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P521)) {
274 0 : aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
275 : } else {
276 0 : return false;
277 : }
278 :
279 0 : return true;
280 : }
281 :
282 : inline bool
283 0 : CheckEncodedECParameters(const SECItem* aEcParams)
284 : {
285 : // Need at least two bytes for a valid ASN.1 encoding.
286 0 : if (aEcParams->len < 2) {
287 0 : return false;
288 : }
289 :
290 : // Check the ASN.1 tag.
291 0 : if (aEcParams->data[0] != SEC_ASN1_OBJECT_ID) {
292 0 : return false;
293 : }
294 :
295 : // OID tags are short, we never need more than one length byte.
296 0 : if (aEcParams->data[1] >= 128) {
297 0 : return false;
298 : }
299 :
300 : // Check that the SECItem's length is correct.
301 0 : if (aEcParams->len != (unsigned)aEcParams->data[1] + 2) {
302 0 : return false;
303 : }
304 :
305 0 : return true;
306 : }
307 :
308 : inline SECItem*
309 0 : CreateECParamsForCurve(const nsString& aNamedCurve, PLArenaPool* aArena)
310 : {
311 0 : MOZ_ASSERT(aArena);
312 : SECOidTag curveOIDTag;
313 :
314 0 : if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P256)) {
315 0 : curveOIDTag = SEC_OID_SECG_EC_SECP256R1;
316 0 : } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P384)) {
317 0 : curveOIDTag = SEC_OID_SECG_EC_SECP384R1;
318 0 : } else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P521)) {
319 0 : curveOIDTag = SEC_OID_SECG_EC_SECP521R1;
320 : } else {
321 0 : return nullptr;
322 : }
323 :
324 : // Retrieve curve data by OID tag.
325 0 : SECOidData* oidData = SECOID_FindOIDByTag(curveOIDTag);
326 0 : if (!oidData) {
327 0 : return nullptr;
328 : }
329 :
330 : // Create parameters.
331 0 : SECItem* params = ::SECITEM_AllocItem(aArena, nullptr, 2 + oidData->oid.len);
332 0 : if (!params) {
333 0 : return nullptr;
334 : }
335 :
336 : // Set parameters.
337 0 : params->data[0] = SEC_ASN1_OBJECT_ID;
338 0 : params->data[1] = oidData->oid.len;
339 0 : memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
340 :
341 : // Sanity check the params we just created.
342 0 : if (!CheckEncodedECParameters(params)) {
343 0 : return nullptr;
344 : }
345 :
346 0 : return params;
347 : }
348 :
349 : } // namespace dom
350 : } // namespace mozilla
351 :
352 : #endif // mozilla_dom_WebCryptoCommon_h
|