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/. */
10 #include "nsNSSComponent.h"
11 #include "nsProxyRelease.h"
14 #include "mozilla/Telemetry.h"
15 #include "mozilla/Utf8.h"
16 #include "mozilla/dom/CryptoBuffer.h"
17 #include "mozilla/dom/CryptoKey.h"
18 #include "mozilla/dom/KeyAlgorithmProxy.h"
19 #include "mozilla/dom/TypedArray.h"
20 #include "mozilla/dom/WebCryptoCommon.h"
21 #include "mozilla/dom/WebCryptoTask.h"
22 #include "mozilla/dom/WorkerRef.h"
23 #include "mozilla/dom/WorkerPrivate.h"
24 #include "mozilla/dom/RootedDictionary.h"
26 // Template taken from security/nss/lib/util/templates.c
27 // This (or SGN_EncodeDigestInfo) would ideally be exported
28 // by NSS and until that happens we have to keep our own copy.
29 const SEC_ASN1Template SGN_DigestInfoTemplate
[] = {
30 {SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(SGNDigestInfo
)},
31 {SEC_ASN1_INLINE
, offsetof(SGNDigestInfo
, digestAlgorithm
),
32 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate
)},
33 {SEC_ASN1_OCTET_STRING
, offsetof(SGNDigestInfo
, digest
)},
38 namespace mozilla::dom
{
40 // Pre-defined identifiers for telemetry histograms
42 enum TelemetryMethod
{
57 enum TelemetryAlgorithm
{
58 // Please make additions at the end of the list,
59 // to preserve comparability of histograms over time
66 TA_RSAES_PKCS1
= 5, // NB: This algorithm has been removed
91 // Convenience functions for extracting / converting information
93 // OOM-safe CryptoBuffer initialization, suitable for constructors
94 #define ATTEMPT_BUFFER_INIT(dst, src) \
95 if (!dst.Assign(src)) { \
96 mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \
100 // OOM-safe CryptoBuffer-to-SECItem copy, suitable for DoCrypto
101 #define ATTEMPT_BUFFER_TO_SECITEM(arena, dst, src) \
102 if (!src.ToSECItem(arena, dst)) { \
103 return NS_ERROR_DOM_UNKNOWN_ERR; \
106 // OOM-safe CryptoBuffer copy, suitable for DoCrypto
107 #define ATTEMPT_BUFFER_ASSIGN(dst, src) \
108 if (!dst.Assign(src)) { \
109 return NS_ERROR_DOM_UNKNOWN_ERR; \
112 // Safety check for algorithms that use keys, suitable for constructors
113 #define CHECK_KEY_ALGORITHM(keyAlg, algName) \
115 if (!NORMALIZED_EQUALS(keyAlg.mName, algName)) { \
116 mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; \
121 class ClearException
{
123 explicit ClearException(JSContext
* aCx
) : mCx(aCx
) {}
125 ~ClearException() { JS_ClearPendingException(mCx
); }
132 static nsresult
GetAlgorithmName(JSContext
* aCx
, const OOS
& aAlgorithm
,
134 ClearException
ce(aCx
);
136 if (aAlgorithm
.IsString()) {
137 // If string, then treat as algorithm name
138 aName
.Assign(aAlgorithm
.GetAsString());
140 // Coerce to algorithm and extract name
141 JS::Rooted
<JS::Value
> value(aCx
,
142 JS::ObjectValue(*aAlgorithm
.GetAsObject()));
145 if (!alg
.Init(aCx
, value
)) {
146 return NS_ERROR_DOM_SYNTAX_ERR
;
152 if (!NormalizeToken(aName
, aName
)) {
153 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
159 template <class T
, class OOS
>
160 static nsresult
Coerce(JSContext
* aCx
, T
& aTarget
, const OOS
& aAlgorithm
) {
161 ClearException
ce(aCx
);
163 if (!aAlgorithm
.IsObject()) {
164 return NS_ERROR_DOM_SYNTAX_ERR
;
167 JS::Rooted
<JS::Value
> value(aCx
, JS::ObjectValue(*aAlgorithm
.GetAsObject()));
168 if (!aTarget
.Init(aCx
, value
)) {
169 return NS_ERROR_DOM_TYPE_MISMATCH_ERR
;
175 inline size_t MapHashAlgorithmNameToBlockSize(const nsString
& aName
) {
176 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
) ||
177 aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
181 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
) ||
182 aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
189 inline nsresult
GetKeyLengthForAlgorithmIfSpecified(
190 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, Maybe
<size_t>& aLength
) {
191 // Extract algorithm name
193 if (NS_FAILED(GetAlgorithmName(aCx
, aAlgorithm
, algName
))) {
194 return NS_ERROR_DOM_SYNTAX_ERR
;
197 // Read AES key length from given algorithm object.
198 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
199 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
200 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
201 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
202 RootedDictionary
<AesDerivedKeyParams
> params(aCx
);
203 if (NS_FAILED(Coerce(aCx
, params
, aAlgorithm
))) {
204 return NS_ERROR_DOM_SYNTAX_ERR
;
207 if (params
.mLength
!= 128 && params
.mLength
!= 192 &&
208 params
.mLength
!= 256) {
209 return NS_ERROR_DOM_OPERATION_ERR
;
212 aLength
.emplace(params
.mLength
);
216 // Read HMAC key length from given algorithm object or
217 // determine key length as the block size of the given hash.
218 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
219 RootedDictionary
<HmacDerivedKeyParams
> params(aCx
);
220 if (NS_FAILED(Coerce(aCx
, params
, aAlgorithm
))) {
221 return NS_ERROR_DOM_SYNTAX_ERR
;
224 // Return the passed length, if any.
225 if (params
.mLength
.WasPassed()) {
226 aLength
.emplace(params
.mLength
.Value());
231 if (NS_FAILED(GetAlgorithmName(aCx
, params
.mHash
, hashName
))) {
232 return NS_ERROR_DOM_SYNTAX_ERR
;
235 // Return the given hash algorithm's block size as the key length.
236 size_t blockSize
= MapHashAlgorithmNameToBlockSize(hashName
);
237 if (blockSize
== 0) {
238 return NS_ERROR_DOM_SYNTAX_ERR
;
241 aLength
.emplace(blockSize
);
248 inline nsresult
GetKeyLengthForAlgorithm(JSContext
* aCx
,
249 const ObjectOrString
& aAlgorithm
,
251 Maybe
<size_t> length
;
252 nsresult rv
= GetKeyLengthForAlgorithmIfSpecified(aCx
, aAlgorithm
, length
);
256 if (length
.isNothing()) {
257 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
263 inline bool MapOIDTagToNamedCurve(SECOidTag aOIDTag
, nsString
& aResult
) {
265 case SEC_OID_SECG_EC_SECP256R1
:
266 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256
);
268 case SEC_OID_SECG_EC_SECP384R1
:
269 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384
);
271 case SEC_OID_SECG_EC_SECP521R1
:
272 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521
);
274 case SEC_OID_ED25519_PUBLIC_KEY
:
275 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_ED25519
);
284 inline SECOidTag
MapHashAlgorithmNameToOID(const nsString
& aName
) {
285 SECOidTag
hashOID(SEC_OID_UNKNOWN
);
287 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
288 hashOID
= SEC_OID_SHA1
;
289 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
290 hashOID
= SEC_OID_SHA256
;
291 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
292 hashOID
= SEC_OID_SHA384
;
293 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
294 hashOID
= SEC_OID_SHA512
;
300 inline CK_MECHANISM_TYPE
MapHashAlgorithmNameToMgfMechanism(
301 const nsString
& aName
) {
302 CK_MECHANISM_TYPE
mech(UNKNOWN_CK_MECHANISM
);
304 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
305 mech
= CKG_MGF1_SHA1
;
306 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
307 mech
= CKG_MGF1_SHA256
;
308 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
309 mech
= CKG_MGF1_SHA384
;
310 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
311 mech
= CKG_MGF1_SHA512
;
317 // Implementation of WebCryptoTask methods
319 void WebCryptoTask::DispatchWithPromise(Promise
* aResultPromise
) {
320 mResultPromise
= aResultPromise
;
322 // Fail if an error was set during the constructor
323 MAYBE_EARLY_FAIL(mEarlyRv
)
325 // Perform pre-NSS operations, and fail if they fail
326 mEarlyRv
= BeforeCrypto();
327 MAYBE_EARLY_FAIL(mEarlyRv
)
329 // Skip dispatch if we're already done. Otherwise launch a CryptoTask
330 if (mEarlyComplete
) {
331 CallCallback(mEarlyRv
);
335 // Store calling thread
336 mOriginalEventTarget
= GetCurrentSerialEventTarget();
338 // If we are running on a worker thread we must hold the worker
339 // alive while we work on the thread pool. Otherwise the worker
340 // private may get torn down before we dispatch back to complete
342 if (!NS_IsMainThread()) {
343 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
344 MOZ_ASSERT(workerPrivate
);
346 RefPtr
<StrongWorkerRef
> workerRef
=
347 StrongWorkerRef::Create(workerPrivate
, "WebCryptoTask");
348 if (NS_WARN_IF(!workerRef
)) {
349 mEarlyRv
= NS_BINDING_ABORTED
;
351 mWorkerRef
= new ThreadSafeWorkerRef(workerRef
);
354 MAYBE_EARLY_FAIL(mEarlyRv
);
356 // dispatch to thread pool
358 if (!EnsureNSSInitializedChromeOrContent()) {
359 mEarlyRv
= NS_ERROR_FAILURE
;
361 MAYBE_EARLY_FAIL(mEarlyRv
);
363 mEarlyRv
= NS_DispatchBackgroundTask(this);
364 MAYBE_EARLY_FAIL(mEarlyRv
)
368 WebCryptoTask::Run() {
369 // Run heavy crypto operations on the thread pool, off the original thread.
370 if (!IsOnOriginalThread()) {
371 mRv
= CalculateResult();
373 // Back to the original thread, i.e. continue below.
374 mOriginalEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
);
378 // We're now back on the calling thread.
381 // Stop holding the worker thread alive now that the async work has
383 mWorkerRef
= nullptr;
388 nsresult
WebCryptoTask::Cancel() {
389 MOZ_ASSERT(IsOnOriginalThread());
390 FailWithError(NS_BINDING_ABORTED
);
394 void WebCryptoTask::FailWithError(nsresult aRv
) {
395 MOZ_ASSERT(IsOnOriginalThread());
396 Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED
, false);
398 if (aRv
== NS_ERROR_DOM_TYPE_MISMATCH_ERR
) {
399 mResultPromise
->MaybeRejectWithTypeError(
400 "The operation could not be performed.");
402 // Blindly convert nsresult to DOMException
403 // Individual tasks must ensure they pass the right values
404 mResultPromise
->MaybeReject(aRv
);
406 // Manually release mResultPromise while we're on the main thread
407 mResultPromise
= nullptr;
408 mWorkerRef
= nullptr;
412 nsresult
WebCryptoTask::CalculateResult() {
413 MOZ_ASSERT(!IsOnOriginalThread());
418 void WebCryptoTask::CallCallback(nsresult rv
) {
419 MOZ_ASSERT(IsOnOriginalThread());
425 nsresult rv2
= AfterCrypto();
426 if (NS_FAILED(rv2
)) {
432 Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED
, true);
434 // Manually release mResultPromise while we're on the main thread
435 mResultPromise
= nullptr;
439 // Some generic utility classes
441 class FailureTask
: public WebCryptoTask
{
443 explicit FailureTask(nsresult aRv
) { mEarlyRv
= aRv
; }
446 class ReturnArrayBufferViewTask
: public WebCryptoTask
{
448 CryptoBuffer mResult
;
451 // Returns mResult as an ArrayBufferView, or an error
452 virtual void Resolve() override
{
453 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
454 mResultPromise
->MaybeResolve(ret
);
461 void SetData(const T
& aData
) {
462 mDataIsSet
= mData
.Assign(aData
);
466 DeferredData() : mDataIsSet(false) {}
472 class AesTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
474 AesTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
476 : mMechanism(CKM_INVALID_MECHANISM
),
480 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
483 AesTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
484 const CryptoOperationData
& aData
, bool aEncrypt
)
485 : mMechanism(CKM_INVALID_MECHANISM
),
489 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
493 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
496 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
497 if (NS_FAILED(mEarlyRv
)) {
501 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
502 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
506 // Check that we got a reasonable key
507 if ((mSymKey
.Length() != 16) && (mSymKey
.Length() != 24) &&
508 (mSymKey
.Length() != 32)) {
509 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
513 // Cache parameters depending on the specific algorithm
514 TelemetryAlgorithm telemetryAlg
;
515 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
)) {
516 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_CBC
);
518 mMechanism
= CKM_AES_CBC_PAD
;
519 telemetryAlg
= TA_AES_CBC
;
520 RootedDictionary
<AesCbcParams
> params(aCx
);
521 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
523 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
527 ATTEMPT_BUFFER_INIT(mIv
, params
.mIv
)
528 if (mIv
.Length() != 16) {
529 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
532 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
)) {
533 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_CTR
);
535 mMechanism
= CKM_AES_CTR
;
536 telemetryAlg
= TA_AES_CTR
;
537 RootedDictionary
<AesCtrParams
> params(aCx
);
538 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
540 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
544 ATTEMPT_BUFFER_INIT(mIv
, params
.mCounter
)
545 if (mIv
.Length() != 16) {
546 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
550 mCounterLength
= params
.mLength
;
551 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
552 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_GCM
);
554 mMechanism
= CKM_AES_GCM
;
555 telemetryAlg
= TA_AES_GCM
;
556 RootedDictionary
<AesGcmParams
> params(aCx
);
557 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
559 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
563 ATTEMPT_BUFFER_INIT(mIv
, params
.mIv
)
565 if (params
.mAdditionalData
.WasPassed()) {
566 ATTEMPT_BUFFER_INIT(mAad
, params
.mAdditionalData
.Value())
569 // 32, 64, 96, 104, 112, 120 or 128
571 if (params
.mTagLength
.WasPassed()) {
572 mTagLength
= params
.mTagLength
.Value();
573 if ((mTagLength
> 128) ||
574 !(mTagLength
== 32 || mTagLength
== 64 ||
575 (mTagLength
>= 96 && mTagLength
% 8 == 0))) {
576 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
581 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
584 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
588 CK_MECHANISM_TYPE mMechanism
;
589 CryptoBuffer mSymKey
;
590 CryptoBuffer mIv
; // Initialization vector
591 CryptoBuffer mAad
; // Additional Authenticated Data
593 uint8_t mCounterLength
;
596 virtual nsresult
DoCrypto() override
{
600 return NS_ERROR_DOM_OPERATION_ERR
;
603 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
605 return NS_ERROR_DOM_OPERATION_ERR
;
608 // Construct the parameters object depending on algorithm
609 SECItem param
= {siBuffer
, nullptr, 0};
610 CK_AES_CTR_PARAMS ctrParams
;
611 CK_GCM_PARAMS gcmParams
;
612 switch (mMechanism
) {
613 case CKM_AES_CBC_PAD
:
614 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), ¶m
, mIv
);
617 ctrParams
.ulCounterBits
= mCounterLength
;
618 MOZ_ASSERT(mIv
.Length() == 16);
619 memcpy(&ctrParams
.cb
, mIv
.Elements(), 16);
620 param
.type
= siBuffer
;
621 param
.data
= (unsigned char*)&ctrParams
;
622 param
.len
= sizeof(ctrParams
);
625 gcmParams
.pIv
= mIv
.Elements();
626 gcmParams
.ulIvLen
= mIv
.Length();
627 gcmParams
.ulIvBits
= gcmParams
.ulIvLen
* 8;
628 gcmParams
.pAAD
= mAad
.Elements();
629 gcmParams
.ulAADLen
= mAad
.Length();
630 gcmParams
.ulTagBits
= mTagLength
;
631 param
.type
= siBuffer
;
632 param
.data
= (unsigned char*)&gcmParams
;
633 param
.len
= sizeof(gcmParams
);
636 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
640 SECItem keyItem
= {siBuffer
, nullptr, 0};
641 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
642 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
643 MOZ_ASSERT(slot
.get());
644 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
645 PK11_OriginUnwrap
, CKA_ENCRYPT
,
648 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
651 // Check whether the integer addition would overflow.
652 if (std::numeric_limits
<CryptoBuffer::size_type
>::max() - 16 <
654 return NS_ERROR_DOM_DATA_ERR
;
657 // Initialize the output buffer (enough space for padding / a full tag)
658 if (!mResult
.SetLength(mData
.Length() + 16, fallible
)) {
659 return NS_ERROR_DOM_UNKNOWN_ERR
;
664 // Perform the encryption/decryption
666 rv
= MapSECStatus(PK11_Encrypt(
667 symKey
.get(), mMechanism
, ¶m
, mResult
.Elements(), &outLen
,
668 mResult
.Length(), mData
.Elements(), mData
.Length()));
670 rv
= MapSECStatus(PK11_Decrypt(
671 symKey
.get(), mMechanism
, ¶m
, mResult
.Elements(), &outLen
,
672 mResult
.Length(), mData
.Elements(), mData
.Length()));
674 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
676 mResult
.TruncateLength(outLen
);
681 // This class looks like an encrypt/decrypt task, like AesTask,
682 // but it is only exposed to wrapKey/unwrapKey, not encrypt/decrypt
683 class AesKwTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
685 AesKwTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
687 : mMechanism(CKM_NSS_AES_KEY_WRAP
), mEncrypt(aEncrypt
) {
688 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
691 AesKwTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
692 const CryptoOperationData
& aData
, bool aEncrypt
)
693 : mMechanism(CKM_NSS_AES_KEY_WRAP
), mEncrypt(aEncrypt
) {
694 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
698 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
700 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_KW
);
703 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
704 if (NS_FAILED(mEarlyRv
)) {
708 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
709 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
713 // Check that we got a reasonable key
714 if ((mSymKey
.Length() != 16) && (mSymKey
.Length() != 24) &&
715 (mSymKey
.Length() != 32)) {
716 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
720 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_AES_KW
);
724 CK_MECHANISM_TYPE mMechanism
;
725 CryptoBuffer mSymKey
;
728 virtual nsresult
DoCrypto() override
{
732 return NS_ERROR_DOM_OPERATION_ERR
;
735 // Check that the input is a multiple of 64 bits long
736 if (mData
.Length() == 0 || mData
.Length() % 8 != 0) {
737 return NS_ERROR_DOM_DATA_ERR
;
740 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
742 return NS_ERROR_DOM_OPERATION_ERR
;
746 SECItem keyItem
= {siBuffer
, nullptr, 0};
747 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
748 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
749 MOZ_ASSERT(slot
.get());
750 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
751 PK11_OriginUnwrap
, CKA_WRAP
,
754 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
757 // Import the data to a SECItem
758 SECItem dataItem
= {siBuffer
, nullptr, 0};
759 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &dataItem
, mData
);
761 // Parameters for the fake keys
762 CK_MECHANISM_TYPE fakeMechanism
= CKM_SHA_1_HMAC
;
763 CK_ATTRIBUTE_TYPE fakeOperation
= CKA_SIGN
;
766 // Import the data into a fake PK11SymKey structure
767 UniquePK11SymKey
keyToWrap(
768 PK11_ImportSymKey(slot
.get(), fakeMechanism
, PK11_OriginUnwrap
,
769 fakeOperation
, &dataItem
, nullptr));
771 return NS_ERROR_DOM_OPERATION_ERR
;
774 // Encrypt and return the wrapped key
775 // AES-KW encryption results in a wrapped key 64 bits longer
776 if (!mResult
.SetLength(mData
.Length() + 8, fallible
)) {
777 return NS_ERROR_DOM_OPERATION_ERR
;
779 SECItem resultItem
= {siBuffer
, mResult
.Elements(),
780 (unsigned int)mResult
.Length()};
781 rv
= MapSECStatus(PK11_WrapSymKey(mMechanism
, nullptr, symKey
.get(),
782 keyToWrap
.get(), &resultItem
));
783 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
785 // Decrypt the ciphertext into a temporary PK11SymKey
786 // Unwrapped key should be 64 bits shorter
787 int keySize
= mData
.Length() - 8;
788 UniquePK11SymKey
unwrappedKey(
789 PK11_UnwrapSymKey(symKey
.get(), mMechanism
, nullptr, &dataItem
,
790 fakeMechanism
, fakeOperation
, keySize
));
792 return NS_ERROR_DOM_OPERATION_ERR
;
795 // Export the key to get the cleartext
796 rv
= MapSECStatus(PK11_ExtractKeyValue(unwrappedKey
.get()));
798 return NS_ERROR_DOM_UNKNOWN_ERR
;
800 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(unwrappedKey
.get()));
807 class RsaOaepTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
809 RsaOaepTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
811 : mPrivKey(aKey
.GetPrivateKey()),
812 mPubKey(aKey
.GetPublicKey()),
814 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
817 RsaOaepTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
818 const CryptoOperationData
& aData
, bool aEncrypt
)
819 : mPrivKey(aKey
.GetPrivateKey()),
820 mPubKey(aKey
.GetPublicKey()),
822 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
826 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
828 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSA_OAEP
);
830 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSA_OAEP
);
834 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
837 mStrength
= SECKEY_PublicKeyStrength(mPubKey
.get());
840 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
843 mStrength
= PK11_GetPrivateModulusLen(mPrivKey
.get());
846 // The algorithm could just be given as a string
847 // in which case there would be no label specified.
848 if (!aAlgorithm
.IsString()) {
849 RootedDictionary
<RsaOaepParams
> params(aCx
);
850 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
851 if (NS_FAILED(mEarlyRv
)) {
852 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
856 if (params
.mLabel
.WasPassed()) {
857 ATTEMPT_BUFFER_INIT(mLabel
, params
.mLabel
.Value());
860 // Otherwise mLabel remains the empty octet string, as intended
862 KeyAlgorithm
& hashAlg
= aKey
.Algorithm().mRsa
.mHash
;
863 mHashMechanism
= KeyAlgorithmProxy::GetMechanism(hashAlg
);
864 mMgfMechanism
= MapHashAlgorithmNameToMgfMechanism(hashAlg
.mName
);
866 // Check we found appropriate mechanisms.
867 if (mHashMechanism
== UNKNOWN_CK_MECHANISM
||
868 mMgfMechanism
== UNKNOWN_CK_MECHANISM
) {
869 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
875 CK_MECHANISM_TYPE mHashMechanism
;
876 CK_MECHANISM_TYPE mMgfMechanism
;
877 UniqueSECKEYPrivateKey mPrivKey
;
878 UniqueSECKEYPublicKey mPubKey
;
883 virtual nsresult
DoCrypto() override
{
887 return NS_ERROR_DOM_OPERATION_ERR
;
890 // Ciphertext is an integer mod the modulus, so it will be
891 // no longer than mStrength octets
892 if (!mResult
.SetLength(mStrength
, fallible
)) {
893 return NS_ERROR_DOM_UNKNOWN_ERR
;
896 CK_RSA_PKCS_OAEP_PARAMS oaepParams
;
897 oaepParams
.source
= CKZ_DATA_SPECIFIED
;
899 oaepParams
.pSourceData
= mLabel
.Length() ? mLabel
.Elements() : nullptr;
900 oaepParams
.ulSourceDataLen
= mLabel
.Length();
902 oaepParams
.mgf
= mMgfMechanism
;
903 oaepParams
.hashAlg
= mHashMechanism
;
906 param
.type
= siBuffer
;
907 param
.data
= (unsigned char*)&oaepParams
;
908 param
.len
= sizeof(oaepParams
);
912 // PK11_PubEncrypt() checks the plaintext's length and fails if it is too
913 // long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
914 // being the length in octets of the RSA modulus n and 'hLen' being the
915 // output length in octets of the chosen hash function.
916 // <https://tools.ietf.org/html/rfc3447#section-7.1>
917 rv
= MapSECStatus(PK11_PubEncrypt(
918 mPubKey
.get(), CKM_RSA_PKCS_OAEP
, ¶m
, mResult
.Elements(), &outLen
,
919 mResult
.Length(), mData
.Elements(), mData
.Length(), nullptr));
921 rv
= MapSECStatus(PK11_PrivDecrypt(
922 mPrivKey
.get(), CKM_RSA_PKCS_OAEP
, ¶m
, mResult
.Elements(),
923 &outLen
, mResult
.Length(), mData
.Elements(), mData
.Length()));
925 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
927 mResult
.TruncateLength(outLen
);
932 class HmacTask
: public WebCryptoTask
{
934 HmacTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
935 const CryptoOperationData
& aSignature
,
936 const CryptoOperationData
& aData
, bool aSign
)
937 : mMechanism(aKey
.Algorithm().Mechanism()), mSign(aSign
) {
938 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_HMAC
);
940 ATTEMPT_BUFFER_INIT(mData
, aData
);
942 ATTEMPT_BUFFER_INIT(mSignature
, aSignature
);
945 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
946 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
950 // Check that we got a symmetric key
951 if (mSymKey
.Length() == 0) {
952 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
956 TelemetryAlgorithm telemetryAlg
;
957 switch (mMechanism
) {
959 telemetryAlg
= TA_HMAC_SHA_1
;
961 case CKM_SHA224_HMAC
:
962 telemetryAlg
= TA_HMAC_SHA_224
;
964 case CKM_SHA256_HMAC
:
965 telemetryAlg
= TA_HMAC_SHA_256
;
967 case CKM_SHA384_HMAC
:
968 telemetryAlg
= TA_HMAC_SHA_384
;
970 case CKM_SHA512_HMAC
:
971 telemetryAlg
= TA_HMAC_SHA_512
;
974 telemetryAlg
= TA_UNKNOWN
;
976 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
980 CK_MECHANISM_TYPE mMechanism
;
981 CryptoBuffer mSymKey
;
983 CryptoBuffer mSignature
;
984 CryptoBuffer mResult
;
987 virtual nsresult
DoCrypto() override
{
988 // Initialize the output buffer
989 if (!mResult
.SetLength(HASH_LENGTH_MAX
, fallible
)) {
990 return NS_ERROR_DOM_UNKNOWN_ERR
;
993 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
995 return NS_ERROR_DOM_OPERATION_ERR
;
1000 SECItem keyItem
= {siBuffer
, nullptr, 0};
1001 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
1002 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
1003 MOZ_ASSERT(slot
.get());
1004 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
1005 PK11_OriginUnwrap
, CKA_SIGN
,
1006 &keyItem
, nullptr));
1008 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1012 SECItem param
= {siBuffer
, nullptr, 0};
1013 UniquePK11Context
ctx(
1014 PK11_CreateContextBySymKey(mMechanism
, CKA_SIGN
, symKey
.get(), ¶m
));
1016 return NS_ERROR_DOM_OPERATION_ERR
;
1018 nsresult rv
= MapSECStatus(PK11_DigestBegin(ctx
.get()));
1019 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
1021 PK11_DigestOp(ctx
.get(), mData
.Elements(), mData
.Length()));
1022 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
1023 rv
= MapSECStatus(PK11_DigestFinal(ctx
.get(), mResult
.Elements(), &outLen
,
1025 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
1027 mResult
.TruncateLength(outLen
);
1031 // Returns mResult as an ArrayBufferView, or an error
1032 virtual void Resolve() override
{
1034 // Return the computed MAC
1035 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
1036 mResultPromise
->MaybeResolve(ret
);
1038 // Compare the MAC to the provided signature
1039 // No truncation allowed
1040 bool equal
= (mResult
.Length() == mSignature
.Length());
1042 int cmp
= NSS_SecureMemcmp(mSignature
.Elements(), mResult
.Elements(),
1043 mSignature
.Length());
1046 mResultPromise
->MaybeResolve(equal
);
1051 class AsymmetricSignVerifyTask
: public WebCryptoTask
{
1053 AsymmetricSignVerifyTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
1055 const CryptoOperationData
& aSignature
,
1056 const CryptoOperationData
& aData
, bool aSign
)
1057 : mOidTag(SEC_OID_UNKNOWN
),
1058 mHashMechanism(UNKNOWN_CK_MECHANISM
),
1059 mMgfMechanism(UNKNOWN_CK_MECHANISM
),
1060 mPrivKey(aKey
.GetPrivateKey()),
1061 mPubKey(aKey
.GetPublicKey()),
1065 mAlgorithm(Algorithm::UNKNOWN
) {
1066 ATTEMPT_BUFFER_INIT(mData
, aData
);
1068 ATTEMPT_BUFFER_INIT(mSignature
, aSignature
);
1072 nsString hashAlgName
;
1073 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
1074 if (NS_FAILED(mEarlyRv
)) {
1078 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
)) {
1079 mAlgorithm
= Algorithm::RSA_PKCS1
;
1080 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSASSA_PKCS1
);
1081 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1
);
1082 hashAlgName
= aKey
.Algorithm().mRsa
.mHash
.mName
;
1083 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1084 mAlgorithm
= Algorithm::RSA_PSS
;
1085 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSA_PSS
);
1086 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSA_PSS
);
1088 KeyAlgorithm
& hashAlg
= aKey
.Algorithm().mRsa
.mHash
;
1089 hashAlgName
= hashAlg
.mName
;
1090 mHashMechanism
= KeyAlgorithmProxy::GetMechanism(hashAlg
);
1091 mMgfMechanism
= MapHashAlgorithmNameToMgfMechanism(hashAlgName
);
1093 // Check we found appropriate mechanisms.
1094 if (mHashMechanism
== UNKNOWN_CK_MECHANISM
||
1095 mMgfMechanism
== UNKNOWN_CK_MECHANISM
) {
1096 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1100 RootedDictionary
<RsaPssParams
> params(aCx
);
1101 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1102 if (NS_FAILED(mEarlyRv
)) {
1103 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1107 mSaltLength
= params
.mSaltLength
;
1108 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
1109 mAlgorithm
= Algorithm::ECDSA
;
1110 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_ECDSA
);
1111 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_ECDSA
);
1113 // For ECDSA, the hash name comes from the algorithm parameter
1114 RootedDictionary
<EcdsaParams
> params(aCx
);
1115 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1116 if (NS_FAILED(mEarlyRv
)) {
1117 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1121 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashAlgName
);
1122 if (NS_FAILED(mEarlyRv
)) {
1123 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1126 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
1127 mAlgorithm
= Algorithm::ED25519
;
1128 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_ED25519
);
1130 // This shouldn't happen; CreateSignVerifyTask shouldn't create
1131 // one of these unless it's for the above algorithms.
1135 // Must have a valid algorithm by now.
1136 MOZ_ASSERT(mAlgorithm
!= Algorithm::UNKNOWN
);
1138 // Determine hash algorithm to use.
1139 mOidTag
= MapHashAlgorithmNameToOID(hashAlgName
);
1141 if (mOidTag
== SEC_OID_UNKNOWN
&& AlgorithmRequiresHashing(mAlgorithm
)) {
1142 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1146 // Check that we have the appropriate key
1147 if ((mSign
&& !mPrivKey
) || (!mSign
&& !mPubKey
)) {
1148 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1155 CK_MECHANISM_TYPE mHashMechanism
;
1156 CK_MECHANISM_TYPE mMgfMechanism
;
1157 UniqueSECKEYPrivateKey mPrivKey
;
1158 UniqueSECKEYPublicKey mPubKey
;
1159 CryptoBuffer mSignature
;
1161 uint32_t mSaltLength
;
1165 // The signature algorithm to use.
1166 enum class Algorithm
: uint8_t {
1173 Algorithm mAlgorithm
;
1175 bool AlgorithmRequiresHashing(Algorithm aAlgorithm
) {
1176 MOZ_ASSERT(aAlgorithm
!= Algorithm::UNKNOWN
);
1177 /* Currently, only ED25519 does not require hashing.*/
1178 switch (aAlgorithm
) {
1179 case Algorithm::ED25519
:
1181 case Algorithm::ECDSA
:
1182 case Algorithm::RSA_PKCS1
:
1183 case Algorithm::RSA_PSS
:
1185 case Algorithm::UNKNOWN
:
1188 /*Also impossible, as all the algorithm options should be managed in the
1193 virtual nsresult
DoCrypto() override
{
1197 SECItem
* params
= nullptr;
1198 CK_MECHANISM_TYPE mech
=
1199 PK11_MapSignKeyType(mSign
? mPrivKey
->keyType
: mPubKey
->keyType
);
1201 CK_RSA_PKCS_PSS_PARAMS rsaPssParams
;
1202 SECItem rsaPssParamsItem
= {
1206 // Set up parameters for RSA-PSS.
1207 if (mAlgorithm
== Algorithm::RSA_PSS
) {
1208 rsaPssParams
.hashAlg
= mHashMechanism
;
1209 rsaPssParams
.mgf
= mMgfMechanism
;
1210 rsaPssParams
.sLen
= mSaltLength
;
1212 rsaPssParamsItem
.data
= (unsigned char*)&rsaPssParams
;
1213 rsaPssParamsItem
.len
= sizeof(rsaPssParams
);
1214 params
= &rsaPssParamsItem
;
1216 mech
= CKM_RSA_PKCS_PSS
;
1219 if (AlgorithmRequiresHashing(mAlgorithm
)) {
1220 // Compute digest over given data.
1221 hash
.reset(::SECITEM_AllocItem(nullptr, nullptr,
1222 HASH_ResultLenByOidTag(mOidTag
)));
1224 if (!hash
|| !hash
->data
|| hash
->len
> PR_INT32_MAX
) {
1225 return NS_ERROR_DOM_OPERATION_ERR
;
1228 rv
= PK11_HashBuf(mOidTag
, hash
->data
, mData
.Elements(),
1229 static_cast<PRInt32
>(mData
.Length()));
1230 NS_ENSURE_SUCCESS(MapSECStatus(rv
), NS_ERROR_DOM_OPERATION_ERR
);
1233 // Wrap hash in a digest info template (RSA-PKCS1 only).
1234 if (mAlgorithm
== Algorithm::RSA_PKCS1
) {
1236 return NS_ERROR_DOM_OPERATION_ERR
;
1239 UniqueSGNDigestInfo
di(
1240 SGN_CreateDigestInfo(mOidTag
, hash
->data
, hash
->len
));
1242 return NS_ERROR_DOM_OPERATION_ERR
;
1246 SECITEM_FreeItem(hash
.get(), false);
1247 if (!SEC_ASN1EncodeItem(nullptr, hash
.get(), di
.get(),
1248 SGN_DigestInfoTemplate
)) {
1249 return NS_ERROR_DOM_OPERATION_ERR
;
1253 // Allocate SECItem to hold the signature.
1254 uint32_t len
= mSign
? PK11_SignatureLen(mPrivKey
.get()) : 0;
1255 UniqueSECItem
sig(::SECITEM_AllocItem(nullptr, nullptr, len
));
1257 return NS_ERROR_DOM_OPERATION_ERR
;
1260 // Buffer for signature/verification input.
1261 SECItem dataToOperateOn
;
1263 if (AlgorithmRequiresHashing(mAlgorithm
)) {
1264 dataToOperateOn
= {siBuffer
, hash
->data
, hash
->len
};
1266 dataToOperateOn
= {siBuffer
, mData
.Elements(),
1267 static_cast<unsigned int>(mData
.Length())};
1271 rv
= PK11_SignWithMechanism(mPrivKey
.get(), mech
, params
, sig
.get(),
1273 NS_ENSURE_SUCCESS(MapSECStatus(rv
), NS_ERROR_DOM_OPERATION_ERR
);
1274 ATTEMPT_BUFFER_ASSIGN(mSignature
, sig
.get());
1276 if (AlgorithmRequiresHashing(mAlgorithm
)) {
1277 dataToOperateOn
= {siBuffer
, hash
->data
, hash
->len
};
1279 dataToOperateOn
= {siBuffer
, mData
.Elements(),
1280 static_cast<unsigned int>(mData
.Length())};
1283 // Copy the given signature to the SECItem.
1284 if (!mSignature
.ToSECItem(nullptr, sig
.get())) {
1285 return NS_ERROR_DOM_OPERATION_ERR
;
1288 // Verify the signature.
1289 rv
= PK11_VerifyWithMechanism(mPubKey
.get(), mech
, params
, sig
.get(),
1290 &dataToOperateOn
, nullptr);
1291 mVerified
= NS_SUCCEEDED(MapSECStatus(rv
));
1297 virtual void Resolve() override
{
1299 TypedArrayCreator
<ArrayBuffer
> ret(mSignature
);
1300 mResultPromise
->MaybeResolve(ret
);
1302 mResultPromise
->MaybeResolve(mVerified
);
1307 class DigestTask
: public ReturnArrayBufferViewTask
{
1309 DigestTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
1310 const CryptoOperationData
& aData
) {
1311 ATTEMPT_BUFFER_INIT(mData
, aData
);
1314 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
1315 if (NS_FAILED(mEarlyRv
)) {
1316 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1320 TelemetryAlgorithm telemetryAlg
;
1321 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
1322 telemetryAlg
= TA_SHA_1
;
1323 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
1324 telemetryAlg
= TA_SHA_224
;
1325 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
1326 telemetryAlg
= TA_SHA_256
;
1327 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
1328 telemetryAlg
= TA_SHA_384
;
1330 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1333 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
1334 mOidTag
= MapHashAlgorithmNameToOID(algName
);
1341 virtual nsresult
DoCrypto() override
{
1342 // Resize the result buffer
1343 uint32_t hashLen
= HASH_ResultLenByOidTag(mOidTag
);
1344 if (!mResult
.SetLength(hashLen
, fallible
)) {
1345 return NS_ERROR_DOM_UNKNOWN_ERR
;
1349 nsresult rv
= MapSECStatus(PK11_HashBuf(mOidTag
, mResult
.Elements(),
1350 mData
.Elements(), mData
.Length()));
1351 if (NS_FAILED(rv
)) {
1352 return NS_ERROR_DOM_UNKNOWN_ERR
;
1359 class ImportKeyTask
: public WebCryptoTask
{
1361 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1362 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1363 const Sequence
<nsString
>& aKeyUsages
) {
1368 // This stuff pretty much always happens, so we'll do it here
1369 mKey
= new CryptoKey(aGlobal
);
1370 mKey
->SetExtractable(aExtractable
);
1371 mKey
->ClearUsages();
1372 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
1373 mEarlyRv
= mKey
->AddUsage(aKeyUsages
[i
]);
1374 if (NS_FAILED(mEarlyRv
)) {
1379 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, mAlgName
);
1380 if (NS_FAILED(mEarlyRv
)) {
1381 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1386 static bool JwkCompatible(const JsonWebKey
& aJwk
, const CryptoKey
* aKey
) {
1388 if (!aJwk
.mKty
.EqualsLiteral(JWK_TYPE_OKP
) && aJwk
.mAlg
.WasPassed() &&
1389 aJwk
.mAlg
.Value() != aKey
->Algorithm().JwkAlg()) {
1394 if (aKey
->Extractable() && aJwk
.mExt
.WasPassed() && !aJwk
.mExt
.Value()) {
1399 if (aJwk
.mKey_ops
.WasPassed()) {
1400 nsTArray
<nsString
> usages
;
1401 aKey
->GetUsages(usages
);
1402 for (size_t i
= 0; i
< usages
.Length(); ++i
) {
1403 if (!aJwk
.mKey_ops
.Value().Contains(usages
[i
])) {
1409 // Individual algorithms may still have to check 'use'
1413 void SetKeyData(JSContext
* aCx
, JS::Handle
<JSObject
*> aKeyData
) {
1417 RootedSpiderMonkeyInterface
<ArrayBuffer
> ab(aCx
);
1418 if (ab
.Init(aKeyData
)) {
1419 if (!mKeyData
.Assign(ab
)) {
1420 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1425 // Try ArrayBufferView
1426 RootedSpiderMonkeyInterface
<ArrayBufferView
> abv(aCx
);
1427 if (abv
.Init(aKeyData
)) {
1428 if (!mKeyData
.Assign(abv
)) {
1429 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1435 ClearException
ce(aCx
);
1436 JS::Rooted
<JS::Value
> value(aCx
, JS::ObjectValue(*aKeyData
));
1437 if (!mJwk
.Init(aCx
, value
)) {
1438 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1445 void SetKeyDataMaybeParseJWK(const CryptoBuffer
& aKeyData
) {
1446 if (!mKeyData
.Assign(aKeyData
)) {
1447 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1453 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1454 nsDependentCSubstring
utf8(
1455 (const char*)mKeyData
.Elements(),
1456 (const char*)(mKeyData
.Elements() + mKeyData
.Length()));
1457 if (!IsUtf8(utf8
)) {
1458 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1462 nsString json
= NS_ConvertUTF8toUTF16(utf8
);
1463 if (!mJwk
.Init(json
)) {
1464 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1472 void SetRawKeyData(const CryptoBuffer
& aKeyData
) {
1473 if (!mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1474 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1478 if (!mKeyData
.Assign(aKeyData
)) {
1479 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1488 RefPtr
<CryptoKey
> mKey
;
1489 CryptoBuffer mKeyData
;
1496 virtual void Resolve() override
{ mResultPromise
->MaybeResolve(mKey
); }
1498 virtual void Cleanup() override
{ mKey
= nullptr; }
1501 class ImportSymmetricKeyTask
: public ImportKeyTask
{
1503 ImportSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1504 const nsAString
& aFormat
,
1505 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1506 const Sequence
<nsString
>& aKeyUsages
) {
1507 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1510 ImportSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1511 const nsAString
& aFormat
,
1512 const JS::Handle
<JSObject
*> aKeyData
,
1513 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1514 const Sequence
<nsString
>& aKeyUsages
) {
1515 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1516 if (NS_FAILED(mEarlyRv
)) {
1520 SetKeyData(aCx
, aKeyData
);
1521 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1522 if (mDataIsJwk
&& !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1523 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1528 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1529 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1530 const Sequence
<nsString
>& aKeyUsages
) {
1531 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1533 if (NS_FAILED(mEarlyRv
)) {
1537 // This task only supports raw and JWK format.
1538 if (!mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1539 !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1540 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1544 // If this is an HMAC key, import the hash name
1545 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
1546 RootedDictionary
<HmacImportParams
> params(aCx
);
1547 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1548 if (NS_FAILED(mEarlyRv
)) {
1549 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1552 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, mHashName
);
1553 if (NS_FAILED(mEarlyRv
)) {
1554 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1560 virtual nsresult
BeforeCrypto() override
{
1562 // If we're doing a JWK import, import the key data
1564 if (!mJwk
.mK
.WasPassed()) {
1565 return NS_ERROR_DOM_DATA_ERR
;
1568 // Import the key material
1569 rv
= mKeyData
.FromJwkBase64(mJwk
.mK
.Value());
1570 if (NS_FAILED(rv
)) {
1571 return NS_ERROR_DOM_DATA_ERR
;
1574 // Check that we have valid key data.
1575 if (mKeyData
.Length() == 0 &&
1576 (!mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
) &&
1577 !mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HKDF
))) {
1578 return NS_ERROR_DOM_DATA_ERR
;
1581 // Construct an appropriate KeyAlgorithm,
1582 // and verify that usages are appropriate
1583 if (mKeyData
.Length() > UINT32_MAX
/ 8) {
1584 return NS_ERROR_DOM_DATA_ERR
;
1586 uint32_t length
= 8 * mKeyData
.Length(); // bytes to bits
1587 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
1588 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
1589 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
1590 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
1591 if (mKey
->HasUsageOtherThan(CryptoKey::ENCRYPT
| CryptoKey::DECRYPT
|
1592 CryptoKey::WRAPKEY
| CryptoKey::UNWRAPKEY
)) {
1593 return NS_ERROR_DOM_DATA_ERR
;
1596 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) &&
1597 mKey
->HasUsageOtherThan(CryptoKey::WRAPKEY
| CryptoKey::UNWRAPKEY
)) {
1598 return NS_ERROR_DOM_DATA_ERR
;
1601 if ((length
!= 128) && (length
!= 192) && (length
!= 256)) {
1602 return NS_ERROR_DOM_DATA_ERR
;
1604 mKey
->Algorithm().MakeAes(mAlgName
, length
);
1606 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed() &&
1607 !mJwk
.mUse
.Value().EqualsLiteral(JWK_USE_ENC
)) {
1608 return NS_ERROR_DOM_DATA_ERR
;
1610 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HKDF
) ||
1611 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
)) {
1612 if (mKey
->HasUsageOtherThan(CryptoKey::DERIVEKEY
|
1613 CryptoKey::DERIVEBITS
)) {
1614 return NS_ERROR_DOM_DATA_ERR
;
1616 mKey
->Algorithm().MakeKDF(mAlgName
);
1618 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed()) {
1619 // There is not a 'use' value consistent with PBKDF or HKDF
1620 return NS_ERROR_DOM_DATA_ERR
;
1622 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
1623 if (mKey
->HasUsageOtherThan(CryptoKey::SIGN
| CryptoKey::VERIFY
)) {
1624 return NS_ERROR_DOM_DATA_ERR
;
1627 mKey
->Algorithm().MakeHmac(length
, mHashName
);
1629 if (mKey
->Algorithm().Mechanism() == UNKNOWN_CK_MECHANISM
) {
1630 return NS_ERROR_DOM_SYNTAX_ERR
;
1633 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed() &&
1634 !mJwk
.mUse
.Value().EqualsLiteral(JWK_USE_SIG
)) {
1635 return NS_ERROR_DOM_DATA_ERR
;
1638 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1641 if (!mKey
->HasAnyUsage()) {
1642 return NS_ERROR_DOM_SYNTAX_ERR
;
1645 if (NS_FAILED(mKey
->SetSymKey(mKeyData
))) {
1646 return NS_ERROR_DOM_OPERATION_ERR
;
1649 mKey
->SetType(CryptoKey::SECRET
);
1651 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
1652 return NS_ERROR_DOM_DATA_ERR
;
1655 mEarlyComplete
= true;
1663 class ImportRsaKeyTask
: public ImportKeyTask
{
1665 ImportRsaKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1666 const nsAString
& aFormat
, const ObjectOrString
& aAlgorithm
,
1667 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
)
1668 : mModulusLength(0) {
1669 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1672 ImportRsaKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1673 const nsAString
& aFormat
, JS::Handle
<JSObject
*> aKeyData
,
1674 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1675 const Sequence
<nsString
>& aKeyUsages
)
1676 : mModulusLength(0) {
1677 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1678 if (NS_FAILED(mEarlyRv
)) {
1682 SetKeyData(aCx
, aKeyData
);
1683 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1684 if (mDataIsJwk
&& !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1685 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1690 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1691 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1692 const Sequence
<nsString
>& aKeyUsages
) {
1693 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1695 if (NS_FAILED(mEarlyRv
)) {
1699 // If this is RSA with a hash, cache the hash name
1700 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
1701 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
1702 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1703 RootedDictionary
<RsaHashedImportParams
> params(aCx
);
1704 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1705 if (NS_FAILED(mEarlyRv
)) {
1706 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1710 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, mHashName
);
1711 if (NS_FAILED(mEarlyRv
)) {
1712 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1717 // Check support for the algorithm and hash names
1718 CK_MECHANISM_TYPE mech1
= MapAlgorithmNameToMechanism(mAlgName
);
1719 CK_MECHANISM_TYPE mech2
= MapAlgorithmNameToMechanism(mHashName
);
1720 if ((mech1
== UNKNOWN_CK_MECHANISM
) || (mech2
== UNKNOWN_CK_MECHANISM
)) {
1721 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1728 uint32_t mModulusLength
;
1729 CryptoBuffer mPublicExponent
;
1731 virtual nsresult
DoCrypto() override
{
1732 // Import the key data itself
1733 UniqueSECKEYPublicKey pubKey
;
1734 UniqueSECKEYPrivateKey privKey
;
1735 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) ||
1736 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1737 !mJwk
.mD
.WasPassed())) {
1738 // Public key import
1739 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1740 pubKey
= CryptoKey::PublicKeyFromSpki(mKeyData
);
1742 pubKey
= CryptoKey::PublicKeyFromJwk(mJwk
);
1746 return NS_ERROR_DOM_DATA_ERR
;
1749 if (NS_FAILED(mKey
->SetPublicKey(pubKey
.get()))) {
1750 return NS_ERROR_DOM_OPERATION_ERR
;
1753 mKey
->SetType(CryptoKey::PUBLIC
);
1754 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) ||
1755 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1756 mJwk
.mD
.WasPassed())) {
1757 // Private key import
1758 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
1759 privKey
= CryptoKey::PrivateKeyFromPkcs8(mKeyData
);
1761 privKey
= CryptoKey::PrivateKeyFromJwk(mJwk
);
1765 return NS_ERROR_DOM_DATA_ERR
;
1768 if (NS_FAILED(mKey
->SetPrivateKey(privKey
.get()))) {
1769 return NS_ERROR_DOM_OPERATION_ERR
;
1772 mKey
->SetType(CryptoKey::PRIVATE
);
1773 pubKey
= UniqueSECKEYPublicKey(SECKEY_ConvertToPublicKey(privKey
.get()));
1775 return NS_ERROR_DOM_UNKNOWN_ERR
;
1778 // Invalid key format
1779 return NS_ERROR_DOM_SYNTAX_ERR
;
1782 if (pubKey
->keyType
!= rsaKey
) {
1783 return NS_ERROR_DOM_DATA_ERR
;
1785 // Extract relevant information from the public key
1786 mModulusLength
= 8 * pubKey
->u
.rsa
.modulus
.len
;
1787 if (!mPublicExponent
.Assign(&pubKey
->u
.rsa
.publicExponent
)) {
1788 return NS_ERROR_DOM_OPERATION_ERR
;
1794 virtual nsresult
AfterCrypto() override
{
1795 // Check permissions for the requested operation
1796 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
1797 if ((mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
1798 mKey
->HasUsageOtherThan(CryptoKey::ENCRYPT
| CryptoKey::WRAPKEY
)) ||
1799 (mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
1800 mKey
->HasUsageOtherThan(CryptoKey::DECRYPT
|
1801 CryptoKey::UNWRAPKEY
))) {
1802 return NS_ERROR_DOM_DATA_ERR
;
1804 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
1805 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1806 if ((mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
1807 mKey
->HasUsageOtherThan(CryptoKey::VERIFY
)) ||
1808 (mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
1809 mKey
->HasUsageOtherThan(CryptoKey::SIGN
))) {
1810 return NS_ERROR_DOM_DATA_ERR
;
1814 if (mKey
->GetKeyType() == CryptoKey::PRIVATE
&& !mKey
->HasAnyUsage()) {
1815 return NS_ERROR_DOM_SYNTAX_ERR
;
1818 // Set an appropriate KeyAlgorithm
1819 if (!mKey
->Algorithm().MakeRsa(mAlgName
, mModulusLength
, mPublicExponent
,
1821 return NS_ERROR_DOM_OPERATION_ERR
;
1824 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
1825 return NS_ERROR_DOM_DATA_ERR
;
1832 class ImportEcKeyTask
: public ImportKeyTask
{
1834 ImportEcKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1835 const nsAString
& aFormat
, const ObjectOrString
& aAlgorithm
,
1836 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
1837 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1840 ImportEcKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1841 const nsAString
& aFormat
, JS::Handle
<JSObject
*> aKeyData
,
1842 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1843 const Sequence
<nsString
>& aKeyUsages
) {
1844 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1845 if (NS_FAILED(mEarlyRv
)) {
1849 SetKeyData(aCx
, aKeyData
);
1850 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1853 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1854 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1855 const Sequence
<nsString
>& aKeyUsages
) {
1856 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1858 if (NS_FAILED(mEarlyRv
)) {
1862 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1863 RootedDictionary
<EcKeyImportParams
> params(aCx
);
1864 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1865 if (NS_FAILED(mEarlyRv
) || !params
.mNamedCurve
.WasPassed()) {
1866 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1870 if (!NormalizeToken(params
.mNamedCurve
.Value(), mNamedCurve
)) {
1871 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1878 nsString mNamedCurve
;
1880 virtual nsresult
DoCrypto() override
{
1881 // Import the key data itself
1882 UniqueSECKEYPublicKey pubKey
;
1883 UniqueSECKEYPrivateKey privKey
;
1885 if ((mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1886 mJwk
.mD
.WasPassed()) ||
1887 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
1888 // Private key import
1889 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1890 privKey
= CryptoKey::PrivateKeyFromJwk(mJwk
);
1892 return NS_ERROR_DOM_DATA_ERR
;
1895 privKey
= CryptoKey::PrivateKeyFromPkcs8(mKeyData
);
1897 return NS_ERROR_DOM_DATA_ERR
;
1900 ScopedAutoSECItem ecParams
;
1901 if (PK11_ReadRawAttribute(PK11_TypePrivKey
, privKey
.get(),
1902 CKA_EC_PARAMS
, &ecParams
) != SECSuccess
) {
1903 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1907 if (!FindOIDTagForEncodedParameters(&ecParams
, &tag
)) {
1908 return NS_ERROR_DOM_DATA_ERR
;
1911 // Find a matching and supported named curve.
1912 if (!MapOIDTagToNamedCurve(tag
, mNamedCurve
)) {
1913 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1917 if (NS_FAILED(mKey
->SetPrivateKey(privKey
.get()))) {
1918 return NS_ERROR_DOM_OPERATION_ERR
;
1921 mKey
->SetType(CryptoKey::PRIVATE
);
1922 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) ||
1923 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) ||
1924 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1925 !mJwk
.mD
.WasPassed())) {
1926 // Public key import
1927 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1928 pubKey
= CryptoKey::PublicECKeyFromRaw(mKeyData
, mNamedCurve
);
1929 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1930 pubKey
= CryptoKey::PublicKeyFromSpki(mKeyData
);
1931 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1932 pubKey
= CryptoKey::PublicKeyFromJwk(mJwk
);
1938 return NS_ERROR_DOM_DATA_ERR
;
1941 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1942 if (pubKey
->keyType
!= ecKey
) {
1943 return NS_ERROR_DOM_DATA_ERR
;
1945 if (!CheckEncodedParameters(&pubKey
->u
.ec
.DEREncodedParams
)) {
1946 return NS_ERROR_DOM_OPERATION_ERR
;
1950 if (!FindOIDTagForEncodedParameters(&pubKey
->u
.ec
.DEREncodedParams
,
1952 return NS_ERROR_DOM_DATA_ERR
;
1955 // Find a matching and supported named curve.
1956 if (!MapOIDTagToNamedCurve(tag
, mNamedCurve
)) {
1957 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1961 if (NS_FAILED(mKey
->SetPublicKey(pubKey
.get()))) {
1962 return NS_ERROR_DOM_OPERATION_ERR
;
1965 mKey
->SetType(CryptoKey::PUBLIC
);
1967 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1970 // Extract 'crv' parameter from JWKs.
1971 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1972 if (!NormalizeToken(mJwk
.mCrv
.Value(), mNamedCurve
)) {
1973 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1979 virtual nsresult
AfterCrypto() override
{
1980 uint32_t privateAllowedUsages
= 0, publicAllowedUsages
= 0;
1981 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
)) {
1982 privateAllowedUsages
= CryptoKey::DERIVEBITS
| CryptoKey::DERIVEKEY
;
1983 publicAllowedUsages
= CryptoKey::DERIVEBITS
| CryptoKey::DERIVEKEY
;
1984 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
1985 privateAllowedUsages
= CryptoKey::SIGN
;
1986 publicAllowedUsages
= CryptoKey::VERIFY
;
1989 // Check permissions for the requested operation
1990 if ((mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
1991 mKey
->HasUsageOtherThan(privateAllowedUsages
)) ||
1992 (mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
1993 mKey
->HasUsageOtherThan(publicAllowedUsages
))) {
1994 return NS_ERROR_DOM_DATA_ERR
;
1997 if (mKey
->GetKeyType() == CryptoKey::PRIVATE
&& !mKey
->HasAnyUsage()) {
1998 return NS_ERROR_DOM_SYNTAX_ERR
;
2001 mKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
2003 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
2004 return NS_ERROR_DOM_DATA_ERR
;
2011 class ImportEdKeyTask
: public ImportKeyTask
{
2013 ImportEdKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2014 const nsAString
& aFormat
, const ObjectOrString
& aAlgorithm
,
2015 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
2016 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
2019 ImportEdKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2020 const nsAString
& aFormat
, JS::Handle
<JSObject
*> aKeyData
,
2021 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
2022 const Sequence
<nsString
>& aKeyUsages
) {
2023 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
2024 if (NS_FAILED(mEarlyRv
)) {
2028 SetKeyData(aCx
, aKeyData
);
2029 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
2032 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
2033 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
2034 const Sequence
<nsString
>& aKeyUsages
) {
2035 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
2037 if (NS_FAILED(mEarlyRv
)) {
2041 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
2042 RootedDictionary
<Algorithm
> params(aCx
);
2043 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2044 if (NS_FAILED(mEarlyRv
)) {
2045 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2050 if (!NormalizeToken(params
.mName
, algName
)) {
2051 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2055 // Construct an appropriate KeyAlgorithm
2056 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
2057 mNamedCurve
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_ED25519
);
2059 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2066 nsString mNamedCurve
;
2068 virtual nsresult
DoCrypto() override
{
2069 // Import the key data itself
2070 UniqueSECKEYPublicKey pubKey
;
2071 UniqueSECKEYPrivateKey privKey
;
2073 if ((mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
2074 mJwk
.mD
.WasPassed()) ||
2075 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
2076 // Private key import
2077 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2078 privKey
= CryptoKey::PrivateKeyFromJwk(mJwk
);
2080 return NS_ERROR_DOM_DATA_ERR
;
2083 privKey
= CryptoKey::PrivateKeyFromPkcs8(mKeyData
);
2085 return NS_ERROR_DOM_DATA_ERR
;
2088 ScopedAutoSECItem ecParams
;
2089 if (PK11_ReadRawAttribute(PK11_TypePrivKey
, privKey
.get(),
2090 CKA_EC_PARAMS
, &ecParams
) != SECSuccess
) {
2091 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2095 if (!FindOIDTagForEncodedParameters(&ecParams
, &tag
)) {
2096 return NS_ERROR_DOM_DATA_ERR
;
2099 // Find a matching and supported named curve.
2100 if (!MapOIDTagToNamedCurve(tag
, mNamedCurve
)) {
2101 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2105 if (NS_FAILED(mKey
->SetPrivateKey(privKey
.get()))) {
2106 return NS_ERROR_DOM_OPERATION_ERR
;
2109 mKey
->SetType(CryptoKey::PRIVATE
);
2110 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) ||
2111 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) ||
2112 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
2113 !mJwk
.mD
.WasPassed())) {
2114 // Public key import
2115 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
2116 pubKey
= CryptoKey::PublicEDKeyFromRaw(mKeyData
, mNamedCurve
);
2117 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
2118 pubKey
= CryptoKey::PublicKeyFromSpki(mKeyData
);
2119 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2120 pubKey
= CryptoKey::PublicKeyFromJwk(mJwk
);
2126 return NS_ERROR_DOM_DATA_ERR
;
2129 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
2130 if (pubKey
->keyType
!= edKey
) {
2131 return NS_ERROR_DOM_DATA_ERR
;
2133 if (!CheckEncodedParameters(&pubKey
->u
.ec
.DEREncodedParams
)) {
2134 return NS_ERROR_DOM_OPERATION_ERR
;
2138 if (!FindOIDTagForEncodedParameters(&pubKey
->u
.ec
.DEREncodedParams
,
2140 return NS_ERROR_DOM_OPERATION_ERR
;
2143 // Find a matching and supported named curve.
2144 if (!MapOIDTagToNamedCurve(tag
, mNamedCurve
)) {
2145 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2149 if (NS_FAILED(mKey
->SetPublicKey(pubKey
.get()))) {
2150 return NS_ERROR_DOM_OPERATION_ERR
;
2153 mKey
->SetType(CryptoKey::PUBLIC
);
2155 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2158 // Extract 'crv' parameter from JWKs.
2159 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2160 if (!NormalizeToken(mJwk
.mCrv
.Value(), mNamedCurve
)) {
2161 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2168 virtual nsresult
AfterCrypto() override
{
2169 // Only Ed25519 is supported.
2170 uint32_t privateAllowedUsages
= CryptoKey::SIGN
;
2171 uint32_t publicAllowedUsages
= CryptoKey::VERIFY
;
2173 // Check permissions for the requested operation
2174 if ((mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
2175 mKey
->HasUsageOtherThan(publicAllowedUsages
))) {
2176 return NS_ERROR_DOM_SYNTAX_ERR
;
2179 if ((mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
2180 mKey
->HasUsageOtherThan(privateAllowedUsages
))) {
2181 return NS_ERROR_DOM_SYNTAX_ERR
;
2184 if (mKey
->GetKeyType() == CryptoKey::PRIVATE
&& !mKey
->HasAnyUsage()) {
2185 return NS_ERROR_DOM_SYNTAX_ERR
;
2188 mKey
->Algorithm().MakeEd(mAlgName
);
2190 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
2191 return NS_ERROR_DOM_DATA_ERR
;
2198 class ExportKeyTask
: public WebCryptoTask
{
2200 ExportKeyTask(const nsAString
& aFormat
, CryptoKey
& aKey
)
2202 mPrivateKey(aKey
.GetPrivateKey()),
2203 mPublicKey(aKey
.GetPublicKey()),
2204 mKeyType(aKey
.GetKeyType()),
2205 mExtractable(aKey
.Extractable()),
2206 mAlg(aKey
.Algorithm().JwkAlg()) {
2207 aKey
.GetUsages(mKeyUsages
);
2209 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
2210 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
2217 CryptoBuffer mSymKey
;
2218 UniqueSECKEYPrivateKey mPrivateKey
;
2219 UniqueSECKEYPublicKey mPublicKey
;
2220 CryptoKey::KeyType mKeyType
;
2223 nsTArray
<nsString
> mKeyUsages
;
2224 CryptoBuffer mResult
;
2228 virtual nsresult
DoCrypto() override
{
2229 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
2230 if (mPublicKey
&& mPublicKey
->keyType
== dhKey
) {
2231 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2235 (mPublicKey
->keyType
== ecKey
|| mPublicKey
->keyType
== edKey
)) {
2236 nsresult rv
= CryptoKey::PublicECKeyToRaw(mPublicKey
.get(), mResult
);
2237 if (NS_FAILED(rv
)) {
2238 return NS_ERROR_DOM_OPERATION_ERR
;
2243 if (!mResult
.Assign(mSymKey
)) {
2244 return NS_ERROR_OUT_OF_MEMORY
;
2246 if (mResult
.Length() == 0) {
2247 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2251 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
2253 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2256 switch (mPrivateKey
->keyType
) {
2261 CryptoKey::PrivateKeyToPkcs8(mPrivateKey
.get(), mResult
);
2262 if (NS_FAILED(rv
)) {
2263 return NS_ERROR_DOM_OPERATION_ERR
;
2268 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2270 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
2272 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2275 return CryptoKey::PublicKeyToSpki(mPublicKey
.get(), mResult
);
2276 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2277 if (mKeyType
== CryptoKey::SECRET
) {
2279 nsresult rv
= mSymKey
.ToJwkBase64(k
);
2280 if (NS_FAILED(rv
)) {
2281 return NS_ERROR_DOM_OPERATION_ERR
;
2283 mJwk
.mK
.Construct(k
);
2284 mJwk
.mKty
= NS_LITERAL_STRING_FROM_CSTRING(JWK_TYPE_SYMMETRIC
);
2285 } else if (mKeyType
== CryptoKey::PUBLIC
) {
2287 return NS_ERROR_DOM_UNKNOWN_ERR
;
2290 nsresult rv
= CryptoKey::PublicKeyToJwk(mPublicKey
.get(), mJwk
);
2291 if (NS_FAILED(rv
)) {
2292 return NS_ERROR_DOM_OPERATION_ERR
;
2294 } else if (mKeyType
== CryptoKey::PRIVATE
) {
2296 return NS_ERROR_DOM_UNKNOWN_ERR
;
2299 nsresult rv
= CryptoKey::PrivateKeyToJwk(mPrivateKey
.get(), mJwk
);
2300 if (NS_FAILED(rv
)) {
2301 return NS_ERROR_DOM_OPERATION_ERR
;
2305 if (!mAlg
.IsEmpty()) {
2306 mJwk
.mAlg
.Construct(mAlg
);
2309 mJwk
.mExt
.Construct(mExtractable
);
2311 mJwk
.mKey_ops
.Construct();
2312 if (!mJwk
.mKey_ops
.Value().AppendElements(mKeyUsages
, fallible
)) {
2313 return NS_ERROR_OUT_OF_MEMORY
;
2319 return NS_ERROR_DOM_SYNTAX_ERR
;
2322 // Returns mResult as an ArrayBufferView or JWK, as appropriate
2323 virtual void Resolve() override
{
2324 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2325 mResultPromise
->MaybeResolve(mJwk
);
2329 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
2330 mResultPromise
->MaybeResolve(ret
);
2334 class GenerateSymmetricKeyTask
: public WebCryptoTask
{
2336 GenerateSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2337 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
2338 const Sequence
<nsString
>& aKeyUsages
) {
2339 // Create an empty key and set easy attributes
2340 mKey
= new CryptoKey(aGlobal
);
2341 mKey
->SetExtractable(aExtractable
);
2342 mKey
->SetType(CryptoKey::SECRET
);
2344 // Extract algorithm name
2346 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
2347 if (NS_FAILED(mEarlyRv
)) {
2351 // Construct an appropriate KeyAlorithm
2352 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
2353 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
2354 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
2355 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
2356 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aAlgorithm
, mLength
);
2357 if (NS_FAILED(mEarlyRv
)) {
2360 mKey
->Algorithm().MakeAes(algName
, mLength
);
2362 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
2363 RootedDictionary
<HmacKeyGenParams
> params(aCx
);
2364 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2365 if (NS_FAILED(mEarlyRv
)) {
2366 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2371 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2372 if (NS_FAILED(mEarlyRv
)) {
2376 if (params
.mLength
.WasPassed()) {
2377 mLength
= params
.mLength
.Value();
2379 mLength
= MapHashAlgorithmNameToBlockSize(hashName
);
2383 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
2387 mKey
->Algorithm().MakeHmac(mLength
, hashName
);
2389 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2394 mKey
->ClearUsages();
2395 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
2396 mEarlyRv
= mKey
->AddAllowedUsageIntersecting(aKeyUsages
[i
], algName
);
2397 if (NS_FAILED(mEarlyRv
)) {
2401 if (!mKey
->HasAnyUsage()) {
2402 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2406 mLength
= mLength
>> 3; // bits to bytes
2407 mMechanism
= mKey
->Algorithm().Mechanism();
2408 // SetSymKey done in Resolve, after we've done the keygen
2412 RefPtr
<CryptoKey
> mKey
;
2414 CK_MECHANISM_TYPE mMechanism
;
2415 CryptoBuffer mKeyData
;
2417 virtual nsresult
DoCrypto() override
{
2418 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2419 MOZ_ASSERT(slot
.get());
2421 UniquePK11SymKey
symKey(
2422 PK11_KeyGen(slot
.get(), mMechanism
, nullptr, mLength
, nullptr));
2424 return NS_ERROR_DOM_UNKNOWN_ERR
;
2427 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2428 if (NS_FAILED(rv
)) {
2429 return NS_ERROR_DOM_UNKNOWN_ERR
;
2432 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2433 // just refers to a buffer managed by symKey. The assignment copies the
2434 // data, so mKeyData manages one copy, while symKey manages another.
2435 ATTEMPT_BUFFER_ASSIGN(mKeyData
, PK11_GetKeyData(symKey
.get()));
2439 virtual void Resolve() override
{
2440 if (NS_SUCCEEDED(mKey
->SetSymKey(mKeyData
))) {
2441 mResultPromise
->MaybeResolve(mKey
);
2443 mResultPromise
->MaybeReject(NS_ERROR_DOM_OPERATION_ERR
);
2447 virtual void Cleanup() override
{ mKey
= nullptr; }
2450 GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
2451 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2452 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
)
2453 : mKeyPair(new CryptoKeyPair()),
2454 mMechanism(CKM_INVALID_MECHANISM
),
2457 mArena
= UniquePLArenaPool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
2459 mEarlyRv
= NS_ERROR_DOM_UNKNOWN_ERR
;
2463 // Create an empty key pair and set easy attributes
2464 mKeyPair
->mPrivateKey
= new CryptoKey(aGlobal
);
2465 mKeyPair
->mPublicKey
= new CryptoKey(aGlobal
);
2467 // Extract algorithm name
2468 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, mAlgName
);
2469 if (NS_FAILED(mEarlyRv
)) {
2473 // Construct an appropriate KeyAlorithm
2474 uint32_t privateAllowedUsages
= 0, publicAllowedUsages
= 0;
2475 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2476 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
2477 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
2478 RootedDictionary
<RsaHashedKeyGenParams
> params(aCx
);
2479 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2480 if (NS_FAILED(mEarlyRv
)) {
2481 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2485 // Pull relevant info
2486 uint32_t modulusLength
= params
.mModulusLength
;
2487 CryptoBuffer publicExponent
;
2488 ATTEMPT_BUFFER_INIT(publicExponent
, params
.mPublicExponent
);
2490 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2491 if (NS_FAILED(mEarlyRv
)) {
2496 if (!mKeyPair
->mPublicKey
->Algorithm().MakeRsa(mAlgName
, modulusLength
,
2497 publicExponent
, hashName
)) {
2498 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2501 if (!mKeyPair
->mPrivateKey
->Algorithm().MakeRsa(mAlgName
, modulusLength
,
2502 publicExponent
, hashName
)) {
2503 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2506 mMechanism
= CKM_RSA_PKCS_KEY_PAIR_GEN
;
2508 // Set up params struct
2509 mRsaParams
.keySizeInBits
= modulusLength
;
2510 bool converted
= publicExponent
.GetBigIntValue(mRsaParams
.pe
);
2512 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2515 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
2516 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
2517 RootedDictionary
<EcKeyGenParams
> params(aCx
);
2518 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2519 if (NS_FAILED(mEarlyRv
)) {
2520 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2524 if (!NormalizeToken(params
.mNamedCurve
, mNamedCurve
)) {
2525 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2529 // Create algorithm.
2530 mKeyPair
->mPublicKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
2531 mKeyPair
->mPrivateKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
2532 mMechanism
= CKM_EC_KEY_PAIR_GEN
;
2535 else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
2536 mKeyPair
->mPublicKey
->Algorithm().MakeEd(mAlgName
);
2537 mKeyPair
->mPrivateKey
->Algorithm().MakeEd(mAlgName
);
2538 mMechanism
= CKM_EC_EDWARDS_KEY_PAIR_GEN
;
2539 mNamedCurve
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_ED25519
);
2543 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2548 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2549 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
2550 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
) ||
2551 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)
2554 privateAllowedUsages
= CryptoKey::SIGN
;
2555 publicAllowedUsages
= CryptoKey::VERIFY
;
2556 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
2557 privateAllowedUsages
= CryptoKey::DECRYPT
| CryptoKey::UNWRAPKEY
;
2558 publicAllowedUsages
= CryptoKey::ENCRYPT
| CryptoKey::WRAPKEY
;
2559 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
)) {
2560 privateAllowedUsages
= CryptoKey::DERIVEKEY
| CryptoKey::DERIVEBITS
;
2561 publicAllowedUsages
= 0;
2563 MOZ_ASSERT(false); // This shouldn't happen.
2566 mKeyPair
->mPrivateKey
->SetExtractable(aExtractable
);
2567 mKeyPair
->mPrivateKey
->SetType(CryptoKey::PRIVATE
);
2569 mKeyPair
->mPublicKey
->SetExtractable(true);
2570 mKeyPair
->mPublicKey
->SetType(CryptoKey::PUBLIC
);
2572 mKeyPair
->mPrivateKey
->ClearUsages();
2573 mKeyPair
->mPublicKey
->ClearUsages();
2574 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
2575 mEarlyRv
= mKeyPair
->mPrivateKey
->AddAllowedUsageIntersecting(
2576 aKeyUsages
[i
], mAlgName
, privateAllowedUsages
);
2577 if (NS_FAILED(mEarlyRv
)) {
2581 mEarlyRv
= mKeyPair
->mPublicKey
->AddAllowedUsageIntersecting(
2582 aKeyUsages
[i
], mAlgName
, publicAllowedUsages
);
2583 if (NS_FAILED(mEarlyRv
)) {
2589 nsresult
GenerateAsymmetricKeyTask::DoCrypto() {
2590 MOZ_ASSERT(mKeyPair
);
2592 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2593 MOZ_ASSERT(slot
.get());
2596 switch (mMechanism
) {
2597 case CKM_RSA_PKCS_KEY_PAIR_GEN
:
2598 param
= &mRsaParams
;
2600 case CKM_DH_PKCS_KEY_PAIR_GEN
:
2603 case CKM_EC_EDWARDS_KEY_PAIR_GEN
:
2604 case CKM_EC_KEY_PAIR_GEN
: {
2605 param
= CreateECParamsForCurve(mNamedCurve
, mArena
.get());
2607 return NS_ERROR_DOM_UNKNOWN_ERR
;
2612 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2615 mPrivateKey
= UniqueSECKEYPrivateKey(PK11_GenerateKeyPair(
2616 slot
.get(), mMechanism
, param
, TempPtrToSetter(&mPublicKey
), PR_FALSE
,
2617 PR_FALSE
, nullptr));
2619 if (!mPrivateKey
.get() || !mPublicKey
.get()) {
2620 return NS_ERROR_DOM_OPERATION_ERR
;
2623 // If no usages ended up being allowed, SyntaxError
2624 if (!mKeyPair
->mPrivateKey
->HasAnyUsage()) {
2625 return NS_ERROR_DOM_SYNTAX_ERR
;
2628 nsresult rv
= mKeyPair
->mPrivateKey
->SetPrivateKey(mPrivateKey
.get());
2629 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2630 rv
= mKeyPair
->mPublicKey
->SetPublicKey(mPublicKey
.get());
2631 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2632 // PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the
2633 // private key, we need this later when exporting to PKCS8 and JWK though.
2634 if (mMechanism
== CKM_EC_KEY_PAIR_GEN
||
2635 mMechanism
== CKM_EC_EDWARDS_KEY_PAIR_GEN
) {
2636 rv
= mKeyPair
->mPrivateKey
->AddPublicKeyData(mPublicKey
.get());
2637 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2643 void GenerateAsymmetricKeyTask::Resolve() {
2644 mResultPromise
->MaybeResolve(*mKeyPair
);
2647 void GenerateAsymmetricKeyTask::Cleanup() { mKeyPair
= nullptr; }
2649 class DeriveHkdfBitsTask
: public ReturnArrayBufferViewTask
{
2651 DeriveHkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2652 CryptoKey
& aKey
, uint32_t aLength
)
2653 : mMechanism(CKM_INVALID_MECHANISM
) {
2654 Init(aCx
, aAlgorithm
, aKey
, aLength
);
2657 DeriveHkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2658 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2659 : mLengthInBits(0), mLengthInBytes(0), mMechanism(CKM_INVALID_MECHANISM
) {
2661 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aTargetAlgorithm
, length
);
2663 if (NS_SUCCEEDED(mEarlyRv
)) {
2664 Init(aCx
, aAlgorithm
, aKey
, length
);
2668 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
2670 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_HKDF
);
2671 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_HKDF
);
2673 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
2674 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
2678 RootedDictionary
<HkdfParams
> params(aCx
);
2679 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2680 if (NS_FAILED(mEarlyRv
)) {
2681 mEarlyRv
= NS_ERROR_DOM_TYPE_MISMATCH_ERR
;
2685 // length must be greater than zero.
2687 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2691 // Extract the hash algorithm.
2693 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2694 if (NS_FAILED(mEarlyRv
)) {
2698 // Check the given hash algorithm.
2699 switch (MapAlgorithmNameToMechanism(hashName
)) {
2701 mMechanism
= CKM_NSS_HKDF_SHA1
;
2704 mMechanism
= CKM_NSS_HKDF_SHA256
;
2707 mMechanism
= CKM_NSS_HKDF_SHA384
;
2710 mMechanism
= CKM_NSS_HKDF_SHA512
;
2713 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2717 ATTEMPT_BUFFER_INIT(mSalt
, params
.mSalt
)
2718 ATTEMPT_BUFFER_INIT(mInfo
, params
.mInfo
)
2719 mLengthInBytes
= ceil((double)aLength
/ 8);
2720 mLengthInBits
= aLength
;
2724 size_t mLengthInBits
;
2725 size_t mLengthInBytes
;
2728 CryptoBuffer mSymKey
;
2729 CK_MECHANISM_TYPE mMechanism
;
2731 virtual nsresult
DoCrypto() override
{
2732 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
2734 return NS_ERROR_DOM_OPERATION_ERR
;
2738 SECItem keyItem
= {siBuffer
, nullptr, 0};
2739 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
2741 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2743 return NS_ERROR_DOM_OPERATION_ERR
;
2746 UniquePK11SymKey
baseKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
2747 PK11_OriginUnwrap
, CKA_WRAP
,
2748 &keyItem
, nullptr));
2750 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2753 SECItem salt
= {siBuffer
, nullptr, 0};
2754 SECItem info
= {siBuffer
, nullptr, 0};
2755 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &salt
, mSalt
);
2756 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &info
, mInfo
);
2758 CK_NSS_HKDFParams hkdfParams
= {true, salt
.data
, salt
.len
,
2759 true, info
.data
, info
.len
};
2760 SECItem params
= {siBuffer
, (unsigned char*)&hkdfParams
,
2761 sizeof(hkdfParams
)};
2763 // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
2764 // derived symmetric key and don't matter because we ignore them anyway.
2765 UniquePK11SymKey
symKey(PK11_Derive(baseKey
.get(), mMechanism
, ¶ms
,
2766 CKM_SHA512_HMAC
, CKA_SIGN
,
2769 if (!symKey
.get()) {
2770 return NS_ERROR_DOM_OPERATION_ERR
;
2773 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2774 if (NS_FAILED(rv
)) {
2775 return NS_ERROR_DOM_OPERATION_ERR
;
2778 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2779 // just refers to a buffer managed by symKey. The assignment copies the
2780 // data, so mResult manages one copy, while symKey manages another.
2781 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
2783 if (mLengthInBytes
> mResult
.Length()) {
2784 return NS_ERROR_DOM_DATA_ERR
;
2787 if (!mResult
.SetLength(mLengthInBytes
, fallible
)) {
2788 return NS_ERROR_DOM_UNKNOWN_ERR
;
2791 // If the number of bits to derive is not a multiple of 8 we need to
2792 // zero out the remaining bits that were derived but not requested.
2793 if (mLengthInBits
% 8) {
2794 mResult
[mResult
.Length() - 1] &= 0xff << (mLengthInBits
% 8);
2801 class DerivePbkdfBitsTask
: public ReturnArrayBufferViewTask
{
2803 DerivePbkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2804 CryptoKey
& aKey
, uint32_t aLength
)
2805 : mHashOidTag(SEC_OID_UNKNOWN
) {
2806 Init(aCx
, aAlgorithm
, aKey
, aLength
);
2809 DerivePbkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2810 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2811 : mLength(0), mIterations(0), mHashOidTag(SEC_OID_UNKNOWN
) {
2813 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aTargetAlgorithm
, length
);
2815 if (NS_SUCCEEDED(mEarlyRv
)) {
2816 Init(aCx
, aAlgorithm
, aKey
, length
);
2820 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
2822 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_PBKDF2
);
2823 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_PBKDF2
);
2825 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
2826 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
2830 RootedDictionary
<Pbkdf2Params
> params(aCx
);
2831 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2832 if (NS_FAILED(mEarlyRv
)) {
2833 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2837 // length must be a multiple of 8 bigger than zero.
2838 if (aLength
== 0 || aLength
% 8) {
2839 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2843 // Extract the hash algorithm.
2845 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2846 if (NS_FAILED(mEarlyRv
)) {
2850 // Check the given hash algorithm.
2851 switch (MapAlgorithmNameToMechanism(hashName
)) {
2853 mHashOidTag
= SEC_OID_HMAC_SHA1
;
2856 mHashOidTag
= SEC_OID_HMAC_SHA256
;
2859 mHashOidTag
= SEC_OID_HMAC_SHA384
;
2862 mHashOidTag
= SEC_OID_HMAC_SHA512
;
2865 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2869 ATTEMPT_BUFFER_INIT(mSalt
, params
.mSalt
)
2870 mLength
= aLength
>> 3; // bits to bytes
2871 mIterations
= params
.mIterations
;
2878 CryptoBuffer mSymKey
;
2879 SECOidTag mHashOidTag
;
2881 virtual nsresult
DoCrypto() override
{
2882 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
2884 return NS_ERROR_DOM_OPERATION_ERR
;
2887 SECItem salt
= {siBuffer
, nullptr, 0};
2888 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &salt
, mSalt
);
2889 // PK11_CreatePBEV2AlgorithmID will "helpfully" create PBKDF2 parameters
2890 // with a random salt if given a SECItem* that is either null or has a null
2891 // data pointer. This obviously isn't what we want, so we have to fake it
2892 // out by passing in a SECItem* with a non-null data pointer but with zero
2895 MOZ_ASSERT(salt
.len
== 0);
2897 reinterpret_cast<unsigned char*>(PORT_ArenaAlloc(arena
.get(), 1));
2899 return NS_ERROR_DOM_UNKNOWN_ERR
;
2903 // Always pass in cipherAlg=SEC_OID_HMAC_SHA1 (i.e. PBMAC1) as this
2904 // parameter is unused for key generation. It is currently only used
2905 // for PBKDF2 authentication or key (un)wrapping when specifying an
2906 // encryption algorithm (PBES2).
2907 UniqueSECAlgorithmID
algID(
2908 PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2
, SEC_OID_HMAC_SHA1
,
2909 mHashOidTag
, mLength
, mIterations
, &salt
));
2912 return NS_ERROR_DOM_OPERATION_ERR
;
2915 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2917 return NS_ERROR_DOM_OPERATION_ERR
;
2920 SECItem keyItem
= {siBuffer
, nullptr, 0};
2921 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
2923 UniquePK11SymKey
symKey(
2924 PK11_PBEKeyGen(slot
.get(), algID
.get(), &keyItem
, false, nullptr));
2925 if (!symKey
.get()) {
2926 return NS_ERROR_DOM_OPERATION_ERR
;
2929 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2930 if (NS_FAILED(rv
)) {
2931 return NS_ERROR_DOM_OPERATION_ERR
;
2934 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2935 // just refers to a buffer managed by symKey. The assignment copies the
2936 // data, so mResult manages one copy, while symKey manages another.
2937 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
2942 template <class DeriveBitsTask
>
2943 class DeriveKeyTask
: public DeriveBitsTask
{
2945 DeriveKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2946 const ObjectOrString
& aAlgorithm
, CryptoKey
& aBaseKey
,
2947 const ObjectOrString
& aDerivedKeyType
, bool aExtractable
,
2948 const Sequence
<nsString
>& aKeyUsages
)
2949 : DeriveBitsTask(aCx
, aAlgorithm
, aBaseKey
, aDerivedKeyType
) {
2950 if (NS_FAILED(this->mEarlyRv
)) {
2954 constexpr auto format
=
2955 NS_LITERAL_STRING_FROM_CSTRING(WEBCRYPTO_KEY_FORMAT_RAW
);
2956 mTask
= new ImportSymmetricKeyTask(aGlobal
, aCx
, format
, aDerivedKeyType
,
2957 aExtractable
, aKeyUsages
);
2961 RefPtr
<ImportSymmetricKeyTask
> mTask
;
2964 virtual void Resolve() override
{
2965 mTask
->SetRawKeyData(this->mResult
);
2966 mTask
->DispatchWithPromise(this->mResultPromise
);
2969 virtual void Cleanup() override
{ mTask
= nullptr; }
2971 class DeriveEcdhBitsTask
: public ReturnArrayBufferViewTask
{
2973 DeriveEcdhBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2974 CryptoKey
& aKey
, uint32_t aLength
)
2975 : mLength(Some(aLength
)), mPrivKey(aKey
.GetPrivateKey()) {
2976 Init(aCx
, aAlgorithm
, aKey
);
2979 DeriveEcdhBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2980 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2981 : mPrivKey(aKey
.GetPrivateKey()) {
2983 GetKeyLengthForAlgorithmIfSpecified(aCx
, aTargetAlgorithm
, mLength
);
2984 if (NS_SUCCEEDED(mEarlyRv
)) {
2985 Init(aCx
, aAlgorithm
, aKey
);
2989 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
) {
2990 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_ECDH
);
2991 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_ECDH
);
2993 // Check that we have a private key.
2995 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2999 // If specified, length must be a multiple of 8 bigger than zero
3000 // (otherwise, the full output of the key derivation is used).
3002 if (*mLength
== 0 || *mLength
% 8) {
3003 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
3006 *mLength
= *mLength
>> 3; // bits to bytes
3009 // Retrieve the peer's public key.
3010 RootedDictionary
<EcdhKeyDeriveParams
> params(aCx
);
3011 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
3012 if (NS_FAILED(mEarlyRv
)) {
3013 /* The returned code is installed by Coerce function. */
3017 CryptoKey
* publicKey
= params
.mPublic
;
3018 mPubKey
= publicKey
->GetPublicKey();
3020 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
3024 CHECK_KEY_ALGORITHM(publicKey
->Algorithm(), WEBCRYPTO_ALG_ECDH
);
3026 // Both keys must use the same named curve.
3027 nsString curve1
= aKey
.Algorithm().mEc
.mNamedCurve
;
3028 nsString curve2
= publicKey
->Algorithm().mEc
.mNamedCurve
;
3030 if (!curve1
.Equals(curve2
)) {
3031 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
3037 Maybe
<size_t> mLength
;
3038 UniqueSECKEYPrivateKey mPrivKey
;
3039 UniqueSECKEYPublicKey mPubKey
;
3041 virtual nsresult
DoCrypto() override
{
3042 // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
3043 // derived symmetric key and don't matter because we ignore them anyway.
3044 UniquePK11SymKey
symKey(
3045 PK11_PubDeriveWithKDF(mPrivKey
.get(), mPubKey
.get(), PR_FALSE
, nullptr,
3046 nullptr, CKM_ECDH1_DERIVE
, CKM_SHA512_HMAC
,
3047 CKA_SIGN
, 0, CKD_NULL
, nullptr, nullptr));
3049 if (!symKey
.get()) {
3050 return NS_ERROR_DOM_OPERATION_ERR
;
3053 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
3054 if (NS_FAILED(rv
)) {
3055 return NS_ERROR_DOM_OPERATION_ERR
;
3058 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
3059 // just refers to a buffer managed by symKey. The assignment copies the
3060 // data, so mResult manages one copy, while symKey manages another.
3061 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
3064 if (*mLength
> mResult
.Length()) {
3065 return NS_ERROR_DOM_OPERATION_ERR
;
3067 if (!mResult
.SetLength(*mLength
, fallible
)) {
3068 return NS_ERROR_DOM_UNKNOWN_ERR
;
3076 template <class KeyEncryptTask
>
3077 class WrapKeyTask
: public ExportKeyTask
{
3079 WrapKeyTask(JSContext
* aCx
, const nsAString
& aFormat
, CryptoKey
& aKey
,
3080 CryptoKey
& aWrappingKey
, const ObjectOrString
& aWrapAlgorithm
)
3081 : ExportKeyTask(aFormat
, aKey
) {
3082 if (NS_FAILED(mEarlyRv
)) {
3086 mTask
= new KeyEncryptTask(aCx
, aWrapAlgorithm
, aWrappingKey
, true);
3090 RefPtr
<KeyEncryptTask
> mTask
;
3092 virtual nsresult
AfterCrypto() override
{
3093 // If wrapping JWK, stringify the JSON
3094 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
3096 if (!mJwk
.ToJSON(json
)) {
3097 return NS_ERROR_DOM_OPERATION_ERR
;
3100 NS_ConvertUTF16toUTF8
utf8(json
);
3101 if (!mResult
.Assign((const uint8_t*)utf8
.BeginReading(), utf8
.Length())) {
3102 return NS_ERROR_DOM_OPERATION_ERR
;
3109 virtual void Resolve() override
{
3110 mTask
->SetData(mResult
);
3111 mTask
->DispatchWithPromise(mResultPromise
);
3114 virtual void Cleanup() override
{ mTask
= nullptr; }
3117 template <class KeyEncryptTask
>
3118 class UnwrapKeyTask
: public KeyEncryptTask
{
3120 UnwrapKeyTask(JSContext
* aCx
, const ArrayBufferViewOrArrayBuffer
& aWrappedKey
,
3121 CryptoKey
& aUnwrappingKey
,
3122 const ObjectOrString
& aUnwrapAlgorithm
, ImportKeyTask
* aTask
)
3123 : KeyEncryptTask(aCx
, aUnwrapAlgorithm
, aUnwrappingKey
, aWrappedKey
,
3128 RefPtr
<ImportKeyTask
> mTask
;
3130 virtual void Resolve() override
{
3131 mTask
->SetKeyDataMaybeParseJWK(KeyEncryptTask::mResult
);
3132 mTask
->DispatchWithPromise(KeyEncryptTask::mResultPromise
);
3135 virtual void Cleanup() override
{ mTask
= nullptr; }
3138 // Task creation methods for WebCryptoTask
3140 // Note: We do not perform algorithm normalization as a monolithic process,
3141 // as described in the spec. Instead:
3142 // * Each method handles its slice of the supportedAlgorithms structure
3143 // * Task constructors take care of:
3144 // * Coercing the algorithm to the proper concrete type
3145 // * Cloning subordinate data items
3146 // * Cloning input data as needed
3148 // Thus, support for different algorithms is determined by the if-statements
3149 // below, rather than a data structure.
3151 // This results in algorithm normalization coming after some other checks,
3152 // and thus slightly more steps being done synchronously than the spec calls
3153 // for. But none of these steps is especially time-consuming.
3155 WebCryptoTask
* WebCryptoTask::CreateEncryptDecryptTask(
3156 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
3157 const CryptoOperationData
& aData
, bool aEncrypt
) {
3158 TelemetryMethod method
= (aEncrypt
) ? TM_ENCRYPT
: TM_DECRYPT
;
3159 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, method
);
3160 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_ENC
,
3161 aKey
.Extractable());
3163 // Ensure key is usable for this operation
3164 if ((aEncrypt
&& !aKey
.HasUsage(CryptoKey::ENCRYPT
)) ||
3165 (!aEncrypt
&& !aKey
.HasUsage(CryptoKey::DECRYPT
))) {
3166 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3170 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3171 if (NS_FAILED(rv
)) {
3172 return new FailureTask(rv
);
3175 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3176 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3177 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
3178 return new AesTask(aCx
, aAlgorithm
, aKey
, aData
, aEncrypt
);
3179 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
3180 return new RsaOaepTask(aCx
, aAlgorithm
, aKey
, aData
, aEncrypt
);
3183 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3186 WebCryptoTask
* WebCryptoTask::CreateSignVerifyTask(
3187 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
3188 const CryptoOperationData
& aSignature
, const CryptoOperationData
& aData
,
3190 TelemetryMethod method
= (aSign
) ? TM_SIGN
: TM_VERIFY
;
3191 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, method
);
3192 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_SIG
,
3193 aKey
.Extractable());
3195 // Ensure key is usable for this operation
3196 if ((aSign
&& !aKey
.HasUsage(CryptoKey::SIGN
)) ||
3197 (!aSign
&& !aKey
.HasUsage(CryptoKey::VERIFY
))) {
3198 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3202 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3203 if (NS_FAILED(rv
)) {
3204 return new FailureTask(rv
);
3207 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
3208 return new HmacTask(aCx
, aAlgorithm
, aKey
, aSignature
, aData
, aSign
);
3209 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3210 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
3211 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
) ||
3212 algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
3213 return new AsymmetricSignVerifyTask(aCx
, aAlgorithm
, aKey
, aSignature
,
3217 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3220 WebCryptoTask
* WebCryptoTask::CreateDigestTask(
3221 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3222 const CryptoOperationData
& aData
) {
3223 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DIGEST
);
3226 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3227 if (NS_FAILED(rv
)) {
3228 return new FailureTask(rv
);
3231 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
) ||
3232 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
) ||
3233 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
) ||
3234 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
3235 return new DigestTask(aCx
, aAlgorithm
, aData
);
3238 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3241 WebCryptoTask
* WebCryptoTask::CreateImportKeyTask(
3242 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
3243 JS::Handle
<JSObject
*> aKeyData
, const ObjectOrString
& aAlgorithm
,
3244 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
3245 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_IMPORTKEY
);
3246 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT
, aExtractable
);
3248 // Verify that the format is recognized
3249 if (!aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) &&
3250 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) &&
3251 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) &&
3252 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
3253 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3256 // Verify that aKeyUsages does not contain an unrecognized value
3257 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3258 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3262 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3263 if (NS_FAILED(rv
)) {
3264 return new FailureTask(rv
);
3267 // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation.
3268 // However, the spec should be updated to allow it.
3269 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3270 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3271 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
3272 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) ||
3273 algName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
) ||
3274 algName
.EqualsLiteral(WEBCRYPTO_ALG_HKDF
) ||
3275 algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
3276 return new ImportSymmetricKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
,
3277 aAlgorithm
, aExtractable
, aKeyUsages
);
3278 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3279 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
3280 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
3281 return new ImportRsaKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
, aAlgorithm
,
3282 aExtractable
, aKeyUsages
);
3283 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
3284 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
3285 return new ImportEcKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
, aAlgorithm
,
3286 aExtractable
, aKeyUsages
);
3287 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
3288 return new ImportEdKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
, aAlgorithm
,
3289 aExtractable
, aKeyUsages
);
3291 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3295 WebCryptoTask
* WebCryptoTask::CreateExportKeyTask(const nsAString
& aFormat
,
3297 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_EXPORTKEY
);
3299 // Verify that the format is recognized
3300 if (!aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) &&
3301 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) &&
3302 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) &&
3303 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
3304 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3307 // Verify that the key is extractable
3308 if (!aKey
.Extractable()) {
3309 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3312 // Verify that the algorithm supports export
3313 // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation.
3314 // However, the spec should be updated to allow it.
3315 nsString algName
= aKey
.Algorithm().mName
;
3316 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3317 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3318 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
3319 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) ||
3320 algName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
) ||
3321 algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
) ||
3322 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3323 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
3324 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
3325 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
) ||
3326 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
3327 algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
3328 return new ExportKeyTask(aFormat
, aKey
);
3330 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3333 WebCryptoTask
* WebCryptoTask::CreateGenerateKeyTask(
3334 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3335 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
3336 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_GENERATEKEY
);
3337 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_GENERATE
,
3339 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3340 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3344 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3345 if (NS_FAILED(rv
)) {
3346 return new FailureTask(rv
);
3349 if (algName
.EqualsASCII(WEBCRYPTO_ALG_AES_CBC
) ||
3350 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_CTR
) ||
3351 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_GCM
) ||
3352 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_KW
) ||
3353 algName
.EqualsASCII(WEBCRYPTO_ALG_HMAC
)) {
3354 return new GenerateSymmetricKeyTask(aGlobal
, aCx
, aAlgorithm
, aExtractable
,
3356 } else if (algName
.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3357 algName
.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP
) ||
3358 algName
.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS
) ||
3359 algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
) ||
3360 algName
.EqualsASCII(WEBCRYPTO_ALG_ECDSA
) ||
3361 algName
.EqualsASCII(WEBCRYPTO_ALG_ED25519
)
3364 return new GenerateAsymmetricKeyTask(aGlobal
, aCx
, aAlgorithm
, aExtractable
,
3367 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3371 WebCryptoTask
* WebCryptoTask::CreateDeriveKeyTask(
3372 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3373 CryptoKey
& aBaseKey
, const ObjectOrString
& aDerivedKeyType
,
3374 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
3375 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DERIVEKEY
);
3377 // Ensure baseKey is usable for this operation
3378 if (!aBaseKey
.HasUsage(CryptoKey::DERIVEKEY
)) {
3379 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3382 // Verify that aKeyUsages does not contain an unrecognized value
3383 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3384 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3388 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3389 if (NS_FAILED(rv
)) {
3390 return new FailureTask(rv
);
3393 if (algName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
)) {
3394 return new DeriveKeyTask
<DeriveHkdfBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3395 aBaseKey
, aDerivedKeyType
,
3396 aExtractable
, aKeyUsages
);
3399 if (algName
.EqualsASCII(WEBCRYPTO_ALG_PBKDF2
)) {
3400 return new DeriveKeyTask
<DerivePbkdfBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3401 aBaseKey
, aDerivedKeyType
,
3402 aExtractable
, aKeyUsages
);
3405 if (algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
)) {
3406 return new DeriveKeyTask
<DeriveEcdhBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3407 aBaseKey
, aDerivedKeyType
,
3408 aExtractable
, aKeyUsages
);
3411 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3414 WebCryptoTask
* WebCryptoTask::CreateDeriveBitsTask(
3415 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
3417 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DERIVEBITS
);
3419 // Ensure baseKey is usable for this operation
3420 if (!aKey
.HasUsage(CryptoKey::DERIVEBITS
)) {
3421 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3425 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3426 if (NS_FAILED(rv
)) {
3427 return new FailureTask(rv
);
3430 if (algName
.EqualsASCII(WEBCRYPTO_ALG_PBKDF2
)) {
3431 return new DerivePbkdfBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3434 if (algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
)) {
3435 return new DeriveEcdhBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3438 if (algName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
)) {
3439 return new DeriveHkdfBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3442 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3445 WebCryptoTask
* WebCryptoTask::CreateWrapKeyTask(
3446 JSContext
* aCx
, const nsAString
& aFormat
, CryptoKey
& aKey
,
3447 CryptoKey
& aWrappingKey
, const ObjectOrString
& aWrapAlgorithm
) {
3448 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_WRAPKEY
);
3450 // Verify that the format is recognized
3451 if (!aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) &&
3452 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) &&
3453 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) &&
3454 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
3455 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3458 // Ensure wrappingKey is usable for this operation
3459 if (!aWrappingKey
.HasUsage(CryptoKey::WRAPKEY
)) {
3460 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3463 // Ensure key is extractable
3464 if (!aKey
.Extractable()) {
3465 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3468 nsString wrapAlgName
;
3469 nsresult rv
= GetAlgorithmName(aCx
, aWrapAlgorithm
, wrapAlgName
);
3470 if (NS_FAILED(rv
)) {
3471 return new FailureTask(rv
);
3474 if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3475 wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3476 wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
3477 return new WrapKeyTask
<AesTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3479 } else if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
3480 return new WrapKeyTask
<AesKwTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3482 } else if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
3483 return new WrapKeyTask
<RsaOaepTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3487 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3490 WebCryptoTask
* WebCryptoTask::CreateUnwrapKeyTask(
3491 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
3492 const ArrayBufferViewOrArrayBuffer
& aWrappedKey
, CryptoKey
& aUnwrappingKey
,
3493 const ObjectOrString
& aUnwrapAlgorithm
,
3494 const ObjectOrString
& aUnwrappedKeyAlgorithm
, bool aExtractable
,
3495 const Sequence
<nsString
>& aKeyUsages
) {
3496 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_UNWRAPKEY
);
3498 // Ensure key is usable for this operation
3499 if (!aUnwrappingKey
.HasUsage(CryptoKey::UNWRAPKEY
)) {
3500 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3503 // Verify that aKeyUsages does not contain an unrecognized value
3504 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3505 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3508 nsString keyAlgName
;
3509 nsresult rv
= GetAlgorithmName(aCx
, aUnwrappedKeyAlgorithm
, keyAlgName
);
3510 if (NS_FAILED(rv
)) {
3511 return new FailureTask(rv
);
3514 CryptoOperationData dummy
;
3515 RefPtr
<ImportKeyTask
> importTask
;
3516 if (keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_CBC
) ||
3517 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_CTR
) ||
3518 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_GCM
) ||
3519 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_KW
) ||
3520 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
) ||
3521 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_HMAC
)) {
3522 importTask
= new ImportSymmetricKeyTask(aGlobal
, aCx
, aFormat
,
3523 aUnwrappedKeyAlgorithm
,
3524 aExtractable
, aKeyUsages
);
3525 } else if (keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3526 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP
) ||
3527 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS
)) {
3529 new ImportRsaKeyTask(aGlobal
, aCx
, aFormat
, aUnwrappedKeyAlgorithm
,
3530 aExtractable
, aKeyUsages
);
3531 } else if (keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
3532 keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
3534 new ImportEcKeyTask(aGlobal
, aCx
, aFormat
, aUnwrappedKeyAlgorithm
,
3535 aExtractable
, aKeyUsages
);
3536 } else if (keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
3538 new ImportEdKeyTask(aGlobal
, aCx
, aFormat
, aUnwrappedKeyAlgorithm
,
3539 aExtractable
, aKeyUsages
);
3541 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3544 nsString unwrapAlgName
;
3545 rv
= GetAlgorithmName(aCx
, aUnwrapAlgorithm
, unwrapAlgName
);
3546 if (NS_FAILED(rv
)) {
3547 return new FailureTask(rv
);
3549 if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3550 unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3551 unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
3552 return new UnwrapKeyTask
<AesTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3553 aUnwrapAlgorithm
, importTask
);
3554 } else if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
3555 return new UnwrapKeyTask
<AesKwTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3556 aUnwrapAlgorithm
, importTask
);
3557 } else if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
3558 return new UnwrapKeyTask
<RsaOaepTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3559 aUnwrapAlgorithm
, importTask
);
3562 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3565 WebCryptoTask::WebCryptoTask()
3566 : CancelableRunnable("WebCryptoTask"),
3568 mEarlyComplete(false),
3569 mOriginalEventTarget(nullptr),
3570 mRv(NS_ERROR_NOT_INITIALIZED
) {}
3572 WebCryptoTask::~WebCryptoTask() = default;
3574 } // namespace mozilla::dom