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