/src/mozilla-central/dom/crypto/WebCryptoTask.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "pk11pub.h" |
8 | | #include "cryptohi.h" |
9 | | #include "secerr.h" |
10 | | #include "nsNSSComponent.h" |
11 | | #include "nsProxyRelease.h" |
12 | | |
13 | | #include "jsapi.h" |
14 | | #include "mozilla/Telemetry.h" |
15 | | #include "mozilla/dom/CryptoBuffer.h" |
16 | | #include "mozilla/dom/CryptoKey.h" |
17 | | #include "mozilla/dom/KeyAlgorithmProxy.h" |
18 | | #include "mozilla/dom/TypedArray.h" |
19 | | #include "mozilla/dom/WebCryptoCommon.h" |
20 | | #include "mozilla/dom/WebCryptoTask.h" |
21 | | #include "mozilla/dom/WebCryptoThreadPool.h" |
22 | | #include "mozilla/dom/WorkerRef.h" |
23 | | #include "mozilla/dom/WorkerPrivate.h" |
24 | | |
25 | | // Template taken from security/nss/lib/util/templates.c |
26 | | // This (or SGN_EncodeDigestInfo) would ideally be exported |
27 | | // by NSS and until that happens we have to keep our own copy. |
28 | | const SEC_ASN1Template SGN_DigestInfoTemplate[] = { |
29 | | { SEC_ASN1_SEQUENCE, |
30 | | 0, NULL, sizeof(SGNDigestInfo) }, |
31 | | { SEC_ASN1_INLINE, |
32 | | offsetof(SGNDigestInfo,digestAlgorithm), |
33 | | SEC_ASN1_GET(SECOID_AlgorithmIDTemplate) }, |
34 | | { SEC_ASN1_OCTET_STRING, |
35 | | offsetof(SGNDigestInfo,digest) }, |
36 | | { 0, } |
37 | | }; |
38 | | |
39 | | namespace mozilla { |
40 | | namespace dom { |
41 | | |
42 | | // Pre-defined identifiers for telemetry histograms |
43 | | |
44 | | enum TelemetryMethod { |
45 | | TM_ENCRYPT = 0, |
46 | | TM_DECRYPT = 1, |
47 | | TM_SIGN = 2, |
48 | | TM_VERIFY = 3, |
49 | | TM_DIGEST = 4, |
50 | | TM_GENERATEKEY = 5, |
51 | | TM_DERIVEKEY = 6, |
52 | | TM_DERIVEBITS = 7, |
53 | | TM_IMPORTKEY = 8, |
54 | | TM_EXPORTKEY = 9, |
55 | | TM_WRAPKEY = 10, |
56 | | TM_UNWRAPKEY = 11 |
57 | | }; |
58 | | |
59 | | enum TelemetryAlgorithm { |
60 | | // Please make additions at the end of the list, |
61 | | // to preserve comparability of histograms over time |
62 | | TA_UNKNOWN = 0, |
63 | | // encrypt / decrypt |
64 | | TA_AES_CBC = 1, |
65 | | TA_AES_CFB = 2, |
66 | | TA_AES_CTR = 3, |
67 | | TA_AES_GCM = 4, |
68 | | TA_RSAES_PKCS1 = 5, // NB: This algorithm has been removed |
69 | | TA_RSA_OAEP = 6, |
70 | | // sign/verify |
71 | | TA_RSASSA_PKCS1 = 7, |
72 | | TA_RSA_PSS = 8, |
73 | | TA_HMAC_SHA_1 = 9, |
74 | | TA_HMAC_SHA_224 = 10, |
75 | | TA_HMAC_SHA_256 = 11, |
76 | | TA_HMAC_SHA_384 = 12, |
77 | | TA_HMAC_SHA_512 = 13, |
78 | | // digest |
79 | | TA_SHA_1 = 14, |
80 | | TA_SHA_224 = 15, |
81 | | TA_SHA_256 = 16, |
82 | | TA_SHA_384 = 17, |
83 | | TA_SHA_512 = 18, |
84 | | // Later additions |
85 | | TA_AES_KW = 19, |
86 | | TA_ECDH = 20, |
87 | | TA_PBKDF2 = 21, |
88 | | TA_ECDSA = 22, |
89 | | TA_HKDF = 23, |
90 | | }; |
91 | | |
92 | | // Convenience functions for extracting / converting information |
93 | | |
94 | | // OOM-safe CryptoBuffer initialization, suitable for constructors |
95 | | #define ATTEMPT_BUFFER_INIT(dst, src) \ |
96 | 0 | if (!dst.Assign(src)) { \ |
97 | 0 | mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \ |
98 | 0 | return; \ |
99 | 0 | } |
100 | | |
101 | | // OOM-safe CryptoBuffer-to-SECItem copy, suitable for DoCrypto |
102 | | #define ATTEMPT_BUFFER_TO_SECITEM(arena, dst, src) \ |
103 | 0 | if (!src.ToSECItem(arena, dst)) { \ |
104 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; \ |
105 | 0 | } |
106 | | |
107 | | // OOM-safe CryptoBuffer copy, suitable for DoCrypto |
108 | | #define ATTEMPT_BUFFER_ASSIGN(dst, src) \ |
109 | 0 | if (!dst.Assign(src)) { \ |
110 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; \ |
111 | 0 | } |
112 | | |
113 | | // Safety check for algorithms that use keys, suitable for constructors |
114 | | #define CHECK_KEY_ALGORITHM(keyAlg, algName) \ |
115 | 0 | { \ |
116 | 0 | if (!NORMALIZED_EQUALS(keyAlg.mName, algName)) { \ |
117 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; \ |
118 | 0 | return; \ |
119 | 0 | } \ |
120 | 0 | } |
121 | | |
122 | | class ClearException |
123 | | { |
124 | | public: |
125 | | explicit ClearException(JSContext* aCx) |
126 | | : mCx(aCx) |
127 | 0 | {} |
128 | | |
129 | | ~ClearException() |
130 | 0 | { |
131 | 0 | JS_ClearPendingException(mCx); |
132 | 0 | } |
133 | | |
134 | | private: |
135 | | JSContext* mCx; |
136 | | }; |
137 | | |
138 | | template<class OOS> |
139 | | static nsresult |
140 | | GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm, nsString& aName) |
141 | 0 | { |
142 | 0 | ClearException ce(aCx); |
143 | 0 |
|
144 | 0 | if (aAlgorithm.IsString()) { |
145 | 0 | // If string, then treat as algorithm name |
146 | 0 | aName.Assign(aAlgorithm.GetAsString()); |
147 | 0 | } else { |
148 | 0 | // Coerce to algorithm and extract name |
149 | 0 | JS::RootedValue value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject())); |
150 | 0 | Algorithm alg; |
151 | 0 |
|
152 | 0 | if (!alg.Init(aCx, value)) { |
153 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
154 | 0 | } |
155 | 0 | |
156 | 0 | aName = alg.mName; |
157 | 0 | } |
158 | 0 |
|
159 | 0 | if (!NormalizeToken(aName, aName)) { |
160 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
161 | 0 | } |
162 | 0 | |
163 | 0 | return NS_OK; |
164 | 0 | } Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::GetAlgorithmName<mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::ObjectOrString const&, nsTString<char16_t>&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::GetAlgorithmName<mozilla::dom::OwningObjectOrString>(JSContext*, mozilla::dom::OwningObjectOrString const&, nsTString<char16_t>&) |
165 | | |
166 | | template<class T, class OOS> |
167 | | static nsresult |
168 | | Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm) |
169 | 0 | { |
170 | 0 | ClearException ce(aCx); |
171 | 0 |
|
172 | 0 | if (!aAlgorithm.IsObject()) { |
173 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
174 | 0 | } |
175 | 0 | |
176 | 0 | JS::RootedValue value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject())); |
177 | 0 | if (!aTarget.Init(aCx, value)) { |
178 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
179 | 0 | } |
180 | 0 | |
181 | 0 | return NS_OK; |
182 | 0 | } Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::AesCbcParams, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::AesCbcParams&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::AesCtrParams, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::AesCtrParams&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::AesGcmParams, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::AesGcmParams&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::RsaOaepParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::RsaOaepParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::RsaPssParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::RsaPssParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::EcdsaParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::EcdsaParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::HmacImportParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::HmacImportParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::RsaHashedImportParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::RsaHashedImportParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::EcKeyImportParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::EcKeyImportParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::DhImportKeyParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::DhImportKeyParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::AesDerivedKeyParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::AesDerivedKeyParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::HmacDerivedKeyParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::HmacDerivedKeyParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::HmacKeyGenParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::HmacKeyGenParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::Pbkdf2Params>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::Pbkdf2Params>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::EcdhKeyDeriveParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::EcdhKeyDeriveParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::DhKeyDeriveParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::DhKeyDeriveParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::HkdfParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::HkdfParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::RsaHashedKeyGenParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::RsaHashedKeyGenParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::EcKeyGenParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::EcKeyGenParams>&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::DhKeyGenParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::DhKeyGenParams>&, mozilla::dom::ObjectOrString const&) |
183 | | |
184 | | inline size_t |
185 | | MapHashAlgorithmNameToBlockSize(const nsString& aName) |
186 | 0 | { |
187 | 0 | if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1) || |
188 | 0 | aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { |
189 | 0 | return 512; |
190 | 0 | } |
191 | 0 | |
192 | 0 | if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384) || |
193 | 0 | aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { |
194 | 0 | return 1024; |
195 | 0 | } |
196 | 0 | |
197 | 0 | return 0; |
198 | 0 | } |
199 | | |
200 | | inline nsresult |
201 | | GetKeyLengthForAlgorithm(JSContext* aCx, const ObjectOrString& aAlgorithm, |
202 | | size_t& aLength) |
203 | 0 | { |
204 | 0 | aLength = 0; |
205 | 0 |
|
206 | 0 | // Extract algorithm name |
207 | 0 | nsString algName; |
208 | 0 | if (NS_FAILED(GetAlgorithmName(aCx, aAlgorithm, algName))) { |
209 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
210 | 0 | } |
211 | 0 | |
212 | 0 | // Read AES key length from given algorithm object. |
213 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || |
214 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || |
215 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) || |
216 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { |
217 | 0 | RootedDictionary<AesDerivedKeyParams> params(aCx); |
218 | 0 | if (NS_FAILED(Coerce(aCx, params, aAlgorithm))) { |
219 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
220 | 0 | } |
221 | 0 | |
222 | 0 | if (params.mLength != 128 && |
223 | 0 | params.mLength != 192 && |
224 | 0 | params.mLength != 256) { |
225 | 0 | return NS_ERROR_DOM_DATA_ERR; |
226 | 0 | } |
227 | 0 | |
228 | 0 | aLength = params.mLength; |
229 | 0 | return NS_OK; |
230 | 0 | } |
231 | 0 | |
232 | 0 | // Read HMAC key length from given algorithm object or |
233 | 0 | // determine key length as the block size of the given hash. |
234 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { |
235 | 0 | RootedDictionary<HmacDerivedKeyParams> params(aCx); |
236 | 0 | if (NS_FAILED(Coerce(aCx, params, aAlgorithm))) { |
237 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
238 | 0 | } |
239 | 0 | |
240 | 0 | // Return the passed length, if any. |
241 | 0 | if (params.mLength.WasPassed()) { |
242 | 0 | aLength = params.mLength.Value(); |
243 | 0 | return NS_OK; |
244 | 0 | } |
245 | 0 | |
246 | 0 | nsString hashName; |
247 | 0 | if (NS_FAILED(GetAlgorithmName(aCx, params.mHash, hashName))) { |
248 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
249 | 0 | } |
250 | 0 | |
251 | 0 | // Return the given hash algorithm's block size as the key length. |
252 | 0 | size_t length = MapHashAlgorithmNameToBlockSize(hashName); |
253 | 0 | if (length == 0) { |
254 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
255 | 0 | } |
256 | 0 | |
257 | 0 | aLength = length; |
258 | 0 | return NS_OK; |
259 | 0 | } |
260 | 0 | |
261 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
262 | 0 | } |
263 | | |
264 | | inline bool |
265 | | MapOIDTagToNamedCurve(SECOidTag aOIDTag, nsString& aResult) |
266 | 0 | { |
267 | 0 | switch (aOIDTag) { |
268 | 0 | case SEC_OID_SECG_EC_SECP256R1: |
269 | 0 | aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256); |
270 | 0 | break; |
271 | 0 | case SEC_OID_SECG_EC_SECP384R1: |
272 | 0 | aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384); |
273 | 0 | break; |
274 | 0 | case SEC_OID_SECG_EC_SECP521R1: |
275 | 0 | aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521); |
276 | 0 | break; |
277 | 0 | default: |
278 | 0 | return false; |
279 | 0 | } |
280 | 0 | |
281 | 0 | return true; |
282 | 0 | } |
283 | | |
284 | | inline SECOidTag |
285 | | MapHashAlgorithmNameToOID(const nsString& aName) |
286 | 0 | { |
287 | 0 | SECOidTag hashOID(SEC_OID_UNKNOWN); |
288 | 0 |
|
289 | 0 | if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) { |
290 | 0 | hashOID = SEC_OID_SHA1; |
291 | 0 | } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { |
292 | 0 | hashOID = SEC_OID_SHA256; |
293 | 0 | } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) { |
294 | 0 | hashOID = SEC_OID_SHA384; |
295 | 0 | } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { |
296 | 0 | hashOID = SEC_OID_SHA512; |
297 | 0 | } |
298 | 0 |
|
299 | 0 | return hashOID; |
300 | 0 | } |
301 | | |
302 | | inline CK_MECHANISM_TYPE |
303 | 0 | MapHashAlgorithmNameToMgfMechanism(const nsString& aName) { |
304 | 0 | CK_MECHANISM_TYPE mech(UNKNOWN_CK_MECHANISM); |
305 | 0 |
|
306 | 0 | if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) { |
307 | 0 | mech = CKG_MGF1_SHA1; |
308 | 0 | } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { |
309 | 0 | mech = CKG_MGF1_SHA256; |
310 | 0 | } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) { |
311 | 0 | mech = CKG_MGF1_SHA384; |
312 | 0 | } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { |
313 | 0 | mech = CKG_MGF1_SHA512; |
314 | 0 | } |
315 | 0 |
|
316 | 0 | return mech; |
317 | 0 | } |
318 | | |
319 | | // Implementation of WebCryptoTask methods |
320 | | |
321 | | void |
322 | | WebCryptoTask::DispatchWithPromise(Promise* aResultPromise) |
323 | 0 | { |
324 | 0 | mResultPromise = aResultPromise; |
325 | 0 |
|
326 | 0 | // Fail if an error was set during the constructor |
327 | 0 | MAYBE_EARLY_FAIL(mEarlyRv) |
328 | 0 |
|
329 | 0 | // Perform pre-NSS operations, and fail if they fail |
330 | 0 | mEarlyRv = BeforeCrypto(); |
331 | 0 | MAYBE_EARLY_FAIL(mEarlyRv) |
332 | 0 |
|
333 | 0 | // Skip dispatch if we're already done. Otherwise launch a CryptoTask |
334 | 0 | if (mEarlyComplete) { |
335 | 0 | CallCallback(mEarlyRv); |
336 | 0 | return; |
337 | 0 | } |
338 | 0 | |
339 | 0 | // Store calling thread |
340 | 0 | mOriginalEventTarget = GetCurrentThreadSerialEventTarget(); |
341 | 0 |
|
342 | 0 | // If we are running on a worker thread we must hold the worker |
343 | 0 | // alive while we work on the thread pool. Otherwise the worker |
344 | 0 | // private may get torn down before we dispatch back to complete |
345 | 0 | // the transaction. |
346 | 0 | if (!NS_IsMainThread()) { |
347 | 0 | WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); |
348 | 0 | MOZ_ASSERT(workerPrivate); |
349 | 0 |
|
350 | 0 | RefPtr<StrongWorkerRef> workerRef = |
351 | 0 | StrongWorkerRef::Create(workerPrivate, "WebCryptoTask"); |
352 | 0 | if (NS_WARN_IF(!workerRef)) { |
353 | 0 | mEarlyRv = NS_BINDING_ABORTED; |
354 | 0 | } else { |
355 | 0 | mWorkerRef = new ThreadSafeWorkerRef(workerRef); |
356 | 0 | } |
357 | 0 | } |
358 | 0 | MAYBE_EARLY_FAIL(mEarlyRv); |
359 | 0 |
|
360 | 0 | // dispatch to thread pool |
361 | 0 | mEarlyRv = WebCryptoThreadPool::Dispatch(this); |
362 | 0 | MAYBE_EARLY_FAIL(mEarlyRv) |
363 | 0 | } |
364 | | |
365 | | NS_IMETHODIMP |
366 | | WebCryptoTask::Run() |
367 | 0 | { |
368 | 0 | // Run heavy crypto operations on the thread pool, off the original thread. |
369 | 0 | if (!IsOnOriginalThread()) { |
370 | 0 | mRv = CalculateResult(); |
371 | 0 |
|
372 | 0 | // Back to the original thread, i.e. continue below. |
373 | 0 | mOriginalEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); |
374 | 0 | return NS_OK; |
375 | 0 | } |
376 | 0 |
|
377 | 0 | // We're now back on the calling thread. |
378 | 0 | CallCallback(mRv); |
379 | 0 |
|
380 | 0 | // Stop holding the worker thread alive now that the async work has |
381 | 0 | // been completed. |
382 | 0 | mWorkerRef = nullptr; |
383 | 0 |
|
384 | 0 | return NS_OK; |
385 | 0 | } |
386 | | |
387 | | nsresult |
388 | | WebCryptoTask::Cancel() |
389 | 0 | { |
390 | 0 | MOZ_ASSERT(IsOnOriginalThread()); |
391 | 0 | FailWithError(NS_BINDING_ABORTED); |
392 | 0 | return NS_OK; |
393 | 0 | } |
394 | | |
395 | | void |
396 | | WebCryptoTask::FailWithError(nsresult aRv) |
397 | 0 | { |
398 | 0 | MOZ_ASSERT(IsOnOriginalThread()); |
399 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, false); |
400 | 0 |
|
401 | 0 | // Blindly convert nsresult to DOMException |
402 | 0 | // Individual tasks must ensure they pass the right values |
403 | 0 | mResultPromise->MaybeReject(aRv); |
404 | 0 | // Manually release mResultPromise while we're on the main thread |
405 | 0 | mResultPromise = nullptr; |
406 | 0 | mWorkerRef = nullptr; |
407 | 0 | Cleanup(); |
408 | 0 | } |
409 | | |
410 | | nsresult |
411 | | WebCryptoTask::CalculateResult() |
412 | 0 | { |
413 | 0 | MOZ_ASSERT(!IsOnOriginalThread()); |
414 | 0 |
|
415 | 0 | return DoCrypto(); |
416 | 0 | } |
417 | | |
418 | | void |
419 | | WebCryptoTask::CallCallback(nsresult rv) |
420 | 0 | { |
421 | 0 | MOZ_ASSERT(IsOnOriginalThread()); |
422 | 0 | if (NS_FAILED(rv)) { |
423 | 0 | FailWithError(rv); |
424 | 0 | return; |
425 | 0 | } |
426 | 0 | |
427 | 0 | nsresult rv2 = AfterCrypto(); |
428 | 0 | if (NS_FAILED(rv2)) { |
429 | 0 | FailWithError(rv2); |
430 | 0 | return; |
431 | 0 | } |
432 | 0 | |
433 | 0 | Resolve(); |
434 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, true); |
435 | 0 |
|
436 | 0 | // Manually release mResultPromise while we're on the main thread |
437 | 0 | mResultPromise = nullptr; |
438 | 0 | Cleanup(); |
439 | 0 | } |
440 | | |
441 | | // Some generic utility classes |
442 | | |
443 | | class FailureTask : public WebCryptoTask |
444 | | { |
445 | | public: |
446 | 0 | explicit FailureTask(nsresult aRv) { |
447 | 0 | mEarlyRv = aRv; |
448 | 0 | } |
449 | | }; |
450 | | |
451 | | class ReturnArrayBufferViewTask : public WebCryptoTask |
452 | | { |
453 | | protected: |
454 | | CryptoBuffer mResult; |
455 | | |
456 | | private: |
457 | | // Returns mResult as an ArrayBufferView, or an error |
458 | | virtual void Resolve() override |
459 | 0 | { |
460 | 0 | TypedArrayCreator<ArrayBuffer> ret(mResult); |
461 | 0 | mResultPromise->MaybeResolve(ret); |
462 | 0 | } |
463 | | }; |
464 | | |
465 | | class DeferredData |
466 | | { |
467 | | public: |
468 | | template<class T> |
469 | 0 | void SetData(const T& aData) { |
470 | 0 | mDataIsSet = mData.Assign(aData); |
471 | 0 | } Unexecuted instantiation: void mozilla::dom::DeferredData::SetData<mozilla::dom::ArrayBufferViewOrArrayBuffer>(mozilla::dom::ArrayBufferViewOrArrayBuffer const&) Unexecuted instantiation: void mozilla::dom::DeferredData::SetData<mozilla::dom::CryptoBuffer>(mozilla::dom::CryptoBuffer const&) |
472 | | |
473 | | protected: |
474 | | DeferredData() |
475 | | : mDataIsSet(false) |
476 | 0 | {} |
477 | | |
478 | | CryptoBuffer mData; |
479 | | bool mDataIsSet; |
480 | | }; |
481 | | |
482 | | class AesTask : public ReturnArrayBufferViewTask, |
483 | | public DeferredData |
484 | | { |
485 | | public: |
486 | | AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
487 | | CryptoKey& aKey, bool aEncrypt) |
488 | | : mMechanism(CKM_INVALID_MECHANISM) |
489 | | , mSymKey(aKey.GetSymKey()) |
490 | | , mTagLength(0) |
491 | | , mCounterLength(0) |
492 | | , mEncrypt(aEncrypt) |
493 | 0 | { |
494 | 0 | Init(aCx, aAlgorithm, aKey, aEncrypt); |
495 | 0 | } |
496 | | |
497 | | AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
498 | | CryptoKey& aKey, const CryptoOperationData& aData, |
499 | | bool aEncrypt) |
500 | | : mMechanism(CKM_INVALID_MECHANISM) |
501 | | , mSymKey(aKey.GetSymKey()) |
502 | | , mTagLength(0) |
503 | | , mCounterLength(0) |
504 | | , mEncrypt(aEncrypt) |
505 | 0 | { |
506 | 0 | Init(aCx, aAlgorithm, aKey, aEncrypt); |
507 | 0 | SetData(aData); |
508 | 0 | } |
509 | | |
510 | | void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, |
511 | | CryptoKey& aKey, bool aEncrypt) |
512 | 0 | { |
513 | 0 | nsString algName; |
514 | 0 | mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName); |
515 | 0 | if (NS_FAILED(mEarlyRv)) { |
516 | 0 | return; |
517 | 0 | } |
518 | 0 | |
519 | 0 | // Check that we got a reasonable key |
520 | 0 | if ((mSymKey.Length() != 16) && |
521 | 0 | (mSymKey.Length() != 24) && |
522 | 0 | (mSymKey.Length() != 32)) |
523 | 0 | { |
524 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
525 | 0 | return; |
526 | 0 | } |
527 | 0 | |
528 | 0 | // Cache parameters depending on the specific algorithm |
529 | 0 | TelemetryAlgorithm telemetryAlg; |
530 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) { |
531 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_CBC); |
532 | 0 |
|
533 | 0 | mMechanism = CKM_AES_CBC_PAD; |
534 | 0 | telemetryAlg = TA_AES_CBC; |
535 | 0 | AesCbcParams params; |
536 | 0 | nsresult rv = Coerce(aCx, params, aAlgorithm); |
537 | 0 | if (NS_FAILED(rv)) { |
538 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
539 | 0 | return; |
540 | 0 | } |
541 | 0 | |
542 | 0 | ATTEMPT_BUFFER_INIT(mIv, params.mIv) |
543 | 0 | if (mIv.Length() != 16) { |
544 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
545 | 0 | return; |
546 | 0 | } |
547 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) { |
548 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_CTR); |
549 | 0 |
|
550 | 0 | mMechanism = CKM_AES_CTR; |
551 | 0 | telemetryAlg = TA_AES_CTR; |
552 | 0 | AesCtrParams params; |
553 | 0 | nsresult rv = Coerce(aCx, params, aAlgorithm); |
554 | 0 | if (NS_FAILED(rv)) { |
555 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
556 | 0 | return; |
557 | 0 | } |
558 | 0 | |
559 | 0 | ATTEMPT_BUFFER_INIT(mIv, params.mCounter) |
560 | 0 | if (mIv.Length() != 16) { |
561 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
562 | 0 | return; |
563 | 0 | } |
564 | 0 | |
565 | 0 | mCounterLength = params.mLength; |
566 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) { |
567 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_GCM); |
568 | 0 |
|
569 | 0 | mMechanism = CKM_AES_GCM; |
570 | 0 | telemetryAlg = TA_AES_GCM; |
571 | 0 | AesGcmParams params; |
572 | 0 | nsresult rv = Coerce(aCx, params, aAlgorithm); |
573 | 0 | if (NS_FAILED(rv)) { |
574 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
575 | 0 | return; |
576 | 0 | } |
577 | 0 | |
578 | 0 | ATTEMPT_BUFFER_INIT(mIv, params.mIv) |
579 | 0 |
|
580 | 0 | if (params.mAdditionalData.WasPassed()) { |
581 | 0 | ATTEMPT_BUFFER_INIT(mAad, params.mAdditionalData.Value()) |
582 | 0 | } |
583 | 0 |
|
584 | 0 | // 32, 64, 96, 104, 112, 120 or 128 |
585 | 0 | mTagLength = 128; |
586 | 0 | if (params.mTagLength.WasPassed()) { |
587 | 0 | mTagLength = params.mTagLength.Value(); |
588 | 0 | if ((mTagLength > 128) || |
589 | 0 | !(mTagLength == 32 || mTagLength == 64 || |
590 | 0 | (mTagLength >= 96 && mTagLength % 8 == 0))) { |
591 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
592 | 0 | return; |
593 | 0 | } |
594 | 0 | } |
595 | 0 | } else { |
596 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
597 | 0 | return; |
598 | 0 | } |
599 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg); |
600 | 0 | } |
601 | | |
602 | | private: |
603 | | CK_MECHANISM_TYPE mMechanism; |
604 | | CryptoBuffer mSymKey; |
605 | | CryptoBuffer mIv; // Initialization vector |
606 | | CryptoBuffer mAad; // Additional Authenticated Data |
607 | | uint8_t mTagLength; |
608 | | uint8_t mCounterLength; |
609 | | bool mEncrypt; |
610 | | |
611 | | virtual nsresult DoCrypto() override |
612 | 0 | { |
613 | 0 | nsresult rv; |
614 | 0 |
|
615 | 0 | if (!mDataIsSet) { |
616 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
617 | 0 | } |
618 | 0 | |
619 | 0 | UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
620 | 0 | if (!arena) { |
621 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
622 | 0 | } |
623 | 0 | |
624 | 0 | // Construct the parameters object depending on algorithm |
625 | 0 | SECItem param = { siBuffer, nullptr, 0 }; |
626 | 0 | CK_AES_CTR_PARAMS ctrParams; |
627 | 0 | CK_GCM_PARAMS gcmParams; |
628 | 0 | switch (mMechanism) { |
629 | 0 | case CKM_AES_CBC_PAD: |
630 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), ¶m, mIv); |
631 | 0 | break; |
632 | 0 | case CKM_AES_CTR: |
633 | 0 | ctrParams.ulCounterBits = mCounterLength; |
634 | 0 | MOZ_ASSERT(mIv.Length() == 16); |
635 | 0 | memcpy(&ctrParams.cb, mIv.Elements(), 16); |
636 | 0 | param.type = siBuffer; |
637 | 0 | param.data = (unsigned char*) &ctrParams; |
638 | 0 | param.len = sizeof(ctrParams); |
639 | 0 | break; |
640 | 0 | case CKM_AES_GCM: |
641 | 0 | gcmParams.pIv = mIv.Elements(); |
642 | 0 | gcmParams.ulIvLen = mIv.Length(); |
643 | 0 | gcmParams.pAAD = mAad.Elements(); |
644 | 0 | gcmParams.ulAADLen = mAad.Length(); |
645 | 0 | gcmParams.ulTagBits = mTagLength; |
646 | 0 | param.type = siBuffer; |
647 | 0 | param.data = (unsigned char*) &gcmParams; |
648 | 0 | param.len = sizeof(gcmParams); |
649 | 0 | break; |
650 | 0 | default: |
651 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
652 | 0 | } |
653 | 0 | |
654 | 0 | // Import the key |
655 | 0 | SECItem keyItem = { siBuffer, nullptr, 0 }; |
656 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey); |
657 | 0 | UniquePK11SlotInfo slot(PK11_GetInternalSlot()); |
658 | 0 | MOZ_ASSERT(slot.get()); |
659 | 0 | UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism, |
660 | 0 | PK11_OriginUnwrap, CKA_ENCRYPT, |
661 | 0 | &keyItem, nullptr)); |
662 | 0 | if (!symKey) { |
663 | 0 | return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
664 | 0 | } |
665 | 0 | |
666 | 0 | // Check whether the integer addition would overflow. |
667 | 0 | if (std::numeric_limits<CryptoBuffer::size_type>::max() - 16 < mData.Length()) { |
668 | 0 | return NS_ERROR_DOM_DATA_ERR; |
669 | 0 | } |
670 | 0 | |
671 | 0 | // Initialize the output buffer (enough space for padding / a full tag) |
672 | 0 | if (!mResult.SetLength(mData.Length() + 16, fallible)) { |
673 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
674 | 0 | } |
675 | 0 | |
676 | 0 | uint32_t outLen = 0; |
677 | 0 |
|
678 | 0 | // Perform the encryption/decryption |
679 | 0 | if (mEncrypt) { |
680 | 0 | rv = MapSECStatus(PK11_Encrypt(symKey.get(), mMechanism, ¶m, |
681 | 0 | mResult.Elements(), &outLen, |
682 | 0 | mResult.Length(), mData.Elements(), |
683 | 0 | mData.Length())); |
684 | 0 | } else { |
685 | 0 | rv = MapSECStatus(PK11_Decrypt(symKey.get(), mMechanism, ¶m, |
686 | 0 | mResult.Elements(), &outLen, |
687 | 0 | mResult.Length(), mData.Elements(), |
688 | 0 | mData.Length())); |
689 | 0 | } |
690 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
691 | 0 |
|
692 | 0 | mResult.TruncateLength(outLen); |
693 | 0 | return rv; |
694 | 0 | } |
695 | | }; |
696 | | |
697 | | // This class looks like an encrypt/decrypt task, like AesTask, |
698 | | // but it is only exposed to wrapKey/unwrapKey, not encrypt/decrypt |
699 | | class AesKwTask : public ReturnArrayBufferViewTask, |
700 | | public DeferredData |
701 | | { |
702 | | public: |
703 | | AesKwTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
704 | | CryptoKey& aKey, bool aEncrypt) |
705 | | : mMechanism(CKM_NSS_AES_KEY_WRAP) |
706 | | , mSymKey(aKey.GetSymKey()) |
707 | | , mEncrypt(aEncrypt) |
708 | 0 | { |
709 | 0 | Init(aCx, aAlgorithm, aKey, aEncrypt); |
710 | 0 | } |
711 | | |
712 | | AesKwTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
713 | | CryptoKey& aKey, const CryptoOperationData& aData, |
714 | | bool aEncrypt) |
715 | | : mMechanism(CKM_NSS_AES_KEY_WRAP) |
716 | | , mSymKey(aKey.GetSymKey()) |
717 | | , mEncrypt(aEncrypt) |
718 | 0 | { |
719 | 0 | Init(aCx, aAlgorithm, aKey, aEncrypt); |
720 | 0 | SetData(aData); |
721 | 0 | } |
722 | | |
723 | | void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, |
724 | | CryptoKey& aKey, bool aEncrypt) |
725 | 0 | { |
726 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_KW); |
727 | 0 |
|
728 | 0 | nsString algName; |
729 | 0 | mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName); |
730 | 0 | if (NS_FAILED(mEarlyRv)) { |
731 | 0 | return; |
732 | 0 | } |
733 | 0 | |
734 | 0 | // Check that we got a reasonable key |
735 | 0 | if ((mSymKey.Length() != 16) && |
736 | 0 | (mSymKey.Length() != 24) && |
737 | 0 | (mSymKey.Length() != 32)) |
738 | 0 | { |
739 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
740 | 0 | return; |
741 | 0 | } |
742 | 0 | |
743 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_AES_KW); |
744 | 0 | } |
745 | | |
746 | | private: |
747 | | CK_MECHANISM_TYPE mMechanism; |
748 | | CryptoBuffer mSymKey; |
749 | | bool mEncrypt; |
750 | | |
751 | | virtual nsresult DoCrypto() override |
752 | 0 | { |
753 | 0 | nsresult rv; |
754 | 0 |
|
755 | 0 | if (!mDataIsSet) { |
756 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
757 | 0 | } |
758 | 0 | |
759 | 0 | // Check that the input is a multiple of 64 bits long |
760 | 0 | if (mData.Length() == 0 || mData.Length() % 8 != 0) { |
761 | 0 | return NS_ERROR_DOM_DATA_ERR; |
762 | 0 | } |
763 | 0 | |
764 | 0 | UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
765 | 0 | if (!arena) { |
766 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
767 | 0 | } |
768 | 0 | |
769 | 0 | // Import the key |
770 | 0 | SECItem keyItem = { siBuffer, nullptr, 0 }; |
771 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey); |
772 | 0 | UniquePK11SlotInfo slot(PK11_GetInternalSlot()); |
773 | 0 | MOZ_ASSERT(slot.get()); |
774 | 0 | UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism, |
775 | 0 | PK11_OriginUnwrap, CKA_WRAP, |
776 | 0 | &keyItem, nullptr)); |
777 | 0 | if (!symKey) { |
778 | 0 | return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
779 | 0 | } |
780 | 0 | |
781 | 0 | // Import the data to a SECItem |
782 | 0 | SECItem dataItem = { siBuffer, nullptr, 0 }; |
783 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &dataItem, mData); |
784 | 0 |
|
785 | 0 | // Parameters for the fake keys |
786 | 0 | CK_MECHANISM_TYPE fakeMechanism = CKM_SHA_1_HMAC; |
787 | 0 | CK_ATTRIBUTE_TYPE fakeOperation = CKA_SIGN; |
788 | 0 |
|
789 | 0 | if (mEncrypt) { |
790 | 0 | // Import the data into a fake PK11SymKey structure |
791 | 0 | UniquePK11SymKey keyToWrap(PK11_ImportSymKey(slot.get(), fakeMechanism, |
792 | 0 | PK11_OriginUnwrap, fakeOperation, |
793 | 0 | &dataItem, nullptr)); |
794 | 0 | if (!keyToWrap) { |
795 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
796 | 0 | } |
797 | 0 | |
798 | 0 | // Encrypt and return the wrapped key |
799 | 0 | // AES-KW encryption results in a wrapped key 64 bits longer |
800 | 0 | if (!mResult.SetLength(mData.Length() + 8, fallible)) { |
801 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
802 | 0 | } |
803 | 0 | SECItem resultItem = {siBuffer, mResult.Elements(), |
804 | 0 | (unsigned int) mResult.Length()}; |
805 | 0 | rv = MapSECStatus(PK11_WrapSymKey(mMechanism, nullptr, symKey.get(), |
806 | 0 | keyToWrap.get(), &resultItem)); |
807 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
808 | 0 | } else { |
809 | 0 | // Decrypt the ciphertext into a temporary PK11SymKey |
810 | 0 | // Unwrapped key should be 64 bits shorter |
811 | 0 | int keySize = mData.Length() - 8; |
812 | 0 | UniquePK11SymKey unwrappedKey( |
813 | 0 | PK11_UnwrapSymKey(symKey.get(), mMechanism, nullptr, &dataItem, |
814 | 0 | fakeMechanism, fakeOperation, keySize)); |
815 | 0 | if (!unwrappedKey) { |
816 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
817 | 0 | } |
818 | 0 | |
819 | 0 | // Export the key to get the cleartext |
820 | 0 | rv = MapSECStatus(PK11_ExtractKeyValue(unwrappedKey.get())); |
821 | 0 | if (NS_FAILED(rv)) { |
822 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
823 | 0 | } |
824 | 0 | ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(unwrappedKey.get())); |
825 | 0 | } |
826 | 0 |
|
827 | 0 | return rv; |
828 | 0 | } |
829 | | }; |
830 | | |
831 | | class RsaOaepTask : public ReturnArrayBufferViewTask, |
832 | | public DeferredData |
833 | | { |
834 | | public: |
835 | | RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
836 | | CryptoKey& aKey, bool aEncrypt) |
837 | | : mPrivKey(aKey.GetPrivateKey()) |
838 | | , mPubKey(aKey.GetPublicKey()) |
839 | | , mEncrypt(aEncrypt) |
840 | 0 | { |
841 | 0 | Init(aCx, aAlgorithm, aKey, aEncrypt); |
842 | 0 | } |
843 | | |
844 | | RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
845 | | CryptoKey& aKey, const CryptoOperationData& aData, |
846 | | bool aEncrypt) |
847 | | : mPrivKey(aKey.GetPrivateKey()) |
848 | | , mPubKey(aKey.GetPublicKey()) |
849 | | , mEncrypt(aEncrypt) |
850 | 0 | { |
851 | 0 | Init(aCx, aAlgorithm, aKey, aEncrypt); |
852 | 0 | SetData(aData); |
853 | 0 | } |
854 | | |
855 | | void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, |
856 | | CryptoKey& aKey, bool aEncrypt) |
857 | 0 | { |
858 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_OAEP); |
859 | 0 |
|
860 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_OAEP); |
861 | 0 |
|
862 | 0 | if (mEncrypt) { |
863 | 0 | if (!mPubKey) { |
864 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
865 | 0 | return; |
866 | 0 | } |
867 | 0 | mStrength = SECKEY_PublicKeyStrength(mPubKey.get()); |
868 | 0 | } else { |
869 | 0 | if (!mPrivKey) { |
870 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
871 | 0 | return; |
872 | 0 | } |
873 | 0 | mStrength = PK11_GetPrivateModulusLen(mPrivKey.get()); |
874 | 0 | } |
875 | 0 |
|
876 | 0 | // The algorithm could just be given as a string |
877 | 0 | // in which case there would be no label specified. |
878 | 0 | if (!aAlgorithm.IsString()) { |
879 | 0 | RootedDictionary<RsaOaepParams> params(aCx); |
880 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
881 | 0 | if (NS_FAILED(mEarlyRv)) { |
882 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
883 | 0 | return; |
884 | 0 | } |
885 | 0 | |
886 | 0 | if (params.mLabel.WasPassed()) { |
887 | 0 | ATTEMPT_BUFFER_INIT(mLabel, params.mLabel.Value()); |
888 | 0 | } |
889 | 0 | } |
890 | 0 | // Otherwise mLabel remains the empty octet string, as intended |
891 | 0 |
|
892 | 0 | KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash; |
893 | 0 | mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg); |
894 | 0 | mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlg.mName); |
895 | 0 |
|
896 | 0 | // Check we found appropriate mechanisms. |
897 | 0 | if (mHashMechanism == UNKNOWN_CK_MECHANISM || |
898 | 0 | mMgfMechanism == UNKNOWN_CK_MECHANISM) { |
899 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
900 | 0 | return; |
901 | 0 | } |
902 | 0 | } |
903 | | |
904 | | private: |
905 | | CK_MECHANISM_TYPE mHashMechanism; |
906 | | CK_MECHANISM_TYPE mMgfMechanism; |
907 | | UniqueSECKEYPrivateKey mPrivKey; |
908 | | UniqueSECKEYPublicKey mPubKey; |
909 | | CryptoBuffer mLabel; |
910 | | uint32_t mStrength; |
911 | | bool mEncrypt; |
912 | | |
913 | | virtual nsresult DoCrypto() override |
914 | 0 | { |
915 | 0 | nsresult rv; |
916 | 0 |
|
917 | 0 | if (!mDataIsSet) { |
918 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
919 | 0 | } |
920 | 0 | |
921 | 0 | // Ciphertext is an integer mod the modulus, so it will be |
922 | 0 | // no longer than mStrength octets |
923 | 0 | if (!mResult.SetLength(mStrength, fallible)) { |
924 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
925 | 0 | } |
926 | 0 | |
927 | 0 | CK_RSA_PKCS_OAEP_PARAMS oaepParams; |
928 | 0 | oaepParams.source = CKZ_DATA_SPECIFIED; |
929 | 0 |
|
930 | 0 | oaepParams.pSourceData = mLabel.Length() ? mLabel.Elements() : nullptr; |
931 | 0 | oaepParams.ulSourceDataLen = mLabel.Length(); |
932 | 0 |
|
933 | 0 | oaepParams.mgf = mMgfMechanism; |
934 | 0 | oaepParams.hashAlg = mHashMechanism; |
935 | 0 |
|
936 | 0 | SECItem param; |
937 | 0 | param.type = siBuffer; |
938 | 0 | param.data = (unsigned char*) &oaepParams; |
939 | 0 | param.len = sizeof(oaepParams); |
940 | 0 |
|
941 | 0 | uint32_t outLen = 0; |
942 | 0 | if (mEncrypt) { |
943 | 0 | // PK11_PubEncrypt() checks the plaintext's length and fails if it is too |
944 | 0 | // long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k' |
945 | 0 | // being the length in octets of the RSA modulus n and 'hLen' being the |
946 | 0 | // output length in octets of the chosen hash function. |
947 | 0 | // <https://tools.ietf.org/html/rfc3447#section-7.1> |
948 | 0 | rv = MapSECStatus(PK11_PubEncrypt( |
949 | 0 | mPubKey.get(), CKM_RSA_PKCS_OAEP, ¶m, |
950 | 0 | mResult.Elements(), &outLen, mResult.Length(), |
951 | 0 | mData.Elements(), mData.Length(), nullptr)); |
952 | 0 | } else { |
953 | 0 | rv = MapSECStatus(PK11_PrivDecrypt( |
954 | 0 | mPrivKey.get(), CKM_RSA_PKCS_OAEP, ¶m, |
955 | 0 | mResult.Elements(), &outLen, mResult.Length(), |
956 | 0 | mData.Elements(), mData.Length())); |
957 | 0 | } |
958 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
959 | 0 |
|
960 | 0 | mResult.TruncateLength(outLen); |
961 | 0 | return NS_OK; |
962 | 0 | } |
963 | | }; |
964 | | |
965 | | class HmacTask : public WebCryptoTask |
966 | | { |
967 | | public: |
968 | | HmacTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
969 | | CryptoKey& aKey, |
970 | | const CryptoOperationData& aSignature, |
971 | | const CryptoOperationData& aData, |
972 | | bool aSign) |
973 | | : mMechanism(aKey.Algorithm().Mechanism()) |
974 | | , mSymKey(aKey.GetSymKey()) |
975 | | , mSign(aSign) |
976 | 0 | { |
977 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HMAC); |
978 | 0 |
|
979 | 0 | ATTEMPT_BUFFER_INIT(mData, aData); |
980 | 0 | if (!aSign) { |
981 | 0 | ATTEMPT_BUFFER_INIT(mSignature, aSignature); |
982 | 0 | } |
983 | 0 |
|
984 | 0 | // Check that we got a symmetric key |
985 | 0 | if (mSymKey.Length() == 0) { |
986 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
987 | 0 | return; |
988 | 0 | } |
989 | 0 | |
990 | 0 | TelemetryAlgorithm telemetryAlg; |
991 | 0 | switch (mMechanism) { |
992 | 0 | case CKM_SHA_1_HMAC: telemetryAlg = TA_HMAC_SHA_1; break; |
993 | 0 | case CKM_SHA224_HMAC: telemetryAlg = TA_HMAC_SHA_224; break; |
994 | 0 | case CKM_SHA256_HMAC: telemetryAlg = TA_HMAC_SHA_256; break; |
995 | 0 | case CKM_SHA384_HMAC: telemetryAlg = TA_HMAC_SHA_384; break; |
996 | 0 | case CKM_SHA512_HMAC: telemetryAlg = TA_HMAC_SHA_512; break; |
997 | 0 | default: telemetryAlg = TA_UNKNOWN; |
998 | 0 | } |
999 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg); |
1000 | 0 | } |
1001 | | |
1002 | | private: |
1003 | | CK_MECHANISM_TYPE mMechanism; |
1004 | | CryptoBuffer mSymKey; |
1005 | | CryptoBuffer mData; |
1006 | | CryptoBuffer mSignature; |
1007 | | CryptoBuffer mResult; |
1008 | | bool mSign; |
1009 | | |
1010 | | virtual nsresult DoCrypto() override |
1011 | 0 | { |
1012 | 0 | // Initialize the output buffer |
1013 | 0 | if (!mResult.SetLength(HASH_LENGTH_MAX, fallible)) { |
1014 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
1015 | 0 | } |
1016 | 0 | |
1017 | 0 | UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
1018 | 0 | if (!arena) { |
1019 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1020 | 0 | } |
1021 | 0 | |
1022 | 0 | // Import the key |
1023 | 0 | uint32_t outLen; |
1024 | 0 | SECItem keyItem = { siBuffer, nullptr, 0 }; |
1025 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey); |
1026 | 0 | UniquePK11SlotInfo slot(PK11_GetInternalSlot()); |
1027 | 0 | MOZ_ASSERT(slot.get()); |
1028 | 0 | UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism, |
1029 | 0 | PK11_OriginUnwrap, CKA_SIGN, |
1030 | 0 | &keyItem, nullptr)); |
1031 | 0 | if (!symKey) { |
1032 | 0 | return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
1033 | 0 | } |
1034 | 0 | |
1035 | 0 | // Compute the MAC |
1036 | 0 | SECItem param = { siBuffer, nullptr, 0 }; |
1037 | 0 | UniquePK11Context ctx(PK11_CreateContextBySymKey(mMechanism, CKA_SIGN, |
1038 | 0 | symKey.get(), ¶m)); |
1039 | 0 | if (!ctx.get()) { |
1040 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1041 | 0 | } |
1042 | 0 | nsresult rv = MapSECStatus(PK11_DigestBegin(ctx.get())); |
1043 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
1044 | 0 | rv = MapSECStatus(PK11_DigestOp(ctx.get(), mData.Elements(), mData.Length())); |
1045 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
1046 | 0 | rv = MapSECStatus(PK11_DigestFinal(ctx.get(), mResult.Elements(), |
1047 | 0 | &outLen, mResult.Length())); |
1048 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
1049 | 0 |
|
1050 | 0 | mResult.TruncateLength(outLen); |
1051 | 0 | return rv; |
1052 | 0 | } |
1053 | | |
1054 | | // Returns mResult as an ArrayBufferView, or an error |
1055 | | virtual void Resolve() override |
1056 | 0 | { |
1057 | 0 | if (mSign) { |
1058 | 0 | // Return the computed MAC |
1059 | 0 | TypedArrayCreator<ArrayBuffer> ret(mResult); |
1060 | 0 | mResultPromise->MaybeResolve(ret); |
1061 | 0 | } else { |
1062 | 0 | // Compare the MAC to the provided signature |
1063 | 0 | // No truncation allowed |
1064 | 0 | bool equal = (mResult.Length() == mSignature.Length()); |
1065 | 0 | if (equal) { |
1066 | 0 | int cmp = NSS_SecureMemcmp(mSignature.Elements(), |
1067 | 0 | mResult.Elements(), |
1068 | 0 | mSignature.Length()); |
1069 | 0 | equal = (cmp == 0); |
1070 | 0 | } |
1071 | 0 | mResultPromise->MaybeResolve(equal); |
1072 | 0 | } |
1073 | 0 | } |
1074 | | }; |
1075 | | |
1076 | | class AsymmetricSignVerifyTask : public WebCryptoTask |
1077 | | { |
1078 | | public: |
1079 | | AsymmetricSignVerifyTask(JSContext* aCx, |
1080 | | const ObjectOrString& aAlgorithm, |
1081 | | CryptoKey& aKey, |
1082 | | const CryptoOperationData& aSignature, |
1083 | | const CryptoOperationData& aData, |
1084 | | bool aSign) |
1085 | | : mOidTag(SEC_OID_UNKNOWN) |
1086 | | , mHashMechanism(UNKNOWN_CK_MECHANISM) |
1087 | | , mMgfMechanism(UNKNOWN_CK_MECHANISM) |
1088 | | , mPrivKey(aKey.GetPrivateKey()) |
1089 | | , mPubKey(aKey.GetPublicKey()) |
1090 | | , mSaltLength(0) |
1091 | | , mSign(aSign) |
1092 | | , mVerified(false) |
1093 | | , mAlgorithm(Algorithm::UNKNOWN) |
1094 | 0 | { |
1095 | 0 | ATTEMPT_BUFFER_INIT(mData, aData); |
1096 | 0 | if (!aSign) { |
1097 | 0 | ATTEMPT_BUFFER_INIT(mSignature, aSignature); |
1098 | 0 | } |
1099 | 0 |
|
1100 | 0 | nsString algName; |
1101 | 0 | nsString hashAlgName; |
1102 | 0 | mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName); |
1103 | 0 | if (NS_FAILED(mEarlyRv)) { |
1104 | 0 | return; |
1105 | 0 | } |
1106 | 0 | |
1107 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { |
1108 | 0 | mAlgorithm = Algorithm::RSA_PKCS1; |
1109 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1); |
1110 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1); |
1111 | 0 | hashAlgName = aKey.Algorithm().mRsa.mHash.mName; |
1112 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) { |
1113 | 0 | mAlgorithm = Algorithm::RSA_PSS; |
1114 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_PSS); |
1115 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_PSS); |
1116 | 0 |
|
1117 | 0 | KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash; |
1118 | 0 | hashAlgName = hashAlg.mName; |
1119 | 0 | mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg); |
1120 | 0 | mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlgName); |
1121 | 0 |
|
1122 | 0 | // Check we found appropriate mechanisms. |
1123 | 0 | if (mHashMechanism == UNKNOWN_CK_MECHANISM || |
1124 | 0 | mMgfMechanism == UNKNOWN_CK_MECHANISM) { |
1125 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1126 | 0 | return; |
1127 | 0 | } |
1128 | 0 | |
1129 | 0 | RootedDictionary<RsaPssParams> params(aCx); |
1130 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
1131 | 0 | if (NS_FAILED(mEarlyRv)) { |
1132 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1133 | 0 | return; |
1134 | 0 | } |
1135 | 0 | |
1136 | 0 | mSaltLength = params.mSaltLength; |
1137 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { |
1138 | 0 | mAlgorithm = Algorithm::ECDSA; |
1139 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA); |
1140 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA); |
1141 | 0 |
|
1142 | 0 | // For ECDSA, the hash name comes from the algorithm parameter |
1143 | 0 | RootedDictionary<EcdsaParams> params(aCx); |
1144 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
1145 | 0 | if (NS_FAILED(mEarlyRv)) { |
1146 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1147 | 0 | return; |
1148 | 0 | } |
1149 | 0 | |
1150 | 0 | mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashAlgName); |
1151 | 0 | if (NS_FAILED(mEarlyRv)) { |
1152 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1153 | 0 | return; |
1154 | 0 | } |
1155 | 0 | } else { |
1156 | 0 | // This shouldn't happen; CreateSignVerifyTask shouldn't create |
1157 | 0 | // one of these unless it's for the above algorithms. |
1158 | 0 | MOZ_ASSERT(false); |
1159 | 0 | } |
1160 | 0 |
|
1161 | 0 | // Must have a valid algorithm by now. |
1162 | 0 | MOZ_ASSERT(mAlgorithm != Algorithm::UNKNOWN); |
1163 | 0 |
|
1164 | 0 | // Determine hash algorithm to use. |
1165 | 0 | mOidTag = MapHashAlgorithmNameToOID(hashAlgName); |
1166 | 0 | if (mOidTag == SEC_OID_UNKNOWN) { |
1167 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1168 | 0 | return; |
1169 | 0 | } |
1170 | 0 | |
1171 | 0 | // Check that we have the appropriate key |
1172 | 0 | if ((mSign && !mPrivKey) || (!mSign && !mPubKey)) { |
1173 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
1174 | 0 | return; |
1175 | 0 | } |
1176 | 0 | } |
1177 | | |
1178 | | private: |
1179 | | SECOidTag mOidTag; |
1180 | | CK_MECHANISM_TYPE mHashMechanism; |
1181 | | CK_MECHANISM_TYPE mMgfMechanism; |
1182 | | UniqueSECKEYPrivateKey mPrivKey; |
1183 | | UniqueSECKEYPublicKey mPubKey; |
1184 | | CryptoBuffer mSignature; |
1185 | | CryptoBuffer mData; |
1186 | | uint32_t mSaltLength; |
1187 | | bool mSign; |
1188 | | bool mVerified; |
1189 | | |
1190 | | // The signature algorithm to use. |
1191 | | enum class Algorithm: uint8_t {ECDSA, RSA_PKCS1, RSA_PSS, UNKNOWN}; |
1192 | | Algorithm mAlgorithm; |
1193 | | |
1194 | | virtual nsresult DoCrypto() override |
1195 | 0 | { |
1196 | 0 | SECStatus rv; |
1197 | 0 | UniqueSECItem hash(::SECITEM_AllocItem(nullptr, nullptr, |
1198 | 0 | HASH_ResultLenByOidTag(mOidTag))); |
1199 | 0 | if (!hash) { |
1200 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1201 | 0 | } |
1202 | 0 | |
1203 | 0 | // Compute digest over given data. |
1204 | 0 | rv = PK11_HashBuf(mOidTag, hash->data, mData.Elements(), mData.Length()); |
1205 | 0 | NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR); |
1206 | 0 |
|
1207 | 0 | // Wrap hash in a digest info template (RSA-PKCS1 only). |
1208 | 0 | if (mAlgorithm == Algorithm::RSA_PKCS1) { |
1209 | 0 | UniqueSGNDigestInfo di(SGN_CreateDigestInfo(mOidTag, hash->data, |
1210 | 0 | hash->len)); |
1211 | 0 | if (!di) { |
1212 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1213 | 0 | } |
1214 | 0 | |
1215 | 0 | // Reuse |hash|. |
1216 | 0 | SECITEM_FreeItem(hash.get(), false); |
1217 | 0 | if (!SEC_ASN1EncodeItem(nullptr, hash.get(), di.get(), |
1218 | 0 | SGN_DigestInfoTemplate)) { |
1219 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1220 | 0 | } |
1221 | 0 | } |
1222 | 0 | |
1223 | 0 | SECItem* params = nullptr; |
1224 | 0 | CK_MECHANISM_TYPE mech = PK11_MapSignKeyType((mSign ? mPrivKey->keyType : |
1225 | 0 | mPubKey->keyType)); |
1226 | 0 |
|
1227 | 0 | CK_RSA_PKCS_PSS_PARAMS rsaPssParams; |
1228 | 0 | SECItem rsaPssParamsItem = { siBuffer, }; |
1229 | 0 |
|
1230 | 0 | // Set up parameters for RSA-PSS. |
1231 | 0 | if (mAlgorithm == Algorithm::RSA_PSS) { |
1232 | 0 | rsaPssParams.hashAlg = mHashMechanism; |
1233 | 0 | rsaPssParams.mgf = mMgfMechanism; |
1234 | 0 | rsaPssParams.sLen = mSaltLength; |
1235 | 0 |
|
1236 | 0 | rsaPssParamsItem.data = (unsigned char*)&rsaPssParams; |
1237 | 0 | rsaPssParamsItem.len = sizeof(rsaPssParams); |
1238 | 0 | params = &rsaPssParamsItem; |
1239 | 0 |
|
1240 | 0 | mech = CKM_RSA_PKCS_PSS; |
1241 | 0 | } |
1242 | 0 |
|
1243 | 0 | // Allocate SECItem to hold the signature. |
1244 | 0 | uint32_t len = mSign ? PK11_SignatureLen(mPrivKey.get()) : 0; |
1245 | 0 | UniqueSECItem sig(::SECITEM_AllocItem(nullptr, nullptr, len)); |
1246 | 0 | if (!sig) { |
1247 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1248 | 0 | } |
1249 | 0 | |
1250 | 0 | if (mSign) { |
1251 | 0 | // Sign the hash. |
1252 | 0 | rv = PK11_SignWithMechanism(mPrivKey.get(), mech, params, sig.get(), |
1253 | 0 | hash.get()); |
1254 | 0 | NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR); |
1255 | 0 | ATTEMPT_BUFFER_ASSIGN(mSignature, sig.get()); |
1256 | 0 | } else { |
1257 | 0 | // Copy the given signature to the SECItem. |
1258 | 0 | if (!mSignature.ToSECItem(nullptr, sig.get())) { |
1259 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1260 | 0 | } |
1261 | 0 | |
1262 | 0 | // Verify the signature. |
1263 | 0 | rv = PK11_VerifyWithMechanism(mPubKey.get(), mech, params, sig.get(), |
1264 | 0 | hash.get(), nullptr); |
1265 | 0 | mVerified = NS_SUCCEEDED(MapSECStatus(rv)); |
1266 | 0 | } |
1267 | 0 |
|
1268 | 0 | return NS_OK; |
1269 | 0 | } |
1270 | | |
1271 | | virtual void Resolve() override |
1272 | 0 | { |
1273 | 0 | if (mSign) { |
1274 | 0 | TypedArrayCreator<ArrayBuffer> ret(mSignature); |
1275 | 0 | mResultPromise->MaybeResolve(ret); |
1276 | 0 | } else { |
1277 | 0 | mResultPromise->MaybeResolve(mVerified); |
1278 | 0 | } |
1279 | 0 | } |
1280 | | }; |
1281 | | |
1282 | | class DigestTask : public ReturnArrayBufferViewTask |
1283 | | { |
1284 | | public: |
1285 | | DigestTask(JSContext* aCx, |
1286 | | const ObjectOrString& aAlgorithm, |
1287 | | const CryptoOperationData& aData) |
1288 | 0 | { |
1289 | 0 | ATTEMPT_BUFFER_INIT(mData, aData); |
1290 | 0 |
|
1291 | 0 | nsString algName; |
1292 | 0 | mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName); |
1293 | 0 | if (NS_FAILED(mEarlyRv)) { |
1294 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1295 | 0 | return; |
1296 | 0 | } |
1297 | 0 | |
1298 | 0 | TelemetryAlgorithm telemetryAlg; |
1299 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) { |
1300 | 0 | telemetryAlg = TA_SHA_1; |
1301 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { |
1302 | 0 | telemetryAlg = TA_SHA_224; |
1303 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) { |
1304 | 0 | telemetryAlg = TA_SHA_256; |
1305 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { |
1306 | 0 | telemetryAlg = TA_SHA_384; |
1307 | 0 | } else { |
1308 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1309 | 0 | return; |
1310 | 0 | } |
1311 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg); |
1312 | 0 | mOidTag = MapHashAlgorithmNameToOID(algName); |
1313 | 0 | } |
1314 | | |
1315 | | private: |
1316 | | SECOidTag mOidTag; |
1317 | | CryptoBuffer mData; |
1318 | | |
1319 | | virtual nsresult DoCrypto() override |
1320 | 0 | { |
1321 | 0 | // Resize the result buffer |
1322 | 0 | uint32_t hashLen = HASH_ResultLenByOidTag(mOidTag); |
1323 | 0 | if (!mResult.SetLength(hashLen, fallible)) { |
1324 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
1325 | 0 | } |
1326 | 0 | |
1327 | 0 | // Compute the hash |
1328 | 0 | nsresult rv = MapSECStatus(PK11_HashBuf(mOidTag, mResult.Elements(), |
1329 | 0 | mData.Elements(), mData.Length())); |
1330 | 0 | if (NS_FAILED(rv)) { |
1331 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
1332 | 0 | } |
1333 | 0 | |
1334 | 0 | return rv; |
1335 | 0 | } |
1336 | | }; |
1337 | | |
1338 | | class ImportKeyTask : public WebCryptoTask |
1339 | | { |
1340 | | public: |
1341 | | void Init(nsIGlobalObject* aGlobal, JSContext* aCx, |
1342 | | const nsAString& aFormat, const ObjectOrString& aAlgorithm, |
1343 | | bool aExtractable, const Sequence<nsString>& aKeyUsages) |
1344 | 0 | { |
1345 | 0 | mFormat = aFormat; |
1346 | 0 | mDataIsSet = false; |
1347 | 0 | mDataIsJwk = false; |
1348 | 0 |
|
1349 | 0 | // This stuff pretty much always happens, so we'll do it here |
1350 | 0 | mKey = new CryptoKey(aGlobal); |
1351 | 0 | mKey->SetExtractable(aExtractable); |
1352 | 0 | mKey->ClearUsages(); |
1353 | 0 | for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) { |
1354 | 0 | mEarlyRv = mKey->AddUsage(aKeyUsages[i]); |
1355 | 0 | if (NS_FAILED(mEarlyRv)) { |
1356 | 0 | return; |
1357 | 0 | } |
1358 | 0 | } |
1359 | 0 |
|
1360 | 0 | mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName); |
1361 | 0 | if (NS_FAILED(mEarlyRv)) { |
1362 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
1363 | 0 | return; |
1364 | 0 | } |
1365 | 0 | } |
1366 | | |
1367 | | static bool JwkCompatible(const JsonWebKey& aJwk, const CryptoKey* aKey) |
1368 | 0 | { |
1369 | 0 | // Check 'ext' |
1370 | 0 | if (aKey->Extractable() && |
1371 | 0 | aJwk.mExt.WasPassed() && !aJwk.mExt.Value()) { |
1372 | 0 | return false; |
1373 | 0 | } |
1374 | 0 | |
1375 | 0 | // Check 'alg' |
1376 | 0 | if (aJwk.mAlg.WasPassed() && |
1377 | 0 | aJwk.mAlg.Value() != aKey->Algorithm().JwkAlg()) { |
1378 | 0 | return false; |
1379 | 0 | } |
1380 | 0 | |
1381 | 0 | // Check 'key_ops' |
1382 | 0 | if (aJwk.mKey_ops.WasPassed()) { |
1383 | 0 | nsTArray<nsString> usages; |
1384 | 0 | aKey->GetUsages(usages); |
1385 | 0 | for (size_t i = 0; i < usages.Length(); ++i) { |
1386 | 0 | if (!aJwk.mKey_ops.Value().Contains(usages[i])) { |
1387 | 0 | return false; |
1388 | 0 | } |
1389 | 0 | } |
1390 | 0 | } |
1391 | 0 |
|
1392 | 0 | // Individual algorithms may still have to check 'use' |
1393 | 0 | return true; |
1394 | 0 | } |
1395 | | |
1396 | | void SetKeyData(JSContext* aCx, JS::Handle<JSObject*> aKeyData) |
1397 | 0 | { |
1398 | 0 | mDataIsJwk = false; |
1399 | 0 |
|
1400 | 0 | // Try ArrayBuffer |
1401 | 0 | RootedSpiderMonkeyInterface<ArrayBuffer> ab(aCx); |
1402 | 0 | if (ab.Init(aKeyData)) { |
1403 | 0 | if (!mKeyData.Assign(ab)) { |
1404 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
1405 | 0 | } |
1406 | 0 | return; |
1407 | 0 | } |
1408 | 0 |
|
1409 | 0 | // Try ArrayBufferView |
1410 | 0 | RootedSpiderMonkeyInterface<ArrayBufferView> abv(aCx); |
1411 | 0 | if (abv.Init(aKeyData)) { |
1412 | 0 | if (!mKeyData.Assign(abv)) { |
1413 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
1414 | 0 | } |
1415 | 0 | return; |
1416 | 0 | } |
1417 | 0 |
|
1418 | 0 | // Try JWK |
1419 | 0 | ClearException ce(aCx); |
1420 | 0 | JS::RootedValue value(aCx, JS::ObjectValue(*aKeyData)); |
1421 | 0 | if (!mJwk.Init(aCx, value)) { |
1422 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
1423 | 0 | return; |
1424 | 0 | } |
1425 | 0 | |
1426 | 0 | mDataIsJwk = true; |
1427 | 0 | } |
1428 | | |
1429 | | void SetKeyDataMaybeParseJWK(const CryptoBuffer& aKeyData) |
1430 | 0 | { |
1431 | 0 | if (!mKeyData.Assign(aKeyData)) { |
1432 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
1433 | 0 | return; |
1434 | 0 | } |
1435 | 0 | |
1436 | 0 | mDataIsJwk = false; |
1437 | 0 |
|
1438 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
1439 | 0 | nsDependentCSubstring utf8((const char*) mKeyData.Elements(), |
1440 | 0 | (const char*) (mKeyData.Elements() + |
1441 | 0 | mKeyData.Length())); |
1442 | 0 | if (!IsUTF8(utf8)) { |
1443 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
1444 | 0 | return; |
1445 | 0 | } |
1446 | 0 | |
1447 | 0 | nsString json = NS_ConvertUTF8toUTF16(utf8); |
1448 | 0 | if (!mJwk.Init(json)) { |
1449 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
1450 | 0 | return; |
1451 | 0 | } |
1452 | 0 | |
1453 | 0 | mDataIsJwk = true; |
1454 | 0 | } |
1455 | 0 | } |
1456 | | |
1457 | | void SetRawKeyData(const CryptoBuffer& aKeyData) |
1458 | 0 | { |
1459 | 0 | if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) { |
1460 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
1461 | 0 | return; |
1462 | 0 | } |
1463 | 0 | |
1464 | 0 | if (!mKeyData.Assign(aKeyData)) { |
1465 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
1466 | 0 | return; |
1467 | 0 | } |
1468 | 0 | |
1469 | 0 | mDataIsJwk = false; |
1470 | 0 | } |
1471 | | |
1472 | | protected: |
1473 | | nsString mFormat; |
1474 | | RefPtr<CryptoKey> mKey; |
1475 | | CryptoBuffer mKeyData; |
1476 | | bool mDataIsSet; |
1477 | | bool mDataIsJwk; |
1478 | | JsonWebKey mJwk; |
1479 | | nsString mAlgName; |
1480 | | |
1481 | | private: |
1482 | | virtual void Resolve() override |
1483 | 0 | { |
1484 | 0 | mResultPromise->MaybeResolve(mKey); |
1485 | 0 | } |
1486 | | |
1487 | | virtual void Cleanup() override |
1488 | 0 | { |
1489 | 0 | mKey = nullptr; |
1490 | 0 | } |
1491 | | }; |
1492 | | |
1493 | | |
1494 | | class ImportSymmetricKeyTask : public ImportKeyTask |
1495 | | { |
1496 | | public: |
1497 | | ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
1498 | | const nsAString& aFormat, |
1499 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1500 | | const Sequence<nsString>& aKeyUsages) |
1501 | 0 | { |
1502 | 0 | Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1503 | 0 | } |
1504 | | |
1505 | | ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
1506 | | const nsAString& aFormat, const JS::Handle<JSObject*> aKeyData, |
1507 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1508 | | const Sequence<nsString>& aKeyUsages) |
1509 | 0 | { |
1510 | 0 | Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1511 | 0 | if (NS_FAILED(mEarlyRv)) { |
1512 | 0 | return; |
1513 | 0 | } |
1514 | 0 | |
1515 | 0 | SetKeyData(aCx, aKeyData); |
1516 | 0 | NS_ENSURE_SUCCESS_VOID(mEarlyRv); |
1517 | 0 | if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
1518 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1519 | 0 | return; |
1520 | 0 | } |
1521 | 0 | } |
1522 | | |
1523 | | void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat, |
1524 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1525 | | const Sequence<nsString>& aKeyUsages) |
1526 | 0 | { |
1527 | 0 | ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1528 | 0 | if (NS_FAILED(mEarlyRv)) { |
1529 | 0 | return; |
1530 | 0 | } |
1531 | 0 | |
1532 | 0 | // This task only supports raw and JWK format. |
1533 | 0 | if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) && |
1534 | 0 | !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) { |
1535 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1536 | 0 | return; |
1537 | 0 | } |
1538 | 0 | |
1539 | 0 | // If this is an HMAC key, import the hash name |
1540 | 0 | if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { |
1541 | 0 | RootedDictionary<HmacImportParams> params(aCx); |
1542 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
1543 | 0 | if (NS_FAILED(mEarlyRv)) { |
1544 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1545 | 0 | return; |
1546 | 0 | } |
1547 | 0 | mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName); |
1548 | 0 | if (NS_FAILED(mEarlyRv)) { |
1549 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1550 | 0 | return; |
1551 | 0 | } |
1552 | 0 | } |
1553 | 0 | } |
1554 | | |
1555 | | virtual nsresult BeforeCrypto() override |
1556 | 0 | { |
1557 | 0 | nsresult rv; |
1558 | 0 |
|
1559 | 0 | // If we're doing a JWK import, import the key data |
1560 | 0 | if (mDataIsJwk) { |
1561 | 0 | if (!mJwk.mK.WasPassed()) { |
1562 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1563 | 0 | } |
1564 | 0 | |
1565 | 0 | // Import the key material |
1566 | 0 | rv = mKeyData.FromJwkBase64(mJwk.mK.Value()); |
1567 | 0 | if (NS_FAILED(rv)) { |
1568 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1569 | 0 | } |
1570 | 0 | } |
1571 | 0 | |
1572 | 0 | // Check that we have valid key data. |
1573 | 0 | if (mKeyData.Length() == 0) { |
1574 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1575 | 0 | } |
1576 | 0 | |
1577 | 0 | // Construct an appropriate KeyAlorithm, |
1578 | 0 | // and verify that usages are appropriate |
1579 | 0 | uint32_t length = 8 * mKeyData.Length(); // bytes to bits |
1580 | 0 | if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || |
1581 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || |
1582 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) || |
1583 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { |
1584 | 0 | if (mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::DECRYPT | |
1585 | 0 | CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) { |
1586 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1587 | 0 | } |
1588 | 0 | |
1589 | 0 | if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) && |
1590 | 0 | mKey->HasUsageOtherThan(CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) { |
1591 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1592 | 0 | } |
1593 | 0 | |
1594 | 0 | if ( (length != 128) && (length != 192) && (length != 256) ) { |
1595 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1596 | 0 | } |
1597 | 0 | mKey->Algorithm().MakeAes(mAlgName, length); |
1598 | 0 |
|
1599 | 0 | if (mDataIsJwk && mJwk.mUse.WasPassed() && |
1600 | 0 | !mJwk.mUse.Value().EqualsLiteral(JWK_USE_ENC)) { |
1601 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1602 | 0 | } |
1603 | 0 | } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) || |
1604 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) { |
1605 | 0 | if (mKey->HasUsageOtherThan(CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS)) { |
1606 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1607 | 0 | } |
1608 | 0 | mKey->Algorithm().MakeAes(mAlgName, length); |
1609 | 0 |
|
1610 | 0 | if (mDataIsJwk && mJwk.mUse.WasPassed()) { |
1611 | 0 | // There is not a 'use' value consistent with PBKDF or HKDF |
1612 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1613 | 0 | }; |
1614 | 0 | } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { |
1615 | 0 | if (mKey->HasUsageOtherThan(CryptoKey::SIGN | CryptoKey::VERIFY)) { |
1616 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1617 | 0 | } |
1618 | 0 | |
1619 | 0 | mKey->Algorithm().MakeHmac(length, mHashName); |
1620 | 0 |
|
1621 | 0 | if (mKey->Algorithm().Mechanism() == UNKNOWN_CK_MECHANISM) { |
1622 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
1623 | 0 | } |
1624 | 0 | |
1625 | 0 | if (mDataIsJwk && mJwk.mUse.WasPassed() && |
1626 | 0 | !mJwk.mUse.Value().EqualsLiteral(JWK_USE_SIG)) { |
1627 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1628 | 0 | } |
1629 | 0 | } else { |
1630 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1631 | 0 | } |
1632 | 0 | |
1633 | 0 | if (NS_FAILED(mKey->SetSymKey(mKeyData))) { |
1634 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1635 | 0 | } |
1636 | 0 | |
1637 | 0 | mKey->SetType(CryptoKey::SECRET); |
1638 | 0 |
|
1639 | 0 | if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) { |
1640 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1641 | 0 | } |
1642 | 0 | |
1643 | 0 | mEarlyComplete = true; |
1644 | 0 | return NS_OK; |
1645 | 0 | } |
1646 | | |
1647 | | private: |
1648 | | nsString mHashName; |
1649 | | }; |
1650 | | |
1651 | | class ImportRsaKeyTask : public ImportKeyTask |
1652 | | { |
1653 | | public: |
1654 | | ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
1655 | | const nsAString& aFormat, |
1656 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1657 | | const Sequence<nsString>& aKeyUsages) |
1658 | | : mModulusLength(0) |
1659 | 0 | { |
1660 | 0 | Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1661 | 0 | } |
1662 | | |
1663 | | ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
1664 | | const nsAString& aFormat, JS::Handle<JSObject*> aKeyData, |
1665 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1666 | | const Sequence<nsString>& aKeyUsages) |
1667 | | : mModulusLength(0) |
1668 | 0 | { |
1669 | 0 | Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1670 | 0 | if (NS_FAILED(mEarlyRv)) { |
1671 | 0 | return; |
1672 | 0 | } |
1673 | 0 | |
1674 | 0 | SetKeyData(aCx, aKeyData); |
1675 | 0 | NS_ENSURE_SUCCESS_VOID(mEarlyRv); |
1676 | 0 | if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
1677 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1678 | 0 | return; |
1679 | 0 | } |
1680 | 0 | } |
1681 | | |
1682 | | void Init(nsIGlobalObject* aGlobal, JSContext* aCx, |
1683 | | const nsAString& aFormat, |
1684 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1685 | | const Sequence<nsString>& aKeyUsages) |
1686 | 0 | { |
1687 | 0 | ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1688 | 0 | if (NS_FAILED(mEarlyRv)) { |
1689 | 0 | return; |
1690 | 0 | } |
1691 | 0 | |
1692 | 0 | // If this is RSA with a hash, cache the hash name |
1693 | 0 | if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
1694 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) || |
1695 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) { |
1696 | 0 | RootedDictionary<RsaHashedImportParams> params(aCx); |
1697 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
1698 | 0 | if (NS_FAILED(mEarlyRv)) { |
1699 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
1700 | 0 | return; |
1701 | 0 | } |
1702 | 0 | |
1703 | 0 | mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName); |
1704 | 0 | if (NS_FAILED(mEarlyRv)) { |
1705 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
1706 | 0 | return; |
1707 | 0 | } |
1708 | 0 | } |
1709 | 0 | |
1710 | 0 | // Check support for the algorithm and hash names |
1711 | 0 | CK_MECHANISM_TYPE mech1 = MapAlgorithmNameToMechanism(mAlgName); |
1712 | 0 | CK_MECHANISM_TYPE mech2 = MapAlgorithmNameToMechanism(mHashName); |
1713 | 0 | if ((mech1 == UNKNOWN_CK_MECHANISM) || (mech2 == UNKNOWN_CK_MECHANISM)) { |
1714 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1715 | 0 | return; |
1716 | 0 | } |
1717 | 0 | } |
1718 | | |
1719 | | private: |
1720 | | nsString mHashName; |
1721 | | uint32_t mModulusLength; |
1722 | | CryptoBuffer mPublicExponent; |
1723 | | |
1724 | | virtual nsresult DoCrypto() override |
1725 | 0 | { |
1726 | 0 | // Import the key data itself |
1727 | 0 | UniqueSECKEYPublicKey pubKey; |
1728 | 0 | UniqueSECKEYPrivateKey privKey; |
1729 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) || |
1730 | 0 | (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) && |
1731 | 0 | !mJwk.mD.WasPassed())) { |
1732 | 0 | // Public key import |
1733 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) { |
1734 | 0 | pubKey = CryptoKey::PublicKeyFromSpki(mKeyData); |
1735 | 0 | } else { |
1736 | 0 | pubKey = CryptoKey::PublicKeyFromJwk(mJwk); |
1737 | 0 | } |
1738 | 0 |
|
1739 | 0 | if (!pubKey) { |
1740 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1741 | 0 | } |
1742 | 0 | |
1743 | 0 | if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) { |
1744 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1745 | 0 | } |
1746 | 0 | |
1747 | 0 | mKey->SetType(CryptoKey::PUBLIC); |
1748 | 0 | } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) || |
1749 | 0 | (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) && |
1750 | 0 | mJwk.mD.WasPassed())) { |
1751 | 0 | // Private key import |
1752 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) { |
1753 | 0 | privKey = CryptoKey::PrivateKeyFromPkcs8(mKeyData); |
1754 | 0 | } else { |
1755 | 0 | privKey = CryptoKey::PrivateKeyFromJwk(mJwk); |
1756 | 0 | } |
1757 | 0 |
|
1758 | 0 | if (!privKey) { |
1759 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1760 | 0 | } |
1761 | 0 | |
1762 | 0 | if (NS_FAILED(mKey->SetPrivateKey(privKey.get()))) { |
1763 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1764 | 0 | } |
1765 | 0 | |
1766 | 0 | mKey->SetType(CryptoKey::PRIVATE); |
1767 | 0 | pubKey = UniqueSECKEYPublicKey(SECKEY_ConvertToPublicKey(privKey.get())); |
1768 | 0 | if (!pubKey) { |
1769 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
1770 | 0 | } |
1771 | 0 | } else { |
1772 | 0 | // Invalid key format |
1773 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
1774 | 0 | } |
1775 | 0 | |
1776 | 0 | // Extract relevant information from the public key |
1777 | 0 | mModulusLength = 8 * pubKey->u.rsa.modulus.len; |
1778 | 0 | if (!mPublicExponent.Assign(&pubKey->u.rsa.publicExponent)) { |
1779 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1780 | 0 | } |
1781 | 0 | |
1782 | 0 | return NS_OK; |
1783 | 0 | } |
1784 | | |
1785 | | virtual nsresult AfterCrypto() override |
1786 | 0 | { |
1787 | 0 | // Check permissions for the requested operation |
1788 | 0 | if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { |
1789 | 0 | if ((mKey->GetKeyType() == CryptoKey::PUBLIC && |
1790 | 0 | mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::WRAPKEY)) || |
1791 | 0 | (mKey->GetKeyType() == CryptoKey::PRIVATE && |
1792 | 0 | mKey->HasUsageOtherThan(CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY))) { |
1793 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1794 | 0 | } |
1795 | 0 | } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
1796 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) { |
1797 | 0 | if ((mKey->GetKeyType() == CryptoKey::PUBLIC && |
1798 | 0 | mKey->HasUsageOtherThan(CryptoKey::VERIFY)) || |
1799 | 0 | (mKey->GetKeyType() == CryptoKey::PRIVATE && |
1800 | 0 | mKey->HasUsageOtherThan(CryptoKey::SIGN))) { |
1801 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1802 | 0 | } |
1803 | 0 | } |
1804 | 0 | |
1805 | 0 | // Set an appropriate KeyAlgorithm |
1806 | 0 | if (!mKey->Algorithm().MakeRsa(mAlgName, mModulusLength, |
1807 | 0 | mPublicExponent, mHashName)) { |
1808 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1809 | 0 | } |
1810 | 0 | |
1811 | 0 | if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) { |
1812 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1813 | 0 | } |
1814 | 0 | |
1815 | 0 | return NS_OK; |
1816 | 0 | } |
1817 | | }; |
1818 | | |
1819 | | class ImportEcKeyTask : public ImportKeyTask |
1820 | | { |
1821 | | public: |
1822 | | ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
1823 | | const nsAString& aFormat, const ObjectOrString& aAlgorithm, |
1824 | | bool aExtractable, const Sequence<nsString>& aKeyUsages) |
1825 | 0 | { |
1826 | 0 | Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1827 | 0 | } |
1828 | | |
1829 | | ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
1830 | | const nsAString& aFormat, JS::Handle<JSObject*> aKeyData, |
1831 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1832 | | const Sequence<nsString>& aKeyUsages) |
1833 | 0 | { |
1834 | 0 | Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1835 | 0 | if (NS_FAILED(mEarlyRv)) { |
1836 | 0 | return; |
1837 | 0 | } |
1838 | 0 | |
1839 | 0 | SetKeyData(aCx, aKeyData); |
1840 | 0 | NS_ENSURE_SUCCESS_VOID(mEarlyRv); |
1841 | 0 | } |
1842 | | |
1843 | | void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat, |
1844 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1845 | | const Sequence<nsString>& aKeyUsages) |
1846 | 0 | { |
1847 | 0 | ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1848 | 0 | if (NS_FAILED(mEarlyRv)) { |
1849 | 0 | return; |
1850 | 0 | } |
1851 | 0 | |
1852 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) { |
1853 | 0 | RootedDictionary<EcKeyImportParams> params(aCx); |
1854 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
1855 | 0 | if (NS_FAILED(mEarlyRv) || !params.mNamedCurve.WasPassed()) { |
1856 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
1857 | 0 | return; |
1858 | 0 | } |
1859 | 0 | |
1860 | 0 | if (!NormalizeToken(params.mNamedCurve.Value(), mNamedCurve)) { |
1861 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1862 | 0 | return; |
1863 | 0 | } |
1864 | 0 | } |
1865 | 0 | } |
1866 | | |
1867 | | private: |
1868 | | nsString mNamedCurve; |
1869 | | |
1870 | | virtual nsresult DoCrypto() override |
1871 | 0 | { |
1872 | 0 | // Import the key data itself |
1873 | 0 | UniqueSECKEYPublicKey pubKey; |
1874 | 0 | UniqueSECKEYPrivateKey privKey; |
1875 | 0 |
|
1876 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) && mJwk.mD.WasPassed()) { |
1877 | 0 | // Private key import |
1878 | 0 | privKey = CryptoKey::PrivateKeyFromJwk(mJwk); |
1879 | 0 | if (!privKey) { |
1880 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1881 | 0 | } |
1882 | 0 | |
1883 | 0 | if (NS_FAILED(mKey->SetPrivateKey(privKey.get()))) { |
1884 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1885 | 0 | } |
1886 | 0 | |
1887 | 0 | mKey->SetType(CryptoKey::PRIVATE); |
1888 | 0 | } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) || |
1889 | 0 | mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) || |
1890 | 0 | (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) && |
1891 | 0 | !mJwk.mD.WasPassed())) { |
1892 | 0 | // Public key import |
1893 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) { |
1894 | 0 | pubKey = CryptoKey::PublicECKeyFromRaw(mKeyData, mNamedCurve); |
1895 | 0 | } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) { |
1896 | 0 | pubKey = CryptoKey::PublicKeyFromSpki(mKeyData); |
1897 | 0 | } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
1898 | 0 | pubKey = CryptoKey::PublicKeyFromJwk(mJwk); |
1899 | 0 | } else { |
1900 | 0 | MOZ_ASSERT(false); |
1901 | 0 | } |
1902 | 0 |
|
1903 | 0 | if (!pubKey) { |
1904 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1905 | 0 | } |
1906 | 0 | |
1907 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) { |
1908 | 0 | if (!CheckEncodedECParameters(&pubKey->u.ec.DEREncodedParams)) { |
1909 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1910 | 0 | } |
1911 | 0 | |
1912 | 0 | // Construct the OID tag. |
1913 | 0 | SECItem oid = { siBuffer, nullptr, 0 }; |
1914 | 0 | oid.len = pubKey->u.ec.DEREncodedParams.data[1]; |
1915 | 0 | oid.data = pubKey->u.ec.DEREncodedParams.data + 2; |
1916 | 0 |
|
1917 | 0 | // Find a matching and supported named curve. |
1918 | 0 | if (!MapOIDTagToNamedCurve(SECOID_FindOIDTag(&oid), mNamedCurve)) { |
1919 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1920 | 0 | } |
1921 | 0 | } |
1922 | 0 | |
1923 | 0 | if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) { |
1924 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
1925 | 0 | } |
1926 | 0 | |
1927 | 0 | mKey->SetType(CryptoKey::PUBLIC); |
1928 | 0 | } else { |
1929 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1930 | 0 | } |
1931 | 0 | |
1932 | 0 | // Extract 'crv' parameter from JWKs. |
1933 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
1934 | 0 | if (!NormalizeToken(mJwk.mCrv.Value(), mNamedCurve)) { |
1935 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
1936 | 0 | } |
1937 | 0 | } |
1938 | 0 | |
1939 | 0 | return NS_OK; |
1940 | 0 | } |
1941 | | |
1942 | | virtual nsresult AfterCrypto() override |
1943 | 0 | { |
1944 | 0 | uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0; |
1945 | 0 | if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { |
1946 | 0 | privateAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY; |
1947 | 0 | publicAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY; |
1948 | 0 | } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { |
1949 | 0 | privateAllowedUsages = CryptoKey::SIGN; |
1950 | 0 | publicAllowedUsages = CryptoKey::VERIFY; |
1951 | 0 | } |
1952 | 0 |
|
1953 | 0 | // Check permissions for the requested operation |
1954 | 0 | if ((mKey->GetKeyType() == CryptoKey::PRIVATE && |
1955 | 0 | mKey->HasUsageOtherThan(privateAllowedUsages)) || |
1956 | 0 | (mKey->GetKeyType() == CryptoKey::PUBLIC && |
1957 | 0 | mKey->HasUsageOtherThan(publicAllowedUsages))) { |
1958 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1959 | 0 | } |
1960 | 0 | |
1961 | 0 | mKey->Algorithm().MakeEc(mAlgName, mNamedCurve); |
1962 | 0 |
|
1963 | 0 | if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) { |
1964 | 0 | return NS_ERROR_DOM_DATA_ERR; |
1965 | 0 | } |
1966 | 0 | |
1967 | 0 | return NS_OK; |
1968 | 0 | } |
1969 | | }; |
1970 | | |
1971 | | class ImportDhKeyTask : public ImportKeyTask |
1972 | | { |
1973 | | public: |
1974 | | ImportDhKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
1975 | | const nsAString& aFormat, const ObjectOrString& aAlgorithm, |
1976 | | bool aExtractable, const Sequence<nsString>& aKeyUsages) |
1977 | 0 | { |
1978 | 0 | Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1979 | 0 | } |
1980 | | |
1981 | | ImportDhKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
1982 | | const nsAString& aFormat, JS::Handle<JSObject*> aKeyData, |
1983 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1984 | | const Sequence<nsString>& aKeyUsages) |
1985 | 0 | { |
1986 | 0 | Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1987 | 0 | if (NS_SUCCEEDED(mEarlyRv)) { |
1988 | 0 | SetKeyData(aCx, aKeyData); |
1989 | 0 | NS_ENSURE_SUCCESS_VOID(mEarlyRv); |
1990 | 0 | } |
1991 | 0 | } |
1992 | | |
1993 | | void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat, |
1994 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
1995 | | const Sequence<nsString>& aKeyUsages) |
1996 | 0 | { |
1997 | 0 | ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages); |
1998 | 0 | if (NS_FAILED(mEarlyRv)) { |
1999 | 0 | return; |
2000 | 0 | } |
2001 | 0 | |
2002 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) { |
2003 | 0 | RootedDictionary<DhImportKeyParams> params(aCx); |
2004 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
2005 | 0 | if (NS_FAILED(mEarlyRv)) { |
2006 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2007 | 0 | return; |
2008 | 0 | } |
2009 | 0 | |
2010 | 0 | CryptoBuffer prime; |
2011 | 0 | ATTEMPT_BUFFER_INIT(mPrime, params.mPrime); |
2012 | 0 |
|
2013 | 0 | CryptoBuffer generator; |
2014 | 0 | ATTEMPT_BUFFER_INIT(mGenerator, params.mGenerator); |
2015 | 0 | } |
2016 | 0 | } |
2017 | | |
2018 | | private: |
2019 | | CryptoBuffer mPrime; |
2020 | | CryptoBuffer mGenerator; |
2021 | | |
2022 | | virtual nsresult DoCrypto() override |
2023 | 0 | { |
2024 | 0 | // Import the key data itself |
2025 | 0 | UniqueSECKEYPublicKey pubKey; |
2026 | 0 |
|
2027 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) || |
2028 | 0 | mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) { |
2029 | 0 | // Public key import |
2030 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) { |
2031 | 0 | pubKey = CryptoKey::PublicDhKeyFromRaw(mKeyData, mPrime, mGenerator); |
2032 | 0 | } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) { |
2033 | 0 | pubKey = CryptoKey::PublicKeyFromSpki(mKeyData); |
2034 | 0 | } else { |
2035 | 0 | MOZ_ASSERT(false); |
2036 | 0 | } |
2037 | 0 |
|
2038 | 0 | if (!pubKey) { |
2039 | 0 | return NS_ERROR_DOM_DATA_ERR; |
2040 | 0 | } |
2041 | 0 | |
2042 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) { |
2043 | 0 | ATTEMPT_BUFFER_ASSIGN(mPrime, &pubKey->u.dh.prime); |
2044 | 0 | ATTEMPT_BUFFER_ASSIGN(mGenerator, &pubKey->u.dh.base); |
2045 | 0 | } |
2046 | 0 |
|
2047 | 0 | if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) { |
2048 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2049 | 0 | } |
2050 | 0 | |
2051 | 0 | mKey->SetType(CryptoKey::PUBLIC); |
2052 | 0 | } else { |
2053 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2054 | 0 | } |
2055 | 0 | |
2056 | 0 | return NS_OK; |
2057 | 0 | } |
2058 | | |
2059 | | virtual nsresult AfterCrypto() override |
2060 | 0 | { |
2061 | 0 | // Check permissions for the requested operation |
2062 | 0 | if (mKey->HasUsageOtherThan(CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY)) { |
2063 | 0 | return NS_ERROR_DOM_DATA_ERR; |
2064 | 0 | } |
2065 | 0 | |
2066 | 0 | if (!mKey->Algorithm().MakeDh(mAlgName, mPrime, mGenerator)) { |
2067 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2068 | 0 | } |
2069 | 0 | return NS_OK; |
2070 | 0 | } |
2071 | | }; |
2072 | | |
2073 | | class ExportKeyTask : public WebCryptoTask |
2074 | | { |
2075 | | public: |
2076 | | ExportKeyTask(const nsAString& aFormat, CryptoKey& aKey) |
2077 | | : mFormat(aFormat) |
2078 | | , mSymKey(aKey.GetSymKey()) |
2079 | | , mPrivateKey(aKey.GetPrivateKey()) |
2080 | | , mPublicKey(aKey.GetPublicKey()) |
2081 | | , mKeyType(aKey.GetKeyType()) |
2082 | | , mExtractable(aKey.Extractable()) |
2083 | | , mAlg(aKey.Algorithm().JwkAlg()) |
2084 | 0 | { |
2085 | 0 | aKey.GetUsages(mKeyUsages); |
2086 | 0 | } |
2087 | | |
2088 | | |
2089 | | protected: |
2090 | | nsString mFormat; |
2091 | | CryptoBuffer mSymKey; |
2092 | | UniqueSECKEYPrivateKey mPrivateKey; |
2093 | | UniqueSECKEYPublicKey mPublicKey; |
2094 | | CryptoKey::KeyType mKeyType; |
2095 | | bool mExtractable; |
2096 | | nsString mAlg; |
2097 | | nsTArray<nsString> mKeyUsages; |
2098 | | CryptoBuffer mResult; |
2099 | | JsonWebKey mJwk; |
2100 | | |
2101 | | private: |
2102 | | virtual nsresult DoCrypto() override |
2103 | 0 | { |
2104 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) { |
2105 | 0 | if (mPublicKey && mPublicKey->keyType == dhKey) { |
2106 | 0 | nsresult rv = CryptoKey::PublicDhKeyToRaw(mPublicKey.get(), mResult); |
2107 | 0 | if (NS_FAILED(rv)) { |
2108 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2109 | 0 | } |
2110 | 0 | return NS_OK; |
2111 | 0 | } |
2112 | 0 | |
2113 | 0 | if (mPublicKey && mPublicKey->keyType == ecKey) { |
2114 | 0 | nsresult rv = CryptoKey::PublicECKeyToRaw(mPublicKey.get(), mResult); |
2115 | 0 | if (NS_FAILED(rv)) { |
2116 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2117 | 0 | } |
2118 | 0 | return NS_OK; |
2119 | 0 | } |
2120 | 0 | |
2121 | 0 | mResult = mSymKey; |
2122 | 0 | if (mResult.Length() == 0) { |
2123 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2124 | 0 | } |
2125 | 0 | |
2126 | 0 | return NS_OK; |
2127 | 0 | } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) { |
2128 | 0 | if (!mPrivateKey) { |
2129 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2130 | 0 | } |
2131 | 0 | |
2132 | 0 | switch (mPrivateKey->keyType) { |
2133 | 0 | case rsaKey: { |
2134 | 0 | nsresult rv = CryptoKey::PrivateKeyToPkcs8(mPrivateKey.get(), mResult); |
2135 | 0 | if (NS_FAILED(rv)) { |
2136 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2137 | 0 | } |
2138 | 0 | return NS_OK; |
2139 | 0 | } |
2140 | 0 | default: |
2141 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2142 | 0 | } |
2143 | 0 | } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) { |
2144 | 0 | if (!mPublicKey) { |
2145 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2146 | 0 | } |
2147 | 0 | |
2148 | 0 | return CryptoKey::PublicKeyToSpki(mPublicKey.get(), mResult); |
2149 | 0 | } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
2150 | 0 | if (mKeyType == CryptoKey::SECRET) { |
2151 | 0 | nsString k; |
2152 | 0 | nsresult rv = mSymKey.ToJwkBase64(k); |
2153 | 0 | if (NS_FAILED(rv)) { |
2154 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2155 | 0 | } |
2156 | 0 | mJwk.mK.Construct(k); |
2157 | 0 | mJwk.mKty = NS_LITERAL_STRING(JWK_TYPE_SYMMETRIC); |
2158 | 0 | } else if (mKeyType == CryptoKey::PUBLIC) { |
2159 | 0 | if (!mPublicKey) { |
2160 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
2161 | 0 | } |
2162 | 0 | |
2163 | 0 | nsresult rv = CryptoKey::PublicKeyToJwk(mPublicKey.get(), mJwk); |
2164 | 0 | if (NS_FAILED(rv)) { |
2165 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2166 | 0 | } |
2167 | 0 | } else if (mKeyType == CryptoKey::PRIVATE) { |
2168 | 0 | if (!mPrivateKey) { |
2169 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
2170 | 0 | } |
2171 | 0 | |
2172 | 0 | nsresult rv = CryptoKey::PrivateKeyToJwk(mPrivateKey.get(), mJwk); |
2173 | 0 | if (NS_FAILED(rv)) { |
2174 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2175 | 0 | } |
2176 | 0 | } |
2177 | 0 | |
2178 | 0 | if (!mAlg.IsEmpty()) { |
2179 | 0 | mJwk.mAlg.Construct(mAlg); |
2180 | 0 | } |
2181 | 0 |
|
2182 | 0 | mJwk.mExt.Construct(mExtractable); |
2183 | 0 |
|
2184 | 0 | mJwk.mKey_ops.Construct(); |
2185 | 0 | if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages, fallible)) { |
2186 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
2187 | 0 | } |
2188 | 0 | |
2189 | 0 | return NS_OK; |
2190 | 0 | } |
2191 | 0 | |
2192 | 0 | return NS_ERROR_DOM_SYNTAX_ERR; |
2193 | 0 | } |
2194 | | |
2195 | | // Returns mResult as an ArrayBufferView or JWK, as appropriate |
2196 | | virtual void Resolve() override |
2197 | 0 | { |
2198 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
2199 | 0 | mResultPromise->MaybeResolve(mJwk); |
2200 | 0 | return; |
2201 | 0 | } |
2202 | 0 | |
2203 | 0 | TypedArrayCreator<ArrayBuffer> ret(mResult); |
2204 | 0 | mResultPromise->MaybeResolve(ret); |
2205 | 0 | } |
2206 | | }; |
2207 | | |
2208 | | class GenerateSymmetricKeyTask : public WebCryptoTask |
2209 | | { |
2210 | | public: |
2211 | | GenerateSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
2212 | | const ObjectOrString& aAlgorithm, bool aExtractable, |
2213 | | const Sequence<nsString>& aKeyUsages) |
2214 | 0 | { |
2215 | 0 | // Create an empty key and set easy attributes |
2216 | 0 | mKey = new CryptoKey(aGlobal); |
2217 | 0 | mKey->SetExtractable(aExtractable); |
2218 | 0 | mKey->SetType(CryptoKey::SECRET); |
2219 | 0 |
|
2220 | 0 | // Extract algorithm name |
2221 | 0 | nsString algName; |
2222 | 0 | mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName); |
2223 | 0 | if (NS_FAILED(mEarlyRv)) { |
2224 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2225 | 0 | return; |
2226 | 0 | } |
2227 | 0 | |
2228 | 0 | // Construct an appropriate KeyAlorithm |
2229 | 0 | uint32_t allowedUsages = 0; |
2230 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || |
2231 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || |
2232 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) || |
2233 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { |
2234 | 0 | mEarlyRv = GetKeyLengthForAlgorithm(aCx, aAlgorithm, mLength); |
2235 | 0 | if (NS_FAILED(mEarlyRv)) { |
2236 | 0 | return; |
2237 | 0 | } |
2238 | 0 | mKey->Algorithm().MakeAes(algName, mLength); |
2239 | 0 |
|
2240 | 0 | allowedUsages = CryptoKey::ENCRYPT | CryptoKey::DECRYPT | |
2241 | 0 | CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY; |
2242 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { |
2243 | 0 | RootedDictionary<HmacKeyGenParams> params(aCx); |
2244 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
2245 | 0 | if (NS_FAILED(mEarlyRv)) { |
2246 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2247 | 0 | return; |
2248 | 0 | } |
2249 | 0 | |
2250 | 0 | nsString hashName; |
2251 | 0 | mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); |
2252 | 0 | if (NS_FAILED(mEarlyRv)) { |
2253 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2254 | 0 | return; |
2255 | 0 | } |
2256 | 0 | |
2257 | 0 | if (params.mLength.WasPassed()) { |
2258 | 0 | mLength = params.mLength.Value(); |
2259 | 0 | } else { |
2260 | 0 | mLength = MapHashAlgorithmNameToBlockSize(hashName); |
2261 | 0 | } |
2262 | 0 |
|
2263 | 0 | if (mLength == 0) { |
2264 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
2265 | 0 | return; |
2266 | 0 | } |
2267 | 0 | |
2268 | 0 | mKey->Algorithm().MakeHmac(mLength, hashName); |
2269 | 0 | allowedUsages = CryptoKey::SIGN | CryptoKey::VERIFY; |
2270 | 0 | } else { |
2271 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2272 | 0 | return; |
2273 | 0 | } |
2274 | 0 | |
2275 | 0 | // Add key usages |
2276 | 0 | mKey->ClearUsages(); |
2277 | 0 | for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) { |
2278 | 0 | mEarlyRv = mKey->AddUsageIntersecting(aKeyUsages[i], allowedUsages); |
2279 | 0 | if (NS_FAILED(mEarlyRv)) { |
2280 | 0 | return; |
2281 | 0 | } |
2282 | 0 | } |
2283 | 0 |
|
2284 | 0 | mLength = mLength >> 3; // bits to bytes |
2285 | 0 | mMechanism = mKey->Algorithm().Mechanism(); |
2286 | 0 | // SetSymKey done in Resolve, after we've done the keygen |
2287 | 0 | } |
2288 | | |
2289 | | private: |
2290 | | RefPtr<CryptoKey> mKey; |
2291 | | size_t mLength; |
2292 | | CK_MECHANISM_TYPE mMechanism; |
2293 | | CryptoBuffer mKeyData; |
2294 | | |
2295 | | virtual nsresult DoCrypto() override |
2296 | 0 | { |
2297 | 0 | UniquePK11SlotInfo slot(PK11_GetInternalSlot()); |
2298 | 0 | MOZ_ASSERT(slot.get()); |
2299 | 0 |
|
2300 | 0 | UniquePK11SymKey symKey(PK11_KeyGen(slot.get(), mMechanism, nullptr, |
2301 | 0 | mLength, nullptr)); |
2302 | 0 | if (!symKey) { |
2303 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
2304 | 0 | } |
2305 | 0 | |
2306 | 0 | nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get())); |
2307 | 0 | if (NS_FAILED(rv)) { |
2308 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
2309 | 0 | } |
2310 | 0 | |
2311 | 0 | // This doesn't leak, because the SECItem* returned by PK11_GetKeyData |
2312 | 0 | // just refers to a buffer managed by symKey. The assignment copies the |
2313 | 0 | // data, so mKeyData manages one copy, while symKey manages another. |
2314 | 0 | ATTEMPT_BUFFER_ASSIGN(mKeyData, PK11_GetKeyData(symKey.get())); |
2315 | 0 | return NS_OK; |
2316 | 0 | } |
2317 | | |
2318 | | virtual void Resolve() override |
2319 | 0 | { |
2320 | 0 | if (NS_SUCCEEDED(mKey->SetSymKey(mKeyData))) { |
2321 | 0 | mResultPromise->MaybeResolve(mKey); |
2322 | 0 | } else { |
2323 | 0 | mResultPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR); |
2324 | 0 | } |
2325 | 0 | } |
2326 | | |
2327 | | virtual void Cleanup() override |
2328 | 0 | { |
2329 | 0 | mKey = nullptr; |
2330 | 0 | } |
2331 | | }; |
2332 | | |
2333 | | GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask( |
2334 | | nsIGlobalObject* aGlobal, JSContext* aCx, const ObjectOrString& aAlgorithm, |
2335 | | bool aExtractable, const Sequence<nsString>& aKeyUsages) |
2336 | | : mKeyPair(new CryptoKeyPair()) |
2337 | | , mMechanism(CKM_INVALID_MECHANISM) |
2338 | | , mRsaParams() |
2339 | | , mDhParams() |
2340 | 0 | { |
2341 | 0 | mArena = UniquePLArenaPool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
2342 | 0 | if (!mArena) { |
2343 | 0 | mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; |
2344 | 0 | return; |
2345 | 0 | } |
2346 | 0 | |
2347 | 0 | // Create an empty key pair and set easy attributes |
2348 | 0 | mKeyPair->mPrivateKey = new CryptoKey(aGlobal); |
2349 | 0 | mKeyPair->mPublicKey = new CryptoKey(aGlobal); |
2350 | 0 |
|
2351 | 0 | // Extract algorithm name |
2352 | 0 | mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName); |
2353 | 0 | if (NS_FAILED(mEarlyRv)) { |
2354 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2355 | 0 | return; |
2356 | 0 | } |
2357 | 0 | |
2358 | 0 | // Construct an appropriate KeyAlorithm |
2359 | 0 | uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0; |
2360 | 0 | if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
2361 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) || |
2362 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) { |
2363 | 0 | RootedDictionary<RsaHashedKeyGenParams> params(aCx); |
2364 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
2365 | 0 | if (NS_FAILED(mEarlyRv)) { |
2366 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2367 | 0 | return; |
2368 | 0 | } |
2369 | 0 | |
2370 | 0 | // Pull relevant info |
2371 | 0 | uint32_t modulusLength = params.mModulusLength; |
2372 | 0 | CryptoBuffer publicExponent; |
2373 | 0 | ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent); |
2374 | 0 | nsString hashName; |
2375 | 0 | mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); |
2376 | 0 | if (NS_FAILED(mEarlyRv)) { |
2377 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2378 | 0 | return; |
2379 | 0 | } |
2380 | 0 | |
2381 | 0 | // Create algorithm |
2382 | 0 | if (!mKeyPair->mPublicKey.get()->Algorithm().MakeRsa(mAlgName, |
2383 | 0 | modulusLength, |
2384 | 0 | publicExponent, |
2385 | 0 | hashName)) { |
2386 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
2387 | 0 | return; |
2388 | 0 | } |
2389 | 0 | if (!mKeyPair->mPrivateKey.get()->Algorithm().MakeRsa(mAlgName, |
2390 | 0 | modulusLength, |
2391 | 0 | publicExponent, |
2392 | 0 | hashName)) { |
2393 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
2394 | 0 | return; |
2395 | 0 | } |
2396 | 0 | mMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; |
2397 | 0 |
|
2398 | 0 | // Set up params struct |
2399 | 0 | mRsaParams.keySizeInBits = modulusLength; |
2400 | 0 | bool converted = publicExponent.GetBigIntValue(mRsaParams.pe); |
2401 | 0 | if (!converted) { |
2402 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
2403 | 0 | return; |
2404 | 0 | } |
2405 | 0 | } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) || |
2406 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { |
2407 | 0 | RootedDictionary<EcKeyGenParams> params(aCx); |
2408 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
2409 | 0 | if (NS_FAILED(mEarlyRv)) { |
2410 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2411 | 0 | return; |
2412 | 0 | } |
2413 | 0 | |
2414 | 0 | if (!NormalizeToken(params.mNamedCurve, mNamedCurve)) { |
2415 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2416 | 0 | return; |
2417 | 0 | } |
2418 | 0 | |
2419 | 0 | // Create algorithm. |
2420 | 0 | mKeyPair->mPublicKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve); |
2421 | 0 | mKeyPair->mPrivateKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve); |
2422 | 0 | mMechanism = CKM_EC_KEY_PAIR_GEN; |
2423 | 0 | } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_DH)) { |
2424 | 0 | RootedDictionary<DhKeyGenParams> params(aCx); |
2425 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
2426 | 0 | if (NS_FAILED(mEarlyRv)) { |
2427 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2428 | 0 | return; |
2429 | 0 | } |
2430 | 0 | |
2431 | 0 | CryptoBuffer prime; |
2432 | 0 | ATTEMPT_BUFFER_INIT(prime, params.mPrime); |
2433 | 0 |
|
2434 | 0 | CryptoBuffer generator; |
2435 | 0 | ATTEMPT_BUFFER_INIT(generator, params.mGenerator); |
2436 | 0 |
|
2437 | 0 | // Set up params. |
2438 | 0 | if (!prime.ToSECItem(mArena.get(), &mDhParams.prime) || |
2439 | 0 | !generator.ToSECItem(mArena.get(), &mDhParams.base)) { |
2440 | 0 | mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; |
2441 | 0 | return; |
2442 | 0 | } |
2443 | 0 | |
2444 | 0 | // Create algorithm. |
2445 | 0 | if (!mKeyPair->mPublicKey.get()->Algorithm().MakeDh(mAlgName, |
2446 | 0 | prime, |
2447 | 0 | generator)) { |
2448 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
2449 | 0 | return; |
2450 | 0 | } |
2451 | 0 | if (!mKeyPair->mPrivateKey.get()->Algorithm().MakeDh(mAlgName, |
2452 | 0 | prime, |
2453 | 0 | generator)) { |
2454 | 0 | mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; |
2455 | 0 | return; |
2456 | 0 | } |
2457 | 0 | mMechanism = CKM_DH_PKCS_KEY_PAIR_GEN; |
2458 | 0 | } else { |
2459 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2460 | 0 | return; |
2461 | 0 | } |
2462 | 0 | |
2463 | 0 | // Set key usages. |
2464 | 0 | if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
2465 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) || |
2466 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { |
2467 | 0 | privateAllowedUsages = CryptoKey::SIGN; |
2468 | 0 | publicAllowedUsages = CryptoKey::VERIFY; |
2469 | 0 | } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { |
2470 | 0 | privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY; |
2471 | 0 | publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY; |
2472 | 0 | } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) || |
2473 | 0 | mAlgName.EqualsLiteral(WEBCRYPTO_ALG_DH)) { |
2474 | 0 | privateAllowedUsages = CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS; |
2475 | 0 | publicAllowedUsages = 0; |
2476 | 0 | } else { |
2477 | 0 | MOZ_ASSERT(false); // This shouldn't happen. |
2478 | 0 | } |
2479 | 0 |
|
2480 | 0 | mKeyPair->mPrivateKey.get()->SetExtractable(aExtractable); |
2481 | 0 | mKeyPair->mPrivateKey.get()->SetType(CryptoKey::PRIVATE); |
2482 | 0 |
|
2483 | 0 | mKeyPair->mPublicKey.get()->SetExtractable(true); |
2484 | 0 | mKeyPair->mPublicKey.get()->SetType(CryptoKey::PUBLIC); |
2485 | 0 |
|
2486 | 0 | mKeyPair->mPrivateKey.get()->ClearUsages(); |
2487 | 0 | mKeyPair->mPublicKey.get()->ClearUsages(); |
2488 | 0 | for (uint32_t i=0; i < aKeyUsages.Length(); ++i) { |
2489 | 0 | mEarlyRv = mKeyPair->mPrivateKey.get()->AddUsageIntersecting(aKeyUsages[i], |
2490 | 0 | privateAllowedUsages); |
2491 | 0 | if (NS_FAILED(mEarlyRv)) { |
2492 | 0 | return; |
2493 | 0 | } |
2494 | 0 | |
2495 | 0 | mEarlyRv = mKeyPair->mPublicKey.get()->AddUsageIntersecting(aKeyUsages[i], |
2496 | 0 | publicAllowedUsages); |
2497 | 0 | if (NS_FAILED(mEarlyRv)) { |
2498 | 0 | return; |
2499 | 0 | } |
2500 | 0 | } |
2501 | 0 |
|
2502 | 0 | // If no usages ended up being allowed, DataError |
2503 | 0 | if (!mKeyPair->mPublicKey.get()->HasAnyUsage() && |
2504 | 0 | !mKeyPair->mPrivateKey.get()->HasAnyUsage()) { |
2505 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
2506 | 0 | return; |
2507 | 0 | } |
2508 | 0 | } |
2509 | | |
2510 | | nsresult |
2511 | | GenerateAsymmetricKeyTask::DoCrypto() |
2512 | 0 | { |
2513 | 0 | MOZ_ASSERT(mKeyPair); |
2514 | 0 |
|
2515 | 0 | UniquePK11SlotInfo slot(PK11_GetInternalSlot()); |
2516 | 0 | MOZ_ASSERT(slot.get()); |
2517 | 0 |
|
2518 | 0 | void* param; |
2519 | 0 | switch (mMechanism) { |
2520 | 0 | case CKM_RSA_PKCS_KEY_PAIR_GEN: |
2521 | 0 | param = &mRsaParams; |
2522 | 0 | break; |
2523 | 0 | case CKM_DH_PKCS_KEY_PAIR_GEN: |
2524 | 0 | param = &mDhParams; |
2525 | 0 | break; |
2526 | 0 | case CKM_EC_KEY_PAIR_GEN: { |
2527 | 0 | param = CreateECParamsForCurve(mNamedCurve, mArena.get()); |
2528 | 0 | if (!param) { |
2529 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
2530 | 0 | } |
2531 | 0 | break; |
2532 | 0 | } |
2533 | 0 | default: |
2534 | 0 | return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2535 | 0 | } |
2536 | 0 | |
2537 | 0 | SECKEYPublicKey* pubKey = nullptr; |
2538 | 0 | mPrivateKey = UniqueSECKEYPrivateKey( |
2539 | 0 | PK11_GenerateKeyPair(slot.get(), mMechanism, param, &pubKey, PR_FALSE, |
2540 | 0 | PR_FALSE, nullptr)); |
2541 | 0 | mPublicKey = UniqueSECKEYPublicKey(pubKey); |
2542 | 0 | pubKey = nullptr; |
2543 | 0 | if (!mPrivateKey.get() || !mPublicKey.get()) { |
2544 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
2545 | 0 | } |
2546 | 0 | |
2547 | 0 | nsresult rv = mKeyPair->mPrivateKey.get()->SetPrivateKey(mPrivateKey.get()); |
2548 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
2549 | 0 | rv = mKeyPair->mPublicKey.get()->SetPublicKey(mPublicKey.get()); |
2550 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
2551 | 0 |
|
2552 | 0 | // PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the |
2553 | 0 | // private key, we need this later when exporting to PKCS8 and JWK though. |
2554 | 0 | if (mMechanism == CKM_EC_KEY_PAIR_GEN) { |
2555 | 0 | rv = mKeyPair->mPrivateKey->AddPublicKeyData(mPublicKey.get()); |
2556 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); |
2557 | 0 | } |
2558 | 0 |
|
2559 | 0 | return NS_OK; |
2560 | 0 | } |
2561 | | |
2562 | | void |
2563 | | GenerateAsymmetricKeyTask::Resolve() |
2564 | 0 | { |
2565 | 0 | mResultPromise->MaybeResolve(*mKeyPair); |
2566 | 0 | } |
2567 | | |
2568 | | void |
2569 | | GenerateAsymmetricKeyTask::Cleanup() |
2570 | 0 | { |
2571 | 0 | mKeyPair = nullptr; |
2572 | 0 | } |
2573 | | |
2574 | | class DeriveHkdfBitsTask : public ReturnArrayBufferViewTask |
2575 | | { |
2576 | | public: |
2577 | | DeriveHkdfBitsTask(JSContext* aCx, |
2578 | | const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength) |
2579 | | : mSymKey(aKey.GetSymKey()) |
2580 | | , mMechanism(CKM_INVALID_MECHANISM) |
2581 | 0 | { |
2582 | 0 | Init(aCx, aAlgorithm, aKey, aLength); |
2583 | 0 | } |
2584 | | |
2585 | | DeriveHkdfBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
2586 | | CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm) |
2587 | | : mLengthInBits(0) |
2588 | | , mLengthInBytes(0) |
2589 | | , mSymKey(aKey.GetSymKey()) |
2590 | | , mMechanism(CKM_INVALID_MECHANISM) |
2591 | 0 | { |
2592 | 0 | size_t length; |
2593 | 0 | mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, length); |
2594 | 0 |
|
2595 | 0 | if (NS_SUCCEEDED(mEarlyRv)) { |
2596 | 0 | Init(aCx, aAlgorithm, aKey, length); |
2597 | 0 | } |
2598 | 0 | } |
2599 | | |
2600 | | void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey, |
2601 | | uint32_t aLength) |
2602 | 0 | { |
2603 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_HKDF); |
2604 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HKDF); |
2605 | 0 |
|
2606 | 0 | // Check that we have a key. |
2607 | 0 | if (mSymKey.Length() == 0) { |
2608 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
2609 | 0 | return; |
2610 | 0 | } |
2611 | 0 | |
2612 | 0 | RootedDictionary<HkdfParams> params(aCx); |
2613 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
2614 | 0 | if (NS_FAILED(mEarlyRv)) { |
2615 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2616 | 0 | return; |
2617 | 0 | } |
2618 | 0 | |
2619 | 0 | // length must be greater than zero. |
2620 | 0 | if (aLength == 0) { |
2621 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
2622 | 0 | return; |
2623 | 0 | } |
2624 | 0 | |
2625 | 0 | // Extract the hash algorithm. |
2626 | 0 | nsString hashName; |
2627 | 0 | mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); |
2628 | 0 | if (NS_FAILED(mEarlyRv)) { |
2629 | 0 | return; |
2630 | 0 | } |
2631 | 0 | |
2632 | 0 | // Check the given hash algorithm. |
2633 | 0 | switch (MapAlgorithmNameToMechanism(hashName)) { |
2634 | 0 | case CKM_SHA_1: mMechanism = CKM_NSS_HKDF_SHA1; break; |
2635 | 0 | case CKM_SHA256: mMechanism = CKM_NSS_HKDF_SHA256; break; |
2636 | 0 | case CKM_SHA384: mMechanism = CKM_NSS_HKDF_SHA384; break; |
2637 | 0 | case CKM_SHA512: mMechanism = CKM_NSS_HKDF_SHA512; break; |
2638 | 0 | default: |
2639 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2640 | 0 | return; |
2641 | 0 | } |
2642 | 0 | |
2643 | 0 | ATTEMPT_BUFFER_INIT(mSalt, params.mSalt) |
2644 | 0 | ATTEMPT_BUFFER_INIT(mInfo, params.mInfo) |
2645 | 0 | mLengthInBytes = ceil((double)aLength / 8); |
2646 | 0 | mLengthInBits = aLength; |
2647 | 0 | } |
2648 | | |
2649 | | private: |
2650 | | size_t mLengthInBits; |
2651 | | size_t mLengthInBytes; |
2652 | | CryptoBuffer mSalt; |
2653 | | CryptoBuffer mInfo; |
2654 | | CryptoBuffer mSymKey; |
2655 | | CK_MECHANISM_TYPE mMechanism; |
2656 | | |
2657 | | virtual nsresult DoCrypto() override |
2658 | 0 | { |
2659 | 0 | UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
2660 | 0 | if (!arena) { |
2661 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2662 | 0 | } |
2663 | 0 | |
2664 | 0 | // Import the key |
2665 | 0 | SECItem keyItem = { siBuffer, nullptr, 0 }; |
2666 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey); |
2667 | 0 |
|
2668 | 0 | UniquePK11SlotInfo slot(PK11_GetInternalSlot()); |
2669 | 0 | if (!slot.get()) { |
2670 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2671 | 0 | } |
2672 | 0 | |
2673 | 0 | UniquePK11SymKey baseKey(PK11_ImportSymKey(slot.get(), mMechanism, |
2674 | 0 | PK11_OriginUnwrap, CKA_WRAP, |
2675 | 0 | &keyItem, nullptr)); |
2676 | 0 | if (!baseKey) { |
2677 | 0 | return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
2678 | 0 | } |
2679 | 0 | |
2680 | 0 | SECItem salt = { siBuffer, nullptr, 0 }; |
2681 | 0 | SECItem info = { siBuffer, nullptr, 0 }; |
2682 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &salt, mSalt); |
2683 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &info, mInfo); |
2684 | 0 |
|
2685 | 0 | CK_NSS_HKDFParams hkdfParams = { true, salt.data, salt.len, |
2686 | 0 | true, info.data, info.len }; |
2687 | 0 | SECItem params = { siBuffer, (unsigned char*)&hkdfParams, |
2688 | 0 | sizeof(hkdfParams) }; |
2689 | 0 |
|
2690 | 0 | // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the |
2691 | 0 | // derived symmetric key and don't matter because we ignore them anyway. |
2692 | 0 | UniquePK11SymKey symKey(PK11_Derive(baseKey.get(), mMechanism, ¶ms, |
2693 | 0 | CKM_SHA512_HMAC, CKA_SIGN, |
2694 | 0 | mLengthInBytes)); |
2695 | 0 |
|
2696 | 0 | if (!symKey.get()) { |
2697 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2698 | 0 | } |
2699 | 0 | |
2700 | 0 | nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get())); |
2701 | 0 | if (NS_FAILED(rv)) { |
2702 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2703 | 0 | } |
2704 | 0 | |
2705 | 0 | // This doesn't leak, because the SECItem* returned by PK11_GetKeyData |
2706 | 0 | // just refers to a buffer managed by symKey. The assignment copies the |
2707 | 0 | // data, so mResult manages one copy, while symKey manages another. |
2708 | 0 | ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get())); |
2709 | 0 |
|
2710 | 0 | if (mLengthInBytes > mResult.Length()) { |
2711 | 0 | return NS_ERROR_DOM_DATA_ERR; |
2712 | 0 | } |
2713 | 0 | |
2714 | 0 | if (!mResult.SetLength(mLengthInBytes, fallible)) { |
2715 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
2716 | 0 | } |
2717 | 0 | |
2718 | 0 | // If the number of bits to derive is not a multiple of 8 we need to |
2719 | 0 | // zero out the remaining bits that were derived but not requested. |
2720 | 0 | if (mLengthInBits % 8) { |
2721 | 0 | mResult[mResult.Length() - 1] &= 0xff << (mLengthInBits % 8); |
2722 | 0 | } |
2723 | 0 |
|
2724 | 0 | return NS_OK; |
2725 | 0 | } |
2726 | | }; |
2727 | | |
2728 | | class DerivePbkdfBitsTask : public ReturnArrayBufferViewTask |
2729 | | { |
2730 | | public: |
2731 | | DerivePbkdfBitsTask(JSContext* aCx, |
2732 | | const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength) |
2733 | | : mSymKey(aKey.GetSymKey()) |
2734 | | , mHashOidTag(SEC_OID_UNKNOWN) |
2735 | 0 | { |
2736 | 0 | Init(aCx, aAlgorithm, aKey, aLength); |
2737 | 0 | } |
2738 | | |
2739 | | DerivePbkdfBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
2740 | | CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm) |
2741 | | : mLength(0) |
2742 | | , mIterations(0) |
2743 | | , mSymKey(aKey.GetSymKey()) |
2744 | | , mHashOidTag(SEC_OID_UNKNOWN) |
2745 | 0 | { |
2746 | 0 | size_t length; |
2747 | 0 | mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, length); |
2748 | 0 |
|
2749 | 0 | if (NS_SUCCEEDED(mEarlyRv)) { |
2750 | 0 | Init(aCx, aAlgorithm, aKey, length); |
2751 | 0 | } |
2752 | 0 | } |
2753 | | |
2754 | | void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey, |
2755 | | uint32_t aLength) |
2756 | 0 | { |
2757 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_PBKDF2); |
2758 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_PBKDF2); |
2759 | 0 |
|
2760 | 0 | // Check that we got a symmetric key |
2761 | 0 | if (mSymKey.Length() == 0) { |
2762 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
2763 | 0 | return; |
2764 | 0 | } |
2765 | 0 | |
2766 | 0 | RootedDictionary<Pbkdf2Params> params(aCx); |
2767 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
2768 | 0 | if (NS_FAILED(mEarlyRv)) { |
2769 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2770 | 0 | return; |
2771 | 0 | } |
2772 | 0 | |
2773 | 0 | // length must be a multiple of 8 bigger than zero. |
2774 | 0 | if (aLength == 0 || aLength % 8) { |
2775 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
2776 | 0 | return; |
2777 | 0 | } |
2778 | 0 | |
2779 | 0 | // Extract the hash algorithm. |
2780 | 0 | nsString hashName; |
2781 | 0 | mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); |
2782 | 0 | if (NS_FAILED(mEarlyRv)) { |
2783 | 0 | return; |
2784 | 0 | } |
2785 | 0 | |
2786 | 0 | // Check the given hash algorithm. |
2787 | 0 | switch (MapAlgorithmNameToMechanism(hashName)) { |
2788 | 0 | case CKM_SHA_1: mHashOidTag = SEC_OID_HMAC_SHA1; break; |
2789 | 0 | case CKM_SHA256: mHashOidTag = SEC_OID_HMAC_SHA256; break; |
2790 | 0 | case CKM_SHA384: mHashOidTag = SEC_OID_HMAC_SHA384; break; |
2791 | 0 | case CKM_SHA512: mHashOidTag = SEC_OID_HMAC_SHA512; break; |
2792 | 0 | default: |
2793 | 0 | mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
2794 | 0 | return; |
2795 | 0 | } |
2796 | 0 | |
2797 | 0 | ATTEMPT_BUFFER_INIT(mSalt, params.mSalt) |
2798 | 0 | mLength = aLength >> 3; // bits to bytes |
2799 | 0 | mIterations = params.mIterations; |
2800 | 0 | } |
2801 | | |
2802 | | private: |
2803 | | size_t mLength; |
2804 | | size_t mIterations; |
2805 | | CryptoBuffer mSalt; |
2806 | | CryptoBuffer mSymKey; |
2807 | | SECOidTag mHashOidTag; |
2808 | | |
2809 | | virtual nsresult DoCrypto() override |
2810 | 0 | { |
2811 | 0 | UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
2812 | 0 | if (!arena) { |
2813 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2814 | 0 | } |
2815 | 0 | |
2816 | 0 | SECItem salt = { siBuffer, nullptr, 0 }; |
2817 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &salt, mSalt); |
2818 | 0 | // PK11_CreatePBEV2AlgorithmID will "helpfully" create PBKDF2 parameters |
2819 | 0 | // with a random salt if given a SECItem* that is either null or has a null |
2820 | 0 | // data pointer. This obviously isn't what we want, so we have to fake it |
2821 | 0 | // out by passing in a SECItem* with a non-null data pointer but with zero |
2822 | 0 | // length. |
2823 | 0 | if (!salt.data) { |
2824 | 0 | MOZ_ASSERT(salt.len == 0); |
2825 | 0 | salt.data = |
2826 | 0 | reinterpret_cast<unsigned char*>(PORT_ArenaAlloc(arena.get(), 1)); |
2827 | 0 | if (!salt.data) { |
2828 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
2829 | 0 | } |
2830 | 0 | } |
2831 | 0 | |
2832 | 0 | // Always pass in cipherAlg=SEC_OID_HMAC_SHA1 (i.e. PBMAC1) as this |
2833 | 0 | // parameter is unused for key generation. It is currently only used |
2834 | 0 | // for PBKDF2 authentication or key (un)wrapping when specifying an |
2835 | 0 | // encryption algorithm (PBES2). |
2836 | 0 | UniqueSECAlgorithmID algID(PK11_CreatePBEV2AlgorithmID( |
2837 | 0 | SEC_OID_PKCS5_PBKDF2, SEC_OID_HMAC_SHA1, mHashOidTag, |
2838 | 0 | mLength, mIterations, &salt)); |
2839 | 0 |
|
2840 | 0 | if (!algID) { |
2841 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2842 | 0 | } |
2843 | 0 | |
2844 | 0 | UniquePK11SlotInfo slot(PK11_GetInternalSlot()); |
2845 | 0 | if (!slot.get()) { |
2846 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2847 | 0 | } |
2848 | 0 | |
2849 | 0 | SECItem keyItem = { siBuffer, nullptr, 0 }; |
2850 | 0 | ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey); |
2851 | 0 |
|
2852 | 0 | UniquePK11SymKey symKey(PK11_PBEKeyGen(slot.get(), algID.get(), &keyItem, |
2853 | 0 | false, nullptr)); |
2854 | 0 | if (!symKey.get()) { |
2855 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2856 | 0 | } |
2857 | 0 | |
2858 | 0 | nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get())); |
2859 | 0 | if (NS_FAILED(rv)) { |
2860 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2861 | 0 | } |
2862 | 0 | |
2863 | 0 | // This doesn't leak, because the SECItem* returned by PK11_GetKeyData |
2864 | 0 | // just refers to a buffer managed by symKey. The assignment copies the |
2865 | 0 | // data, so mResult manages one copy, while symKey manages another. |
2866 | 0 | ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get())); |
2867 | 0 | return NS_OK; |
2868 | 0 | } |
2869 | | }; |
2870 | | |
2871 | | template<class DeriveBitsTask> |
2872 | | class DeriveKeyTask : public DeriveBitsTask |
2873 | | { |
2874 | | public: |
2875 | | DeriveKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, |
2876 | | const ObjectOrString& aAlgorithm, CryptoKey& aBaseKey, |
2877 | | const ObjectOrString& aDerivedKeyType, bool aExtractable, |
2878 | | const Sequence<nsString>& aKeyUsages) |
2879 | | : DeriveBitsTask(aCx, aAlgorithm, aBaseKey, aDerivedKeyType) |
2880 | 0 | { |
2881 | 0 | if (NS_FAILED(this->mEarlyRv)) { |
2882 | 0 | return; |
2883 | 0 | } |
2884 | 0 | |
2885 | 0 | NS_NAMED_LITERAL_STRING(format, WEBCRYPTO_KEY_FORMAT_RAW); |
2886 | 0 | mTask = new ImportSymmetricKeyTask(aGlobal, aCx, format, aDerivedKeyType, |
2887 | 0 | aExtractable, aKeyUsages); |
2888 | 0 | } Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveHkdfBitsTask>::DeriveKeyTask(nsIGlobalObject*, JSContext*, mozilla::dom::ObjectOrString const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, bool, mozilla::dom::Sequence<nsTString<char16_t> > const&) Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DerivePbkdfBitsTask>::DeriveKeyTask(nsIGlobalObject*, JSContext*, mozilla::dom::ObjectOrString const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, bool, mozilla::dom::Sequence<nsTString<char16_t> > const&) Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveEcdhBitsTask>::DeriveKeyTask(nsIGlobalObject*, JSContext*, mozilla::dom::ObjectOrString const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, bool, mozilla::dom::Sequence<nsTString<char16_t> > const&) |
2889 | | |
2890 | | protected: |
2891 | | RefPtr<ImportSymmetricKeyTask> mTask; |
2892 | | |
2893 | | private: |
2894 | 0 | virtual void Resolve() override { |
2895 | 0 | mTask->SetRawKeyData(this->mResult); |
2896 | 0 | mTask->DispatchWithPromise(this->mResultPromise); |
2897 | 0 | } Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveHkdfBitsTask>::Resolve() Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DerivePbkdfBitsTask>::Resolve() Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveEcdhBitsTask>::Resolve() |
2898 | | |
2899 | | virtual void Cleanup() override |
2900 | 0 | { |
2901 | 0 | mTask = nullptr; |
2902 | 0 | } Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveHkdfBitsTask>::Cleanup() Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DerivePbkdfBitsTask>::Cleanup() Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveEcdhBitsTask>::Cleanup() |
2903 | | }; |
2904 | | |
2905 | | class DeriveEcdhBitsTask : public ReturnArrayBufferViewTask |
2906 | | { |
2907 | | public: |
2908 | | DeriveEcdhBitsTask(JSContext* aCx, |
2909 | | const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength) |
2910 | | : mLength(aLength), |
2911 | | mPrivKey(aKey.GetPrivateKey()) |
2912 | 0 | { |
2913 | 0 | Init(aCx, aAlgorithm, aKey); |
2914 | 0 | } |
2915 | | |
2916 | | DeriveEcdhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
2917 | | CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm) |
2918 | | : mPrivKey(aKey.GetPrivateKey()) |
2919 | 0 | { |
2920 | 0 | mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, mLength); |
2921 | 0 | if (NS_SUCCEEDED(mEarlyRv)) { |
2922 | 0 | Init(aCx, aAlgorithm, aKey); |
2923 | 0 | } |
2924 | 0 | } |
2925 | | |
2926 | | void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey) |
2927 | 0 | { |
2928 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDH); |
2929 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDH); |
2930 | 0 |
|
2931 | 0 | // Check that we have a private key. |
2932 | 0 | if (!mPrivKey) { |
2933 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
2934 | 0 | return; |
2935 | 0 | } |
2936 | 0 | |
2937 | 0 | // Length must be a multiple of 8 bigger than zero. |
2938 | 0 | if (mLength == 0 || mLength % 8) { |
2939 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
2940 | 0 | return; |
2941 | 0 | } |
2942 | 0 | |
2943 | 0 | mLength = mLength >> 3; // bits to bytes |
2944 | 0 |
|
2945 | 0 | // Retrieve the peer's public key. |
2946 | 0 | RootedDictionary<EcdhKeyDeriveParams> params(aCx); |
2947 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
2948 | 0 | if (NS_FAILED(mEarlyRv)) { |
2949 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
2950 | 0 | return; |
2951 | 0 | } |
2952 | 0 | |
2953 | 0 | CryptoKey* publicKey = params.mPublic; |
2954 | 0 | mPubKey = publicKey->GetPublicKey(); |
2955 | 0 | if (!mPubKey) { |
2956 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
2957 | 0 | return; |
2958 | 0 | } |
2959 | 0 | |
2960 | 0 | CHECK_KEY_ALGORITHM(publicKey->Algorithm(), WEBCRYPTO_ALG_ECDH); |
2961 | 0 |
|
2962 | 0 | // Both keys must use the same named curve. |
2963 | 0 | nsString curve1 = aKey.Algorithm().mEc.mNamedCurve; |
2964 | 0 | nsString curve2 = publicKey->Algorithm().mEc.mNamedCurve; |
2965 | 0 |
|
2966 | 0 | if (!curve1.Equals(curve2)) { |
2967 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
2968 | 0 | return; |
2969 | 0 | } |
2970 | 0 | } |
2971 | | |
2972 | | private: |
2973 | | size_t mLength; |
2974 | | UniqueSECKEYPrivateKey mPrivKey; |
2975 | | UniqueSECKEYPublicKey mPubKey; |
2976 | | |
2977 | | virtual nsresult DoCrypto() override |
2978 | 0 | { |
2979 | 0 | // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the |
2980 | 0 | // derived symmetric key and don't matter because we ignore them anyway. |
2981 | 0 | UniquePK11SymKey symKey(PK11_PubDeriveWithKDF( |
2982 | 0 | mPrivKey.get(), mPubKey.get(), PR_FALSE, nullptr, nullptr, |
2983 | 0 | CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, CKA_SIGN, 0, CKD_NULL, nullptr, |
2984 | 0 | nullptr)); |
2985 | 0 |
|
2986 | 0 | if (!symKey.get()) { |
2987 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2988 | 0 | } |
2989 | 0 | |
2990 | 0 | nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get())); |
2991 | 0 | if (NS_FAILED(rv)) { |
2992 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
2993 | 0 | } |
2994 | 0 | |
2995 | 0 | // This doesn't leak, because the SECItem* returned by PK11_GetKeyData |
2996 | 0 | // just refers to a buffer managed by symKey. The assignment copies the |
2997 | 0 | // data, so mResult manages one copy, while symKey manages another. |
2998 | 0 | ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get())); |
2999 | 0 |
|
3000 | 0 | if (mLength > mResult.Length()) { |
3001 | 0 | return NS_ERROR_DOM_DATA_ERR; |
3002 | 0 | } |
3003 | 0 | |
3004 | 0 | if (!mResult.SetLength(mLength, fallible)) { |
3005 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
3006 | 0 | } |
3007 | 0 | |
3008 | 0 | return NS_OK; |
3009 | 0 | } |
3010 | | }; |
3011 | | |
3012 | | class DeriveDhBitsTask : public ReturnArrayBufferViewTask |
3013 | | { |
3014 | | public: |
3015 | | DeriveDhBitsTask(JSContext* aCx, |
3016 | | const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength) |
3017 | | : mLength(aLength), |
3018 | | mPrivKey(aKey.GetPrivateKey()) |
3019 | 0 | { |
3020 | 0 | Init(aCx, aAlgorithm, aKey); |
3021 | 0 | } |
3022 | | |
3023 | | DeriveDhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm, |
3024 | | CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm) |
3025 | | : mPrivKey(aKey.GetPrivateKey()) |
3026 | 0 | { |
3027 | 0 | mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, mLength); |
3028 | 0 | if (NS_SUCCEEDED(mEarlyRv)) { |
3029 | 0 | Init(aCx, aAlgorithm, aKey); |
3030 | 0 | } |
3031 | 0 | } |
3032 | | |
3033 | | void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey) |
3034 | 0 | { |
3035 | 0 | CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_DH); |
3036 | 0 |
|
3037 | 0 | // Check that we have a private key. |
3038 | 0 | if (!mPrivKey) { |
3039 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
3040 | 0 | return; |
3041 | 0 | } |
3042 | 0 | |
3043 | 0 | mLength = mLength >> 3; // bits to bytes |
3044 | 0 |
|
3045 | 0 | // Retrieve the peer's public key. |
3046 | 0 | RootedDictionary<DhKeyDeriveParams> params(aCx); |
3047 | 0 | mEarlyRv = Coerce(aCx, params, aAlgorithm); |
3048 | 0 | if (NS_FAILED(mEarlyRv)) { |
3049 | 0 | mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; |
3050 | 0 | return; |
3051 | 0 | } |
3052 | 0 | |
3053 | 0 | CryptoKey* publicKey = params.mPublic; |
3054 | 0 | mPubKey = publicKey->GetPublicKey(); |
3055 | 0 | if (!mPubKey) { |
3056 | 0 | mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; |
3057 | 0 | return; |
3058 | 0 | } |
3059 | 0 | |
3060 | 0 | KeyAlgorithmProxy alg1 = publicKey->Algorithm(); |
3061 | 0 | CHECK_KEY_ALGORITHM(alg1, WEBCRYPTO_ALG_DH); |
3062 | 0 |
|
3063 | 0 | // Both keys must use the same prime and generator. |
3064 | 0 | KeyAlgorithmProxy alg2 = aKey.Algorithm(); |
3065 | 0 | if (alg1.mDh.mPrime != alg2.mDh.mPrime || |
3066 | 0 | alg1.mDh.mGenerator != alg2.mDh.mGenerator) { |
3067 | 0 | mEarlyRv = NS_ERROR_DOM_DATA_ERR; |
3068 | 0 | return; |
3069 | 0 | } |
3070 | 0 | } |
3071 | | |
3072 | | private: |
3073 | | size_t mLength; |
3074 | | UniqueSECKEYPrivateKey mPrivKey; |
3075 | | UniqueSECKEYPublicKey mPubKey; |
3076 | | |
3077 | | virtual nsresult DoCrypto() override |
3078 | 0 | { |
3079 | 0 | // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the |
3080 | 0 | // derived symmetric key and don't matter because we ignore them anyway. |
3081 | 0 | UniquePK11SymKey symKey(PK11_PubDeriveWithKDF( |
3082 | 0 | mPrivKey.get(), mPubKey.get(), PR_FALSE, nullptr, nullptr, |
3083 | 0 | CKM_DH_PKCS_DERIVE, CKM_SHA512_HMAC, CKA_SIGN, 0, CKD_NULL, nullptr, |
3084 | 0 | nullptr)); |
3085 | 0 |
|
3086 | 0 | if (!symKey.get()) { |
3087 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
3088 | 0 | } |
3089 | 0 | |
3090 | 0 | nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get())); |
3091 | 0 | if (NS_FAILED(rv)) { |
3092 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
3093 | 0 | } |
3094 | 0 | |
3095 | 0 | // This doesn't leak, because the SECItem* returned by PK11_GetKeyData |
3096 | 0 | // just refers to a buffer managed by symKey. The assignment copies the |
3097 | 0 | // data, so mResult manages one copy, while symKey manages another. |
3098 | 0 | ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get())); |
3099 | 0 |
|
3100 | 0 | if (mLength > mResult.Length()) { |
3101 | 0 | return NS_ERROR_DOM_DATA_ERR; |
3102 | 0 | } |
3103 | 0 | |
3104 | 0 | if (!mResult.SetLength(mLength, fallible)) { |
3105 | 0 | return NS_ERROR_DOM_UNKNOWN_ERR; |
3106 | 0 | } |
3107 | 0 | |
3108 | 0 | return NS_OK; |
3109 | 0 | } |
3110 | | }; |
3111 | | |
3112 | | template<class KeyEncryptTask> |
3113 | | class WrapKeyTask : public ExportKeyTask |
3114 | | { |
3115 | | public: |
3116 | | WrapKeyTask(JSContext* aCx, |
3117 | | const nsAString& aFormat, |
3118 | | CryptoKey& aKey, |
3119 | | CryptoKey& aWrappingKey, |
3120 | | const ObjectOrString& aWrapAlgorithm) |
3121 | | : ExportKeyTask(aFormat, aKey) |
3122 | 0 | { |
3123 | 0 | if (NS_FAILED(mEarlyRv)) { |
3124 | 0 | return; |
3125 | 0 | } |
3126 | 0 | |
3127 | 0 | mTask = new KeyEncryptTask(aCx, aWrapAlgorithm, aWrappingKey, true); |
3128 | 0 | } Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesTask>::WrapKeyTask(JSContext*, nsTSubstring<char16_t> const&, mozilla::dom::CryptoKey&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesKwTask>::WrapKeyTask(JSContext*, nsTSubstring<char16_t> const&, mozilla::dom::CryptoKey&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&) Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::RsaOaepTask>::WrapKeyTask(JSContext*, nsTSubstring<char16_t> const&, mozilla::dom::CryptoKey&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&) |
3129 | | |
3130 | | private: |
3131 | | RefPtr<KeyEncryptTask> mTask; |
3132 | | |
3133 | 0 | virtual nsresult AfterCrypto() override { |
3134 | 0 | // If wrapping JWK, stringify the JSON |
3135 | 0 | if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
3136 | 0 | nsAutoString json; |
3137 | 0 | if (!mJwk.ToJSON(json)) { |
3138 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
3139 | 0 | } |
3140 | 0 | |
3141 | 0 | NS_ConvertUTF16toUTF8 utf8(json); |
3142 | 0 | if (!mResult.Assign((const uint8_t*) utf8.BeginReading(), utf8.Length())) { |
3143 | 0 | return NS_ERROR_DOM_OPERATION_ERR; |
3144 | 0 | } |
3145 | 0 | } |
3146 | 0 | |
3147 | 0 | return NS_OK; |
3148 | 0 | } Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesTask>::AfterCrypto() Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesKwTask>::AfterCrypto() Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::RsaOaepTask>::AfterCrypto() |
3149 | | |
3150 | | virtual void Resolve() override |
3151 | 0 | { |
3152 | 0 | mTask->SetData(mResult); |
3153 | 0 | mTask->DispatchWithPromise(mResultPromise); |
3154 | 0 | } Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesTask>::Resolve() Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesKwTask>::Resolve() Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::RsaOaepTask>::Resolve() |
3155 | | |
3156 | | virtual void Cleanup() override |
3157 | 0 | { |
3158 | 0 | mTask = nullptr; |
3159 | 0 | } Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesTask>::Cleanup() Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesKwTask>::Cleanup() Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::RsaOaepTask>::Cleanup() |
3160 | | }; |
3161 | | |
3162 | | template<class KeyEncryptTask> |
3163 | | class UnwrapKeyTask : public KeyEncryptTask |
3164 | | { |
3165 | | public: |
3166 | | UnwrapKeyTask(JSContext* aCx, |
3167 | | const ArrayBufferViewOrArrayBuffer& aWrappedKey, |
3168 | | CryptoKey& aUnwrappingKey, |
3169 | | const ObjectOrString& aUnwrapAlgorithm, |
3170 | | ImportKeyTask* aTask) |
3171 | | : KeyEncryptTask(aCx, aUnwrapAlgorithm, aUnwrappingKey, aWrappedKey, false) |
3172 | | , mTask(aTask) |
3173 | 0 | {} Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesTask>::UnwrapKeyTask(JSContext*, mozilla::dom::ArrayBufferViewOrArrayBuffer const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, mozilla::dom::ImportKeyTask*) Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesKwTask>::UnwrapKeyTask(JSContext*, mozilla::dom::ArrayBufferViewOrArrayBuffer const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, mozilla::dom::ImportKeyTask*) Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::RsaOaepTask>::UnwrapKeyTask(JSContext*, mozilla::dom::ArrayBufferViewOrArrayBuffer const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, mozilla::dom::ImportKeyTask*) |
3174 | | |
3175 | | private: |
3176 | | RefPtr<ImportKeyTask> mTask; |
3177 | | |
3178 | | virtual void Resolve() override |
3179 | 0 | { |
3180 | 0 | mTask->SetKeyDataMaybeParseJWK(KeyEncryptTask::mResult); |
3181 | 0 | mTask->DispatchWithPromise(KeyEncryptTask::mResultPromise); |
3182 | 0 | } Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesTask>::Resolve() Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesKwTask>::Resolve() Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::RsaOaepTask>::Resolve() |
3183 | | |
3184 | | virtual void Cleanup() override |
3185 | 0 | { |
3186 | 0 | mTask = nullptr; |
3187 | 0 | } Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesTask>::Cleanup() Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesKwTask>::Cleanup() Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::RsaOaepTask>::Cleanup() |
3188 | | }; |
3189 | | |
3190 | | // Task creation methods for WebCryptoTask |
3191 | | |
3192 | | // Note: We do not perform algorithm normalization as a monolithic process, |
3193 | | // as described in the spec. Instead: |
3194 | | // * Each method handles its slice of the supportedAlgorithms structure |
3195 | | // * Task constructors take care of: |
3196 | | // * Coercing the algorithm to the proper concrete type |
3197 | | // * Cloning subordinate data items |
3198 | | // * Cloning input data as needed |
3199 | | // |
3200 | | // Thus, support for different algorithms is determined by the if-statements |
3201 | | // below, rather than a data structure. |
3202 | | // |
3203 | | // This results in algorithm normalization coming after some other checks, |
3204 | | // and thus slightly more steps being done synchronously than the spec calls |
3205 | | // for. But none of these steps is especially time-consuming. |
3206 | | |
3207 | | WebCryptoTask* |
3208 | | WebCryptoTask::CreateEncryptDecryptTask(JSContext* aCx, |
3209 | | const ObjectOrString& aAlgorithm, |
3210 | | CryptoKey& aKey, |
3211 | | const CryptoOperationData& aData, |
3212 | | bool aEncrypt) |
3213 | 0 | { |
3214 | 0 | TelemetryMethod method = (aEncrypt)? TM_ENCRYPT : TM_DECRYPT; |
3215 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, method); |
3216 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_ENC, aKey.Extractable()); |
3217 | 0 |
|
3218 | 0 | // Ensure key is usable for this operation |
3219 | 0 | if ((aEncrypt && !aKey.HasUsage(CryptoKey::ENCRYPT)) || |
3220 | 0 | (!aEncrypt && !aKey.HasUsage(CryptoKey::DECRYPT))) { |
3221 | 0 | return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
3222 | 0 | } |
3223 | 0 | |
3224 | 0 | nsString algName; |
3225 | 0 | nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); |
3226 | 0 | if (NS_FAILED(rv)) { |
3227 | 0 | return new FailureTask(rv); |
3228 | 0 | } |
3229 | 0 | |
3230 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || |
3231 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || |
3232 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) { |
3233 | 0 | return new AesTask(aCx, aAlgorithm, aKey, aData, aEncrypt); |
3234 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { |
3235 | 0 | return new RsaOaepTask(aCx, aAlgorithm, aKey, aData, aEncrypt); |
3236 | 0 | } |
3237 | 0 | |
3238 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3239 | 0 | } |
3240 | | |
3241 | | WebCryptoTask* |
3242 | | WebCryptoTask::CreateSignVerifyTask(JSContext* aCx, |
3243 | | const ObjectOrString& aAlgorithm, |
3244 | | CryptoKey& aKey, |
3245 | | const CryptoOperationData& aSignature, |
3246 | | const CryptoOperationData& aData, |
3247 | | bool aSign) |
3248 | 0 | { |
3249 | 0 | TelemetryMethod method = (aSign)? TM_SIGN : TM_VERIFY; |
3250 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, method); |
3251 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_SIG, aKey.Extractable()); |
3252 | 0 |
|
3253 | 0 | // Ensure key is usable for this operation |
3254 | 0 | if ((aSign && !aKey.HasUsage(CryptoKey::SIGN)) || |
3255 | 0 | (!aSign && !aKey.HasUsage(CryptoKey::VERIFY))) { |
3256 | 0 | return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
3257 | 0 | } |
3258 | 0 | |
3259 | 0 | nsString algName; |
3260 | 0 | nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); |
3261 | 0 | if (NS_FAILED(rv)) { |
3262 | 0 | return new FailureTask(rv); |
3263 | 0 | } |
3264 | 0 | |
3265 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { |
3266 | 0 | return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign); |
3267 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
3268 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) || |
3269 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { |
3270 | 0 | return new AsymmetricSignVerifyTask(aCx, aAlgorithm, aKey, aSignature, |
3271 | 0 | aData, aSign); |
3272 | 0 | } |
3273 | 0 | |
3274 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3275 | 0 | } |
3276 | | |
3277 | | WebCryptoTask* |
3278 | | WebCryptoTask::CreateDigestTask(JSContext* aCx, |
3279 | | const ObjectOrString& aAlgorithm, |
3280 | | const CryptoOperationData& aData) |
3281 | 0 | { |
3282 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DIGEST); |
3283 | 0 |
|
3284 | 0 | nsString algName; |
3285 | 0 | nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); |
3286 | 0 | if (NS_FAILED(rv)) { |
3287 | 0 | return new FailureTask(rv); |
3288 | 0 | } |
3289 | 0 | |
3290 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1) || |
3291 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256) || |
3292 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_SHA384) || |
3293 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { |
3294 | 0 | return new DigestTask(aCx, aAlgorithm, aData); |
3295 | 0 | } |
3296 | 0 | |
3297 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3298 | 0 | } |
3299 | | |
3300 | | WebCryptoTask* |
3301 | | WebCryptoTask::CreateImportKeyTask(nsIGlobalObject* aGlobal, |
3302 | | JSContext* aCx, |
3303 | | const nsAString& aFormat, |
3304 | | JS::Handle<JSObject*> aKeyData, |
3305 | | const ObjectOrString& aAlgorithm, |
3306 | | bool aExtractable, |
3307 | | const Sequence<nsString>& aKeyUsages) |
3308 | 0 | { |
3309 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_IMPORTKEY); |
3310 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT, aExtractable); |
3311 | 0 |
|
3312 | 0 | // Verify that the format is recognized |
3313 | 0 | if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && |
3314 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && |
3315 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) && |
3316 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
3317 | 0 | return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); |
3318 | 0 | } |
3319 | 0 | |
3320 | 0 | // Verify that aKeyUsages does not contain an unrecognized value |
3321 | 0 | if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) { |
3322 | 0 | return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); |
3323 | 0 | } |
3324 | 0 | |
3325 | 0 | nsString algName; |
3326 | 0 | nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); |
3327 | 0 | if (NS_FAILED(rv)) { |
3328 | 0 | return new FailureTask(rv); |
3329 | 0 | } |
3330 | 0 | |
3331 | 0 | // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation. |
3332 | 0 | // However, the spec should be updated to allow it. |
3333 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || |
3334 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || |
3335 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) || |
3336 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) || |
3337 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) || |
3338 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) || |
3339 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { |
3340 | 0 | return new ImportSymmetricKeyTask(aGlobal, aCx, aFormat, aKeyData, |
3341 | 0 | aAlgorithm, aExtractable, aKeyUsages); |
3342 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
3343 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) || |
3344 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) { |
3345 | 0 | return new ImportRsaKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm, |
3346 | 0 | aExtractable, aKeyUsages); |
3347 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) || |
3348 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { |
3349 | 0 | return new ImportEcKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm, |
3350 | 0 | aExtractable, aKeyUsages); |
3351 | 0 | } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) { |
3352 | 0 | return new ImportDhKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm, |
3353 | 0 | aExtractable, aKeyUsages); |
3354 | 0 | } else { |
3355 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3356 | 0 | } |
3357 | 0 | } |
3358 | | |
3359 | | WebCryptoTask* |
3360 | | WebCryptoTask::CreateExportKeyTask(const nsAString& aFormat, |
3361 | | CryptoKey& aKey) |
3362 | 0 | { |
3363 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_EXPORTKEY); |
3364 | 0 |
|
3365 | 0 | // Verify that the format is recognized |
3366 | 0 | if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && |
3367 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && |
3368 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) && |
3369 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
3370 | 0 | return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); |
3371 | 0 | } |
3372 | 0 | |
3373 | 0 | // Verify that the key is extractable |
3374 | 0 | if (!aKey.Extractable()) { |
3375 | 0 | return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
3376 | 0 | } |
3377 | 0 | |
3378 | 0 | // Verify that the algorithm supports export |
3379 | 0 | // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation. |
3380 | 0 | // However, the spec should be updated to allow it. |
3381 | 0 | nsString algName = aKey.Algorithm().mName; |
3382 | 0 | if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || |
3383 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || |
3384 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) || |
3385 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) || |
3386 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) || |
3387 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC) || |
3388 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
3389 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) || |
3390 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) || |
3391 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA) || |
3392 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) || |
3393 | 0 | algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) { |
3394 | 0 | return new ExportKeyTask(aFormat, aKey); |
3395 | 0 | } |
3396 | 0 | |
3397 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3398 | 0 | } |
3399 | | |
3400 | | WebCryptoTask* |
3401 | | WebCryptoTask::CreateGenerateKeyTask(nsIGlobalObject* aGlobal, |
3402 | | JSContext* aCx, |
3403 | | const ObjectOrString& aAlgorithm, |
3404 | | bool aExtractable, |
3405 | | const Sequence<nsString>& aKeyUsages) |
3406 | 0 | { |
3407 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_GENERATEKEY); |
3408 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_GENERATE, aExtractable); |
3409 | 0 |
|
3410 | 0 | // Verify that aKeyUsages does not contain an unrecognized value |
3411 | 0 | // SPEC-BUG: Spec says that this should be InvalidAccessError, but that |
3412 | 0 | // is inconsistent with other analogous points in the spec |
3413 | 0 | if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) { |
3414 | 0 | return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); |
3415 | 0 | } |
3416 | 0 | |
3417 | 0 | nsString algName; |
3418 | 0 | nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); |
3419 | 0 | if (NS_FAILED(rv)) { |
3420 | 0 | return new FailureTask(rv); |
3421 | 0 | } |
3422 | 0 | |
3423 | 0 | if (algName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) || |
3424 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) || |
3425 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) || |
3426 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_AES_KW) || |
3427 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) { |
3428 | 0 | return new GenerateSymmetricKeyTask(aGlobal, aCx, aAlgorithm, aExtractable, |
3429 | 0 | aKeyUsages); |
3430 | 0 | } else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
3431 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) || |
3432 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS) || |
3433 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) || |
3434 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA) || |
3435 | 0 | algName.EqualsASCII(WEBCRYPTO_ALG_DH)) { |
3436 | 0 | return new GenerateAsymmetricKeyTask(aGlobal, aCx, aAlgorithm, aExtractable, |
3437 | 0 | aKeyUsages); |
3438 | 0 | } else { |
3439 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3440 | 0 | } |
3441 | 0 | } |
3442 | | |
3443 | | WebCryptoTask* |
3444 | | WebCryptoTask::CreateDeriveKeyTask(nsIGlobalObject* aGlobal, |
3445 | | JSContext* aCx, |
3446 | | const ObjectOrString& aAlgorithm, |
3447 | | CryptoKey& aBaseKey, |
3448 | | const ObjectOrString& aDerivedKeyType, |
3449 | | bool aExtractable, |
3450 | | const Sequence<nsString>& aKeyUsages) |
3451 | 0 | { |
3452 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DERIVEKEY); |
3453 | 0 |
|
3454 | 0 | // Ensure baseKey is usable for this operation |
3455 | 0 | if (!aBaseKey.HasUsage(CryptoKey::DERIVEKEY)) { |
3456 | 0 | return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
3457 | 0 | } |
3458 | 0 | |
3459 | 0 | // Verify that aKeyUsages does not contain an unrecognized value |
3460 | 0 | if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) { |
3461 | 0 | return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); |
3462 | 0 | } |
3463 | 0 | |
3464 | 0 | nsString algName; |
3465 | 0 | nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); |
3466 | 0 | if (NS_FAILED(rv)) { |
3467 | 0 | return new FailureTask(rv); |
3468 | 0 | } |
3469 | 0 | |
3470 | 0 | if (algName.EqualsASCII(WEBCRYPTO_ALG_HKDF)) { |
3471 | 0 | return new DeriveKeyTask<DeriveHkdfBitsTask>(aGlobal, aCx, aAlgorithm, |
3472 | 0 | aBaseKey, aDerivedKeyType, |
3473 | 0 | aExtractable, aKeyUsages); |
3474 | 0 | } |
3475 | 0 | |
3476 | 0 | if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) { |
3477 | 0 | return new DeriveKeyTask<DerivePbkdfBitsTask>(aGlobal, aCx, aAlgorithm, |
3478 | 0 | aBaseKey, aDerivedKeyType, |
3479 | 0 | aExtractable, aKeyUsages); |
3480 | 0 | } |
3481 | 0 | |
3482 | 0 | if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) { |
3483 | 0 | return new DeriveKeyTask<DeriveEcdhBitsTask>(aGlobal, aCx, aAlgorithm, |
3484 | 0 | aBaseKey, aDerivedKeyType, |
3485 | 0 | aExtractable, aKeyUsages); |
3486 | 0 | } |
3487 | 0 | |
3488 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3489 | 0 | } |
3490 | | |
3491 | | WebCryptoTask* |
3492 | | WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx, |
3493 | | const ObjectOrString& aAlgorithm, |
3494 | | CryptoKey& aKey, |
3495 | | uint32_t aLength) |
3496 | 0 | { |
3497 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DERIVEBITS); |
3498 | 0 |
|
3499 | 0 | // Ensure baseKey is usable for this operation |
3500 | 0 | if (!aKey.HasUsage(CryptoKey::DERIVEBITS)) { |
3501 | 0 | return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
3502 | 0 | } |
3503 | 0 | |
3504 | 0 | nsString algName; |
3505 | 0 | nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); |
3506 | 0 | if (NS_FAILED(rv)) { |
3507 | 0 | return new FailureTask(rv); |
3508 | 0 | } |
3509 | 0 | |
3510 | 0 | if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) { |
3511 | 0 | return new DerivePbkdfBitsTask(aCx, aAlgorithm, aKey, aLength); |
3512 | 0 | } |
3513 | 0 | |
3514 | 0 | if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) { |
3515 | 0 | return new DeriveEcdhBitsTask(aCx, aAlgorithm, aKey, aLength); |
3516 | 0 | } |
3517 | 0 | |
3518 | 0 | if (algName.EqualsASCII(WEBCRYPTO_ALG_DH)) { |
3519 | 0 | return new DeriveDhBitsTask(aCx, aAlgorithm, aKey, aLength); |
3520 | 0 | } |
3521 | 0 | |
3522 | 0 | if (algName.EqualsASCII(WEBCRYPTO_ALG_HKDF)) { |
3523 | 0 | return new DeriveHkdfBitsTask(aCx, aAlgorithm, aKey, aLength); |
3524 | 0 | } |
3525 | 0 | |
3526 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3527 | 0 | } |
3528 | | |
3529 | | WebCryptoTask* |
3530 | | WebCryptoTask::CreateWrapKeyTask(JSContext* aCx, |
3531 | | const nsAString& aFormat, |
3532 | | CryptoKey& aKey, |
3533 | | CryptoKey& aWrappingKey, |
3534 | | const ObjectOrString& aWrapAlgorithm) |
3535 | 0 | { |
3536 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_WRAPKEY); |
3537 | 0 |
|
3538 | 0 | // Verify that the format is recognized |
3539 | 0 | if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && |
3540 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && |
3541 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) && |
3542 | 0 | !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { |
3543 | 0 | return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); |
3544 | 0 | } |
3545 | 0 | |
3546 | 0 | // Ensure wrappingKey is usable for this operation |
3547 | 0 | if (!aWrappingKey.HasUsage(CryptoKey::WRAPKEY)) { |
3548 | 0 | return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
3549 | 0 | } |
3550 | 0 | |
3551 | 0 | // Ensure key is extractable |
3552 | 0 | if (!aKey.Extractable()) { |
3553 | 0 | return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
3554 | 0 | } |
3555 | 0 | |
3556 | 0 | nsString wrapAlgName; |
3557 | 0 | nsresult rv = GetAlgorithmName(aCx, aWrapAlgorithm, wrapAlgName); |
3558 | 0 | if (NS_FAILED(rv)) { |
3559 | 0 | return new FailureTask(rv); |
3560 | 0 | } |
3561 | 0 | |
3562 | 0 | if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || |
3563 | 0 | wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || |
3564 | 0 | wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) { |
3565 | 0 | return new WrapKeyTask<AesTask>(aCx, aFormat, aKey, |
3566 | 0 | aWrappingKey, aWrapAlgorithm); |
3567 | 0 | } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { |
3568 | 0 | return new WrapKeyTask<AesKwTask>(aCx, aFormat, aKey, |
3569 | 0 | aWrappingKey, aWrapAlgorithm); |
3570 | 0 | } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { |
3571 | 0 | return new WrapKeyTask<RsaOaepTask>(aCx, aFormat, aKey, |
3572 | 0 | aWrappingKey, aWrapAlgorithm); |
3573 | 0 | } |
3574 | 0 | |
3575 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3576 | 0 | } |
3577 | | |
3578 | | WebCryptoTask* |
3579 | | WebCryptoTask::CreateUnwrapKeyTask(nsIGlobalObject* aGlobal, |
3580 | | JSContext* aCx, |
3581 | | const nsAString& aFormat, |
3582 | | const ArrayBufferViewOrArrayBuffer& aWrappedKey, |
3583 | | CryptoKey& aUnwrappingKey, |
3584 | | const ObjectOrString& aUnwrapAlgorithm, |
3585 | | const ObjectOrString& aUnwrappedKeyAlgorithm, |
3586 | | bool aExtractable, |
3587 | | const Sequence<nsString>& aKeyUsages) |
3588 | 0 | { |
3589 | 0 | Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_UNWRAPKEY); |
3590 | 0 |
|
3591 | 0 | // Ensure key is usable for this operation |
3592 | 0 | if (!aUnwrappingKey.HasUsage(CryptoKey::UNWRAPKEY)) { |
3593 | 0 | return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
3594 | 0 | } |
3595 | 0 | |
3596 | 0 | // Verify that aKeyUsages does not contain an unrecognized value |
3597 | 0 | if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) { |
3598 | 0 | return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); |
3599 | 0 | } |
3600 | 0 | |
3601 | 0 | nsString keyAlgName; |
3602 | 0 | nsresult rv = GetAlgorithmName(aCx, aUnwrappedKeyAlgorithm, keyAlgName); |
3603 | 0 | if (NS_FAILED(rv)) { |
3604 | 0 | return new FailureTask(rv); |
3605 | 0 | } |
3606 | 0 | |
3607 | 0 | CryptoOperationData dummy; |
3608 | 0 | RefPtr<ImportKeyTask> importTask; |
3609 | 0 | if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) || |
3610 | 0 | keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) || |
3611 | 0 | keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) || |
3612 | 0 | keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HKDF) || |
3613 | 0 | keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) { |
3614 | 0 | importTask = new ImportSymmetricKeyTask(aGlobal, aCx, aFormat, |
3615 | 0 | aUnwrappedKeyAlgorithm, |
3616 | 0 | aExtractable, aKeyUsages); |
3617 | 0 | } else if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) || |
3618 | 0 | keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) || |
3619 | 0 | keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS)) { |
3620 | 0 | importTask = new ImportRsaKeyTask(aGlobal, aCx, aFormat, |
3621 | 0 | aUnwrappedKeyAlgorithm, |
3622 | 0 | aExtractable, aKeyUsages); |
3623 | 0 | } else { |
3624 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3625 | 0 | } |
3626 | 0 | |
3627 | 0 | nsString unwrapAlgName; |
3628 | 0 | rv = GetAlgorithmName(aCx, aUnwrapAlgorithm, unwrapAlgName); |
3629 | 0 | if (NS_FAILED(rv)) { |
3630 | 0 | return new FailureTask(rv); |
3631 | 0 | } |
3632 | 0 | if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || |
3633 | 0 | unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || |
3634 | 0 | unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) { |
3635 | 0 | return new UnwrapKeyTask<AesTask>(aCx, aWrappedKey, |
3636 | 0 | aUnwrappingKey, aUnwrapAlgorithm, |
3637 | 0 | importTask); |
3638 | 0 | } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { |
3639 | 0 | return new UnwrapKeyTask<AesKwTask>(aCx, aWrappedKey, |
3640 | 0 | aUnwrappingKey, aUnwrapAlgorithm, |
3641 | 0 | importTask); |
3642 | 0 | } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { |
3643 | 0 | return new UnwrapKeyTask<RsaOaepTask>(aCx, aWrappedKey, |
3644 | 0 | aUnwrappingKey, aUnwrapAlgorithm, |
3645 | 0 | importTask); |
3646 | 0 | } |
3647 | 0 | |
3648 | 0 | return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
3649 | 0 | } |
3650 | | |
3651 | | WebCryptoTask::WebCryptoTask() |
3652 | | : CancelableRunnable("WebCryptoTask") |
3653 | | , mEarlyRv(NS_OK) |
3654 | | , mEarlyComplete(false) |
3655 | | , mOriginalEventTarget(nullptr) |
3656 | | , mRv(NS_ERROR_NOT_INITIALIZED) |
3657 | 0 | { |
3658 | 0 | } |
3659 | | |
3660 | 0 | WebCryptoTask::~WebCryptoTask() = default; |
3661 | | |
3662 | | } // namespace dom |
3663 | | } // namespace mozilla |