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 MOZ_GLOBINIT
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
93 // Convenience functions for extracting / converting information
95 // OOM-safe CryptoBuffer initialization, suitable for constructors
96 #define ATTEMPT_BUFFER_INIT(dst, src) \
97 if (!dst.Assign(src)) { \
98 mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \
102 // OOM-safe CryptoBuffer-to-SECItem copy, suitable for DoCrypto
103 #define ATTEMPT_BUFFER_TO_SECITEM(arena, dst, src) \
104 if (!src.ToSECItem(arena, dst)) { \
105 return NS_ERROR_DOM_UNKNOWN_ERR; \
108 // OOM-safe CryptoBuffer copy, suitable for DoCrypto
109 #define ATTEMPT_BUFFER_ASSIGN(dst, src) \
110 if (!dst.Assign(src)) { \
111 return NS_ERROR_DOM_UNKNOWN_ERR; \
114 // Safety check for algorithms that use keys, suitable for constructors
115 #define CHECK_KEY_ALGORITHM(keyAlg, algName) \
117 if (!NORMALIZED_EQUALS(keyAlg.mName, algName)) { \
118 mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; \
123 class ClearException
{
125 explicit ClearException(JSContext
* aCx
) : mCx(aCx
) {}
127 ~ClearException() { JS_ClearPendingException(mCx
); }
134 static nsresult
GetAlgorithmName(JSContext
* aCx
, const OOS
& aAlgorithm
,
136 ClearException
ce(aCx
);
138 if (aAlgorithm
.IsString()) {
139 // If string, then treat as algorithm name
140 aName
.Assign(aAlgorithm
.GetAsString());
142 // Coerce to algorithm and extract name
143 JS::Rooted
<JS::Value
> value(aCx
,
144 JS::ObjectValue(*aAlgorithm
.GetAsObject()));
147 if (!alg
.Init(aCx
, value
)) {
148 return NS_ERROR_DOM_TYPE_MISMATCH_ERR
;
154 if (!NormalizeToken(aName
, aName
)) {
155 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
161 template <class T
, class OOS
>
162 static nsresult
Coerce(JSContext
* aCx
, T
& aTarget
, const OOS
& aAlgorithm
) {
163 ClearException
ce(aCx
);
165 if (!aAlgorithm
.IsObject()) {
166 return NS_ERROR_DOM_SYNTAX_ERR
;
169 JS::Rooted
<JS::Value
> value(aCx
, JS::ObjectValue(*aAlgorithm
.GetAsObject()));
170 if (!aTarget
.Init(aCx
, value
)) {
171 return NS_ERROR_DOM_TYPE_MISMATCH_ERR
;
177 inline size_t MapHashAlgorithmNameToBlockSize(const nsString
& aName
) {
178 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
) ||
179 aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
183 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
) ||
184 aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
191 inline nsresult
GetKeyLengthForAlgorithmIfSpecified(
192 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, Maybe
<size_t>& aLength
) {
193 // Extract algorithm name
195 if (NS_FAILED(GetAlgorithmName(aCx
, aAlgorithm
, algName
))) {
196 return NS_ERROR_DOM_SYNTAX_ERR
;
199 // Read AES key length from given algorithm object.
200 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
201 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
202 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
203 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
204 RootedDictionary
<AesDerivedKeyParams
> params(aCx
);
205 if (NS_FAILED(Coerce(aCx
, params
, aAlgorithm
))) {
206 return NS_ERROR_DOM_SYNTAX_ERR
;
209 if (params
.mLength
!= 128 && params
.mLength
!= 192 &&
210 params
.mLength
!= 256) {
211 return NS_ERROR_DOM_OPERATION_ERR
;
214 aLength
.emplace(params
.mLength
);
218 // Read HMAC key length from given algorithm object or
219 // determine key length as the block size of the given hash.
220 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
221 RootedDictionary
<HmacDerivedKeyParams
> params(aCx
);
222 if (NS_FAILED(Coerce(aCx
, params
, aAlgorithm
))) {
223 return NS_ERROR_DOM_SYNTAX_ERR
;
226 // Return the passed length, if any.
227 if (params
.mLength
.WasPassed()) {
228 aLength
.emplace(params
.mLength
.Value());
233 if (NS_FAILED(GetAlgorithmName(aCx
, params
.mHash
, hashName
))) {
234 return NS_ERROR_DOM_SYNTAX_ERR
;
237 // Return the given hash algorithm's block size as the key length.
238 size_t blockSize
= MapHashAlgorithmNameToBlockSize(hashName
);
239 if (blockSize
== 0) {
240 return NS_ERROR_DOM_SYNTAX_ERR
;
243 aLength
.emplace(blockSize
);
250 inline nsresult
GetKeyLengthForAlgorithm(JSContext
* aCx
,
251 const ObjectOrString
& aAlgorithm
,
253 Maybe
<size_t> length
;
254 nsresult rv
= GetKeyLengthForAlgorithmIfSpecified(aCx
, aAlgorithm
, length
);
258 if (length
.isNothing()) {
259 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
265 inline bool MapOIDTagToNamedCurve(SECOidTag aOIDTag
, nsString
& aResult
) {
267 case SEC_OID_SECG_EC_SECP256R1
:
268 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256
);
270 case SEC_OID_SECG_EC_SECP384R1
:
271 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384
);
273 case SEC_OID_SECG_EC_SECP521R1
:
274 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521
);
276 case SEC_OID_ED25519_PUBLIC_KEY
:
277 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_ED25519
);
280 aResult
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_CURVE25519
);
289 inline SECOidTag
MapHashAlgorithmNameToOID(const nsString
& aName
) {
290 SECOidTag
hashOID(SEC_OID_UNKNOWN
);
292 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
293 hashOID
= SEC_OID_SHA1
;
294 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
295 hashOID
= SEC_OID_SHA256
;
296 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
297 hashOID
= SEC_OID_SHA384
;
298 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
299 hashOID
= SEC_OID_SHA512
;
305 inline CK_MECHANISM_TYPE
MapHashAlgorithmNameToMgfMechanism(
306 const nsString
& aName
) {
307 CK_MECHANISM_TYPE
mech(UNKNOWN_CK_MECHANISM
);
309 if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
310 mech
= CKG_MGF1_SHA1
;
311 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
312 mech
= CKG_MGF1_SHA256
;
313 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
314 mech
= CKG_MGF1_SHA384
;
315 } else if (aName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
316 mech
= CKG_MGF1_SHA512
;
322 // Implementation of WebCryptoTask methods
324 void WebCryptoTask::DispatchWithPromise(Promise
* aResultPromise
) {
325 mResultPromise
= aResultPromise
;
327 // Fail if an error was set during the constructor
328 MAYBE_EARLY_FAIL(mEarlyRv
)
330 // Perform pre-NSS operations, and fail if they fail
331 mEarlyRv
= BeforeCrypto();
332 MAYBE_EARLY_FAIL(mEarlyRv
)
334 // Skip dispatch if we're already done. Otherwise launch a CryptoTask
335 if (mEarlyComplete
) {
336 CallCallback(mEarlyRv
);
340 // Store calling thread
341 mOriginalEventTarget
= GetCurrentSerialEventTarget();
343 // If we are running on a worker thread we must hold the worker
344 // alive while we work on the thread pool. Otherwise the worker
345 // private may get torn down before we dispatch back to complete
347 if (!NS_IsMainThread()) {
348 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
349 MOZ_ASSERT(workerPrivate
);
351 RefPtr
<StrongWorkerRef
> workerRef
=
352 StrongWorkerRef::Create(workerPrivate
, "WebCryptoTask");
353 if (NS_WARN_IF(!workerRef
)) {
354 mEarlyRv
= NS_BINDING_ABORTED
;
356 mWorkerRef
= new ThreadSafeWorkerRef(workerRef
);
359 MAYBE_EARLY_FAIL(mEarlyRv
);
361 // dispatch to thread pool
363 if (!EnsureNSSInitializedChromeOrContent()) {
364 mEarlyRv
= NS_ERROR_FAILURE
;
366 MAYBE_EARLY_FAIL(mEarlyRv
);
368 mEarlyRv
= NS_DispatchBackgroundTask(this);
369 MAYBE_EARLY_FAIL(mEarlyRv
)
373 WebCryptoTask::Run() {
374 // Run heavy crypto operations on the thread pool, off the original thread.
375 if (!IsOnOriginalThread()) {
376 mRv
= CalculateResult();
378 // Back to the original thread, i.e. continue below.
379 mOriginalEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
);
383 // We're now back on the calling thread.
386 // Stop holding the worker thread alive now that the async work has
388 mWorkerRef
= nullptr;
393 nsresult
WebCryptoTask::Cancel() {
394 MOZ_ASSERT(IsOnOriginalThread());
395 FailWithError(NS_BINDING_ABORTED
);
399 void WebCryptoTask::FailWithError(nsresult aRv
) {
400 MOZ_ASSERT(IsOnOriginalThread());
401 Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED
, false);
403 if (aRv
== NS_ERROR_DOM_TYPE_MISMATCH_ERR
) {
404 mResultPromise
->MaybeRejectWithTypeError(
405 "The operation could not be performed.");
407 // Blindly convert nsresult to DOMException
408 // Individual tasks must ensure they pass the right values
409 mResultPromise
->MaybeReject(aRv
);
411 // Manually release mResultPromise while we're on the main thread
412 mResultPromise
= nullptr;
413 mWorkerRef
= nullptr;
417 nsresult
WebCryptoTask::CalculateResult() {
418 MOZ_ASSERT(!IsOnOriginalThread());
423 void WebCryptoTask::CallCallback(nsresult rv
) {
424 MOZ_ASSERT(IsOnOriginalThread());
430 nsresult rv2
= AfterCrypto();
431 if (NS_FAILED(rv2
)) {
437 Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED
, true);
439 // Manually release mResultPromise while we're on the main thread
440 mResultPromise
= nullptr;
444 // Some generic utility classes
446 class FailureTask
: public WebCryptoTask
{
448 explicit FailureTask(nsresult aRv
) { mEarlyRv
= aRv
; }
451 class ReturnArrayBufferViewTask
: public WebCryptoTask
{
453 CryptoBuffer mResult
;
456 // Returns mResult as an ArrayBufferView, or an error
457 virtual void Resolve() override
{
458 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
459 mResultPromise
->MaybeResolve(ret
);
466 void SetData(const T
& aData
) {
467 mDataIsSet
= mData
.Assign(aData
);
471 DeferredData() : mDataIsSet(false) {}
477 class AesTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
479 AesTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
481 : mMechanism(CKM_INVALID_MECHANISM
),
485 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
488 AesTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
489 const CryptoOperationData
& aData
, bool aEncrypt
)
490 : mMechanism(CKM_INVALID_MECHANISM
),
494 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
498 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
501 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
502 if (NS_FAILED(mEarlyRv
)) {
506 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
507 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
511 // Check that we got a reasonable key
512 if ((mSymKey
.Length() != 16) && (mSymKey
.Length() != 24) &&
513 (mSymKey
.Length() != 32)) {
514 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
518 // Cache parameters depending on the specific algorithm
519 TelemetryAlgorithm telemetryAlg
;
520 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
)) {
521 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_CBC
);
523 mMechanism
= CKM_AES_CBC_PAD
;
524 telemetryAlg
= TA_AES_CBC
;
525 RootedDictionary
<AesCbcParams
> params(aCx
);
526 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
528 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
532 ATTEMPT_BUFFER_INIT(mIv
, params
.mIv
)
533 if (mIv
.Length() != 16) {
534 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
537 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
)) {
538 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_CTR
);
540 mMechanism
= CKM_AES_CTR
;
541 telemetryAlg
= TA_AES_CTR
;
542 RootedDictionary
<AesCtrParams
> params(aCx
);
543 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
545 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
549 ATTEMPT_BUFFER_INIT(mIv
, params
.mCounter
)
550 if (mIv
.Length() != 16) {
551 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
555 mCounterLength
= params
.mLength
;
556 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
557 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_GCM
);
559 mMechanism
= CKM_AES_GCM
;
560 telemetryAlg
= TA_AES_GCM
;
561 RootedDictionary
<AesGcmParams
> params(aCx
);
562 nsresult rv
= Coerce(aCx
, params
, aAlgorithm
);
564 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
568 ATTEMPT_BUFFER_INIT(mIv
, params
.mIv
)
570 if (params
.mAdditionalData
.WasPassed()) {
571 ATTEMPT_BUFFER_INIT(mAad
, params
.mAdditionalData
.Value())
574 // 32, 64, 96, 104, 112, 120 or 128
576 if (params
.mTagLength
.WasPassed()) {
577 mTagLength
= params
.mTagLength
.Value();
578 if ((mTagLength
> 128) ||
579 !(mTagLength
== 32 || mTagLength
== 64 ||
580 (mTagLength
>= 96 && mTagLength
% 8 == 0))) {
581 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
586 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
589 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
593 CK_MECHANISM_TYPE mMechanism
;
594 CryptoBuffer mSymKey
;
595 CryptoBuffer mIv
; // Initialization vector
596 CryptoBuffer mAad
; // Additional Authenticated Data
598 uint8_t mCounterLength
;
601 virtual nsresult
DoCrypto() override
{
605 return NS_ERROR_DOM_OPERATION_ERR
;
608 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
610 return NS_ERROR_DOM_OPERATION_ERR
;
613 // Construct the parameters object depending on algorithm
614 SECItem param
= {siBuffer
, nullptr, 0};
615 CK_AES_CTR_PARAMS ctrParams
;
616 CK_GCM_PARAMS gcmParams
;
617 switch (mMechanism
) {
618 case CKM_AES_CBC_PAD
:
619 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), ¶m
, mIv
);
622 ctrParams
.ulCounterBits
= mCounterLength
;
623 MOZ_ASSERT(mIv
.Length() == 16);
624 memcpy(&ctrParams
.cb
, mIv
.Elements(), 16);
625 param
.type
= siBuffer
;
626 param
.data
= (unsigned char*)&ctrParams
;
627 param
.len
= sizeof(ctrParams
);
630 gcmParams
.pIv
= mIv
.Elements();
631 gcmParams
.ulIvLen
= mIv
.Length();
632 gcmParams
.ulIvBits
= gcmParams
.ulIvLen
* 8;
633 gcmParams
.pAAD
= mAad
.Elements();
634 gcmParams
.ulAADLen
= mAad
.Length();
635 gcmParams
.ulTagBits
= mTagLength
;
636 param
.type
= siBuffer
;
637 param
.data
= (unsigned char*)&gcmParams
;
638 param
.len
= sizeof(gcmParams
);
641 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
645 SECItem keyItem
= {siBuffer
, nullptr, 0};
646 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
647 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
648 MOZ_ASSERT(slot
.get());
649 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
650 PK11_OriginUnwrap
, CKA_ENCRYPT
,
653 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
656 // Check whether the integer addition would overflow.
657 if (std::numeric_limits
<CryptoBuffer::size_type
>::max() - 16 <
659 return NS_ERROR_DOM_DATA_ERR
;
662 // Initialize the output buffer (enough space for padding / a full tag)
663 if (!mResult
.SetLength(mData
.Length() + 16, fallible
)) {
664 return NS_ERROR_DOM_UNKNOWN_ERR
;
669 // Perform the encryption/decryption
671 rv
= MapSECStatus(PK11_Encrypt(
672 symKey
.get(), mMechanism
, ¶m
, mResult
.Elements(), &outLen
,
673 mResult
.Length(), mData
.Elements(), mData
.Length()));
675 rv
= MapSECStatus(PK11_Decrypt(
676 symKey
.get(), mMechanism
, ¶m
, mResult
.Elements(), &outLen
,
677 mResult
.Length(), mData
.Elements(), mData
.Length()));
679 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
681 mResult
.TruncateLength(outLen
);
686 // This class looks like an encrypt/decrypt task, like AesTask,
687 // but it is only exposed to wrapKey/unwrapKey, not encrypt/decrypt
688 class AesKwTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
690 AesKwTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
692 : mMechanism(CKM_NSS_AES_KEY_WRAP
), mEncrypt(aEncrypt
) {
693 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
696 AesKwTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
697 const CryptoOperationData
& aData
, bool aEncrypt
)
698 : mMechanism(CKM_NSS_AES_KEY_WRAP
), mEncrypt(aEncrypt
) {
699 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
703 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
705 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_AES_KW
);
708 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
709 if (NS_FAILED(mEarlyRv
)) {
713 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
714 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
718 // Check that we got a reasonable key
719 if ((mSymKey
.Length() != 16) && (mSymKey
.Length() != 24) &&
720 (mSymKey
.Length() != 32)) {
721 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
725 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_AES_KW
);
729 CK_MECHANISM_TYPE mMechanism
;
730 CryptoBuffer mSymKey
;
733 virtual nsresult
DoCrypto() override
{
737 return NS_ERROR_DOM_OPERATION_ERR
;
740 // Check that the input is a multiple of 64 bits long
741 if (mData
.Length() == 0 || mData
.Length() % 8 != 0) {
742 return NS_ERROR_DOM_DATA_ERR
;
745 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
747 return NS_ERROR_DOM_OPERATION_ERR
;
751 SECItem keyItem
= {siBuffer
, nullptr, 0};
752 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
753 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
754 MOZ_ASSERT(slot
.get());
755 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
756 PK11_OriginUnwrap
, CKA_WRAP
,
759 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
762 // Import the data to a SECItem
763 SECItem dataItem
= {siBuffer
, nullptr, 0};
764 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &dataItem
, mData
);
766 // Parameters for the fake keys
767 CK_MECHANISM_TYPE fakeMechanism
= CKM_SHA_1_HMAC
;
768 CK_ATTRIBUTE_TYPE fakeOperation
= CKA_SIGN
;
771 // Import the data into a fake PK11SymKey structure
772 UniquePK11SymKey
keyToWrap(
773 PK11_ImportSymKey(slot
.get(), fakeMechanism
, PK11_OriginUnwrap
,
774 fakeOperation
, &dataItem
, nullptr));
776 return NS_ERROR_DOM_OPERATION_ERR
;
779 // Encrypt and return the wrapped key
780 // AES-KW encryption results in a wrapped key 64 bits longer
781 if (!mResult
.SetLength(mData
.Length() + 8, fallible
)) {
782 return NS_ERROR_DOM_OPERATION_ERR
;
784 SECItem resultItem
= {siBuffer
, mResult
.Elements(),
785 (unsigned int)mResult
.Length()};
786 rv
= MapSECStatus(PK11_WrapSymKey(mMechanism
, nullptr, symKey
.get(),
787 keyToWrap
.get(), &resultItem
));
788 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
790 // Decrypt the ciphertext into a temporary PK11SymKey
791 // Unwrapped key should be 64 bits shorter
792 int keySize
= mData
.Length() - 8;
793 UniquePK11SymKey
unwrappedKey(
794 PK11_UnwrapSymKey(symKey
.get(), mMechanism
, nullptr, &dataItem
,
795 fakeMechanism
, fakeOperation
, keySize
));
797 return NS_ERROR_DOM_OPERATION_ERR
;
800 // Export the key to get the cleartext
801 rv
= MapSECStatus(PK11_ExtractKeyValue(unwrappedKey
.get()));
803 return NS_ERROR_DOM_UNKNOWN_ERR
;
805 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(unwrappedKey
.get()));
812 class RsaOaepTask
: public ReturnArrayBufferViewTask
, public DeferredData
{
814 RsaOaepTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
816 : mPrivKey(aKey
.GetPrivateKey()),
817 mPubKey(aKey
.GetPublicKey()),
819 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
822 RsaOaepTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
823 const CryptoOperationData
& aData
, bool aEncrypt
)
824 : mPrivKey(aKey
.GetPrivateKey()),
825 mPubKey(aKey
.GetPublicKey()),
827 Init(aCx
, aAlgorithm
, aKey
, aEncrypt
);
831 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
833 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSA_OAEP
);
835 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSA_OAEP
);
839 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
842 mStrength
= SECKEY_PublicKeyStrength(mPubKey
.get());
845 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
848 mStrength
= PK11_GetPrivateModulusLen(mPrivKey
.get());
851 // The algorithm could just be given as a string
852 // in which case there would be no label specified.
853 if (!aAlgorithm
.IsString()) {
854 RootedDictionary
<RsaOaepParams
> params(aCx
);
855 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
856 if (NS_FAILED(mEarlyRv
)) {
857 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
861 if (params
.mLabel
.WasPassed()) {
862 ATTEMPT_BUFFER_INIT(mLabel
, params
.mLabel
.Value());
865 // Otherwise mLabel remains the empty octet string, as intended
867 KeyAlgorithm
& hashAlg
= aKey
.Algorithm().mRsa
.mHash
;
868 mHashMechanism
= KeyAlgorithmProxy::GetMechanism(hashAlg
);
869 mMgfMechanism
= MapHashAlgorithmNameToMgfMechanism(hashAlg
.mName
);
871 // Check we found appropriate mechanisms.
872 if (mHashMechanism
== UNKNOWN_CK_MECHANISM
||
873 mMgfMechanism
== UNKNOWN_CK_MECHANISM
) {
874 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
880 CK_MECHANISM_TYPE mHashMechanism
;
881 CK_MECHANISM_TYPE mMgfMechanism
;
882 UniqueSECKEYPrivateKey mPrivKey
;
883 UniqueSECKEYPublicKey mPubKey
;
888 virtual nsresult
DoCrypto() override
{
892 return NS_ERROR_DOM_OPERATION_ERR
;
895 // Ciphertext is an integer mod the modulus, so it will be
896 // no longer than mStrength octets
897 if (!mResult
.SetLength(mStrength
, fallible
)) {
898 return NS_ERROR_DOM_UNKNOWN_ERR
;
901 CK_RSA_PKCS_OAEP_PARAMS oaepParams
;
902 oaepParams
.source
= CKZ_DATA_SPECIFIED
;
904 oaepParams
.pSourceData
= mLabel
.Length() ? mLabel
.Elements() : nullptr;
905 oaepParams
.ulSourceDataLen
= mLabel
.Length();
907 oaepParams
.mgf
= mMgfMechanism
;
908 oaepParams
.hashAlg
= mHashMechanism
;
911 param
.type
= siBuffer
;
912 param
.data
= (unsigned char*)&oaepParams
;
913 param
.len
= sizeof(oaepParams
);
917 // PK11_PubEncrypt() checks the plaintext's length and fails if it is too
918 // long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
919 // being the length in octets of the RSA modulus n and 'hLen' being the
920 // output length in octets of the chosen hash function.
921 // <https://tools.ietf.org/html/rfc3447#section-7.1>
922 rv
= MapSECStatus(PK11_PubEncrypt(
923 mPubKey
.get(), CKM_RSA_PKCS_OAEP
, ¶m
, mResult
.Elements(), &outLen
,
924 mResult
.Length(), mData
.Elements(), mData
.Length(), nullptr));
926 rv
= MapSECStatus(PK11_PrivDecrypt(
927 mPrivKey
.get(), CKM_RSA_PKCS_OAEP
, ¶m
, mResult
.Elements(),
928 &outLen
, mResult
.Length(), mData
.Elements(), mData
.Length()));
930 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
932 mResult
.TruncateLength(outLen
);
937 class HmacTask
: public WebCryptoTask
{
939 HmacTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
940 const CryptoOperationData
& aSignature
,
941 const CryptoOperationData
& aData
, bool aSign
)
942 : mMechanism(aKey
.Algorithm().Mechanism()), mSign(aSign
) {
943 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_HMAC
);
945 ATTEMPT_BUFFER_INIT(mData
, aData
);
947 ATTEMPT_BUFFER_INIT(mSignature
, aSignature
);
950 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
951 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
955 // Check that we got a symmetric key
956 if (mSymKey
.Length() == 0) {
957 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
961 TelemetryAlgorithm telemetryAlg
;
962 switch (mMechanism
) {
964 telemetryAlg
= TA_HMAC_SHA_1
;
966 case CKM_SHA224_HMAC
:
967 telemetryAlg
= TA_HMAC_SHA_224
;
969 case CKM_SHA256_HMAC
:
970 telemetryAlg
= TA_HMAC_SHA_256
;
972 case CKM_SHA384_HMAC
:
973 telemetryAlg
= TA_HMAC_SHA_384
;
975 case CKM_SHA512_HMAC
:
976 telemetryAlg
= TA_HMAC_SHA_512
;
979 telemetryAlg
= TA_UNKNOWN
;
981 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
985 CK_MECHANISM_TYPE mMechanism
;
986 CryptoBuffer mSymKey
;
988 CryptoBuffer mSignature
;
989 CryptoBuffer mResult
;
992 virtual nsresult
DoCrypto() override
{
993 // Initialize the output buffer
994 if (!mResult
.SetLength(HASH_LENGTH_MAX
, fallible
)) {
995 return NS_ERROR_DOM_UNKNOWN_ERR
;
998 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
1000 return NS_ERROR_DOM_OPERATION_ERR
;
1005 SECItem keyItem
= {siBuffer
, nullptr, 0};
1006 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
1007 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
1008 MOZ_ASSERT(slot
.get());
1009 UniquePK11SymKey
symKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
1010 PK11_OriginUnwrap
, CKA_SIGN
,
1011 &keyItem
, nullptr));
1013 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1017 SECItem param
= {siBuffer
, nullptr, 0};
1018 UniquePK11Context
ctx(
1019 PK11_CreateContextBySymKey(mMechanism
, CKA_SIGN
, symKey
.get(), ¶m
));
1021 return NS_ERROR_DOM_OPERATION_ERR
;
1023 nsresult rv
= MapSECStatus(PK11_DigestBegin(ctx
.get()));
1024 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
1026 PK11_DigestOp(ctx
.get(), mData
.Elements(), mData
.Length()));
1027 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
1028 rv
= MapSECStatus(PK11_DigestFinal(ctx
.get(), mResult
.Elements(), &outLen
,
1030 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
1032 mResult
.TruncateLength(outLen
);
1036 // Returns mResult as an ArrayBufferView, or an error
1037 virtual void Resolve() override
{
1039 // Return the computed MAC
1040 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
1041 mResultPromise
->MaybeResolve(ret
);
1043 // Compare the MAC to the provided signature
1044 // No truncation allowed
1045 bool equal
= (mResult
.Length() == mSignature
.Length());
1047 int cmp
= NSS_SecureMemcmp(mSignature
.Elements(), mResult
.Elements(),
1048 mSignature
.Length());
1051 mResultPromise
->MaybeResolve(equal
);
1056 class AsymmetricSignVerifyTask
: public WebCryptoTask
{
1058 AsymmetricSignVerifyTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
1060 const CryptoOperationData
& aSignature
,
1061 const CryptoOperationData
& aData
, bool aSign
)
1062 : mOidTag(SEC_OID_UNKNOWN
),
1063 mHashMechanism(UNKNOWN_CK_MECHANISM
),
1064 mMgfMechanism(UNKNOWN_CK_MECHANISM
),
1065 mPrivKey(aKey
.GetPrivateKey()),
1066 mPubKey(aKey
.GetPublicKey()),
1070 mAlgorithm(Algorithm::UNKNOWN
) {
1071 ATTEMPT_BUFFER_INIT(mData
, aData
);
1073 ATTEMPT_BUFFER_INIT(mSignature
, aSignature
);
1077 nsString hashAlgName
;
1078 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
1079 if (NS_FAILED(mEarlyRv
)) {
1083 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
)) {
1084 mAlgorithm
= Algorithm::RSA_PKCS1
;
1085 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSASSA_PKCS1
);
1086 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1
);
1087 hashAlgName
= aKey
.Algorithm().mRsa
.mHash
.mName
;
1088 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1089 mAlgorithm
= Algorithm::RSA_PSS
;
1090 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_RSA_PSS
);
1091 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_RSA_PSS
);
1093 KeyAlgorithm
& hashAlg
= aKey
.Algorithm().mRsa
.mHash
;
1094 hashAlgName
= hashAlg
.mName
;
1095 mHashMechanism
= KeyAlgorithmProxy::GetMechanism(hashAlg
);
1096 mMgfMechanism
= MapHashAlgorithmNameToMgfMechanism(hashAlgName
);
1098 // Check we found appropriate mechanisms.
1099 if (mHashMechanism
== UNKNOWN_CK_MECHANISM
||
1100 mMgfMechanism
== UNKNOWN_CK_MECHANISM
) {
1101 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1105 RootedDictionary
<RsaPssParams
> params(aCx
);
1106 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1107 if (NS_FAILED(mEarlyRv
)) {
1108 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1112 mSaltLength
= params
.mSaltLength
;
1113 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
1114 mAlgorithm
= Algorithm::ECDSA
;
1115 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_ECDSA
);
1116 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_ECDSA
);
1118 // For ECDSA, the hash name comes from the algorithm parameter
1119 RootedDictionary
<EcdsaParams
> params(aCx
);
1120 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1121 if (NS_FAILED(mEarlyRv
)) {
1122 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1126 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashAlgName
);
1127 if (NS_FAILED(mEarlyRv
)) {
1128 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1131 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
1132 mAlgorithm
= Algorithm::ED25519
;
1133 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_ED25519
);
1134 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_ED25519
);
1136 // This shouldn't happen; CreateSignVerifyTask shouldn't create
1137 // one of these unless it's for the above algorithms.
1141 // Must have a valid algorithm by now.
1142 MOZ_ASSERT(mAlgorithm
!= Algorithm::UNKNOWN
);
1144 // Determine hash algorithm to use.
1145 mOidTag
= MapHashAlgorithmNameToOID(hashAlgName
);
1147 if (mOidTag
== SEC_OID_UNKNOWN
&& AlgorithmRequiresHashing(mAlgorithm
)) {
1148 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1152 // Check that we have the appropriate key
1153 if ((mSign
&& !mPrivKey
) || (!mSign
&& !mPubKey
)) {
1154 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1161 CK_MECHANISM_TYPE mHashMechanism
;
1162 CK_MECHANISM_TYPE mMgfMechanism
;
1163 UniqueSECKEYPrivateKey mPrivKey
;
1164 UniqueSECKEYPublicKey mPubKey
;
1165 CryptoBuffer mSignature
;
1167 uint32_t mSaltLength
;
1171 // The signature algorithm to use.
1172 enum class Algorithm
: uint8_t {
1179 Algorithm mAlgorithm
;
1181 bool AlgorithmRequiresHashing(Algorithm aAlgorithm
) {
1182 MOZ_ASSERT(aAlgorithm
!= Algorithm::UNKNOWN
);
1183 /* Currently, only ED25519 does not require hashing.*/
1184 switch (aAlgorithm
) {
1185 case Algorithm::ED25519
:
1187 case Algorithm::ECDSA
:
1188 case Algorithm::RSA_PKCS1
:
1189 case Algorithm::RSA_PSS
:
1191 case Algorithm::UNKNOWN
:
1194 /*Also impossible, as all the algorithm options should be managed in the
1199 virtual nsresult
DoCrypto() override
{
1203 SECItem
* params
= nullptr;
1204 CK_MECHANISM_TYPE mech
=
1205 PK11_MapSignKeyType(mSign
? mPrivKey
->keyType
: mPubKey
->keyType
);
1207 CK_RSA_PKCS_PSS_PARAMS rsaPssParams
;
1208 SECItem rsaPssParamsItem
= {
1212 // Set up parameters for RSA-PSS.
1213 if (mAlgorithm
== Algorithm::RSA_PSS
) {
1214 rsaPssParams
.hashAlg
= mHashMechanism
;
1215 rsaPssParams
.mgf
= mMgfMechanism
;
1216 rsaPssParams
.sLen
= mSaltLength
;
1218 rsaPssParamsItem
.data
= (unsigned char*)&rsaPssParams
;
1219 rsaPssParamsItem
.len
= sizeof(rsaPssParams
);
1220 params
= &rsaPssParamsItem
;
1222 mech
= CKM_RSA_PKCS_PSS
;
1225 if (AlgorithmRequiresHashing(mAlgorithm
)) {
1226 // Compute digest over given data.
1227 hash
.reset(::SECITEM_AllocItem(nullptr, nullptr,
1228 HASH_ResultLenByOidTag(mOidTag
)));
1230 if (!hash
|| !hash
->data
|| hash
->len
> PR_INT32_MAX
) {
1231 return NS_ERROR_DOM_OPERATION_ERR
;
1234 rv
= PK11_HashBuf(mOidTag
, hash
->data
, mData
.Elements(),
1235 static_cast<PRInt32
>(mData
.Length()));
1236 NS_ENSURE_SUCCESS(MapSECStatus(rv
), NS_ERROR_DOM_OPERATION_ERR
);
1239 // Wrap hash in a digest info template (RSA-PKCS1 only).
1240 if (mAlgorithm
== Algorithm::RSA_PKCS1
) {
1242 return NS_ERROR_DOM_OPERATION_ERR
;
1245 UniqueSGNDigestInfo
di(
1246 SGN_CreateDigestInfo(mOidTag
, hash
->data
, hash
->len
));
1248 return NS_ERROR_DOM_OPERATION_ERR
;
1252 SECITEM_FreeItem(hash
.get(), false);
1253 if (!SEC_ASN1EncodeItem(nullptr, hash
.get(), di
.get(),
1254 SGN_DigestInfoTemplate
)) {
1255 return NS_ERROR_DOM_OPERATION_ERR
;
1259 // Allocate SECItem to hold the signature.
1260 uint32_t len
= mSign
? PK11_SignatureLen(mPrivKey
.get()) : 0;
1261 UniqueSECItem
sig(::SECITEM_AllocItem(nullptr, nullptr, len
));
1263 return NS_ERROR_DOM_OPERATION_ERR
;
1266 // Buffer for signature/verification input.
1267 SECItem dataToOperateOn
;
1269 if (AlgorithmRequiresHashing(mAlgorithm
)) {
1270 dataToOperateOn
= {siBuffer
, hash
->data
, hash
->len
};
1272 dataToOperateOn
= {siBuffer
, mData
.Elements(),
1273 static_cast<unsigned int>(mData
.Length())};
1277 rv
= PK11_SignWithMechanism(mPrivKey
.get(), mech
, params
, sig
.get(),
1279 NS_ENSURE_SUCCESS(MapSECStatus(rv
), NS_ERROR_DOM_OPERATION_ERR
);
1280 ATTEMPT_BUFFER_ASSIGN(mSignature
, sig
.get());
1282 if (AlgorithmRequiresHashing(mAlgorithm
)) {
1283 dataToOperateOn
= {siBuffer
, hash
->data
, hash
->len
};
1285 dataToOperateOn
= {siBuffer
, mData
.Elements(),
1286 static_cast<unsigned int>(mData
.Length())};
1289 // Copy the given signature to the SECItem.
1290 if (!mSignature
.ToSECItem(nullptr, sig
.get())) {
1291 return NS_ERROR_DOM_OPERATION_ERR
;
1294 // Verify the signature.
1295 rv
= PK11_VerifyWithMechanism(mPubKey
.get(), mech
, params
, sig
.get(),
1296 &dataToOperateOn
, nullptr);
1297 mVerified
= NS_SUCCEEDED(MapSECStatus(rv
));
1303 virtual void Resolve() override
{
1305 TypedArrayCreator
<ArrayBuffer
> ret(mSignature
);
1306 mResultPromise
->MaybeResolve(ret
);
1308 mResultPromise
->MaybeResolve(mVerified
);
1313 class DigestTask
: public ReturnArrayBufferViewTask
{
1315 DigestTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
1316 const CryptoOperationData
& aData
) {
1317 ATTEMPT_BUFFER_INIT(mData
, aData
);
1320 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
1321 if (NS_FAILED(mEarlyRv
)) {
1322 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1326 TelemetryAlgorithm telemetryAlg
;
1327 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
)) {
1328 telemetryAlg
= TA_SHA_1
;
1329 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
)) {
1330 telemetryAlg
= TA_SHA_224
;
1331 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
)) {
1332 telemetryAlg
= TA_SHA_256
;
1333 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
1334 telemetryAlg
= TA_SHA_384
;
1336 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1339 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, telemetryAlg
);
1340 mOidTag
= MapHashAlgorithmNameToOID(algName
);
1347 virtual nsresult
DoCrypto() override
{
1348 // Resize the result buffer
1349 uint32_t hashLen
= HASH_ResultLenByOidTag(mOidTag
);
1350 if (!mResult
.SetLength(hashLen
, fallible
)) {
1351 return NS_ERROR_DOM_UNKNOWN_ERR
;
1355 nsresult rv
= MapSECStatus(PK11_HashBuf(mOidTag
, mResult
.Elements(),
1356 mData
.Elements(), mData
.Length()));
1357 if (NS_FAILED(rv
)) {
1358 return NS_ERROR_DOM_UNKNOWN_ERR
;
1365 class ImportKeyTask
: public WebCryptoTask
{
1367 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1368 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1369 const Sequence
<nsString
>& aKeyUsages
) {
1374 // This stuff pretty much always happens, so we'll do it here
1375 mKey
= new CryptoKey(aGlobal
);
1376 mKey
->SetExtractable(aExtractable
);
1377 mKey
->ClearUsages();
1378 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
1379 mEarlyRv
= mKey
->AddUsage(aKeyUsages
[i
]);
1380 if (NS_FAILED(mEarlyRv
)) {
1385 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, mAlgName
);
1386 if (NS_FAILED(mEarlyRv
)) {
1387 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1392 static bool JwkCompatible(const JsonWebKey
& aJwk
, const CryptoKey
* aKey
) {
1394 if (!aJwk
.mKty
.EqualsLiteral(JWK_TYPE_OKP
) &&
1395 !(aJwk
.mKty
.EqualsLiteral(JWK_TYPE_EC
) &&
1396 aKey
->Algorithm().Mechanism() == CKM_ECDH1_DERIVE
) &&
1397 aJwk
.mAlg
.WasPassed() &&
1398 aJwk
.mAlg
.Value() != aKey
->Algorithm().JwkAlg()) {
1403 if (aKey
->Extractable() && aJwk
.mExt
.WasPassed() && !aJwk
.mExt
.Value()) {
1408 if (aJwk
.mKey_ops
.WasPassed()) {
1409 nsTArray
<nsString
> usages
;
1410 aKey
->GetUsages(usages
);
1411 for (size_t i
= 0; i
< usages
.Length(); ++i
) {
1412 if (!aJwk
.mKey_ops
.Value().Contains(usages
[i
])) {
1418 // Individual algorithms may still have to check 'use'
1422 void SetKeyData(JSContext
* aCx
, JS::Handle
<JSObject
*> aKeyData
) {
1426 RootedSpiderMonkeyInterface
<ArrayBuffer
> ab(aCx
);
1427 if (ab
.Init(aKeyData
)) {
1428 if (!mKeyData
.Assign(ab
)) {
1429 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1434 // Try ArrayBufferView
1435 RootedSpiderMonkeyInterface
<ArrayBufferView
> abv(aCx
);
1436 if (abv
.Init(aKeyData
)) {
1437 if (!mKeyData
.Assign(abv
)) {
1438 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1444 ClearException
ce(aCx
);
1445 JS::Rooted
<JS::Value
> value(aCx
, JS::ObjectValue(*aKeyData
));
1446 if (!mJwk
.Init(aCx
, value
)) {
1447 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1454 void SetKeyDataMaybeParseJWK(const CryptoBuffer
& aKeyData
) {
1455 if (!mKeyData
.Assign(aKeyData
)) {
1456 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1462 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1463 nsDependentCSubstring
utf8(
1464 (const char*)mKeyData
.Elements(),
1465 (const char*)(mKeyData
.Elements() + mKeyData
.Length()));
1466 if (!IsUtf8(utf8
)) {
1467 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1471 nsString json
= NS_ConvertUTF8toUTF16(utf8
);
1472 if (!mJwk
.Init(json
)) {
1473 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1481 void SetRawKeyData(const CryptoBuffer
& aKeyData
) {
1482 if (!mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1483 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1487 if (!mKeyData
.Assign(aKeyData
)) {
1488 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
1497 RefPtr
<CryptoKey
> mKey
;
1498 CryptoBuffer mKeyData
;
1505 virtual void Resolve() override
{ mResultPromise
->MaybeResolve(mKey
); }
1507 virtual void Cleanup() override
{ mKey
= nullptr; }
1510 class ImportSymmetricKeyTask
: public ImportKeyTask
{
1512 ImportSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1513 const nsAString
& aFormat
,
1514 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1515 const Sequence
<nsString
>& aKeyUsages
) {
1516 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1519 ImportSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1520 const nsAString
& aFormat
,
1521 const JS::Handle
<JSObject
*> aKeyData
,
1522 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1523 const Sequence
<nsString
>& aKeyUsages
) {
1524 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1525 if (NS_FAILED(mEarlyRv
)) {
1529 SetKeyData(aCx
, aKeyData
);
1530 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1531 if (mDataIsJwk
&& !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1532 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1537 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1538 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1539 const Sequence
<nsString
>& aKeyUsages
) {
1540 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1542 if (NS_FAILED(mEarlyRv
)) {
1546 // This task only supports raw and JWK format.
1547 if (!mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1548 !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1549 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1553 // If this is an HMAC key, import the hash name
1554 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
1555 RootedDictionary
<HmacImportParams
> params(aCx
);
1556 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1557 if (NS_FAILED(mEarlyRv
)) {
1558 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1561 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, mHashName
);
1562 if (NS_FAILED(mEarlyRv
)) {
1563 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1569 virtual nsresult
BeforeCrypto() override
{
1571 // If we're doing a JWK import, import the key data
1573 if (!mJwk
.mK
.WasPassed()) {
1574 return NS_ERROR_DOM_DATA_ERR
;
1577 // Import the key material
1578 rv
= mKeyData
.FromJwkBase64(mJwk
.mK
.Value());
1579 if (NS_FAILED(rv
)) {
1580 return NS_ERROR_DOM_DATA_ERR
;
1583 // Check that we have valid key data.
1584 if (mKeyData
.Length() == 0 &&
1585 (!mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
) &&
1586 !mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HKDF
))) {
1587 return NS_ERROR_DOM_DATA_ERR
;
1590 // Construct an appropriate KeyAlgorithm,
1591 // and verify that usages are appropriate
1592 if (mKeyData
.Length() > UINT32_MAX
/ 8) {
1593 return NS_ERROR_DOM_DATA_ERR
;
1595 uint32_t length
= 8 * mKeyData
.Length(); // bytes to bits
1596 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
1597 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
1598 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
1599 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
1600 if (mKey
->HasUsageOtherThan(CryptoKey::ENCRYPT
| CryptoKey::DECRYPT
|
1601 CryptoKey::WRAPKEY
| CryptoKey::UNWRAPKEY
)) {
1602 return NS_ERROR_DOM_SYNTAX_ERR
;
1605 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) &&
1606 mKey
->HasUsageOtherThan(CryptoKey::WRAPKEY
| CryptoKey::UNWRAPKEY
)) {
1607 return NS_ERROR_DOM_SYNTAX_ERR
;
1610 if ((length
!= 128) && (length
!= 192) && (length
!= 256)) {
1611 return NS_ERROR_DOM_DATA_ERR
;
1613 mKey
->Algorithm().MakeAes(mAlgName
, length
);
1615 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed() &&
1616 !mJwk
.mUse
.Value().EqualsLiteral(JWK_USE_ENC
)) {
1617 return NS_ERROR_DOM_DATA_ERR
;
1619 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HKDF
) ||
1620 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
)) {
1621 if (mKey
->HasUsageOtherThan(CryptoKey::DERIVEKEY
|
1622 CryptoKey::DERIVEBITS
)) {
1623 return NS_ERROR_DOM_SYNTAX_ERR
;
1625 mKey
->Algorithm().MakeKDF(mAlgName
);
1627 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed()) {
1628 // There is not a 'use' value consistent with PBKDF or HKDF
1629 return NS_ERROR_DOM_DATA_ERR
;
1631 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
1632 if (mKey
->HasUsageOtherThan(CryptoKey::SIGN
| CryptoKey::VERIFY
)) {
1633 return NS_ERROR_DOM_SYNTAX_ERR
;
1636 mKey
->Algorithm().MakeHmac(length
, mHashName
);
1638 if (mKey
->Algorithm().Mechanism() == UNKNOWN_CK_MECHANISM
) {
1639 return NS_ERROR_DOM_SYNTAX_ERR
;
1642 if (mDataIsJwk
&& mJwk
.mUse
.WasPassed() &&
1643 !mJwk
.mUse
.Value().EqualsLiteral(JWK_USE_SIG
)) {
1644 return NS_ERROR_DOM_DATA_ERR
;
1647 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1650 if (!mKey
->HasAnyUsage()) {
1651 return NS_ERROR_DOM_SYNTAX_ERR
;
1654 if (NS_FAILED(mKey
->SetSymKey(mKeyData
))) {
1655 return NS_ERROR_DOM_OPERATION_ERR
;
1658 mKey
->SetType(CryptoKey::SECRET
);
1660 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
1661 return NS_ERROR_DOM_DATA_ERR
;
1664 mEarlyComplete
= true;
1672 class ImportRsaKeyTask
: public ImportKeyTask
{
1674 ImportRsaKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1675 const nsAString
& aFormat
, const ObjectOrString
& aAlgorithm
,
1676 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
)
1677 : mModulusLength(0) {
1678 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1681 ImportRsaKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1682 const nsAString
& aFormat
, JS::Handle
<JSObject
*> aKeyData
,
1683 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1684 const Sequence
<nsString
>& aKeyUsages
)
1685 : mModulusLength(0) {
1686 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1687 if (NS_FAILED(mEarlyRv
)) {
1691 SetKeyData(aCx
, aKeyData
);
1692 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1693 if (mDataIsJwk
&& !mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1694 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1699 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1700 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1701 const Sequence
<nsString
>& aKeyUsages
) {
1702 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1704 if (NS_FAILED(mEarlyRv
)) {
1708 // If this is RSA with a hash, cache the hash name
1709 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
1710 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
1711 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1712 RootedDictionary
<RsaHashedImportParams
> params(aCx
);
1713 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1714 if (NS_FAILED(mEarlyRv
)) {
1715 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1719 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, mHashName
);
1720 if (NS_FAILED(mEarlyRv
)) {
1721 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
1726 // Check support for the algorithm and hash names
1727 CK_MECHANISM_TYPE mech1
= MapAlgorithmNameToMechanism(mAlgName
);
1728 CK_MECHANISM_TYPE mech2
= MapAlgorithmNameToMechanism(mHashName
);
1729 if ((mech1
== UNKNOWN_CK_MECHANISM
) || (mech2
== UNKNOWN_CK_MECHANISM
)) {
1730 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1737 uint32_t mModulusLength
;
1738 CryptoBuffer mPublicExponent
;
1740 virtual nsresult
DoCrypto() override
{
1741 // Import the key data itself
1742 UniqueSECKEYPublicKey pubKey
;
1743 UniqueSECKEYPrivateKey privKey
;
1744 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) ||
1745 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1746 !mJwk
.mD
.WasPassed())) {
1747 // Public key import
1748 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1749 pubKey
= CryptoKey::PublicKeyFromSpki(mKeyData
);
1751 pubKey
= CryptoKey::PublicKeyFromJwk(mJwk
);
1755 return NS_ERROR_DOM_DATA_ERR
;
1758 if (NS_FAILED(mKey
->SetPublicKey(pubKey
.get()))) {
1759 return NS_ERROR_DOM_OPERATION_ERR
;
1762 mKey
->SetType(CryptoKey::PUBLIC
);
1763 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) ||
1764 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1765 mJwk
.mD
.WasPassed())) {
1766 // Private key import
1767 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
1768 privKey
= CryptoKey::PrivateKeyFromPkcs8(mKeyData
);
1770 privKey
= CryptoKey::PrivateKeyFromJwk(mJwk
);
1774 return NS_ERROR_DOM_DATA_ERR
;
1777 if (NS_FAILED(mKey
->SetPrivateKey(privKey
.get()))) {
1778 return NS_ERROR_DOM_OPERATION_ERR
;
1781 mKey
->SetType(CryptoKey::PRIVATE
);
1782 pubKey
= UniqueSECKEYPublicKey(SECKEY_ConvertToPublicKey(privKey
.get()));
1784 return NS_ERROR_DOM_UNKNOWN_ERR
;
1787 // Invalid key format
1788 return NS_ERROR_DOM_SYNTAX_ERR
;
1791 if (pubKey
->keyType
!= rsaKey
) {
1792 return NS_ERROR_DOM_DATA_ERR
;
1794 // Extract relevant information from the public key
1795 mModulusLength
= 8 * pubKey
->u
.rsa
.modulus
.len
;
1796 if (!mPublicExponent
.Assign(&pubKey
->u
.rsa
.publicExponent
)) {
1797 return NS_ERROR_DOM_OPERATION_ERR
;
1803 virtual nsresult
AfterCrypto() override
{
1804 // Check permissions for the requested operation
1805 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
1806 if ((mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
1807 mKey
->HasUsageOtherThan(CryptoKey::ENCRYPT
| CryptoKey::WRAPKEY
)) ||
1808 (mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
1809 mKey
->HasUsageOtherThan(CryptoKey::DECRYPT
|
1810 CryptoKey::UNWRAPKEY
))) {
1811 return NS_ERROR_DOM_SYNTAX_ERR
;
1813 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
1814 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
1815 if ((mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
1816 mKey
->HasUsageOtherThan(CryptoKey::VERIFY
)) ||
1817 (mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
1818 mKey
->HasUsageOtherThan(CryptoKey::SIGN
))) {
1819 return NS_ERROR_DOM_SYNTAX_ERR
;
1823 if (mKey
->GetKeyType() == CryptoKey::PRIVATE
&& !mKey
->HasAnyUsage()) {
1824 return NS_ERROR_DOM_SYNTAX_ERR
;
1827 // Set an appropriate KeyAlgorithm
1828 if (!mKey
->Algorithm().MakeRsa(mAlgName
, mModulusLength
, mPublicExponent
,
1830 return NS_ERROR_DOM_OPERATION_ERR
;
1833 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
1834 return NS_ERROR_DOM_DATA_ERR
;
1841 class ImportEcKeyTask
: public ImportKeyTask
{
1843 ImportEcKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1844 const nsAString
& aFormat
, const ObjectOrString
& aAlgorithm
,
1845 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
1846 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1849 ImportEcKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
1850 const nsAString
& aFormat
, JS::Handle
<JSObject
*> aKeyData
,
1851 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1852 const Sequence
<nsString
>& aKeyUsages
) {
1853 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
1854 if (NS_FAILED(mEarlyRv
)) {
1858 SetKeyData(aCx
, aKeyData
);
1859 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
1862 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
1863 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
1864 const Sequence
<nsString
>& aKeyUsages
) {
1865 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
1867 if (NS_FAILED(mEarlyRv
)) {
1871 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) ||
1872 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1873 RootedDictionary
<EcKeyImportParams
> params(aCx
);
1874 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
1875 if (NS_FAILED(mEarlyRv
) || !params
.mNamedCurve
.WasPassed()) {
1876 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
1880 if (!NormalizeToken(params
.mNamedCurve
.Value(), mNamedCurve
)) {
1881 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1888 nsString mNamedCurve
;
1890 virtual nsresult
DoCrypto() override
{
1891 // Import the key data itself
1892 UniqueSECKEYPublicKey pubKey
;
1893 UniqueSECKEYPrivateKey privKey
;
1895 if ((mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1896 mJwk
.mD
.WasPassed()) ||
1897 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
1898 // Private key import
1899 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1900 privKey
= CryptoKey::PrivateKeyFromJwk(mJwk
);
1902 return NS_ERROR_DOM_DATA_ERR
;
1905 privKey
= CryptoKey::PrivateKeyFromPkcs8(mKeyData
);
1907 return NS_ERROR_DOM_DATA_ERR
;
1910 ScopedAutoSECItem ecParams
;
1911 if (PK11_ReadRawAttribute(PK11_TypePrivKey
, privKey
.get(),
1912 CKA_EC_PARAMS
, &ecParams
) != SECSuccess
) {
1913 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1917 if (!FindOIDTagForEncodedParameters(&ecParams
, &tag
)) {
1918 return NS_ERROR_DOM_DATA_ERR
;
1921 // Find a matching and supported named curve.
1922 if (!MapOIDTagToNamedCurve(tag
, mNamedCurve
)) {
1923 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1927 if (NS_FAILED(mKey
->SetPrivateKey(privKey
.get()))) {
1928 return NS_ERROR_DOM_OPERATION_ERR
;
1931 mKey
->SetType(CryptoKey::PRIVATE
);
1932 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) ||
1933 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) ||
1934 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
1935 !mJwk
.mD
.WasPassed())) {
1936 // Public key import
1937 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
1938 pubKey
= CryptoKey::PublicECKeyFromRaw(mKeyData
, mNamedCurve
);
1939 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1940 pubKey
= CryptoKey::PublicKeyFromSpki(mKeyData
);
1941 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1942 pubKey
= CryptoKey::PublicKeyFromJwk(mJwk
);
1948 return NS_ERROR_DOM_DATA_ERR
;
1951 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
1952 if (pubKey
->keyType
!= ecKey
) {
1953 return NS_ERROR_DOM_DATA_ERR
;
1955 if (!CheckEncodedParameters(&pubKey
->u
.ec
.DEREncodedParams
)) {
1956 return NS_ERROR_DOM_OPERATION_ERR
;
1960 if (!FindOIDTagForEncodedParameters(&pubKey
->u
.ec
.DEREncodedParams
,
1962 return NS_ERROR_DOM_DATA_ERR
;
1965 // Find a matching and supported named curve.
1966 if (!MapOIDTagToNamedCurve(tag
, mNamedCurve
)) {
1967 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1971 if (NS_FAILED(mKey
->SetPublicKey(pubKey
.get()))) {
1972 return NS_ERROR_DOM_OPERATION_ERR
;
1975 mKey
->SetType(CryptoKey::PUBLIC
);
1977 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1980 // Checking the 'crv' consistency
1981 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
1982 // the curve stated in 'crv field'
1983 nsString namedCurveFromCrv
;
1984 if (!NormalizeToken(mJwk
.mCrv
.Value(), namedCurveFromCrv
)) {
1985 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1988 // https://w3c.github.io/webcrypto/#ecdh-operations
1989 // https://w3c.github.io/webcrypto/#ecdsa-operations
1990 // If namedCurve is not equal to the namedCurve member of
1991 // normalizedAlgorithm (mNamedCurve in our case), throw a DataError.
1992 if (!mNamedCurve
.Equals(namedCurveFromCrv
)) {
1993 return NS_ERROR_DOM_DATA_ERR
;
1999 virtual nsresult
AfterCrypto() override
{
2000 uint32_t privateAllowedUsages
= 0, publicAllowedUsages
= 0;
2001 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
)) {
2002 privateAllowedUsages
= CryptoKey::DERIVEBITS
| CryptoKey::DERIVEKEY
;
2003 publicAllowedUsages
= 0;
2004 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
2005 privateAllowedUsages
= CryptoKey::SIGN
;
2006 publicAllowedUsages
= CryptoKey::VERIFY
;
2009 // Check permissions for the requested operation
2010 if ((mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
2011 mKey
->HasUsageOtherThan(privateAllowedUsages
)) ||
2012 (mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
2013 mKey
->HasUsageOtherThan(publicAllowedUsages
))) {
2014 return NS_ERROR_DOM_SYNTAX_ERR
;
2017 if (mKey
->GetKeyType() == CryptoKey::PRIVATE
&& !mKey
->HasAnyUsage()) {
2018 return NS_ERROR_DOM_SYNTAX_ERR
;
2021 mKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
2023 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
2024 return NS_ERROR_DOM_DATA_ERR
;
2031 class ImportOKPKeyTask
: public ImportKeyTask
{
2033 ImportOKPKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2034 const nsAString
& aFormat
, const ObjectOrString
& aAlgorithm
,
2035 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
2036 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
2039 ImportOKPKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2040 const nsAString
& aFormat
, JS::Handle
<JSObject
*> aKeyData
,
2041 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
2042 const Sequence
<nsString
>& aKeyUsages
) {
2043 Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
, aKeyUsages
);
2044 if (NS_FAILED(mEarlyRv
)) {
2048 SetKeyData(aCx
, aKeyData
);
2049 NS_ENSURE_SUCCESS_VOID(mEarlyRv
);
2052 void Init(nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
2053 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
2054 const Sequence
<nsString
>& aKeyUsages
) {
2055 ImportKeyTask::Init(aGlobal
, aCx
, aFormat
, aAlgorithm
, aExtractable
,
2057 if (NS_FAILED(mEarlyRv
)) {
2061 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
2062 nsString paramsAlgName
;
2063 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, paramsAlgName
);
2064 if (NS_FAILED(mEarlyRv
)) {
2065 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2070 if (!NormalizeToken(paramsAlgName
, algName
)) {
2071 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2075 // Construct an appropriate KeyAlgorithm
2076 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
2077 mNamedCurve
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_ED25519
);
2078 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_X25519
)) {
2079 mNamedCurve
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_CURVE25519
);
2081 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2088 nsString mNamedCurve
;
2090 virtual nsresult
DoCrypto() override
{
2091 // Import the key data itself
2092 UniqueSECKEYPublicKey pubKey
;
2093 UniqueSECKEYPrivateKey privKey
;
2095 if ((mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
2096 mJwk
.mD
.WasPassed()) ||
2097 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
2098 // Private key import
2099 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2100 privKey
= CryptoKey::PrivateKeyFromJwk(mJwk
);
2102 return NS_ERROR_DOM_DATA_ERR
;
2105 privKey
= CryptoKey::PrivateKeyFromPkcs8(mKeyData
);
2107 return NS_ERROR_DOM_DATA_ERR
;
2110 ScopedAutoSECItem ecParams
;
2111 if (PK11_ReadRawAttribute(PK11_TypePrivKey
, privKey
.get(),
2112 CKA_EC_PARAMS
, &ecParams
) != SECSuccess
) {
2113 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2117 if (!FindOIDTagForEncodedParameters(&ecParams
, &tag
)) {
2118 return NS_ERROR_DOM_DATA_ERR
;
2121 // Find a matching and supported named curve.
2122 if (!MapOIDTagToNamedCurve(tag
, mNamedCurve
)) {
2123 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2127 if (NS_FAILED(mKey
->SetPrivateKey(privKey
.get()))) {
2128 return NS_ERROR_DOM_OPERATION_ERR
;
2131 mKey
->SetType(CryptoKey::PRIVATE
);
2132 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) ||
2133 mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) ||
2134 (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
) &&
2135 !mJwk
.mD
.WasPassed())) {
2136 // Public key import
2137 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
2138 pubKey
= CryptoKey::PublicOKPKeyFromRaw(mKeyData
, mNamedCurve
);
2139 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
2140 pubKey
= CryptoKey::PublicKeyFromSpki(mKeyData
);
2141 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2142 pubKey
= CryptoKey::PublicKeyFromJwk(mJwk
);
2148 return NS_ERROR_DOM_DATA_ERR
;
2151 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
2152 if (pubKey
->keyType
!= edKey
&& pubKey
->keyType
!= ecMontKey
) {
2153 return NS_ERROR_DOM_DATA_ERR
;
2155 if (!CheckEncodedParameters(&pubKey
->u
.ec
.DEREncodedParams
)) {
2156 return NS_ERROR_DOM_OPERATION_ERR
;
2160 if (!FindOIDTagForEncodedParameters(&pubKey
->u
.ec
.DEREncodedParams
,
2162 return NS_ERROR_DOM_OPERATION_ERR
;
2165 // Find a matching and supported named curve.
2166 if (!MapOIDTagToNamedCurve(tag
, mNamedCurve
)) {
2167 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2171 if (NS_FAILED(mKey
->SetPublicKey(pubKey
.get()))) {
2172 return NS_ERROR_DOM_OPERATION_ERR
;
2175 mKey
->SetType(CryptoKey::PUBLIC
);
2177 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2180 // Extract 'crv' parameter from JWKs.
2181 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2182 if (!NormalizeToken(mJwk
.mCrv
.Value(), mNamedCurve
)) {
2183 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2190 virtual nsresult
AfterCrypto() override
{
2191 // Only Ed25519 is supported.
2192 uint32_t privateAllowedUsages
= 0;
2193 uint32_t publicAllowedUsages
= 0;
2195 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_X25519
)) {
2196 privateAllowedUsages
= CryptoKey::DERIVEKEY
| CryptoKey::DERIVEBITS
;
2197 publicAllowedUsages
= 0;
2198 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
2199 privateAllowedUsages
= CryptoKey::SIGN
;
2200 publicAllowedUsages
= CryptoKey::VERIFY
;
2203 // Check permissions for the requested operation
2204 if ((mKey
->GetKeyType() == CryptoKey::PUBLIC
&&
2205 mKey
->HasUsageOtherThan(publicAllowedUsages
))) {
2206 return NS_ERROR_DOM_SYNTAX_ERR
;
2209 if ((mKey
->GetKeyType() == CryptoKey::PRIVATE
&&
2210 mKey
->HasUsageOtherThan(privateAllowedUsages
))) {
2211 return NS_ERROR_DOM_SYNTAX_ERR
;
2214 if (mKey
->GetKeyType() == CryptoKey::PRIVATE
&& !mKey
->HasAnyUsage()) {
2215 return NS_ERROR_DOM_SYNTAX_ERR
;
2218 mKey
->Algorithm().MakeOKP(mAlgName
);
2220 if (mDataIsJwk
&& !JwkCompatible(mJwk
, mKey
)) {
2221 return NS_ERROR_DOM_DATA_ERR
;
2228 class ExportKeyTask
: public WebCryptoTask
{
2230 ExportKeyTask(const nsAString
& aFormat
, CryptoKey
& aKey
)
2232 mPrivateKey(aKey
.GetPrivateKey()),
2233 mPublicKey(aKey
.GetPublicKey()),
2234 mKeyType(aKey
.GetKeyType()),
2235 mExtractable(aKey
.Extractable()),
2236 mAlg(aKey
.Algorithm().JwkAlg()) {
2237 aKey
.GetUsages(mKeyUsages
);
2239 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
2240 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
2247 CryptoBuffer mSymKey
;
2248 UniqueSECKEYPrivateKey mPrivateKey
;
2249 UniqueSECKEYPublicKey mPublicKey
;
2250 CryptoKey::KeyType mKeyType
;
2253 nsTArray
<nsString
> mKeyUsages
;
2254 CryptoBuffer mResult
;
2258 virtual nsresult
DoCrypto() override
{
2259 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
)) {
2260 if (mPublicKey
&& mPublicKey
->keyType
== dhKey
) {
2261 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2265 (mPublicKey
->keyType
== ecKey
|| mPublicKey
->keyType
== edKey
||
2266 mPublicKey
->keyType
== ecMontKey
)) {
2267 nsresult rv
= CryptoKey::PublicECKeyToRaw(mPublicKey
.get(), mResult
);
2268 if (NS_FAILED(rv
)) {
2269 return NS_ERROR_DOM_OPERATION_ERR
;
2274 if (!mResult
.Assign(mSymKey
)) {
2275 return NS_ERROR_OUT_OF_MEMORY
;
2277 if (mResult
.Length() == 0) {
2278 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2282 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
)) {
2284 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2287 switch (mPrivateKey
->keyType
) {
2293 CryptoKey::PrivateKeyToPkcs8(mPrivateKey
.get(), mResult
);
2294 if (NS_FAILED(rv
)) {
2295 return NS_ERROR_DOM_OPERATION_ERR
;
2300 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2302 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
)) {
2304 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2307 return CryptoKey::PublicKeyToSpki(mPublicKey
.get(), mResult
);
2308 } else if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2309 if (mKeyType
== CryptoKey::SECRET
) {
2311 nsresult rv
= mSymKey
.ToJwkBase64(k
);
2312 if (NS_FAILED(rv
)) {
2313 return NS_ERROR_DOM_OPERATION_ERR
;
2315 mJwk
.mK
.Construct(k
);
2316 mJwk
.mKty
= NS_LITERAL_STRING_FROM_CSTRING(JWK_TYPE_SYMMETRIC
);
2317 } else if (mKeyType
== CryptoKey::PUBLIC
) {
2319 return NS_ERROR_DOM_UNKNOWN_ERR
;
2322 nsresult rv
= CryptoKey::PublicKeyToJwk(mPublicKey
.get(), mJwk
);
2323 if (NS_FAILED(rv
)) {
2324 return NS_ERROR_DOM_OPERATION_ERR
;
2326 } else if (mKeyType
== CryptoKey::PRIVATE
) {
2328 return NS_ERROR_DOM_UNKNOWN_ERR
;
2331 nsresult rv
= CryptoKey::PrivateKeyToJwk(mPrivateKey
.get(), mJwk
);
2332 if (NS_FAILED(rv
)) {
2333 return NS_ERROR_DOM_OPERATION_ERR
;
2337 if (!mAlg
.IsEmpty()) {
2338 mJwk
.mAlg
.Construct(mAlg
);
2341 mJwk
.mExt
.Construct(mExtractable
);
2343 mJwk
.mKey_ops
.Construct();
2344 if (!mJwk
.mKey_ops
.Value().AppendElements(mKeyUsages
, fallible
)) {
2345 return NS_ERROR_OUT_OF_MEMORY
;
2351 return NS_ERROR_DOM_SYNTAX_ERR
;
2354 // Returns mResult as an ArrayBufferView or JWK, as appropriate
2355 virtual void Resolve() override
{
2356 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
2357 mResultPromise
->MaybeResolve(mJwk
);
2361 TypedArrayCreator
<ArrayBuffer
> ret(mResult
);
2362 mResultPromise
->MaybeResolve(ret
);
2366 class GenerateSymmetricKeyTask
: public WebCryptoTask
{
2368 GenerateSymmetricKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
2369 const ObjectOrString
& aAlgorithm
, bool aExtractable
,
2370 const Sequence
<nsString
>& aKeyUsages
) {
2371 // Create an empty key and set easy attributes
2372 mKey
= new CryptoKey(aGlobal
);
2373 mKey
->SetExtractable(aExtractable
);
2374 mKey
->SetType(CryptoKey::SECRET
);
2376 // Extract algorithm name
2378 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
2379 if (NS_FAILED(mEarlyRv
)) {
2383 // Construct an appropriate KeyAlorithm
2384 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
2385 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
2386 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
2387 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
2388 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aAlgorithm
, mLength
);
2389 if (NS_FAILED(mEarlyRv
)) {
2392 mKey
->Algorithm().MakeAes(algName
, mLength
);
2394 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
2395 RootedDictionary
<HmacKeyGenParams
> params(aCx
);
2396 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2397 if (NS_FAILED(mEarlyRv
)) {
2398 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2403 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2404 if (NS_FAILED(mEarlyRv
)) {
2408 if (params
.mLength
.WasPassed()) {
2409 mLength
= params
.mLength
.Value();
2411 mLength
= MapHashAlgorithmNameToBlockSize(hashName
);
2415 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
2419 mKey
->Algorithm().MakeHmac(mLength
, hashName
);
2421 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2426 mKey
->ClearUsages();
2427 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
2428 mEarlyRv
= mKey
->AddAllowedUsageIntersecting(aKeyUsages
[i
], algName
);
2429 if (NS_FAILED(mEarlyRv
)) {
2433 if (!mKey
->HasAnyUsage()) {
2434 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2438 mLength
= mLength
>> 3; // bits to bytes
2439 mMechanism
= mKey
->Algorithm().Mechanism();
2440 // SetSymKey done in Resolve, after we've done the keygen
2444 RefPtr
<CryptoKey
> mKey
;
2446 CK_MECHANISM_TYPE mMechanism
;
2447 CryptoBuffer mKeyData
;
2449 virtual nsresult
DoCrypto() override
{
2450 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2451 MOZ_ASSERT(slot
.get());
2453 UniquePK11SymKey
symKey(
2454 PK11_KeyGen(slot
.get(), mMechanism
, nullptr, mLength
, nullptr));
2456 return NS_ERROR_DOM_UNKNOWN_ERR
;
2459 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2460 if (NS_FAILED(rv
)) {
2461 return NS_ERROR_DOM_UNKNOWN_ERR
;
2464 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2465 // just refers to a buffer managed by symKey. The assignment copies the
2466 // data, so mKeyData manages one copy, while symKey manages another.
2467 ATTEMPT_BUFFER_ASSIGN(mKeyData
, PK11_GetKeyData(symKey
.get()));
2471 virtual void Resolve() override
{
2472 if (NS_SUCCEEDED(mKey
->SetSymKey(mKeyData
))) {
2473 mResultPromise
->MaybeResolve(mKey
);
2475 mResultPromise
->MaybeReject(NS_ERROR_DOM_OPERATION_ERR
);
2479 virtual void Cleanup() override
{ mKey
= nullptr; }
2482 class DeriveX25519BitsTask
: public ReturnArrayBufferViewTask
{
2484 DeriveX25519BitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2485 CryptoKey
& aKey
, const Nullable
<uint32_t>& aLength
)
2486 : mLength(aLength
), mPrivKey(aKey
.GetPrivateKey()) {
2487 Init(aCx
, aAlgorithm
, aKey
);
2490 DeriveX25519BitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2491 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2492 : mPrivKey(aKey
.GetPrivateKey()) {
2493 Init(aCx
, aAlgorithm
, aKey
);
2496 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
) {
2497 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_X25519
);
2498 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_X25519
);
2500 // Check that we have a private key.
2502 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2506 // If specified, length must be a multiple of 8.
2507 if (!mLength
.IsNull()) {
2508 if (mLength
.Value() % 8) {
2509 mEarlyRv
= NS_ERROR_DOM_DATA_ERR
;
2512 mLength
.SetValue(mLength
.Value() >> 3); // bits to bytes
2515 // Retrieve the peer's public key.
2516 RootedDictionary
<EcdhKeyDeriveParams
> params(aCx
);
2517 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2519 if (NS_FAILED(mEarlyRv
)) {
2520 /* The returned code is installed by Coerce function. */
2524 CHECK_KEY_ALGORITHM(params
.mPublic
->Algorithm(), WEBCRYPTO_ALG_X25519
);
2526 CryptoKey
* publicKey
= params
.mPublic
;
2527 mPubKey
= publicKey
->GetPublicKey();
2529 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2535 Nullable
<uint32_t> mLength
;
2536 UniqueSECKEYPrivateKey mPrivKey
;
2537 UniqueSECKEYPublicKey mPubKey
;
2539 virtual nsresult
DoCrypto() override
{
2540 // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
2541 // derived symmetric key and don't matter because we ignore them anyway.
2543 // Derive Bits requires checking that the generated key is not all-zero
2545 // https://wicg.github.io/webcrypto-secure-curves/#x25519-operations This
2546 // step is performed internally inside PK11_PubDeriveWithKDF function.
2547 UniquePK11SymKey
symKey(
2548 PK11_PubDeriveWithKDF(mPrivKey
.get(), mPubKey
.get(), PR_FALSE
, nullptr,
2549 nullptr, CKM_ECDH1_DERIVE
, CKM_SHA512_HMAC
,
2550 CKA_DERIVE
, 0, CKD_NULL
, nullptr, nullptr));
2552 if (!symKey
.get()) {
2553 return NS_ERROR_DOM_OPERATION_ERR
;
2556 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2557 if (NS_FAILED(rv
)) {
2558 return NS_ERROR_DOM_OPERATION_ERR
;
2561 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2562 // just refers to a buffer managed by symKey. The assignment copies the
2563 // data, so mResult manages one copy, while symKey manages another.
2564 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
2566 if (!mLength
.IsNull()) {
2567 if (mLength
.Value() > mResult
.Length()) {
2568 return NS_ERROR_DOM_OPERATION_ERR
;
2570 if (!mResult
.SetLength(mLength
.Value(), fallible
)) {
2571 return NS_ERROR_DOM_UNKNOWN_ERR
;
2579 GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
2580 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2581 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
)
2582 : mKeyPair(new CryptoKeyPair()),
2583 mMechanism(CKM_INVALID_MECHANISM
),
2586 mArena
= UniquePLArenaPool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
2588 mEarlyRv
= NS_ERROR_DOM_UNKNOWN_ERR
;
2592 // Create an empty key pair and set easy attributes
2593 mKeyPair
->mPrivateKey
= new CryptoKey(aGlobal
);
2594 mKeyPair
->mPublicKey
= new CryptoKey(aGlobal
);
2596 // Extract algorithm name
2597 mEarlyRv
= GetAlgorithmName(aCx
, aAlgorithm
, mAlgName
);
2598 if (NS_FAILED(mEarlyRv
)) {
2602 // Construct an appropriate KeyAlorithm
2603 uint32_t privateAllowedUsages
= 0, publicAllowedUsages
= 0;
2604 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2605 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
2606 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
2607 RootedDictionary
<RsaHashedKeyGenParams
> params(aCx
);
2608 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2609 if (NS_FAILED(mEarlyRv
)) {
2610 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2614 // Pull relevant info
2615 uint32_t modulusLength
= params
.mModulusLength
;
2616 CryptoBuffer publicExponent
;
2617 ATTEMPT_BUFFER_INIT(publicExponent
, params
.mPublicExponent
);
2619 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2620 if (NS_FAILED(mEarlyRv
)) {
2625 if (!mKeyPair
->mPublicKey
->Algorithm().MakeRsa(mAlgName
, modulusLength
,
2626 publicExponent
, hashName
)) {
2627 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2630 if (!mKeyPair
->mPrivateKey
->Algorithm().MakeRsa(mAlgName
, modulusLength
,
2631 publicExponent
, hashName
)) {
2632 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2635 mMechanism
= CKM_RSA_PKCS_KEY_PAIR_GEN
;
2637 // Set up params struct
2638 mRsaParams
.keySizeInBits
= modulusLength
;
2639 bool converted
= publicExponent
.GetBigIntValue(mRsaParams
.pe
);
2641 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2644 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
2645 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
2646 RootedDictionary
<EcKeyGenParams
> params(aCx
);
2647 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2648 if (NS_FAILED(mEarlyRv
)) {
2649 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2653 if (!NormalizeToken(params
.mNamedCurve
, mNamedCurve
)) {
2654 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2658 // Create algorithm.
2659 mKeyPair
->mPublicKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
2660 mKeyPair
->mPrivateKey
->Algorithm().MakeEc(mAlgName
, mNamedCurve
);
2661 mMechanism
= CKM_EC_KEY_PAIR_GEN
;
2664 else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_X25519
)) {
2665 mKeyPair
->mPublicKey
->Algorithm().MakeOKP(mAlgName
);
2666 mKeyPair
->mPrivateKey
->Algorithm().MakeOKP(mAlgName
);
2667 mMechanism
= CKM_EC_MONTGOMERY_KEY_PAIR_GEN
;
2668 mNamedCurve
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_CURVE25519
);
2671 else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
2672 mKeyPair
->mPublicKey
->Algorithm().MakeOKP(mAlgName
);
2673 mKeyPair
->mPrivateKey
->Algorithm().MakeOKP(mAlgName
);
2674 mMechanism
= CKM_EC_EDWARDS_KEY_PAIR_GEN
;
2675 mNamedCurve
.AssignLiteral(WEBCRYPTO_NAMED_CURVE_ED25519
);
2679 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2684 if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
2685 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
2686 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
) ||
2687 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
2688 privateAllowedUsages
= CryptoKey::SIGN
;
2689 publicAllowedUsages
= CryptoKey::VERIFY
;
2690 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
2691 privateAllowedUsages
= CryptoKey::DECRYPT
| CryptoKey::UNWRAPKEY
;
2692 publicAllowedUsages
= CryptoKey::ENCRYPT
| CryptoKey::WRAPKEY
;
2693 } else if (mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
2694 mAlgName
.EqualsLiteral(WEBCRYPTO_ALG_X25519
)) {
2695 privateAllowedUsages
= CryptoKey::DERIVEKEY
| CryptoKey::DERIVEBITS
;
2696 publicAllowedUsages
= 0;
2698 MOZ_ASSERT(false); // This shouldn't happen.
2701 mKeyPair
->mPrivateKey
->SetExtractable(aExtractable
);
2702 mKeyPair
->mPrivateKey
->SetType(CryptoKey::PRIVATE
);
2704 mKeyPair
->mPublicKey
->SetExtractable(true);
2705 mKeyPair
->mPublicKey
->SetType(CryptoKey::PUBLIC
);
2707 mKeyPair
->mPrivateKey
->ClearUsages();
2708 mKeyPair
->mPublicKey
->ClearUsages();
2709 for (uint32_t i
= 0; i
< aKeyUsages
.Length(); ++i
) {
2710 mEarlyRv
= mKeyPair
->mPrivateKey
->AddAllowedUsageIntersecting(
2711 aKeyUsages
[i
], mAlgName
, privateAllowedUsages
);
2712 if (NS_FAILED(mEarlyRv
)) {
2716 mEarlyRv
= mKeyPair
->mPublicKey
->AddAllowedUsageIntersecting(
2717 aKeyUsages
[i
], mAlgName
, publicAllowedUsages
);
2718 if (NS_FAILED(mEarlyRv
)) {
2724 nsresult
GenerateAsymmetricKeyTask::DoCrypto() {
2725 MOZ_ASSERT(mKeyPair
);
2727 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2728 MOZ_ASSERT(slot
.get());
2731 switch (mMechanism
) {
2732 case CKM_RSA_PKCS_KEY_PAIR_GEN
:
2733 param
= &mRsaParams
;
2735 case CKM_DH_PKCS_KEY_PAIR_GEN
:
2738 case CKM_EC_MONTGOMERY_KEY_PAIR_GEN
:
2739 case CKM_EC_EDWARDS_KEY_PAIR_GEN
:
2740 case CKM_EC_KEY_PAIR_GEN
: {
2741 param
= CreateECParamsForCurve(mNamedCurve
, mArena
.get());
2743 return NS_ERROR_DOM_UNKNOWN_ERR
;
2748 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2751 mPrivateKey
= UniqueSECKEYPrivateKey(PK11_GenerateKeyPair(
2752 slot
.get(), mMechanism
, param
, TempPtrToSetter(&mPublicKey
), PR_FALSE
,
2753 PR_FALSE
, nullptr));
2755 if (!mPrivateKey
.get() || !mPublicKey
.get()) {
2756 return NS_ERROR_DOM_OPERATION_ERR
;
2759 // If no usages ended up being allowed, SyntaxError
2760 if (!mKeyPair
->mPrivateKey
->HasAnyUsage()) {
2761 return NS_ERROR_DOM_SYNTAX_ERR
;
2764 nsresult rv
= mKeyPair
->mPrivateKey
->SetPrivateKey(mPrivateKey
.get());
2765 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2766 rv
= mKeyPair
->mPublicKey
->SetPublicKey(mPublicKey
.get());
2767 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2768 // PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the
2769 // private key, we need this later when exporting to PKCS8 and JWK though.
2770 if (mMechanism
== CKM_EC_KEY_PAIR_GEN
||
2771 mMechanism
== CKM_EC_MONTGOMERY_KEY_PAIR_GEN
||
2772 mMechanism
== CKM_EC_EDWARDS_KEY_PAIR_GEN
) {
2773 rv
= mKeyPair
->mPrivateKey
->AddPublicKeyData(mPublicKey
.get());
2774 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_OPERATION_ERR
);
2780 void GenerateAsymmetricKeyTask::Resolve() {
2781 mResultPromise
->MaybeResolve(*mKeyPair
);
2784 void GenerateAsymmetricKeyTask::Cleanup() { mKeyPair
= nullptr; }
2786 class DeriveHkdfBitsTask
: public ReturnArrayBufferViewTask
{
2788 DeriveHkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2789 CryptoKey
& aKey
, const Nullable
<uint32_t>& aLength
)
2790 : mMechanism(CKM_INVALID_MECHANISM
) {
2791 Init(aCx
, aAlgorithm
, aKey
, aLength
);
2794 DeriveHkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2795 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2796 : mLengthInBits(0), mLengthInBytes(0), mMechanism(CKM_INVALID_MECHANISM
) {
2798 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aTargetAlgorithm
, length
);
2800 const Nullable
<uint32_t> keyLength(length
);
2801 if (NS_SUCCEEDED(mEarlyRv
)) {
2802 Init(aCx
, aAlgorithm
, aKey
, keyLength
);
2806 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
2807 const Nullable
<uint32_t>& aLength
) {
2808 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_HKDF
);
2809 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_HKDF
);
2811 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
2812 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
2816 RootedDictionary
<HkdfParams
> params(aCx
);
2817 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2818 if (NS_FAILED(mEarlyRv
)) {
2819 mEarlyRv
= NS_ERROR_DOM_TYPE_MISMATCH_ERR
;
2823 // length must be non-null and multiple of eight.
2824 if (aLength
.IsNull() || aLength
.Value() % 8 != 0) {
2825 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2829 // Extract the hash algorithm.
2831 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2832 if (NS_FAILED(mEarlyRv
)) {
2836 // Check the given hash algorithm.
2837 switch (MapAlgorithmNameToMechanism(hashName
)) {
2839 mMechanism
= CKM_NSS_HKDF_SHA1
;
2842 mMechanism
= CKM_NSS_HKDF_SHA256
;
2845 mMechanism
= CKM_NSS_HKDF_SHA384
;
2848 mMechanism
= CKM_NSS_HKDF_SHA512
;
2851 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2855 ATTEMPT_BUFFER_INIT(mSalt
, params
.mSalt
)
2856 ATTEMPT_BUFFER_INIT(mInfo
, params
.mInfo
)
2857 mLengthInBytes
= ceil((double)aLength
.Value() / 8);
2858 mLengthInBits
= aLength
.Value();
2862 size_t mLengthInBits
;
2863 size_t mLengthInBytes
;
2866 CryptoBuffer mSymKey
;
2867 CK_MECHANISM_TYPE mMechanism
;
2869 virtual nsresult
DoCrypto() override
{
2870 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
2872 return NS_ERROR_DOM_OPERATION_ERR
;
2876 SECItem keyItem
= {siBuffer
, nullptr, 0};
2877 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
2879 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
2881 return NS_ERROR_DOM_OPERATION_ERR
;
2884 UniquePK11SymKey
baseKey(PK11_ImportSymKey(slot
.get(), mMechanism
,
2885 PK11_OriginUnwrap
, CKA_WRAP
,
2886 &keyItem
, nullptr));
2888 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2891 // We are going to return an empty string, so we can skip the rest.
2892 if (mLengthInBits
== 0) {
2897 SECItem salt
= {siBuffer
, nullptr, 0};
2898 SECItem info
= {siBuffer
, nullptr, 0};
2899 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &salt
, mSalt
);
2900 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &info
, mInfo
);
2902 CK_NSS_HKDFParams hkdfParams
= {true, salt
.data
, salt
.len
,
2903 true, info
.data
, info
.len
};
2904 SECItem params
= {siBuffer
, (unsigned char*)&hkdfParams
,
2905 sizeof(hkdfParams
)};
2907 // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
2908 // derived symmetric key and don't matter because we ignore them anyway.
2909 UniquePK11SymKey
symKey(PK11_Derive(baseKey
.get(), mMechanism
, ¶ms
,
2910 CKM_SHA512_HMAC
, CKA_SIGN
,
2913 if (!symKey
.get()) {
2914 return NS_ERROR_DOM_OPERATION_ERR
;
2917 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
2918 if (NS_FAILED(rv
)) {
2919 return NS_ERROR_DOM_OPERATION_ERR
;
2922 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2923 // just refers to a buffer managed by symKey. The assignment copies the
2924 // data, so mResult manages one copy, while symKey manages another.
2925 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
2927 if (mLengthInBytes
> mResult
.Length()) {
2928 return NS_ERROR_DOM_DATA_ERR
;
2931 if (!mResult
.SetLength(mLengthInBytes
, fallible
)) {
2932 return NS_ERROR_DOM_UNKNOWN_ERR
;
2939 class DerivePbkdfBitsTask
: public ReturnArrayBufferViewTask
{
2941 DerivePbkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2942 CryptoKey
& aKey
, const Nullable
<uint32_t>& aLength
)
2943 : mHashOidTag(SEC_OID_UNKNOWN
) {
2944 Init(aCx
, aAlgorithm
, aKey
, aLength
);
2947 DerivePbkdfBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
2948 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
2949 : mLength(0), mIterations(0), mHashOidTag(SEC_OID_UNKNOWN
) {
2951 mEarlyRv
= GetKeyLengthForAlgorithm(aCx
, aTargetAlgorithm
, length
);
2953 const Nullable
<uint32_t> keyLength(length
);
2954 if (NS_SUCCEEDED(mEarlyRv
)) {
2955 Init(aCx
, aAlgorithm
, aKey
, keyLength
);
2959 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
2960 const Nullable
<uint32_t>& aLength
) {
2961 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_PBKDF2
);
2962 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_PBKDF2
);
2964 if (!mSymKey
.Assign(aKey
.GetSymKey())) {
2965 mEarlyRv
= NS_ERROR_OUT_OF_MEMORY
;
2969 RootedDictionary
<Pbkdf2Params
> params(aCx
);
2970 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
2971 if (NS_FAILED(mEarlyRv
)) {
2972 mEarlyRv
= NS_ERROR_DOM_SYNTAX_ERR
;
2976 // length must be non-null and multiple of eight.
2977 if (aLength
.IsNull() || aLength
.Value() % 8) {
2978 mEarlyRv
= NS_ERROR_DOM_OPERATION_ERR
;
2982 // Extract the hash algorithm.
2984 mEarlyRv
= GetAlgorithmName(aCx
, params
.mHash
, hashName
);
2985 if (NS_FAILED(mEarlyRv
)) {
2989 // Check the given hash algorithm.
2990 switch (MapAlgorithmNameToMechanism(hashName
)) {
2992 mHashOidTag
= SEC_OID_HMAC_SHA1
;
2995 mHashOidTag
= SEC_OID_HMAC_SHA256
;
2998 mHashOidTag
= SEC_OID_HMAC_SHA384
;
3001 mHashOidTag
= SEC_OID_HMAC_SHA512
;
3004 mEarlyRv
= NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
3008 ATTEMPT_BUFFER_INIT(mSalt
, params
.mSalt
)
3009 mLength
= aLength
.Value() >> 3; // bits to bytes
3010 mIterations
= params
.mIterations
;
3017 CryptoBuffer mSymKey
;
3018 SECOidTag mHashOidTag
;
3020 virtual nsresult
DoCrypto() override
{
3021 UniquePLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
3023 return NS_ERROR_DOM_OPERATION_ERR
;
3026 SECItem salt
= {siBuffer
, nullptr, 0};
3027 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &salt
, mSalt
);
3028 // PK11_CreatePBEV2AlgorithmID will "helpfully" create PBKDF2 parameters
3029 // with a random salt if given a SECItem* that is either null or has a null
3030 // data pointer. This obviously isn't what we want, so we have to fake it
3031 // out by passing in a SECItem* with a non-null data pointer but with zero
3034 MOZ_ASSERT(salt
.len
== 0);
3036 reinterpret_cast<unsigned char*>(PORT_ArenaAlloc(arena
.get(), 1));
3038 return NS_ERROR_DOM_UNKNOWN_ERR
;
3042 // Always pass in cipherAlg=SEC_OID_HMAC_SHA1 (i.e. PBMAC1) as this
3043 // parameter is unused for key generation. It is currently only used
3044 // for PBKDF2 authentication or key (un)wrapping when specifying an
3045 // encryption algorithm (PBES2).
3046 UniqueSECAlgorithmID
algID(
3047 PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2
, SEC_OID_HMAC_SHA1
,
3048 mHashOidTag
, mLength
, mIterations
, &salt
));
3051 return NS_ERROR_DOM_OPERATION_ERR
;
3054 // We are going to return an empty string, so we can skip the rest.
3060 UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
3062 return NS_ERROR_DOM_OPERATION_ERR
;
3065 SECItem keyItem
= {siBuffer
, nullptr, 0};
3066 ATTEMPT_BUFFER_TO_SECITEM(arena
.get(), &keyItem
, mSymKey
);
3068 UniquePK11SymKey
symKey(
3069 PK11_PBEKeyGen(slot
.get(), algID
.get(), &keyItem
, false, nullptr));
3070 if (!symKey
.get()) {
3071 return NS_ERROR_DOM_OPERATION_ERR
;
3074 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
3075 if (NS_FAILED(rv
)) {
3076 return NS_ERROR_DOM_OPERATION_ERR
;
3079 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
3080 // just refers to a buffer managed by symKey. The assignment copies the
3081 // data, so mResult manages one copy, while symKey manages another.
3082 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
3087 template <class DeriveBitsTask
>
3088 class DeriveKeyTask
: public DeriveBitsTask
{
3090 DeriveKeyTask(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
3091 const ObjectOrString
& aAlgorithm
, CryptoKey
& aBaseKey
,
3092 const ObjectOrString
& aDerivedKeyType
, bool aExtractable
,
3093 const Sequence
<nsString
>& aKeyUsages
)
3094 : DeriveBitsTask(aCx
, aAlgorithm
, aBaseKey
, aDerivedKeyType
) {
3095 if (NS_FAILED(this->mEarlyRv
)) {
3099 constexpr auto format
=
3100 NS_LITERAL_STRING_FROM_CSTRING(WEBCRYPTO_KEY_FORMAT_RAW
);
3101 mTask
= new ImportSymmetricKeyTask(aGlobal
, aCx
, format
, aDerivedKeyType
,
3102 aExtractable
, aKeyUsages
);
3106 RefPtr
<ImportSymmetricKeyTask
> mTask
;
3109 virtual void Resolve() override
{
3110 mTask
->SetRawKeyData(this->mResult
);
3111 mTask
->DispatchWithPromise(this->mResultPromise
);
3114 virtual void Cleanup() override
{ mTask
= nullptr; }
3116 class DeriveEcdhBitsTask
: public ReturnArrayBufferViewTask
{
3118 DeriveEcdhBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3119 CryptoKey
& aKey
, const Nullable
<uint32_t>& aLength
)
3120 : mLengthInBits(aLength
), mPrivKey(aKey
.GetPrivateKey()) {
3121 Init(aCx
, aAlgorithm
, aKey
);
3124 DeriveEcdhBitsTask(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3125 CryptoKey
& aKey
, const ObjectOrString
& aTargetAlgorithm
)
3126 : mPrivKey(aKey
.GetPrivateKey()) {
3127 Maybe
<size_t> lengthInBits
;
3128 mEarlyRv
= GetKeyLengthForAlgorithmIfSpecified(aCx
, aTargetAlgorithm
,
3130 if (lengthInBits
.isNothing()) {
3131 mLengthInBits
.SetNull();
3133 mLengthInBits
.SetValue(*lengthInBits
);
3135 if (NS_SUCCEEDED(mEarlyRv
)) {
3136 Init(aCx
, aAlgorithm
, aKey
);
3140 void Init(JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
) {
3141 Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG
, TA_ECDH
);
3142 CHECK_KEY_ALGORITHM(aKey
.Algorithm(), WEBCRYPTO_ALG_ECDH
);
3144 // Check that we have a private key.
3146 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
3150 // Retrieve the peer's public key.
3151 RootedDictionary
<EcdhKeyDeriveParams
> params(aCx
);
3152 mEarlyRv
= Coerce(aCx
, params
, aAlgorithm
);
3153 if (NS_FAILED(mEarlyRv
)) {
3154 /* The returned code is installed by Coerce function. */
3158 CryptoKey
* publicKey
= params
.mPublic
;
3159 mPubKey
= publicKey
->GetPublicKey();
3161 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
3165 CHECK_KEY_ALGORITHM(publicKey
->Algorithm(), WEBCRYPTO_ALG_ECDH
);
3167 // Both keys must use the same named curve.
3168 nsString curve1
= aKey
.Algorithm().mEc
.mNamedCurve
;
3169 nsString curve2
= publicKey
->Algorithm().mEc
.mNamedCurve
;
3171 if (!curve1
.Equals(curve2
)) {
3172 mEarlyRv
= NS_ERROR_DOM_INVALID_ACCESS_ERR
;
3178 Nullable
<uint32_t> mLengthInBits
;
3179 UniqueSECKEYPrivateKey mPrivKey
;
3180 UniqueSECKEYPublicKey mPubKey
;
3182 virtual nsresult
DoCrypto() override
{
3183 // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
3184 // derived symmetric key and don't matter because we ignore them anyway.
3185 UniquePK11SymKey
symKey(
3186 PK11_PubDeriveWithKDF(mPrivKey
.get(), mPubKey
.get(), PR_FALSE
, nullptr,
3187 nullptr, CKM_ECDH1_DERIVE
, CKM_SHA512_HMAC
,
3188 CKA_SIGN
, 0, CKD_NULL
, nullptr, nullptr));
3190 if (!symKey
.get()) {
3191 return NS_ERROR_DOM_OPERATION_ERR
;
3194 nsresult rv
= MapSECStatus(PK11_ExtractKeyValue(symKey
.get()));
3195 if (NS_FAILED(rv
)) {
3196 return NS_ERROR_DOM_OPERATION_ERR
;
3199 // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
3200 // just refers to a buffer managed by symKey. The assignment copies the
3201 // data, so mResult manages one copy, while symKey manages another.
3202 ATTEMPT_BUFFER_ASSIGN(mResult
, PK11_GetKeyData(symKey
.get()));
3204 if (!mLengthInBits
.IsNull()) {
3205 size_t length
= mLengthInBits
.Value();
3206 size_t lengthInBytes
= ceil((double)length
/ 8); // bits to bytes
3207 if (lengthInBytes
> mResult
.Length()) {
3208 return NS_ERROR_DOM_OPERATION_ERR
;
3211 if (!mResult
.SetLength(lengthInBytes
, fallible
)) {
3212 return NS_ERROR_DOM_UNKNOWN_ERR
;
3215 // If the number of bits to derive is not a multiple of 8 we need to
3216 // zero out the remaining bits that were derived but not requested.
3218 mResult
[mResult
.Length() - 1] &= 0xff << (8 - (length
% 8));
3226 template <class KeyEncryptTask
>
3227 class WrapKeyTask
: public ExportKeyTask
{
3229 WrapKeyTask(JSContext
* aCx
, const nsAString
& aFormat
, CryptoKey
& aKey
,
3230 CryptoKey
& aWrappingKey
, const ObjectOrString
& aWrapAlgorithm
)
3231 : ExportKeyTask(aFormat
, aKey
) {
3232 if (NS_FAILED(mEarlyRv
)) {
3236 mTask
= new KeyEncryptTask(aCx
, aWrapAlgorithm
, aWrappingKey
, true);
3240 RefPtr
<KeyEncryptTask
> mTask
;
3242 virtual nsresult
AfterCrypto() override
{
3243 // If wrapping JWK, stringify the JSON
3244 if (mFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
3246 if (!mJwk
.ToJSON(json
)) {
3247 return NS_ERROR_DOM_OPERATION_ERR
;
3250 NS_ConvertUTF16toUTF8
utf8(json
);
3251 if (!mResult
.Assign((const uint8_t*)utf8
.BeginReading(), utf8
.Length())) {
3252 return NS_ERROR_DOM_OPERATION_ERR
;
3259 virtual void Resolve() override
{
3260 mTask
->SetData(mResult
);
3261 mTask
->DispatchWithPromise(mResultPromise
);
3264 virtual void Cleanup() override
{ mTask
= nullptr; }
3267 template <class KeyEncryptTask
>
3268 class UnwrapKeyTask
: public KeyEncryptTask
{
3270 UnwrapKeyTask(JSContext
* aCx
, const ArrayBufferViewOrArrayBuffer
& aWrappedKey
,
3271 CryptoKey
& aUnwrappingKey
,
3272 const ObjectOrString
& aUnwrapAlgorithm
, ImportKeyTask
* aTask
)
3273 : KeyEncryptTask(aCx
, aUnwrapAlgorithm
, aUnwrappingKey
, aWrappedKey
,
3278 RefPtr
<ImportKeyTask
> mTask
;
3280 virtual void Resolve() override
{
3281 mTask
->SetKeyDataMaybeParseJWK(KeyEncryptTask::mResult
);
3282 mTask
->DispatchWithPromise(KeyEncryptTask::mResultPromise
);
3285 virtual void Cleanup() override
{ mTask
= nullptr; }
3288 // Task creation methods for WebCryptoTask
3290 // Note: We do not perform algorithm normalization as a monolithic process,
3291 // as described in the spec. Instead:
3292 // * Each method handles its slice of the supportedAlgorithms structure
3293 // * Task constructors take care of:
3294 // * Coercing the algorithm to the proper concrete type
3295 // * Cloning subordinate data items
3296 // * Cloning input data as needed
3298 // Thus, support for different algorithms is determined by the if-statements
3299 // below, rather than a data structure.
3301 // This results in algorithm normalization coming after some other checks,
3302 // and thus slightly more steps being done synchronously than the spec calls
3303 // for. But none of these steps is especially time-consuming.
3305 WebCryptoTask
* WebCryptoTask::CreateEncryptDecryptTask(
3306 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
3307 const CryptoOperationData
& aData
, bool aEncrypt
) {
3308 TelemetryMethod method
= (aEncrypt
) ? TM_ENCRYPT
: TM_DECRYPT
;
3309 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, method
);
3310 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_ENC
,
3311 aKey
.Extractable());
3313 // Ensure key is usable for this operation
3314 if ((aEncrypt
&& !aKey
.HasUsage(CryptoKey::ENCRYPT
)) ||
3315 (!aEncrypt
&& !aKey
.HasUsage(CryptoKey::DECRYPT
))) {
3316 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3320 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3321 if (NS_FAILED(rv
)) {
3322 return new FailureTask(rv
);
3325 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3326 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3327 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
3328 return new AesTask(aCx
, aAlgorithm
, aKey
, aData
, aEncrypt
);
3329 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
3330 return new RsaOaepTask(aCx
, aAlgorithm
, aKey
, aData
, aEncrypt
);
3333 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3336 WebCryptoTask
* WebCryptoTask::CreateSignVerifyTask(
3337 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
3338 const CryptoOperationData
& aSignature
, const CryptoOperationData
& aData
,
3340 TelemetryMethod method
= (aSign
) ? TM_SIGN
: TM_VERIFY
;
3341 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, method
);
3342 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_SIG
,
3343 aKey
.Extractable());
3345 // Ensure key is usable for this operation
3346 if ((aSign
&& !aKey
.HasUsage(CryptoKey::SIGN
)) ||
3347 (!aSign
&& !aKey
.HasUsage(CryptoKey::VERIFY
))) {
3348 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3352 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3353 if (NS_FAILED(rv
)) {
3354 return new FailureTask(rv
);
3357 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
3358 return new HmacTask(aCx
, aAlgorithm
, aKey
, aSignature
, aData
, aSign
);
3359 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3360 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
3361 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
) ||
3362 algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
3363 return new AsymmetricSignVerifyTask(aCx
, aAlgorithm
, aKey
, aSignature
,
3367 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3370 WebCryptoTask
* WebCryptoTask::CreateDigestTask(
3371 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3372 const CryptoOperationData
& aData
) {
3373 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DIGEST
);
3376 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3377 if (NS_FAILED(rv
)) {
3378 return new FailureTask(rv
);
3381 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA1
) ||
3382 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA256
) ||
3383 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA384
) ||
3384 algName
.EqualsLiteral(WEBCRYPTO_ALG_SHA512
)) {
3385 return new DigestTask(aCx
, aAlgorithm
, aData
);
3388 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3391 WebCryptoTask
* WebCryptoTask::CreateImportKeyTask(
3392 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
3393 JS::Handle
<JSObject
*> aKeyData
, const ObjectOrString
& aAlgorithm
,
3394 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
3395 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_IMPORTKEY
);
3396 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT
, aExtractable
);
3398 // Verify that the format is recognized
3399 if (!aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) &&
3400 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) &&
3401 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) &&
3402 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
3403 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3406 // Verify that aKeyUsages does not contain an unrecognized value
3407 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3408 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3412 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3413 if (NS_FAILED(rv
)) {
3414 return new FailureTask(rv
);
3417 // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation.
3418 // However, the spec should be updated to allow it.
3419 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3420 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3421 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
3422 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) ||
3423 algName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
) ||
3424 algName
.EqualsLiteral(WEBCRYPTO_ALG_HKDF
) ||
3425 algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
)) {
3426 return new ImportSymmetricKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
,
3427 aAlgorithm
, aExtractable
, aKeyUsages
);
3428 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3429 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
3430 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
)) {
3431 return new ImportRsaKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
, aAlgorithm
,
3432 aExtractable
, aKeyUsages
);
3433 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
3434 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
3435 return new ImportEcKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
, aAlgorithm
,
3436 aExtractable
, aKeyUsages
);
3437 } else if (algName
.EqualsLiteral(WEBCRYPTO_ALG_X25519
) ||
3438 algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
)) {
3439 return new ImportOKPKeyTask(aGlobal
, aCx
, aFormat
, aKeyData
, aAlgorithm
,
3440 aExtractable
, aKeyUsages
);
3442 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3446 WebCryptoTask
* WebCryptoTask::CreateExportKeyTask(const nsAString
& aFormat
,
3448 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_EXPORTKEY
);
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 // Verify that the key is extractable
3459 if (!aKey
.Extractable()) {
3460 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3463 // Verify that the algorithm supports export
3464 // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation.
3465 // However, the spec should be updated to allow it.
3466 nsString algName
= aKey
.Algorithm().mName
;
3467 if (algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3468 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3469 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
) ||
3470 algName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
) ||
3471 algName
.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2
) ||
3472 algName
.EqualsLiteral(WEBCRYPTO_ALG_HMAC
) ||
3473 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3474 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
) ||
3475 algName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS
) ||
3476 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
) ||
3477 algName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
3478 algName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
) ||
3479 algName
.EqualsLiteral(WEBCRYPTO_ALG_X25519
)) {
3480 return new ExportKeyTask(aFormat
, aKey
);
3482 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3485 WebCryptoTask
* WebCryptoTask::CreateGenerateKeyTask(
3486 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3487 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
3488 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_GENERATEKEY
);
3489 Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_GENERATE
,
3491 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3492 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3496 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3497 if (NS_FAILED(rv
)) {
3498 return new FailureTask(rv
);
3501 if (algName
.EqualsASCII(WEBCRYPTO_ALG_AES_CBC
) ||
3502 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_CTR
) ||
3503 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_GCM
) ||
3504 algName
.EqualsASCII(WEBCRYPTO_ALG_AES_KW
) ||
3505 algName
.EqualsASCII(WEBCRYPTO_ALG_HMAC
)) {
3506 return new GenerateSymmetricKeyTask(aGlobal
, aCx
, aAlgorithm
, aExtractable
,
3508 } else if (algName
.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3509 algName
.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP
) ||
3510 algName
.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS
) ||
3511 algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
) ||
3512 algName
.EqualsASCII(WEBCRYPTO_ALG_ECDSA
) ||
3513 algName
.EqualsASCII(WEBCRYPTO_ALG_ED25519
) ||
3514 algName
.EqualsASCII(WEBCRYPTO_ALG_X25519
)) {
3515 return new GenerateAsymmetricKeyTask(aGlobal
, aCx
, aAlgorithm
, aExtractable
,
3518 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3522 WebCryptoTask
* WebCryptoTask::CreateDeriveKeyTask(
3523 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const ObjectOrString
& aAlgorithm
,
3524 CryptoKey
& aBaseKey
, const ObjectOrString
& aDerivedKeyType
,
3525 bool aExtractable
, const Sequence
<nsString
>& aKeyUsages
) {
3526 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DERIVEKEY
);
3528 // Ensure baseKey is usable for this operation
3529 if (!aBaseKey
.HasUsage(CryptoKey::DERIVEKEY
)) {
3530 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3533 // Verify that aKeyUsages does not contain an unrecognized value
3534 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3535 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3539 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3540 if (NS_FAILED(rv
)) {
3541 return new FailureTask(rv
);
3544 if (algName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
)) {
3545 return new DeriveKeyTask
<DeriveHkdfBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3546 aBaseKey
, aDerivedKeyType
,
3547 aExtractable
, aKeyUsages
);
3550 if (algName
.EqualsASCII(WEBCRYPTO_ALG_X25519
)) {
3551 return new DeriveKeyTask
<DeriveX25519BitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3552 aBaseKey
, aDerivedKeyType
,
3553 aExtractable
, aKeyUsages
);
3556 if (algName
.EqualsASCII(WEBCRYPTO_ALG_PBKDF2
)) {
3557 return new DeriveKeyTask
<DerivePbkdfBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3558 aBaseKey
, aDerivedKeyType
,
3559 aExtractable
, aKeyUsages
);
3562 if (algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
)) {
3563 return new DeriveKeyTask
<DeriveEcdhBitsTask
>(aGlobal
, aCx
, aAlgorithm
,
3564 aBaseKey
, aDerivedKeyType
,
3565 aExtractable
, aKeyUsages
);
3568 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3571 WebCryptoTask
* WebCryptoTask::CreateDeriveBitsTask(
3572 JSContext
* aCx
, const ObjectOrString
& aAlgorithm
, CryptoKey
& aKey
,
3573 const Nullable
<uint32_t>& aLength
) {
3574 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_DERIVEBITS
);
3576 // Ensure baseKey is usable for this operation
3577 if (!aKey
.HasUsage(CryptoKey::DERIVEBITS
)) {
3578 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3582 nsresult rv
= GetAlgorithmName(aCx
, aAlgorithm
, algName
);
3583 if (NS_FAILED(rv
)) {
3584 return new FailureTask(rv
);
3587 if (algName
.EqualsASCII(WEBCRYPTO_ALG_PBKDF2
)) {
3588 return new DerivePbkdfBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3591 if (algName
.EqualsASCII(WEBCRYPTO_ALG_ECDH
)) {
3592 return new DeriveEcdhBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3595 if (algName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
)) {
3596 return new DeriveHkdfBitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3599 if (algName
.EqualsASCII(WEBCRYPTO_ALG_X25519
)) {
3600 return new DeriveX25519BitsTask(aCx
, aAlgorithm
, aKey
, aLength
);
3603 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3606 WebCryptoTask
* WebCryptoTask::CreateWrapKeyTask(
3607 JSContext
* aCx
, const nsAString
& aFormat
, CryptoKey
& aKey
,
3608 CryptoKey
& aWrappingKey
, const ObjectOrString
& aWrapAlgorithm
) {
3609 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_WRAPKEY
);
3611 // Verify that the format is recognized
3612 if (!aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW
) &&
3613 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI
) &&
3614 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8
) &&
3615 !aFormat
.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK
)) {
3616 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3619 // Ensure wrappingKey is usable for this operation
3620 if (!aWrappingKey
.HasUsage(CryptoKey::WRAPKEY
)) {
3621 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3624 // Ensure key is extractable
3625 if (!aKey
.Extractable()) {
3626 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3629 nsString wrapAlgName
;
3630 nsresult rv
= GetAlgorithmName(aCx
, aWrapAlgorithm
, wrapAlgName
);
3631 if (NS_FAILED(rv
)) {
3632 return new FailureTask(rv
);
3635 if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3636 wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3637 wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
3638 return new WrapKeyTask
<AesTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3640 } else if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
3641 return new WrapKeyTask
<AesKwTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3643 } else if (wrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
3644 return new WrapKeyTask
<RsaOaepTask
>(aCx
, aFormat
, aKey
, aWrappingKey
,
3648 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3651 WebCryptoTask
* WebCryptoTask::CreateUnwrapKeyTask(
3652 nsIGlobalObject
* aGlobal
, JSContext
* aCx
, const nsAString
& aFormat
,
3653 const ArrayBufferViewOrArrayBuffer
& aWrappedKey
, CryptoKey
& aUnwrappingKey
,
3654 const ObjectOrString
& aUnwrapAlgorithm
,
3655 const ObjectOrString
& aUnwrappedKeyAlgorithm
, bool aExtractable
,
3656 const Sequence
<nsString
>& aKeyUsages
) {
3657 Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD
, TM_UNWRAPKEY
);
3659 // Ensure key is usable for this operation
3660 if (!aUnwrappingKey
.HasUsage(CryptoKey::UNWRAPKEY
)) {
3661 return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
3664 // Verify that aKeyUsages does not contain an unrecognized value
3665 if (!CryptoKey::AllUsagesRecognized(aKeyUsages
)) {
3666 return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR
);
3669 nsString keyAlgName
;
3670 nsresult rv
= GetAlgorithmName(aCx
, aUnwrappedKeyAlgorithm
, keyAlgName
);
3671 if (NS_FAILED(rv
)) {
3672 return new FailureTask(rv
);
3675 CryptoOperationData dummy
;
3676 RefPtr
<ImportKeyTask
> importTask
;
3677 if (keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_CBC
) ||
3678 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_CTR
) ||
3679 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_GCM
) ||
3680 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_AES_KW
) ||
3681 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_HKDF
) ||
3682 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_HMAC
)) {
3683 importTask
= new ImportSymmetricKeyTask(aGlobal
, aCx
, aFormat
,
3684 aUnwrappedKeyAlgorithm
,
3685 aExtractable
, aKeyUsages
);
3686 } else if (keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1
) ||
3687 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP
) ||
3688 keyAlgName
.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS
)) {
3690 new ImportRsaKeyTask(aGlobal
, aCx
, aFormat
, aUnwrappedKeyAlgorithm
,
3691 aExtractable
, aKeyUsages
);
3692 } else if (keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDH
) ||
3693 keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ECDSA
)) {
3695 new ImportEcKeyTask(aGlobal
, aCx
, aFormat
, aUnwrappedKeyAlgorithm
,
3696 aExtractable
, aKeyUsages
);
3697 } else if (keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_ED25519
) ||
3698 keyAlgName
.EqualsLiteral(WEBCRYPTO_ALG_X25519
)) {
3700 new ImportOKPKeyTask(aGlobal
, aCx
, aFormat
, aUnwrappedKeyAlgorithm
,
3701 aExtractable
, aKeyUsages
);
3703 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3706 nsString unwrapAlgName
;
3707 rv
= GetAlgorithmName(aCx
, aUnwrapAlgorithm
, unwrapAlgName
);
3708 if (NS_FAILED(rv
)) {
3709 return new FailureTask(rv
);
3711 if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC
) ||
3712 unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR
) ||
3713 unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM
)) {
3714 return new UnwrapKeyTask
<AesTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3715 aUnwrapAlgorithm
, importTask
);
3716 } else if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_AES_KW
)) {
3717 return new UnwrapKeyTask
<AesKwTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3718 aUnwrapAlgorithm
, importTask
);
3719 } else if (unwrapAlgName
.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP
)) {
3720 return new UnwrapKeyTask
<RsaOaepTask
>(aCx
, aWrappedKey
, aUnwrappingKey
,
3721 aUnwrapAlgorithm
, importTask
);
3724 return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
3727 WebCryptoTask::WebCryptoTask()
3728 : CancelableRunnable("WebCryptoTask"),
3730 mEarlyComplete(false),
3731 mOriginalEventTarget(nullptr),
3732 mRv(NS_ERROR_NOT_INITIALIZED
) {}
3734 WebCryptoTask::~WebCryptoTask() = default;
3736 } // namespace mozilla::dom