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"
25 // Template taken from security/nss/lib/util/templates.c
26 // This (or SGN_EncodeDigestInfo) would ideally be exported
27 // by NSS and until that happens we have to keep our own copy.
28 const SEC_ASN1Template SGN_DigestInfoTemplate
[] = {
29 {SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(SGNDigestInfo
)},
30 {SEC_ASN1_INLINE
, offsetof(SGNDigestInfo
, digestAlgorithm
),
31 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate
)},
32 {SEC_ASN1_OCTET_STRING
, offsetof(SGNDigestInfo
, digest
)},
37 namespace mozilla::dom
{
39 // Pre-defined identifiers for telemetry histograms
41 enum TelemetryMethod
{
56 enum TelemetryAlgorithm
{
57 // Please make additions at the end of the list,
58 // to preserve comparability of histograms over time
65 TA_RSAES_PKCS1
= 5, // NB: This algorithm has been removed
90 // Convenience functions for extracting / converting information
92 // OOM-safe CryptoBuffer initialization, suitable for constructors
93 #define ATTEMPT_BUFFER_INIT(dst, src) \
94 if (!dst.Assign(src)) { \
95 mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \
99 // OOM-safe CryptoBuffer-to-SECItem copy, suitable for DoCrypto
100 #define ATTEMPT_BUFFER_TO_SECITEM(arena, dst, src) \
101 if (!src.ToSECItem(arena, dst)) { \
102 return NS_ERROR_DOM_UNKNOWN_ERR; \
105 // OOM-safe CryptoBuffer copy, suitable for DoCrypto
106 #define ATTEMPT_BUFFER_ASSIGN(dst, src) \
107 if (!dst.Assign(src)) { \
108 return NS_ERROR_DOM_UNKNOWN_ERR; \
111 // Safety check for algorithms that use keys, suitable for constructors
112 #define CHECK_KEY_ALGORITHM(keyAlg, algName) \
114 if (!NORMALIZED_EQUALS(keyAlg.mName, algName)) { \
115 mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; \
120 class ClearException
{
122 explicit ClearException(JSContext
* aCx
) : mCx(aCx
) {}
124 ~ClearException() { JS_ClearPendingException(mCx
); }
131 static nsresult
GetAlgorithmName(JSContext
* aCx
, const OOS
& aAlgorithm
,
133 ClearException
ce(aCx
);
135 if (aAlgorithm
.IsString()) {
136 // If string, then treat as algorithm name
137 aName
.Assign(aAlgorithm
.GetAsString());
139 // Coerce to algorithm and extract name
140 JS::RootedValue
value(aCx
, JS::ObjectValue(*aAlgorithm
.GetAsObject()));
143 if (!alg
.Init(aCx
, value
)) {
144 return NS_ERROR_DOM_SYNTAX_ERR
;
150 if (!NormalizeToken(aName
, aName
)) {
151 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
157 template <class T
, class OOS
>
158 static nsresult
Coerce(JSContext
* aCx
, T
& aTarget
, const OOS
& aAlgorithm
) {
159 ClearException
ce(aCx
);
161 if (!aAlgorithm
.IsObject()) {
162 return NS_ERROR_DOM_SYNTAX_ERR
;
165 JS::RootedValue
value(aCx
, JS::ObjectValue(*aAlgorithm
.GetAsObject()));
166 if (!aTarget
.Init(aCx
, value
)) {
167 return NS_ERROR_DOM_SYNTAX_ERR
;
173 inline size_t MapHashAlgorithmNameToBlockSize(const nsString
& aName
) {
174 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
) ||
175 aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
179 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
) ||
180 aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
187 inline nsresult
GetKeyLengthForAlgorithm(JSContext
* aCx
,
188 const ObjectOrString
& aAlgorithm
,
192 // Extract algorithm name
194 if (NS_FAILED(GetAlgorithmName(aCx
, aAlgorithm
, algName
))) {
195 return NS_ERROR_DOM_SYNTAX_ERR
;
198 // Read AES key length from given algorithm object.
199 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
200 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
201 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
202 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
203 RootedDictionary
<AesDerivedKeyParams
> params(aCx
);
204 if (NS_FAILED(Coerce(aCx
, params
, aAlgorithm
))) {
205 return NS_ERROR_DOM_SYNTAX_ERR
;
208 if (params
.mLength
!= 128 && params
.mLength
!= 192 &&
209 params
.mLength
!= 256) {
210 return NS_ERROR_DOM_OPERATION_ERR
;
213 aLength
= params
.mLength
;
217 // Read HMAC key length from given algorithm object or
218 // determine key length as the block size of the given hash.
219 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
220 RootedDictionary
<HmacDerivedKeyParams
> params(aCx
);
221 if (NS_FAILED(Coerce(aCx
, params
, aAlgorithm
))) {
222 return NS_ERROR_DOM_SYNTAX_ERR
;
225 // Return the passed length, if any.
226 if (params
.mLength
.WasPassed()) {
227 aLength
= params
.mLength
.Value();
232 if (NS_FAILED(GetAlgorithmName(aCx
, params
.mHash
, hashName
))) {
233 return NS_ERROR_DOM_SYNTAX_ERR
;
236 // Return the given hash algorithm's block size as the key length.
237 size_t length
= MapHashAlgorithmNameToBlockSize(hashName
);
239 return NS_ERROR_DOM_SYNTAX_ERR
;
246 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
249 inline bool MapOIDTagToNamedCurve(SECOidTag aOIDTag
, nsString
& aResult
) {
251 case SEC_OID_SECG_EC_SECP256R1
:
252 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256
);
254 case SEC_OID_SECG_EC_SECP384R1
:
255 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384
);
257 case SEC_OID_SECG_EC_SECP521R1
:
258 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521
);
267 inline SECOidTag
MapHashAlgorithmNameToOID(const nsString
& aName
) {
268 SECOidTag
hashOID(SEC_OID_UNKNOWN
);
270 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
271 hashOID
= SEC_OID_SHA1
;
272 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
273 hashOID
= SEC_OID_SHA256
;
274 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
275 hashOID
= SEC_OID_SHA384
;
276 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
277 hashOID
= SEC_OID_SHA512
;
283 inline CK_MECHANISM_TYPE
MapHashAlgorithmNameToMgfMechanism(
284 const nsString
& aName
) {
285 CK_MECHANISM_TYPE
mech(UNKNOWN_CK_MECHANISM
);
287 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
288 mech
= CKG_MGF1_SHA1
;
289 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
290 mech
= CKG_MGF1_SHA256
;
291 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
292 mech
= CKG_MGF1_SHA384
;
293 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
294 mech
= CKG_MGF1_SHA512
;
300 // Implementation of WebCryptoTask methods
302 void WebCryptoTask::DispatchWithPromise(Promise
* aResultPromise
) {
303 mResultPromise
= aResultPromise
;
305 // Fail if an error was set during the constructor
306 MAYBE_EARLY_FAIL(mEarlyRv
)
308 // Perform pre-NSS operations, and fail if they fail
309 mEarlyRv
= BeforeCrypto();
310 MAYBE_EARLY_FAIL(mEarlyRv
)
312 // Skip dispatch if we're already done. Otherwise launch a CryptoTask
313 if (mEarlyComplete
) {
314 CallCallback(mEarlyRv
);
318 // Store calling thread
319 mOriginalEventTarget
= GetCurrentSerialEventTarget();
321 // If we are running on a worker thread we must hold the worker
322 // alive while we work on the thread pool. Otherwise the worker
323 // private may get torn down before we dispatch back to complete
325 if (!NS_IsMainThread()) {
326 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
327 MOZ_ASSERT(workerPrivate
);
329 RefPtr
<StrongWorkerRef
> workerRef
=
330 StrongWorkerRef::Create(workerPrivate
, "WebCryptoTask");
331 if (NS_WARN_IF(!workerRef
)) {
332 mEarlyRv
= NS_BINDING_ABORTED
;
334 mWorkerRef
= new ThreadSafeWorkerRef(workerRef
);
337 MAYBE_EARLY_FAIL(mEarlyRv
);
339 // dispatch to thread pool
341 if (!EnsureNSSInitializedChromeOrContent()) {
342 mEarlyRv
= NS_ERROR_FAILURE
;
344 MAYBE_EARLY_FAIL(mEarlyRv
);
346 mEarlyRv
= NS_DispatchBackgroundTask(this);
347 MAYBE_EARLY_FAIL(mEarlyRv
)
351 WebCryptoTask::Run() {
352 // Run heavy crypto operations on the thread pool, off the original thread.
353 if (!IsOnOriginalThread()) {
354 mRv
= CalculateResult();
356 // Back to the original thread, i.e. continue below.
357 mOriginalEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
);
361 // We're now back on the calling thread.
364 // Stop holding the worker thread alive now that the async work has
366 mWorkerRef
= nullptr;
371 nsresult
WebCryptoTask::Cancel() {
372 MOZ_ASSERT(IsOnOriginalThread());
373 FailWithError(NS_BINDING_ABORTED
);
377 void WebCryptoTask::FailWithError(nsresult aRv
) {
378 MOZ_ASSERT(IsOnOriginalThread());
379 Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED
, false);
381 // Blindly convert nsresult to DOMException
382 // Individual tasks must ensure they pass the right values
383 mResultPromise
->MaybeReject(aRv
);
384 // Manually release mResultPromise while we're on the main thread
385 mResultPromise
= nullptr;
386 mWorkerRef
= nullptr;
390 nsresult
WebCryptoTask::CalculateResult() {
391 MOZ_ASSERT(!IsOnOriginalThread());
396 void WebCryptoTask::CallCallback(nsresult rv
) {
397 MOZ_ASSERT(IsOnOriginalThread());
403 nsresult rv2
= AfterCrypto();
404 if (NS_FAILED(rv2
)) {
410 Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED
, true);
412 // Manually release mResultPromise while we're on the main thread
413 mResultPromise
= nullptr;
417 // Some generic utility classes
419 class FailureTask
: public WebCryptoTask
{
421 explicit FailureTask(nsresult aRv
) { mEarlyRv
= aRv
; }
424 class ReturnArrayBufferViewTask
: public WebCryptoTask
{
426 CryptoBuffer mResult
;
429 // Returns mResult as an ArrayBufferView, or an error
430 virtual void Resolve() override
{
431 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
432 mResultPromise
->MaybeResolve(ret
);
439 void SetData(const T
& aData
) {
440 mDataIsSet
= mData
.Assign(aData
);
444 DeferredData() : mDataIsSet(false) {}
450 class AesTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
452 AesTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
454 : mMechanism(CKM_INVALID_MECHANISM
),
458 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
461 AesTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
462 const CryptoOperationData
& aData
, bool aEncrypt
)
463 : mMechanism(CKM_INVALID_MECHANISM
),
467 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
471 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
474 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
475 if (NS_FAILED(mEarlyRv
)) {
479 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
480 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
484 // Check that we got a reasonable key
485 if ((mSymKey
.Length() != 16) && (mSymKey
.Length() != 24) &&
486 (mSymKey
.Length() != 32)) {
487 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
491 // Cache parameters depending on the specific algorithm
492 TelemetryAlgorithm telemetryAlg
;
493 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
)) {
494 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_CBC
);
496 mMechanism
= CKM_AES_CBC_PAD
;
497 telemetryAlg
= TA_AES_CBC
;
498 RootedDictionary
<AesCbcParams
> params(aCx
);
499 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
501 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
505 ATTEMPT_BUFFER_INIT(mIv
, params
.mIv
)
506 if (mIv
.Length() != 16) {
507 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
510 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
)) {
511 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_CTR
);
513 mMechanism
= CKM_AES_CTR
;
514 telemetryAlg
= TA_AES_CTR
;
515 RootedDictionary
<AesCtrParams
> params(aCx
);
516 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
518 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
522 ATTEMPT_BUFFER_INIT(mIv
, params
.mCounter
)
523 if (mIv
.Length() != 16) {
524 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
528 mCounterLength
= params
.mLength
;
529 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
530 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_GCM
);
532 mMechanism
= CKM_AES_GCM
;
533 telemetryAlg
= TA_AES_GCM
;
534 RootedDictionary
<AesGcmParams
> params(aCx
);
535 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
537 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
541 ATTEMPT_BUFFER_INIT(mIv
, params
.mIv
)
543 if (params
.mAdditionalData
.WasPassed()) {
544 ATTEMPT_BUFFER_INIT(mAad
, params
.mAdditionalData
.Value())
547 // 32, 64, 96, 104, 112, 120 or 128
549 if (params
.mTagLength
.WasPassed()) {
550 mTagLength
= params
.mTagLength
.Value();
551 if ((mTagLength
> 128) ||
552 !(mTagLength
== 32 || mTagLength
== 64 ||
553 (mTagLength
>= 96 && mTagLength
% 8 == 0))) {
554 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
559 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
562 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
566 CK_MECHANISM_TYPE mMechanism
;
567 CryptoBuffer mSymKey
;
568 CryptoBuffer mIv
; // Initialization vector
569 CryptoBuffer mAad
; // Additional Authenticated Data
571 uint8_t mCounterLength
;
574 virtual nsresult
DoCrypto() override
{
578 return NS_ERROR_DOM_OPERATION_ERR
;
581 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
583 return NS_ERROR_DOM_OPERATION_ERR
;
586 // Construct the parameters object depending on algorithm
587 SECItem param
= {siBuffer
, nullptr, 0};
588 CK_AES_CTR_PARAMS ctrParams
;
589 CK_GCM_PARAMS gcmParams
;
590 switch (mMechanism
) {
591 case CKM_AES_CBC_PAD
:
592 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), ¶m
, mIv
);
595 ctrParams
.ulCounterBits
= mCounterLength
;
596 MOZ_ASSERT(mIv
.Length() == 16);
597 memcpy(&ctrParams
.cb
, mIv
.Elements(), 16);
598 param
.type
= siBuffer
;
599 param
.data
= (unsigned char*)&ctrParams
;
600 param
.len
= sizeof(ctrParams
);
603 gcmParams
.pIv
= mIv
.Elements();
604 gcmParams
.ulIvLen
= mIv
.Length();
605 gcmParams
.ulIvBits
= gcmParams
.ulIvLen
* 8;
606 gcmParams
.pAAD
= mAad
.Elements();
607 gcmParams
.ulAADLen
= mAad
.Length();
608 gcmParams
.ulTagBits
= mTagLength
;
609 param
.type
= siBuffer
;
610 param
.data
= (unsigned char*)&gcmParams
;
611 param
.len
= sizeof(gcmParams
);
614 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
618 SECItem keyItem
= {siBuffer
, nullptr, 0};
619 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
620 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
621 MOZ_ASSERT(slot
.get());
622 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
623 PK11_OriginUnwrap
, CKA_ENCRYPT
,
626 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
629 // Check whether the integer addition would overflow.
630 if (std::numeric_limits
<CryptoBuffer::size_type
>::max() - 16 <
632 return NS_ERROR_DOM_DATA_ERR
;
635 // Initialize the output buffer (enough space for padding / a full tag)
636 if (!mResult
.SetLength(mData
.Length() + 16, fallible
)) {
637 return NS_ERROR_DOM_UNKNOWN_ERR
;
642 // Perform the encryption/decryption
644 rv
= MapSECStatus(PK11_Encrypt(
645 symKey
.get(), mMechanism
, ¶m
, mResult
.Elements(), &outLen
,
646 mResult
.Length(), mData
.Elements(), mData
.Length()));
648 rv
= MapSECStatus(PK11_Decrypt(
649 symKey
.get(), mMechanism
, ¶m
, mResult
.Elements(), &outLen
,
650 mResult
.Length(), mData
.Elements(), mData
.Length()));
652 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
654 mResult
.TruncateLength(outLen
);
659 // This class looks like an encrypt/decrypt task, like AesTask,
660 // but it is only exposed to wrapKey/unwrapKey, not encrypt/decrypt
661 class AesKwTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
663 AesKwTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
665 : mMechanism(CKM_NSS_AES_KEY_WRAP
), mEncrypt(aEncrypt
) {
666 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
669 AesKwTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
670 const CryptoOperationData
& aData
, bool aEncrypt
)
671 : mMechanism(CKM_NSS_AES_KEY_WRAP
), mEncrypt(aEncrypt
) {
672 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
676 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
678 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_KW
);
681 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
682 if (NS_FAILED(mEarlyRv
)) {
686 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
687 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
691 // Check that we got a reasonable key
692 if ((mSymKey
.Length() != 16) && (mSymKey
.Length() != 24) &&
693 (mSymKey
.Length() != 32)) {
694 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
698 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_AES_KW
);
702 CK_MECHANISM_TYPE mMechanism
;
703 CryptoBuffer mSymKey
;
706 virtual nsresult
DoCrypto() override
{
710 return NS_ERROR_DOM_OPERATION_ERR
;
713 // Check that the input is a multiple of 64 bits long
714 if (mData
.Length() == 0 || mData
.Length() % 8 != 0) {
715 return NS_ERROR_DOM_DATA_ERR
;
718 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
720 return NS_ERROR_DOM_OPERATION_ERR
;
724 SECItem keyItem
= {siBuffer
, nullptr, 0};
725 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
726 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
727 MOZ_ASSERT(slot
.get());
728 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
729 PK11_OriginUnwrap
, CKA_WRAP
,
732 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
735 // Import the data to a SECItem
736 SECItem dataItem
= {siBuffer
, nullptr, 0};
737 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &dataItem
, mData
);
739 // Parameters for the fake keys
740 CK_MECHANISM_TYPE fakeMechanism
= CKM_SHA_1_HMAC
;
741 CK_ATTRIBUTE_TYPE fakeOperation
= CKA_SIGN
;
744 // Import the data into a fake PK11SymKey structure
745 UniquePK11SymKey
keyToWrap(
746 PK11_ImportSymKey(slot
.get(), fakeMechanism
, PK11_OriginUnwrap
,
747 fakeOperation
, &dataItem
, nullptr));
749 return NS_ERROR_DOM_OPERATION_ERR
;
752 // Encrypt and return the wrapped key
753 // AES-KW encryption results in a wrapped key 64 bits longer
754 if (!mResult
.SetLength(mData
.Length() + 8, fallible
)) {
755 return NS_ERROR_DOM_OPERATION_ERR
;
757 SECItem resultItem
= {siBuffer
, mResult
.Elements(),
758 (unsigned int)mResult
.Length()};
759 rv
= MapSECStatus(PK11_WrapSymKey(mMechanism
, nullptr, symKey
.get(),
760 keyToWrap
.get(), &resultItem
));
761 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
763 // Decrypt the ciphertext into a temporary PK11SymKey
764 // Unwrapped key should be 64 bits shorter
765 int keySize
= mData
.Length() - 8;
766 UniquePK11SymKey
unwrappedKey(
767 PK11_UnwrapSymKey(symKey
.get(), mMechanism
, nullptr, &dataItem
,
768 fakeMechanism
, fakeOperation
, keySize
));
770 return NS_ERROR_DOM_OPERATION_ERR
;
773 // Export the key to get the cleartext
774 rv
= MapSECStatus(PK11_ExtractKeyValue(unwrappedKey
.get()));
776 return NS_ERROR_DOM_UNKNOWN_ERR
;
778 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(unwrappedKey
.get()));
785 class RsaOaepTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
787 RsaOaepTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
789 : mPrivKey(aKey
.GetPrivateKey()),
790 mPubKey(aKey
.GetPublicKey()),
792 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
795 RsaOaepTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
796 const CryptoOperationData
& aData
, bool aEncrypt
)
797 : mPrivKey(aKey
.GetPrivateKey()),
798 mPubKey(aKey
.GetPublicKey()),
800 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
804 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
806 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSA_OAEP
);
808 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSA_OAEP
);
812 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
815 mStrength
= SECKEY_PublicKeyStrength(mPubKey
.get());
818 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
821 mStrength
= PK11_GetPrivateModulusLen(mPrivKey
.get());
824 // The algorithm could just be given as a string
825 // in which case there would be no label specified.
826 if (!aAlgorithm
.IsString()) {
827 RootedDictionary
<RsaOaepParams
> params(aCx
);
828 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
829 if (NS_FAILED(mEarlyRv
)) {
830 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
834 if (params
.mLabel
.WasPassed()) {
835 ATTEMPT_BUFFER_INIT(mLabel
, params
.mLabel
.Value());
838 // Otherwise mLabel remains the empty octet string, as intended
840 KeyAlgorithm
& hashAlg
= aKey
.Algorithm().mRsa
.mHash
;
841 mHashMechanism
= KeyAlgorithmProxy::GetMechanism(hashAlg
);
842 mMgfMechanism
= MapHashAlgorithmNameToMgfMechanism(hashAlg
.mName
);
844 // Check we found appropriate mechanisms.
845 if (mHashMechanism
== UNKNOWN_CK_MECHANISM
||
846 mMgfMechanism
== UNKNOWN_CK_MECHANISM
) {
847 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
853 CK_MECHANISM_TYPE mHashMechanism
;
854 CK_MECHANISM_TYPE mMgfMechanism
;
855 UniqueSECKEYPrivateKey mPrivKey
;
856 UniqueSECKEYPublicKey mPubKey
;
861 virtual nsresult
DoCrypto() override
{
865 return NS_ERROR_DOM_OPERATION_ERR
;
868 // Ciphertext is an integer mod the modulus, so it will be
869 // no longer than mStrength octets
870 if (!mResult
.SetLength(mStrength
, fallible
)) {
871 return NS_ERROR_DOM_UNKNOWN_ERR
;
874 CK_RSA_PKCS_OAEP_PARAMS oaepParams
;
875 oaepParams
.source
= CKZ_DATA_SPECIFIED
;
877 oaepParams
.pSourceData
= mLabel
.Length() ? mLabel
.Elements() : nullptr;
878 oaepParams
.ulSourceDataLen
= mLabel
.Length();
880 oaepParams
.mgf
= mMgfMechanism
;
881 oaepParams
.hashAlg
= mHashMechanism
;
884 param
.type
= siBuffer
;
885 param
.data
= (unsigned char*)&oaepParams
;
886 param
.len
= sizeof(oaepParams
);
890 // PK11_PubEncrypt() checks the plaintext's length and fails if it is too
891 // long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
892 // being the length in octets of the RSA modulus n and 'hLen' being the
893 // output length in octets of the chosen hash function.
894 // <https://tools.ietf.org/html/rfc3447#section-7.1>
895 rv
= MapSECStatus(PK11_PubEncrypt(
896 mPubKey
.get(), CKM_RSA_PKCS_OAEP
, ¶m
, mResult
.Elements(), &outLen
,
897 mResult
.Length(), mData
.Elements(), mData
.Length(), nullptr));
899 rv
= MapSECStatus(PK11_PrivDecrypt(
900 mPrivKey
.get(), CKM_RSA_PKCS_OAEP
, ¶m
, mResult
.Elements(),
901 &outLen
, mResult
.Length(), mData
.Elements(), mData
.Length()));
903 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
905 mResult
.TruncateLength(outLen
);
910 class HmacTask
: public WebCryptoTask
{
912 HmacTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
913 const CryptoOperationData
& aSignature
,
914 const CryptoOperationData
& aData
, bool aSign
)
915 : mMechanism(aKey
.Algorithm().Mechanism()), mSign(aSign
) {
916 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_HMAC
);
918 ATTEMPT_BUFFER_INIT(mData
, aData
);
920 ATTEMPT_BUFFER_INIT(mSignature
, aSignature
);
923 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
924 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
928 // Check that we got a symmetric key
929 if (mSymKey
.Length() == 0) {
930 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
934 TelemetryAlgorithm telemetryAlg
;
935 switch (mMechanism
) {
937 telemetryAlg
= TA_HMAC_SHA_1
;
939 case CKM_SHA224_HMAC
:
940 telemetryAlg
= TA_HMAC_SHA_224
;
942 case CKM_SHA256_HMAC
:
943 telemetryAlg
= TA_HMAC_SHA_256
;
945 case CKM_SHA384_HMAC
:
946 telemetryAlg
= TA_HMAC_SHA_384
;
948 case CKM_SHA512_HMAC
:
949 telemetryAlg
= TA_HMAC_SHA_512
;
952 telemetryAlg
= TA_UNKNOWN
;
954 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
958 CK_MECHANISM_TYPE mMechanism
;
959 CryptoBuffer mSymKey
;
961 CryptoBuffer mSignature
;
962 CryptoBuffer mResult
;
965 virtual nsresult
DoCrypto() override
{
966 // Initialize the output buffer
967 if (!mResult
.SetLength(HASH_LENGTH_MAX
, fallible
)) {
968 return NS_ERROR_DOM_UNKNOWN_ERR
;
971 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
973 return NS_ERROR_DOM_OPERATION_ERR
;
978 SECItem keyItem
= {siBuffer
, nullptr, 0};
979 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
980 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
981 MOZ_ASSERT(slot
.get());
982 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
983 PK11_OriginUnwrap
, CKA_SIGN
,
986 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
990 SECItem param
= {siBuffer
, nullptr, 0};
991 UniquePK11Context
ctx(
992 PK11_CreateContextBySymKey(mMechanism
, CKA_SIGN
, symKey
.get(), ¶m
));
994 return NS_ERROR_DOM_OPERATION_ERR
;
996 nsresult rv
= MapSECStatus(PK11_DigestBegin(ctx
.get()));
997 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
999 PK11_DigestOp(ctx
.get(), mData
.Elements(), mData
.Length()));
1000 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
1001 rv
= MapSECStatus(PK11_DigestFinal(ctx
.get(), mResult
.Elements(), &outLen
,
1003 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
1005 mResult
.TruncateLength(outLen
);
1009 // Returns mResult as an ArrayBufferView, or an error
1010 virtual void Resolve() override
{
1012 // Return the computed MAC
1013 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
1014 mResultPromise
->MaybeResolve(ret
);
1016 // Compare the MAC to the provided signature
1017 // No truncation allowed
1018 bool equal
= (mResult
.Length() == mSignature
.Length());
1020 int cmp
= NSS_SecureMemcmp(mSignature
.Elements(), mResult
.Elements(),
1021 mSignature
.Length());
1024 mResultPromise
->MaybeResolve(equal
);
1029 class AsymmetricSignVerifyTask
: public WebCryptoTask
{
1031 AsymmetricSignVerifyTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
1033 const CryptoOperationData
& aSignature
,
1034 const CryptoOperationData
& aData
, bool aSign
)
1035 : mOidTag(SEC_OID_UNKNOWN
),
1036 mHashMechanism(UNKNOWN_CK_MECHANISM
),
1037 mMgfMechanism(UNKNOWN_CK_MECHANISM
),
1038 mPrivKey(aKey
.GetPrivateKey()),
1039 mPubKey(aKey
.GetPublicKey()),
1043 mAlgorithm(Algorithm::UNKNOWN
) {
1044 ATTEMPT_BUFFER_INIT(mData
, aData
);
1046 ATTEMPT_BUFFER_INIT(mSignature
, aSignature
);
1050 nsString hashAlgName
;
1051 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
1052 if (NS_FAILED(mEarlyRv
)) {
1056 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
)) {
1057 mAlgorithm
= Algorithm::RSA_PKCS1
;
1058 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSASSA_PKCS1
);
1059 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1
);
1060 hashAlgName
= aKey
.Algorithm().mRsa
.mHash
.mName
;
1061 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1062 mAlgorithm
= Algorithm::RSA_PSS
;
1063 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSA_PSS
);
1064 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSA_PSS
);
1066 KeyAlgorithm
& hashAlg
= aKey
.Algorithm().mRsa
.mHash
;
1067 hashAlgName
= hashAlg
.mName
;
1068 mHashMechanism
= KeyAlgorithmProxy::GetMechanism(hashAlg
);
1069 mMgfMechanism
= MapHashAlgorithmNameToMgfMechanism(hashAlgName
);
1071 // Check we found appropriate mechanisms.
1072 if (mHashMechanism
== UNKNOWN_CK_MECHANISM
||
1073 mMgfMechanism
== UNKNOWN_CK_MECHANISM
) {
1074 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1078 RootedDictionary
<RsaPssParams
> params(aCx
);
1079 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1080 if (NS_FAILED(mEarlyRv
)) {
1081 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1085 mSaltLength
= params
.mSaltLength
;
1086 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
1087 mAlgorithm
= Algorithm::ECDSA
;
1088 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_ECDSA
);
1089 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_ECDSA
);
1091 // For ECDSA, the hash name comes from the algorithm parameter
1092 RootedDictionary
<EcdsaParams
> params(aCx
);
1093 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1094 if (NS_FAILED(mEarlyRv
)) {
1095 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1099 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashAlgName
);
1100 if (NS_FAILED(mEarlyRv
)) {
1101 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1105 // This shouldn't happen; CreateSignVerifyTask shouldn't create
1106 // one of these unless it's for the above algorithms.
1110 // Must have a valid algorithm by now.
1111 MOZ_ASSERT(mAlgorithm
!= Algorithm::UNKNOWN
);
1113 // Determine hash algorithm to use.
1114 mOidTag
= MapHashAlgorithmNameToOID(hashAlgName
);
1115 if (mOidTag
== SEC_OID_UNKNOWN
) {
1116 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1120 // Check that we have the appropriate key
1121 if ((mSign
&& !mPrivKey
) || (!mSign
&& !mPubKey
)) {
1122 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1129 CK_MECHANISM_TYPE mHashMechanism
;
1130 CK_MECHANISM_TYPE mMgfMechanism
;
1131 UniqueSECKEYPrivateKey mPrivKey
;
1132 UniqueSECKEYPublicKey mPubKey
;
1133 CryptoBuffer mSignature
;
1135 uint32_t mSaltLength
;
1139 // The signature algorithm to use.
1140 enum class Algorithm
: uint8_t { ECDSA
, RSA_PKCS1
, RSA_PSS
, UNKNOWN
};
1141 Algorithm mAlgorithm
;
1143 virtual nsresult
DoCrypto() override
{
1146 ::SECITEM_AllocItem(nullptr, nullptr, HASH_ResultLenByOidTag(mOidTag
)));
1148 return NS_ERROR_DOM_OPERATION_ERR
;
1151 // Compute digest over given data.
1152 rv
= PK11_HashBuf(mOidTag
, hash
->data
, mData
.Elements(), mData
.Length());
1153 NS_ENSURE_SUCCESS(MapSECStatus(rv
), NS_ERROR_DOM_OPERATION_ERR
);
1155 // Wrap hash in a digest info template (RSA-PKCS1 only).
1156 if (mAlgorithm
== Algorithm::RSA_PKCS1
) {
1157 UniqueSGNDigestInfo
di(
1158 SGN_CreateDigestInfo(mOidTag
, hash
->data
, hash
->len
));
1160 return NS_ERROR_DOM_OPERATION_ERR
;
1164 SECITEM_FreeItem(hash
.get(), false);
1165 if (!SEC_ASN1EncodeItem(nullptr, hash
.get(), di
.get(),
1166 SGN_DigestInfoTemplate
)) {
1167 return NS_ERROR_DOM_OPERATION_ERR
;
1171 SECItem
* params
= nullptr;
1172 CK_MECHANISM_TYPE mech
=
1173 PK11_MapSignKeyType((mSign
? mPrivKey
->keyType
: mPubKey
->keyType
));
1175 CK_RSA_PKCS_PSS_PARAMS rsaPssParams
;
1176 SECItem rsaPssParamsItem
= {
1180 // Set up parameters for RSA-PSS.
1181 if (mAlgorithm
== Algorithm::RSA_PSS
) {
1182 rsaPssParams
.hashAlg
= mHashMechanism
;
1183 rsaPssParams
.mgf
= mMgfMechanism
;
1184 rsaPssParams
.sLen
= mSaltLength
;
1186 rsaPssParamsItem
.data
= (unsigned char*)&rsaPssParams
;
1187 rsaPssParamsItem
.len
= sizeof(rsaPssParams
);
1188 params
= &rsaPssParamsItem
;
1190 mech
= CKM_RSA_PKCS_PSS
;
1193 // Allocate SECItem to hold the signature.
1194 uint32_t len
= mSign
? PK11_SignatureLen(mPrivKey
.get()) : 0;
1195 UniqueSECItem
sig(::SECITEM_AllocItem(nullptr, nullptr, len
));
1197 return NS_ERROR_DOM_OPERATION_ERR
;
1202 rv
= PK11_SignWithMechanism(mPrivKey
.get(), mech
, params
, sig
.get(),
1204 NS_ENSURE_SUCCESS(MapSECStatus(rv
), NS_ERROR_DOM_OPERATION_ERR
);
1205 ATTEMPT_BUFFER_ASSIGN(mSignature
, sig
.get());
1207 // Copy the given signature to the SECItem.
1208 if (!mSignature
.ToSECItem(nullptr, sig
.get())) {
1209 return NS_ERROR_DOM_OPERATION_ERR
;
1212 // Verify the signature.
1213 rv
= PK11_VerifyWithMechanism(mPubKey
.get(), mech
, params
, sig
.get(),
1214 hash
.get(), nullptr);
1215 mVerified
= NS_SUCCEEDED(MapSECStatus(rv
));
1221 virtual void Resolve() override
{
1223 TypedArrayCreator
<ArrayBuffer
> ret(mSignature
);
1224 mResultPromise
->MaybeResolve(ret
);
1226 mResultPromise
->MaybeResolve(mVerified
);
1231 class DigestTask
: public ReturnArrayBufferViewTask
{
1233 DigestTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
1234 const CryptoOperationData
& aData
) {
1235 ATTEMPT_BUFFER_INIT(mData
, aData
);
1238 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
1239 if (NS_FAILED(mEarlyRv
)) {
1240 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1244 TelemetryAlgorithm telemetryAlg
;
1245 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
1246 telemetryAlg
= TA_SHA_1
;
1247 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
1248 telemetryAlg
= TA_SHA_224
;
1249 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
1250 telemetryAlg
= TA_SHA_256
;
1251 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
1252 telemetryAlg
= TA_SHA_384
;
1254 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1257 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
1258 mOidTag
= MapHashAlgorithmNameToOID(algName
);
1265 virtual nsresult
DoCrypto() override
{
1266 // Resize the result buffer
1267 uint32_t hashLen
= HASH_ResultLenByOidTag(mOidTag
);
1268 if (!mResult
.SetLength(hashLen
, fallible
)) {
1269 return NS_ERROR_DOM_UNKNOWN_ERR
;
1273 nsresult rv
= MapSECStatus(PK11_HashBuf(mOidTag
, mResult
.Elements(),
1274 mData
.Elements(), mData
.Length()));
1275 if (NS_FAILED(rv
)) {
1276 return NS_ERROR_DOM_UNKNOWN_ERR
;
1283 class ImportKeyTask
: public WebCryptoTask
{
1285 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1286 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1287 const Sequence
<nsString
>& aKeyUsages
) {
1292 // This stuff pretty much always happens, so we'll do it here
1293 mKey
= new CryptoKey(aGlobal
);
1294 mKey
->SetExtractable(aExtractable
);
1295 mKey
->ClearUsages();
1296 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
1297 mEarlyRv
= mKey
->AddUsage(aKeyUsages
[i
]);
1298 if (NS_FAILED(mEarlyRv
)) {
1303 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, mAlgName
);
1304 if (NS_FAILED(mEarlyRv
)) {
1305 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1310 static bool JwkCompatible(const JsonWebKey
& aJwk
, const CryptoKey
* aKey
) {
1312 if (aKey
->Extractable() && aJwk
.mExt
.WasPassed() && !aJwk
.mExt
.Value()) {
1317 if (aJwk
.mAlg
.WasPassed() &&
1318 aJwk
.mAlg
.Value() != aKey
->Algorithm().JwkAlg()) {
1323 if (aJwk
.mKey_ops
.WasPassed()) {
1324 nsTArray
<nsString
> usages
;
1325 aKey
->GetUsages(usages
);
1326 for (size_t i
= 0; i
< usages
.Length(); ++i
) {
1327 if (!aJwk
.mKey_ops
.Value().Contains(usages
[i
])) {
1333 // Individual algorithms may still have to check 'use'
1337 void SetKeyData(JSContext
* aCx
, JS::Handle
<JSObject
*> aKeyData
) {
1341 RootedSpiderMonkeyInterface
<ArrayBuffer
> ab(aCx
);
1342 if (ab
.Init(aKeyData
)) {
1343 if (!mKeyData
.Assign(ab
)) {
1344 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1349 // Try ArrayBufferView
1350 RootedSpiderMonkeyInterface
<ArrayBufferView
> abv(aCx
);
1351 if (abv
.Init(aKeyData
)) {
1352 if (!mKeyData
.Assign(abv
)) {
1353 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1359 ClearException
ce(aCx
);
1360 JS::RootedValue
value(aCx
, JS::ObjectValue(*aKeyData
));
1361 if (!mJwk
.Init(aCx
, value
)) {
1362 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1369 void SetKeyDataMaybeParseJWK(const CryptoBuffer
& aKeyData
) {
1370 if (!mKeyData
.Assign(aKeyData
)) {
1371 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1377 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1378 nsDependentCSubstring
utf8(
1379 (const char*)mKeyData
.Elements(),
1380 (const char*)(mKeyData
.Elements() + mKeyData
.Length()));
1381 if (!IsUtf8(utf8
)) {
1382 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1386 nsString json
= NS_ConvertUTF8toUTF16(utf8
);
1387 if (!mJwk
.Init(json
)) {
1388 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1396 void SetRawKeyData(const CryptoBuffer
& aKeyData
) {
1397 if (!mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1398 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1402 if (!mKeyData
.Assign(aKeyData
)) {
1403 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1412 RefPtr
<CryptoKey
> mKey
;
1413 CryptoBuffer mKeyData
;
1420 virtual void Resolve() override
{ mResultPromise
->MaybeResolve(mKey
); }
1422 virtual void Cleanup() override
{ mKey
= nullptr; }
1425 class ImportSymmetricKeyTask
: public ImportKeyTask
{
1427 ImportSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1428 const nsAString
& aFormat
,
1429 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1430 const Sequence
<nsString
>& aKeyUsages
) {
1431 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1434 ImportSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1435 const nsAString
& aFormat
,
1436 const JS::Handle
<JSObject
*> aKeyData
,
1437 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1438 const Sequence
<nsString
>& aKeyUsages
) {
1439 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1440 if (NS_FAILED(mEarlyRv
)) {
1444 SetKeyData(aCx
, aKeyData
);
1445 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1446 if (mDataIsJwk
&& !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1447 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1452 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1453 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1454 const Sequence
<nsString
>& aKeyUsages
) {
1455 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1457 if (NS_FAILED(mEarlyRv
)) {
1461 // This task only supports raw and JWK format.
1462 if (!mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1463 !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1464 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1468 // If this is an HMAC key, import the hash name
1469 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
1470 RootedDictionary
<HmacImportParams
> params(aCx
);
1471 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1472 if (NS_FAILED(mEarlyRv
)) {
1473 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1476 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, mHashName
);
1477 if (NS_FAILED(mEarlyRv
)) {
1478 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1484 virtual nsresult
BeforeCrypto() override
{
1487 // If we're doing a JWK import, import the key data
1489 if (!mJwk
.mK
.WasPassed()) {
1490 return NS_ERROR_DOM_DATA_ERR
;
1493 // Import the key material
1494 rv
= mKeyData
.FromJwkBase64(mJwk
.mK
.Value());
1495 if (NS_FAILED(rv
)) {
1496 return NS_ERROR_DOM_DATA_ERR
;
1499 // Check that we have valid key data.
1500 if (mKeyData
.Length() == 0 &&
1501 !mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
)) {
1502 return NS_ERROR_DOM_DATA_ERR
;
1505 // Construct an appropriate KeyAlorithm,
1506 // and verify that usages are appropriate
1507 uint32_t length
= 8 * mKeyData
.Length(); // bytes to bits
1508 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
1509 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
1510 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
1511 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
1512 if (mKey
->HasUsageOtherThan(CryptoKey::ENCRYPT
| CryptoKey::DECRYPT
|
1513 CryptoKey::WRAPKEY
| CryptoKey::UNWRAPKEY
)) {
1514 return NS_ERROR_DOM_DATA_ERR
;
1517 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) &&
1518 mKey
->HasUsageOtherThan(CryptoKey::WRAPKEY
| CryptoKey::UNWRAPKEY
)) {
1519 return NS_ERROR_DOM_DATA_ERR
;
1522 if ((length
!= 128) && (length
!= 192) && (length
!= 256)) {
1523 return NS_ERROR_DOM_DATA_ERR
;
1525 mKey
->Algorithm().MakeAes(mAlgName
, length
);
1527 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed() &&
1528 !mJwk
.mUse
.Value().EqualsLiteral(JWK_USE_ENC
)) {
1529 return NS_ERROR_DOM_DATA_ERR
;
1531 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HKDF
) ||
1532 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
)) {
1533 if (mKey
->HasUsageOtherThan(CryptoKey::DERIVEKEY
|
1534 CryptoKey::DERIVEBITS
)) {
1535 return NS_ERROR_DOM_DATA_ERR
;
1537 mKey
->Algorithm().MakeAes(mAlgName
, length
);
1539 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed()) {
1540 // There is not a 'use' value consistent with PBKDF or HKDF
1541 return NS_ERROR_DOM_DATA_ERR
;
1543 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
1544 if (mKey
->HasUsageOtherThan(CryptoKey::SIGN
| CryptoKey::VERIFY
)) {
1545 return NS_ERROR_DOM_DATA_ERR
;
1548 mKey
->Algorithm().MakeHmac(length
, mHashName
);
1550 if (mKey
->Algorithm().Mechanism() == UNKNOWN_CK_MECHANISM
) {
1551 return NS_ERROR_DOM_SYNTAX_ERR
;
1554 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed() &&
1555 !mJwk
.mUse
.Value().EqualsLiteral(JWK_USE_SIG
)) {
1556 return NS_ERROR_DOM_DATA_ERR
;
1559 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1562 if (NS_FAILED(mKey
->SetSymKey(mKeyData
))) {
1563 return NS_ERROR_DOM_OPERATION_ERR
;
1566 mKey
->SetType(CryptoKey::SECRET
);
1568 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
1569 return NS_ERROR_DOM_DATA_ERR
;
1572 mEarlyComplete
= true;
1580 class ImportRsaKeyTask
: public ImportKeyTask
{
1582 ImportRsaKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1583 const nsAString
& aFormat
, const ObjectOrString
& aAlgorithm
,
1584 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
)
1585 : mModulusLength(0) {
1586 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1589 ImportRsaKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1590 const nsAString
& aFormat
, JS::Handle
<JSObject
*> aKeyData
,
1591 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1592 const Sequence
<nsString
>& aKeyUsages
)
1593 : mModulusLength(0) {
1594 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1595 if (NS_FAILED(mEarlyRv
)) {
1599 SetKeyData(aCx
, aKeyData
);
1600 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1601 if (mDataIsJwk
&& !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1602 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1607 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1608 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1609 const Sequence
<nsString
>& aKeyUsages
) {
1610 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1612 if (NS_FAILED(mEarlyRv
)) {
1616 // If this is RSA with a hash, cache the hash name
1617 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
1618 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
1619 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1620 RootedDictionary
<RsaHashedImportParams
> params(aCx
);
1621 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1622 if (NS_FAILED(mEarlyRv
)) {
1623 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1627 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, mHashName
);
1628 if (NS_FAILED(mEarlyRv
)) {
1629 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1634 // Check support for the algorithm and hash names
1635 CK_MECHANISM_TYPE mech1
= MapAlgorithmNameToMechanism(mAlgName
);
1636 CK_MECHANISM_TYPE mech2
= MapAlgorithmNameToMechanism(mHashName
);
1637 if ((mech1
== UNKNOWN_CK_MECHANISM
) || (mech2
== UNKNOWN_CK_MECHANISM
)) {
1638 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1645 uint32_t mModulusLength
;
1646 CryptoBuffer mPublicExponent
;
1648 virtual nsresult
DoCrypto() override
{
1649 // Import the key data itself
1650 UniqueSECKEYPublicKey pubKey
;
1651 UniqueSECKEYPrivateKey privKey
;
1652 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) ||
1653 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1654 !mJwk
.mD
.WasPassed())) {
1655 // Public key import
1656 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1657 pubKey
= CryptoKey::PublicKeyFromSpki(mKeyData
);
1659 pubKey
= CryptoKey::PublicKeyFromJwk(mJwk
);
1663 return NS_ERROR_DOM_DATA_ERR
;
1666 if (NS_FAILED(mKey
->SetPublicKey(pubKey
.get()))) {
1667 return NS_ERROR_DOM_OPERATION_ERR
;
1670 mKey
->SetType(CryptoKey::PUBLIC
);
1671 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) ||
1672 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1673 mJwk
.mD
.WasPassed())) {
1674 // Private key import
1675 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
1676 privKey
= CryptoKey::PrivateKeyFromPkcs8(mKeyData
);
1678 privKey
= CryptoKey::PrivateKeyFromJwk(mJwk
);
1682 return NS_ERROR_DOM_DATA_ERR
;
1685 if (NS_FAILED(mKey
->SetPrivateKey(privKey
.get()))) {
1686 return NS_ERROR_DOM_OPERATION_ERR
;
1689 mKey
->SetType(CryptoKey::PRIVATE
);
1690 pubKey
= UniqueSECKEYPublicKey(SECKEY_ConvertToPublicKey(privKey
.get()));
1692 return NS_ERROR_DOM_UNKNOWN_ERR
;
1695 // Invalid key format
1696 return NS_ERROR_DOM_SYNTAX_ERR
;
1699 // Extract relevant information from the public key
1700 mModulusLength
= 8 * pubKey
->u
.rsa
.modulus
.len
;
1701 if (!mPublicExponent
.Assign(&pubKey
->u
.rsa
.publicExponent
)) {
1702 return NS_ERROR_DOM_OPERATION_ERR
;
1708 virtual nsresult
AfterCrypto() override
{
1709 // Check permissions for the requested operation
1710 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
1711 if ((mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
1712 mKey
->HasUsageOtherThan(CryptoKey::ENCRYPT
| CryptoKey::WRAPKEY
)) ||
1713 (mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
1714 mKey
->HasUsageOtherThan(CryptoKey::DECRYPT
|
1715 CryptoKey::UNWRAPKEY
))) {
1716 return NS_ERROR_DOM_DATA_ERR
;
1718 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
1719 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1720 if ((mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
1721 mKey
->HasUsageOtherThan(CryptoKey::VERIFY
)) ||
1722 (mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
1723 mKey
->HasUsageOtherThan(CryptoKey::SIGN
))) {
1724 return NS_ERROR_DOM_DATA_ERR
;
1728 // Set an appropriate KeyAlgorithm
1729 if (!mKey
->Algorithm().MakeRsa(mAlgName
, mModulusLength
, mPublicExponent
,
1731 return NS_ERROR_DOM_OPERATION_ERR
;
1734 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
1735 return NS_ERROR_DOM_DATA_ERR
;
1742 class ImportEcKeyTask
: public ImportKeyTask
{
1744 ImportEcKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1745 const nsAString
& aFormat
, const ObjectOrString
& aAlgorithm
,
1746 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
1747 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1750 ImportEcKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1751 const nsAString
& aFormat
, JS::Handle
<JSObject
*> aKeyData
,
1752 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1753 const Sequence
<nsString
>& aKeyUsages
) {
1754 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1755 if (NS_FAILED(mEarlyRv
)) {
1759 SetKeyData(aCx
, aKeyData
);
1760 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1763 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1764 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1765 const Sequence
<nsString
>& aKeyUsages
) {
1766 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1768 if (NS_FAILED(mEarlyRv
)) {
1772 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1773 RootedDictionary
<EcKeyImportParams
> params(aCx
);
1774 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1775 if (NS_FAILED(mEarlyRv
) || !params
.mNamedCurve
.WasPassed()) {
1776 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1780 if (!NormalizeToken(params
.mNamedCurve
.Value(), mNamedCurve
)) {
1781 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1788 nsString mNamedCurve
;
1790 virtual nsresult
DoCrypto() override
{
1791 // Import the key data itself
1792 UniqueSECKEYPublicKey pubKey
;
1793 UniqueSECKEYPrivateKey privKey
;
1795 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1796 mJwk
.mD
.WasPassed()) {
1797 // Private key import
1798 privKey
= CryptoKey::PrivateKeyFromJwk(mJwk
);
1800 return NS_ERROR_DOM_DATA_ERR
;
1803 if (NS_FAILED(mKey
->SetPrivateKey(privKey
.get()))) {
1804 return NS_ERROR_DOM_OPERATION_ERR
;
1807 mKey
->SetType(CryptoKey::PRIVATE
);
1808 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) ||
1809 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) ||
1810 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1811 !mJwk
.mD
.WasPassed())) {
1812 // Public key import
1813 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1814 pubKey
= CryptoKey::PublicECKeyFromRaw(mKeyData
, mNamedCurve
);
1815 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1816 pubKey
= CryptoKey::PublicKeyFromSpki(mKeyData
);
1817 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1818 pubKey
= CryptoKey::PublicKeyFromJwk(mJwk
);
1824 return NS_ERROR_DOM_DATA_ERR
;
1827 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1828 if (!CheckEncodedECParameters(&pubKey
->u
.ec
.DEREncodedParams
)) {
1829 return NS_ERROR_DOM_OPERATION_ERR
;
1832 // Construct the OID tag.
1833 SECItem oid
= {siBuffer
, nullptr, 0};
1834 oid
.len
= pubKey
->u
.ec
.DEREncodedParams
.data
[1];
1835 oid
.data
= pubKey
->u
.ec
.DEREncodedParams
.data
+ 2;
1837 // Find a matching and supported named curve.
1838 if (!MapOIDTagToNamedCurve(SECOID_FindOIDTag(&oid
), mNamedCurve
)) {
1839 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1843 if (NS_FAILED(mKey
->SetPublicKey(pubKey
.get()))) {
1844 return NS_ERROR_DOM_OPERATION_ERR
;
1847 mKey
->SetType(CryptoKey::PUBLIC
);
1849 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1852 // Extract 'crv' parameter from JWKs.
1853 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1854 if (!NormalizeToken(mJwk
.mCrv
.Value(), mNamedCurve
)) {
1855 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1862 virtual nsresult
AfterCrypto() override
{
1863 uint32_t privateAllowedUsages
= 0, publicAllowedUsages
= 0;
1864 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
)) {
1865 privateAllowedUsages
= CryptoKey::DERIVEBITS
| CryptoKey::DERIVEKEY
;
1866 publicAllowedUsages
= CryptoKey::DERIVEBITS
| CryptoKey::DERIVEKEY
;
1867 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
1868 privateAllowedUsages
= CryptoKey::SIGN
;
1869 publicAllowedUsages
= CryptoKey::VERIFY
;
1872 // Check permissions for the requested operation
1873 if ((mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
1874 mKey
->HasUsageOtherThan(privateAllowedUsages
)) ||
1875 (mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
1876 mKey
->HasUsageOtherThan(publicAllowedUsages
))) {
1877 return NS_ERROR_DOM_DATA_ERR
;
1880 mKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
1882 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
1883 return NS_ERROR_DOM_DATA_ERR
;
1890 class ExportKeyTask
: public WebCryptoTask
{
1892 ExportKeyTask(const nsAString
& aFormat
, CryptoKey
& aKey
)
1894 mPrivateKey(aKey
.GetPrivateKey()),
1895 mPublicKey(aKey
.GetPublicKey()),
1896 mKeyType(aKey
.GetKeyType()),
1897 mExtractable(aKey
.Extractable()),
1898 mAlg(aKey
.Algorithm().JwkAlg()) {
1899 aKey
.GetUsages(mKeyUsages
);
1901 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
1902 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
1909 CryptoBuffer mSymKey
;
1910 UniqueSECKEYPrivateKey mPrivateKey
;
1911 UniqueSECKEYPublicKey mPublicKey
;
1912 CryptoKey::KeyType mKeyType
;
1915 nsTArray
<nsString
> mKeyUsages
;
1916 CryptoBuffer mResult
;
1920 virtual nsresult
DoCrypto() override
{
1921 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1922 if (mPublicKey
&& mPublicKey
->keyType
== dhKey
) {
1923 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1926 if (mPublicKey
&& mPublicKey
->keyType
== ecKey
) {
1927 nsresult rv
= CryptoKey::PublicECKeyToRaw(mPublicKey
.get(), mResult
);
1928 if (NS_FAILED(rv
)) {
1929 return NS_ERROR_DOM_OPERATION_ERR
;
1934 if (!mResult
.Assign(mSymKey
)) {
1935 return NS_ERROR_OUT_OF_MEMORY
;
1937 if (mResult
.Length() == 0) {
1938 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1942 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
1944 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1947 switch (mPrivateKey
->keyType
) {
1950 CryptoKey::PrivateKeyToPkcs8(mPrivateKey
.get(), mResult
);
1951 if (NS_FAILED(rv
)) {
1952 return NS_ERROR_DOM_OPERATION_ERR
;
1957 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1959 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1961 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1964 return CryptoKey::PublicKeyToSpki(mPublicKey
.get(), mResult
);
1965 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1966 if (mKeyType
== CryptoKey::SECRET
) {
1968 nsresult rv
= mSymKey
.ToJwkBase64(k
);
1969 if (NS_FAILED(rv
)) {
1970 return NS_ERROR_DOM_OPERATION_ERR
;
1972 mJwk
.mK
.Construct(k
);
1973 mJwk
.mKty
= NS_LITERAL_STRING_FROM_CSTRING(JWK_TYPE_SYMMETRIC
);
1974 } else if (mKeyType
== CryptoKey::PUBLIC
) {
1976 return NS_ERROR_DOM_UNKNOWN_ERR
;
1979 nsresult rv
= CryptoKey::PublicKeyToJwk(mPublicKey
.get(), mJwk
);
1980 if (NS_FAILED(rv
)) {
1981 return NS_ERROR_DOM_OPERATION_ERR
;
1983 } else if (mKeyType
== CryptoKey::PRIVATE
) {
1985 return NS_ERROR_DOM_UNKNOWN_ERR
;
1988 nsresult rv
= CryptoKey::PrivateKeyToJwk(mPrivateKey
.get(), mJwk
);
1989 if (NS_FAILED(rv
)) {
1990 return NS_ERROR_DOM_OPERATION_ERR
;
1994 if (!mAlg
.IsEmpty()) {
1995 mJwk
.mAlg
.Construct(mAlg
);
1998 mJwk
.mExt
.Construct(mExtractable
);
2000 mJwk
.mKey_ops
.Construct();
2001 if (!mJwk
.mKey_ops
.Value().AppendElements(mKeyUsages
, fallible
)) {
2002 return NS_ERROR_OUT_OF_MEMORY
;
2008 return NS_ERROR_DOM_SYNTAX_ERR
;
2011 // Returns mResult as an ArrayBufferView or JWK, as appropriate
2012 virtual void Resolve() override
{
2013 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2014 mResultPromise
->MaybeResolve(mJwk
);
2018 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
2019 mResultPromise
->MaybeResolve(ret
);
2023 class GenerateSymmetricKeyTask
: public WebCryptoTask
{
2025 GenerateSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2026 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
2027 const Sequence
<nsString
>& aKeyUsages
) {
2028 // Create an empty key and set easy attributes
2029 mKey
= new CryptoKey(aGlobal
);
2030 mKey
->SetExtractable(aExtractable
);
2031 mKey
->SetType(CryptoKey::SECRET
);
2033 // Extract algorithm name
2035 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
2036 if (NS_FAILED(mEarlyRv
)) {
2040 // Construct an appropriate KeyAlorithm
2041 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
2042 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
2043 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
2044 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
2045 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aAlgorithm
, mLength
);
2046 if (NS_FAILED(mEarlyRv
)) {
2049 mKey
->Algorithm().MakeAes(algName
, mLength
);
2051 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
2052 RootedDictionary
<HmacKeyGenParams
> params(aCx
);
2053 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2054 if (NS_FAILED(mEarlyRv
)) {
2055 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2060 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2061 if (NS_FAILED(mEarlyRv
)) {
2065 if (params
.mLength
.WasPassed()) {
2066 mLength
= params
.mLength
.Value();
2068 mLength
= MapHashAlgorithmNameToBlockSize(hashName
);
2072 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
2076 mKey
->Algorithm().MakeHmac(mLength
, hashName
);
2078 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2083 mKey
->ClearUsages();
2084 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
2085 mEarlyRv
= mKey
->AddAllowedUsageIntersecting(aKeyUsages
[i
], algName
);
2086 if (NS_FAILED(mEarlyRv
)) {
2090 if (!mKey
->HasAnyUsage()) {
2091 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2095 mLength
= mLength
>> 3; // bits to bytes
2096 mMechanism
= mKey
->Algorithm().Mechanism();
2097 // SetSymKey done in Resolve, after we've done the keygen
2101 RefPtr
<CryptoKey
> mKey
;
2103 CK_MECHANISM_TYPE mMechanism
;
2104 CryptoBuffer mKeyData
;
2106 virtual nsresult
DoCrypto() override
{
2107 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2108 MOZ_ASSERT(slot
.get());
2110 UniquePK11SymKey
symKey(
2111 PK11_KeyGen(slot
.get(), mMechanism
, nullptr, mLength
, nullptr));
2113 return NS_ERROR_DOM_UNKNOWN_ERR
;
2116 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2117 if (NS_FAILED(rv
)) {
2118 return NS_ERROR_DOM_UNKNOWN_ERR
;
2121 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2122 // just refers to a buffer managed by symKey. The assignment copies the
2123 // data, so mKeyData manages one copy, while symKey manages another.
2124 ATTEMPT_BUFFER_ASSIGN(mKeyData
, PK11_GetKeyData(symKey
.get()));
2128 virtual void Resolve() override
{
2129 if (NS_SUCCEEDED(mKey
->SetSymKey(mKeyData
))) {
2130 mResultPromise
->MaybeResolve(mKey
);
2132 mResultPromise
->MaybeReject(NS_ERROR_DOM_OPERATION_ERR
);
2136 virtual void Cleanup() override
{ mKey
= nullptr; }
2139 GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
2140 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2141 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
)
2142 : mKeyPair(new CryptoKeyPair()),
2143 mMechanism(CKM_INVALID_MECHANISM
),
2146 mArena
= UniquePLArenaPool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
2148 mEarlyRv
= NS_ERROR_DOM_UNKNOWN_ERR
;
2152 // Create an empty key pair and set easy attributes
2153 mKeyPair
->mPrivateKey
= new CryptoKey(aGlobal
);
2154 mKeyPair
->mPublicKey
= new CryptoKey(aGlobal
);
2156 // Extract algorithm name
2157 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, mAlgName
);
2158 if (NS_FAILED(mEarlyRv
)) {
2162 // Construct an appropriate KeyAlorithm
2163 uint32_t privateAllowedUsages
= 0, publicAllowedUsages
= 0;
2164 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2165 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
2166 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
2167 RootedDictionary
<RsaHashedKeyGenParams
> params(aCx
);
2168 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2169 if (NS_FAILED(mEarlyRv
)) {
2170 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2174 // Pull relevant info
2175 uint32_t modulusLength
= params
.mModulusLength
;
2176 CryptoBuffer publicExponent
;
2177 ATTEMPT_BUFFER_INIT(publicExponent
, params
.mPublicExponent
);
2179 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2180 if (NS_FAILED(mEarlyRv
)) {
2185 if (!mKeyPair
->mPublicKey
->Algorithm().MakeRsa(mAlgName
, modulusLength
,
2186 publicExponent
, hashName
)) {
2187 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2190 if (!mKeyPair
->mPrivateKey
->Algorithm().MakeRsa(mAlgName
, modulusLength
,
2191 publicExponent
, hashName
)) {
2192 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2195 mMechanism
= CKM_RSA_PKCS_KEY_PAIR_GEN
;
2197 // Set up params struct
2198 mRsaParams
.keySizeInBits
= modulusLength
;
2199 bool converted
= publicExponent
.GetBigIntValue(mRsaParams
.pe
);
2201 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2204 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
2205 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
2206 RootedDictionary
<EcKeyGenParams
> params(aCx
);
2207 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2208 if (NS_FAILED(mEarlyRv
)) {
2209 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2213 if (!NormalizeToken(params
.mNamedCurve
, mNamedCurve
)) {
2214 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2218 // Create algorithm.
2219 mKeyPair
->mPublicKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
2220 mKeyPair
->mPrivateKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
2221 mMechanism
= CKM_EC_KEY_PAIR_GEN
;
2223 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2228 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2229 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
2230 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
2231 privateAllowedUsages
= CryptoKey::SIGN
;
2232 publicAllowedUsages
= CryptoKey::VERIFY
;
2233 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
2234 privateAllowedUsages
= CryptoKey::DECRYPT
| CryptoKey::UNWRAPKEY
;
2235 publicAllowedUsages
= CryptoKey::ENCRYPT
| CryptoKey::WRAPKEY
;
2236 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
)) {
2237 privateAllowedUsages
= CryptoKey::DERIVEKEY
| CryptoKey::DERIVEBITS
;
2238 publicAllowedUsages
= 0;
2240 MOZ_ASSERT(false); // This shouldn't happen.
2243 mKeyPair
->mPrivateKey
->SetExtractable(aExtractable
);
2244 mKeyPair
->mPrivateKey
->SetType(CryptoKey::PRIVATE
);
2246 mKeyPair
->mPublicKey
->SetExtractable(true);
2247 mKeyPair
->mPublicKey
->SetType(CryptoKey::PUBLIC
);
2249 mKeyPair
->mPrivateKey
->ClearUsages();
2250 mKeyPair
->mPublicKey
->ClearUsages();
2251 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
2252 mEarlyRv
= mKeyPair
->mPrivateKey
->AddAllowedUsageIntersecting(
2253 aKeyUsages
[i
], mAlgName
, privateAllowedUsages
);
2254 if (NS_FAILED(mEarlyRv
)) {
2258 mEarlyRv
= mKeyPair
->mPublicKey
->AddAllowedUsageIntersecting(
2259 aKeyUsages
[i
], mAlgName
, publicAllowedUsages
);
2260 if (NS_FAILED(mEarlyRv
)) {
2266 nsresult
GenerateAsymmetricKeyTask::DoCrypto() {
2267 MOZ_ASSERT(mKeyPair
);
2269 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2270 MOZ_ASSERT(slot
.get());
2273 switch (mMechanism
) {
2274 case CKM_RSA_PKCS_KEY_PAIR_GEN
:
2275 param
= &mRsaParams
;
2277 case CKM_DH_PKCS_KEY_PAIR_GEN
:
2280 case CKM_EC_KEY_PAIR_GEN
: {
2281 param
= CreateECParamsForCurve(mNamedCurve
, mArena
.get());
2283 return NS_ERROR_DOM_UNKNOWN_ERR
;
2288 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2291 SECKEYPublicKey
* pubKey
= nullptr;
2292 mPrivateKey
= UniqueSECKEYPrivateKey(PK11_GenerateKeyPair(
2293 slot
.get(), mMechanism
, param
, &pubKey
, PR_FALSE
, PR_FALSE
, nullptr));
2294 mPublicKey
= UniqueSECKEYPublicKey(pubKey
);
2296 if (!mPrivateKey
.get() || !mPublicKey
.get()) {
2297 return NS_ERROR_DOM_OPERATION_ERR
;
2300 // If no usages ended up being allowed, SyntaxError
2301 if (!mKeyPair
->mPrivateKey
->HasAnyUsage()) {
2302 return NS_ERROR_DOM_SYNTAX_ERR
;
2305 nsresult rv
= mKeyPair
->mPrivateKey
->SetPrivateKey(mPrivateKey
.get());
2306 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2307 rv
= mKeyPair
->mPublicKey
->SetPublicKey(mPublicKey
.get());
2308 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2310 // PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the
2311 // private key, we need this later when exporting to PKCS8 and JWK though.
2312 if (mMechanism
== CKM_EC_KEY_PAIR_GEN
) {
2313 rv
= mKeyPair
->mPrivateKey
->AddPublicKeyData(mPublicKey
.get());
2314 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2320 void GenerateAsymmetricKeyTask::Resolve() {
2321 mResultPromise
->MaybeResolve(*mKeyPair
);
2324 void GenerateAsymmetricKeyTask::Cleanup() { mKeyPair
= nullptr; }
2326 class DeriveHkdfBitsTask
: public ReturnArrayBufferViewTask
{
2328 DeriveHkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2329 CryptoKey
& aKey
, uint32_t aLength
)
2330 : mMechanism(CKM_INVALID_MECHANISM
) {
2331 Init(aCx
, aAlgorithm
, aKey
, aLength
);
2334 DeriveHkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2335 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2336 : mLengthInBits(0), mLengthInBytes(0), mMechanism(CKM_INVALID_MECHANISM
) {
2338 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aTargetAlgorithm
, length
);
2340 if (NS_SUCCEEDED(mEarlyRv
)) {
2341 Init(aCx
, aAlgorithm
, aKey
, length
);
2345 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
2347 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_HKDF
);
2348 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_HKDF
);
2350 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
2351 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
2355 // Check that we have a key.
2356 if (mSymKey
.Length() == 0) {
2357 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2361 RootedDictionary
<HkdfParams
> params(aCx
);
2362 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2363 if (NS_FAILED(mEarlyRv
)) {
2364 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2368 // length must be greater than zero.
2370 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
2374 // Extract the hash algorithm.
2376 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2377 if (NS_FAILED(mEarlyRv
)) {
2381 // Check the given hash algorithm.
2382 switch (MapAlgorithmNameToMechanism(hashName
)) {
2384 mMechanism
= CKM_NSS_HKDF_SHA1
;
2387 mMechanism
= CKM_NSS_HKDF_SHA256
;
2390 mMechanism
= CKM_NSS_HKDF_SHA384
;
2393 mMechanism
= CKM_NSS_HKDF_SHA512
;
2396 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2400 ATTEMPT_BUFFER_INIT(mSalt
, params
.mSalt
)
2401 ATTEMPT_BUFFER_INIT(mInfo
, params
.mInfo
)
2402 mLengthInBytes
= ceil((double)aLength
/ 8);
2403 mLengthInBits
= aLength
;
2407 size_t mLengthInBits
;
2408 size_t mLengthInBytes
;
2411 CryptoBuffer mSymKey
;
2412 CK_MECHANISM_TYPE mMechanism
;
2414 virtual nsresult
DoCrypto() override
{
2415 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
2417 return NS_ERROR_DOM_OPERATION_ERR
;
2421 SECItem keyItem
= {siBuffer
, nullptr, 0};
2422 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
2424 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2426 return NS_ERROR_DOM_OPERATION_ERR
;
2429 UniquePK11SymKey
baseKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
2430 PK11_OriginUnwrap
, CKA_WRAP
,
2431 &keyItem
, nullptr));
2433 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2436 SECItem salt
= {siBuffer
, nullptr, 0};
2437 SECItem info
= {siBuffer
, nullptr, 0};
2438 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &salt
, mSalt
);
2439 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &info
, mInfo
);
2441 CK_NSS_HKDFParams hkdfParams
= {true, salt
.data
, salt
.len
,
2442 true, info
.data
, info
.len
};
2443 SECItem params
= {siBuffer
, (unsigned char*)&hkdfParams
,
2444 sizeof(hkdfParams
)};
2446 // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
2447 // derived symmetric key and don't matter because we ignore them anyway.
2448 UniquePK11SymKey
symKey(PK11_Derive(baseKey
.get(), mMechanism
, ¶ms
,
2449 CKM_SHA512_HMAC
, CKA_SIGN
,
2452 if (!symKey
.get()) {
2453 return NS_ERROR_DOM_OPERATION_ERR
;
2456 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2457 if (NS_FAILED(rv
)) {
2458 return NS_ERROR_DOM_OPERATION_ERR
;
2461 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2462 // just refers to a buffer managed by symKey. The assignment copies the
2463 // data, so mResult manages one copy, while symKey manages another.
2464 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
2466 if (mLengthInBytes
> mResult
.Length()) {
2467 return NS_ERROR_DOM_DATA_ERR
;
2470 if (!mResult
.SetLength(mLengthInBytes
, fallible
)) {
2471 return NS_ERROR_DOM_UNKNOWN_ERR
;
2474 // If the number of bits to derive is not a multiple of 8 we need to
2475 // zero out the remaining bits that were derived but not requested.
2476 if (mLengthInBits
% 8) {
2477 mResult
[mResult
.Length() - 1] &= 0xff << (mLengthInBits
% 8);
2484 class DerivePbkdfBitsTask
: public ReturnArrayBufferViewTask
{
2486 DerivePbkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2487 CryptoKey
& aKey
, uint32_t aLength
)
2488 : mHashOidTag(SEC_OID_UNKNOWN
) {
2489 Init(aCx
, aAlgorithm
, aKey
, aLength
);
2492 DerivePbkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2493 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2494 : mLength(0), mIterations(0), mHashOidTag(SEC_OID_UNKNOWN
) {
2496 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aTargetAlgorithm
, length
);
2498 if (NS_SUCCEEDED(mEarlyRv
)) {
2499 Init(aCx
, aAlgorithm
, aKey
, length
);
2503 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
2505 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_PBKDF2
);
2506 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_PBKDF2
);
2508 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
2509 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
2513 RootedDictionary
<Pbkdf2Params
> params(aCx
);
2514 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2515 if (NS_FAILED(mEarlyRv
)) {
2516 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2520 // length must be a multiple of 8 bigger than zero.
2521 if (aLength
== 0 || aLength
% 8) {
2522 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2526 // Extract the hash algorithm.
2528 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2529 if (NS_FAILED(mEarlyRv
)) {
2533 // Check the given hash algorithm.
2534 switch (MapAlgorithmNameToMechanism(hashName
)) {
2536 mHashOidTag
= SEC_OID_HMAC_SHA1
;
2539 mHashOidTag
= SEC_OID_HMAC_SHA256
;
2542 mHashOidTag
= SEC_OID_HMAC_SHA384
;
2545 mHashOidTag
= SEC_OID_HMAC_SHA512
;
2548 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2552 ATTEMPT_BUFFER_INIT(mSalt
, params
.mSalt
)
2553 mLength
= aLength
>> 3; // bits to bytes
2554 mIterations
= params
.mIterations
;
2561 CryptoBuffer mSymKey
;
2562 SECOidTag mHashOidTag
;
2564 virtual nsresult
DoCrypto() override
{
2565 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
2567 return NS_ERROR_DOM_OPERATION_ERR
;
2570 SECItem salt
= {siBuffer
, nullptr, 0};
2571 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &salt
, mSalt
);
2572 // PK11_CreatePBEV2AlgorithmID will "helpfully" create PBKDF2 parameters
2573 // with a random salt if given a SECItem* that is either null or has a null
2574 // data pointer. This obviously isn't what we want, so we have to fake it
2575 // out by passing in a SECItem* with a non-null data pointer but with zero
2578 MOZ_ASSERT(salt
.len
== 0);
2580 reinterpret_cast<unsigned char*>(PORT_ArenaAlloc(arena
.get(), 1));
2582 return NS_ERROR_DOM_UNKNOWN_ERR
;
2586 // Always pass in cipherAlg=SEC_OID_HMAC_SHA1 (i.e. PBMAC1) as this
2587 // parameter is unused for key generation. It is currently only used
2588 // for PBKDF2 authentication or key (un)wrapping when specifying an
2589 // encryption algorithm (PBES2).
2590 UniqueSECAlgorithmID
algID(
2591 PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2
, SEC_OID_HMAC_SHA1
,
2592 mHashOidTag
, mLength
, mIterations
, &salt
));
2595 return NS_ERROR_DOM_OPERATION_ERR
;
2598 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2600 return NS_ERROR_DOM_OPERATION_ERR
;
2603 SECItem keyItem
= {siBuffer
, nullptr, 0};
2604 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
2606 UniquePK11SymKey
symKey(
2607 PK11_PBEKeyGen(slot
.get(), algID
.get(), &keyItem
, false, nullptr));
2608 if (!symKey
.get()) {
2609 return NS_ERROR_DOM_OPERATION_ERR
;
2612 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2613 if (NS_FAILED(rv
)) {
2614 return NS_ERROR_DOM_OPERATION_ERR
;
2617 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2618 // just refers to a buffer managed by symKey. The assignment copies the
2619 // data, so mResult manages one copy, while symKey manages another.
2620 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
2625 template <class DeriveBitsTask
>
2626 class DeriveKeyTask
: public DeriveBitsTask
{
2628 DeriveKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2629 const ObjectOrString
& aAlgorithm
, CryptoKey
& aBaseKey
,
2630 const ObjectOrString
& aDerivedKeyType
, bool aExtractable
,
2631 const Sequence
<nsString
>& aKeyUsages
)
2632 : DeriveBitsTask(aCx
, aAlgorithm
, aBaseKey
, aDerivedKeyType
) {
2633 if (NS_FAILED(this->mEarlyRv
)) {
2637 constexpr auto format
=
2638 NS_LITERAL_STRING_FROM_CSTRING(WEBCRYPTO_KEY_FORMAT_RAW
);
2639 mTask
= new ImportSymmetricKeyTask(aGlobal
, aCx
, format
, aDerivedKeyType
,
2640 aExtractable
, aKeyUsages
);
2644 RefPtr
<ImportSymmetricKeyTask
> mTask
;
2647 virtual void Resolve() override
{
2648 mTask
->SetRawKeyData(this->mResult
);
2649 mTask
->DispatchWithPromise(this->mResultPromise
);
2652 virtual void Cleanup() override
{ mTask
= nullptr; }
2655 class DeriveEcdhBitsTask
: public ReturnArrayBufferViewTask
{
2657 DeriveEcdhBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2658 CryptoKey
& aKey
, uint32_t aLength
)
2659 : mLength(aLength
), mPrivKey(aKey
.GetPrivateKey()) {
2660 Init(aCx
, aAlgorithm
, aKey
);
2663 DeriveEcdhBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2664 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2665 : mPrivKey(aKey
.GetPrivateKey()) {
2666 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aTargetAlgorithm
, mLength
);
2667 if (NS_SUCCEEDED(mEarlyRv
)) {
2668 Init(aCx
, aAlgorithm
, aKey
);
2672 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
) {
2673 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_ECDH
);
2674 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_ECDH
);
2676 // Check that we have a private key.
2678 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2682 // Length must be a multiple of 8 bigger than zero.
2683 if (mLength
== 0 || mLength
% 8) {
2684 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
2688 mLength
= mLength
>> 3; // bits to bytes
2690 // Retrieve the peer's public key.
2691 RootedDictionary
<EcdhKeyDeriveParams
> params(aCx
);
2692 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2693 if (NS_FAILED(mEarlyRv
)) {
2694 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2698 CryptoKey
* publicKey
= params
.mPublic
;
2699 mPubKey
= publicKey
->GetPublicKey();
2701 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2705 CHECK_KEY_ALGORITHM(publicKey
->Algorithm(), WEBCRYPTO_ALG_ECDH
);
2707 // Both keys must use the same named curve.
2708 nsString curve1
= aKey
.Algorithm().mEc
.mNamedCurve
;
2709 nsString curve2
= publicKey
->Algorithm().mEc
.mNamedCurve
;
2711 if (!curve1
.Equals(curve2
)) {
2712 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
2719 UniqueSECKEYPrivateKey mPrivKey
;
2720 UniqueSECKEYPublicKey mPubKey
;
2722 virtual nsresult
DoCrypto() override
{
2723 // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
2724 // derived symmetric key and don't matter because we ignore them anyway.
2725 UniquePK11SymKey
symKey(
2726 PK11_PubDeriveWithKDF(mPrivKey
.get(), mPubKey
.get(), PR_FALSE
, nullptr,
2727 nullptr, CKM_ECDH1_DERIVE
, CKM_SHA512_HMAC
,
2728 CKA_SIGN
, 0, CKD_NULL
, nullptr, nullptr));
2730 if (!symKey
.get()) {
2731 return NS_ERROR_DOM_OPERATION_ERR
;
2734 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2735 if (NS_FAILED(rv
)) {
2736 return NS_ERROR_DOM_OPERATION_ERR
;
2739 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2740 // just refers to a buffer managed by symKey. The assignment copies the
2741 // data, so mResult manages one copy, while symKey manages another.
2742 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
2744 if (mLength
> mResult
.Length()) {
2745 return NS_ERROR_DOM_DATA_ERR
;
2748 if (!mResult
.SetLength(mLength
, fallible
)) {
2749 return NS_ERROR_DOM_UNKNOWN_ERR
;
2756 template <class KeyEncryptTask
>
2757 class WrapKeyTask
: public ExportKeyTask
{
2759 WrapKeyTask(JSContext
* aCx
, const nsAString
& aFormat
, CryptoKey
& aKey
,
2760 CryptoKey
& aWrappingKey
, const ObjectOrString
& aWrapAlgorithm
)
2761 : ExportKeyTask(aFormat
, aKey
) {
2762 if (NS_FAILED(mEarlyRv
)) {
2766 mTask
= new KeyEncryptTask(aCx
, aWrapAlgorithm
, aWrappingKey
, true);
2770 RefPtr
<KeyEncryptTask
> mTask
;
2772 virtual nsresult
AfterCrypto() override
{
2773 // If wrapping JWK, stringify the JSON
2774 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2776 if (!mJwk
.ToJSON(json
)) {
2777 return NS_ERROR_DOM_OPERATION_ERR
;
2780 NS_ConvertUTF16toUTF8
utf8(json
);
2781 if (!mResult
.Assign((const uint8_t*)utf8
.BeginReading(), utf8
.Length())) {
2782 return NS_ERROR_DOM_OPERATION_ERR
;
2789 virtual void Resolve() override
{
2790 mTask
->SetData(mResult
);
2791 mTask
->DispatchWithPromise(mResultPromise
);
2794 virtual void Cleanup() override
{ mTask
= nullptr; }
2797 template <class KeyEncryptTask
>
2798 class UnwrapKeyTask
: public KeyEncryptTask
{
2800 UnwrapKeyTask(JSContext
* aCx
, const ArrayBufferViewOrArrayBuffer
& aWrappedKey
,
2801 CryptoKey
& aUnwrappingKey
,
2802 const ObjectOrString
& aUnwrapAlgorithm
, ImportKeyTask
* aTask
)
2803 : KeyEncryptTask(aCx
, aUnwrapAlgorithm
, aUnwrappingKey
, aWrappedKey
,
2808 RefPtr
<ImportKeyTask
> mTask
;
2810 virtual void Resolve() override
{
2811 mTask
->SetKeyDataMaybeParseJWK(KeyEncryptTask::mResult
);
2812 mTask
->DispatchWithPromise(KeyEncryptTask::mResultPromise
);
2815 virtual void Cleanup() override
{ mTask
= nullptr; }
2818 // Task creation methods for WebCryptoTask
2820 // Note: We do not perform algorithm normalization as a monolithic process,
2821 // as described in the spec. Instead:
2822 // * Each method handles its slice of the supportedAlgorithms structure
2823 // * Task constructors take care of:
2824 // * Coercing the algorithm to the proper concrete type
2825 // * Cloning subordinate data items
2826 // * Cloning input data as needed
2828 // Thus, support for different algorithms is determined by the if-statements
2829 // below, rather than a data structure.
2831 // This results in algorithm normalization coming after some other checks,
2832 // and thus slightly more steps being done synchronously than the spec calls
2833 // for. But none of these steps is especially time-consuming.
2835 WebCryptoTask
* WebCryptoTask::CreateEncryptDecryptTask(
2836 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
2837 const CryptoOperationData
& aData
, bool aEncrypt
) {
2838 TelemetryMethod method
= (aEncrypt
) ? TM_ENCRYPT
: TM_DECRYPT
;
2839 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, method
);
2840 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_ENC
,
2841 aKey
.Extractable());
2843 // Ensure key is usable for this operation
2844 if ((aEncrypt
&& !aKey
.HasUsage(CryptoKey::ENCRYPT
)) ||
2845 (!aEncrypt
&& !aKey
.HasUsage(CryptoKey::DECRYPT
))) {
2846 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
2850 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
2851 if (NS_FAILED(rv
)) {
2852 return new FailureTask(rv
);
2855 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
2856 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
2857 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
2858 return new AesTask(aCx
, aAlgorithm
, aKey
, aData
, aEncrypt
);
2859 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
2860 return new RsaOaepTask(aCx
, aAlgorithm
, aKey
, aData
, aEncrypt
);
2863 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
2866 WebCryptoTask
* WebCryptoTask::CreateSignVerifyTask(
2867 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
2868 const CryptoOperationData
& aSignature
, const CryptoOperationData
& aData
,
2870 TelemetryMethod method
= (aSign
) ? TM_SIGN
: TM_VERIFY
;
2871 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, method
);
2872 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_SIG
,
2873 aKey
.Extractable());
2875 // Ensure key is usable for this operation
2876 if ((aSign
&& !aKey
.HasUsage(CryptoKey::SIGN
)) ||
2877 (!aSign
&& !aKey
.HasUsage(CryptoKey::VERIFY
))) {
2878 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
2882 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
2883 if (NS_FAILED(rv
)) {
2884 return new FailureTask(rv
);
2887 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
2888 return new HmacTask(aCx
, aAlgorithm
, aKey
, aSignature
, aData
, aSign
);
2889 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2890 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
2891 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
2892 return new AsymmetricSignVerifyTask(aCx
, aAlgorithm
, aKey
, aSignature
,
2896 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
2899 WebCryptoTask
* WebCryptoTask::CreateDigestTask(
2900 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2901 const CryptoOperationData
& aData
) {
2902 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DIGEST
);
2905 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
2906 if (NS_FAILED(rv
)) {
2907 return new FailureTask(rv
);
2910 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
) ||
2911 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
) ||
2912 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
) ||
2913 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
2914 return new DigestTask(aCx
, aAlgorithm
, aData
);
2917 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
2920 WebCryptoTask
* WebCryptoTask::CreateImportKeyTask(
2921 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
2922 JS::Handle
<JSObject
*> aKeyData
, const ObjectOrString
& aAlgorithm
,
2923 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
2924 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_IMPORTKEY
);
2925 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT
, aExtractable
);
2927 // Verify that the format is recognized
2928 if (!aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) &&
2929 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) &&
2930 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) &&
2931 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2932 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
2935 // Verify that aKeyUsages does not contain an unrecognized value
2936 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
2937 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
2941 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
2942 if (NS_FAILED(rv
)) {
2943 return new FailureTask(rv
);
2946 // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation.
2947 // However, the spec should be updated to allow it.
2948 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
2949 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
2950 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
2951 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) ||
2952 algName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
) ||
2953 algName
.EqualsLiteral(WEBCRYPTO_ALG_HKDF
) ||
2954 algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
2955 return new ImportSymmetricKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
,
2956 aAlgorithm
, aExtractable
, aKeyUsages
);
2957 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2958 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
2959 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
2960 return new ImportRsaKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
, aAlgorithm
,
2961 aExtractable
, aKeyUsages
);
2962 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
2963 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
2964 return new ImportEcKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
, aAlgorithm
,
2965 aExtractable
, aKeyUsages
);
2967 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
2971 WebCryptoTask
* WebCryptoTask::CreateExportKeyTask(const nsAString
& aFormat
,
2973 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_EXPORTKEY
);
2975 // Verify that the format is recognized
2976 if (!aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) &&
2977 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) &&
2978 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) &&
2979 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2980 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
2983 // Verify that the key is extractable
2984 if (!aKey
.Extractable()) {
2985 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
2988 // Verify that the algorithm supports export
2989 // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation.
2990 // However, the spec should be updated to allow it.
2991 nsString algName
= aKey
.Algorithm().mName
;
2992 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
2993 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
2994 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
2995 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) ||
2996 algName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
) ||
2997 algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
) ||
2998 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2999 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
3000 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
3001 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
) ||
3002 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
)) {
3003 return new ExportKeyTask(aFormat
, aKey
);
3006 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3009 WebCryptoTask
* WebCryptoTask::CreateGenerateKeyTask(
3010 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3011 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
3012 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_GENERATEKEY
);
3013 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_GENERATE
,
3016 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3017 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3021 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3022 if (NS_FAILED(rv
)) {
3023 return new FailureTask(rv
);
3026 if (algName
.EqualsASCII(WEBCRYPTO_ALG_AES_CBC
) ||
3027 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_CTR
) ||
3028 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_GCM
) ||
3029 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_KW
) ||
3030 algName
.EqualsASCII(WEBCRYPTO_ALG_HMAC
)) {
3031 return new GenerateSymmetricKeyTask(aGlobal
, aCx
, aAlgorithm
, aExtractable
,
3033 } else if (algName
.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3034 algName
.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP
) ||
3035 algName
.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS
) ||
3036 algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
) ||
3037 algName
.EqualsASCII(WEBCRYPTO_ALG_ECDSA
)) {
3038 return new GenerateAsymmetricKeyTask(aGlobal
, aCx
, aAlgorithm
, aExtractable
,
3041 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3045 WebCryptoTask
* WebCryptoTask::CreateDeriveKeyTask(
3046 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3047 CryptoKey
& aBaseKey
, const ObjectOrString
& aDerivedKeyType
,
3048 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
3049 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DERIVEKEY
);
3051 // Ensure baseKey is usable for this operation
3052 if (!aBaseKey
.HasUsage(CryptoKey::DERIVEKEY
)) {
3053 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3056 // Verify that aKeyUsages does not contain an unrecognized value
3057 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3058 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3062 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3063 if (NS_FAILED(rv
)) {
3064 return new FailureTask(rv
);
3067 if (algName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
)) {
3068 return new DeriveKeyTask
<DeriveHkdfBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3069 aBaseKey
, aDerivedKeyType
,
3070 aExtractable
, aKeyUsages
);
3073 if (algName
.EqualsASCII(WEBCRYPTO_ALG_PBKDF2
)) {
3074 return new DeriveKeyTask
<DerivePbkdfBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3075 aBaseKey
, aDerivedKeyType
,
3076 aExtractable
, aKeyUsages
);
3079 if (algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
)) {
3080 return new DeriveKeyTask
<DeriveEcdhBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3081 aBaseKey
, aDerivedKeyType
,
3082 aExtractable
, aKeyUsages
);
3085 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3088 WebCryptoTask
* WebCryptoTask::CreateDeriveBitsTask(
3089 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
3091 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DERIVEBITS
);
3093 // Ensure baseKey is usable for this operation
3094 if (!aKey
.HasUsage(CryptoKey::DERIVEBITS
)) {
3095 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3099 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3100 if (NS_FAILED(rv
)) {
3101 return new FailureTask(rv
);
3104 if (algName
.EqualsASCII(WEBCRYPTO_ALG_PBKDF2
)) {
3105 return new DerivePbkdfBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3108 if (algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
)) {
3109 return new DeriveEcdhBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3112 if (algName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
)) {
3113 return new DeriveHkdfBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3116 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3119 WebCryptoTask
* WebCryptoTask::CreateWrapKeyTask(
3120 JSContext
* aCx
, const nsAString
& aFormat
, CryptoKey
& aKey
,
3121 CryptoKey
& aWrappingKey
, const ObjectOrString
& aWrapAlgorithm
) {
3122 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_WRAPKEY
);
3124 // Verify that the format is recognized
3125 if (!aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) &&
3126 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) &&
3127 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) &&
3128 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
3129 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3132 // Ensure wrappingKey is usable for this operation
3133 if (!aWrappingKey
.HasUsage(CryptoKey::WRAPKEY
)) {
3134 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3137 // Ensure key is extractable
3138 if (!aKey
.Extractable()) {
3139 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3142 nsString wrapAlgName
;
3143 nsresult rv
= GetAlgorithmName(aCx
, aWrapAlgorithm
, wrapAlgName
);
3144 if (NS_FAILED(rv
)) {
3145 return new FailureTask(rv
);
3148 if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3149 wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3150 wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
3151 return new WrapKeyTask
<AesTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3153 } else if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
3154 return new WrapKeyTask
<AesKwTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3156 } else if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
3157 return new WrapKeyTask
<RsaOaepTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3161 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3164 WebCryptoTask
* WebCryptoTask::CreateUnwrapKeyTask(
3165 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
3166 const ArrayBufferViewOrArrayBuffer
& aWrappedKey
, CryptoKey
& aUnwrappingKey
,
3167 const ObjectOrString
& aUnwrapAlgorithm
,
3168 const ObjectOrString
& aUnwrappedKeyAlgorithm
, bool aExtractable
,
3169 const Sequence
<nsString
>& aKeyUsages
) {
3170 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_UNWRAPKEY
);
3172 // Ensure key is usable for this operation
3173 if (!aUnwrappingKey
.HasUsage(CryptoKey::UNWRAPKEY
)) {
3174 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3177 // Verify that aKeyUsages does not contain an unrecognized value
3178 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3179 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3182 nsString keyAlgName
;
3183 nsresult rv
= GetAlgorithmName(aCx
, aUnwrappedKeyAlgorithm
, keyAlgName
);
3184 if (NS_FAILED(rv
)) {
3185 return new FailureTask(rv
);
3188 CryptoOperationData dummy
;
3189 RefPtr
<ImportKeyTask
> importTask
;
3190 if (keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_CBC
) ||
3191 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_CTR
) ||
3192 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_GCM
) ||
3193 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
) ||
3194 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_HMAC
)) {
3195 importTask
= new ImportSymmetricKeyTask(aGlobal
, aCx
, aFormat
,
3196 aUnwrappedKeyAlgorithm
,
3197 aExtractable
, aKeyUsages
);
3198 } else if (keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3199 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP
) ||
3200 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS
)) {
3202 new ImportRsaKeyTask(aGlobal
, aCx
, aFormat
, aUnwrappedKeyAlgorithm
,
3203 aExtractable
, aKeyUsages
);
3204 } else if (keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
3205 keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
3207 new ImportEcKeyTask(aGlobal
, aCx
, aFormat
, aUnwrappedKeyAlgorithm
,
3208 aExtractable
, aKeyUsages
);
3210 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3213 nsString unwrapAlgName
;
3214 rv
= GetAlgorithmName(aCx
, aUnwrapAlgorithm
, unwrapAlgName
);
3215 if (NS_FAILED(rv
)) {
3216 return new FailureTask(rv
);
3218 if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3219 unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3220 unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
3221 return new UnwrapKeyTask
<AesTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3222 aUnwrapAlgorithm
, importTask
);
3223 } else if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
3224 return new UnwrapKeyTask
<AesKwTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3225 aUnwrapAlgorithm
, importTask
);
3226 } else if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
3227 return new UnwrapKeyTask
<RsaOaepTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3228 aUnwrapAlgorithm
, importTask
);
3231 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3234 WebCryptoTask::WebCryptoTask()
3235 : CancelableRunnable("WebCryptoTask"),
3237 mEarlyComplete(false),
3238 mOriginalEventTarget(nullptr),
3239 mRv(NS_ERROR_NOT_INITIALIZED
) {}
3241 WebCryptoTask::~WebCryptoTask() = default;
3243 } // namespace mozilla::dom