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