Changeset 209155 in webkit


Ignore:
Timestamp:
Nov 30, 2016 2:26:10 PM (7 years ago)
Author:
jiewen_tan@apple.com
Message:

Update SubtleCrypto::wrapKey to match the latest spec
https://bugs.webkit.org/show_bug.cgi?id=164746
<rdar://problem/29258160>

Reviewed by Brent Fulgham.

LayoutTests/imported/w3c:

  • WebCryptoAPI/idlharness-expected.txt:

Source/WebCore:

This patch does following few things:

  1. It updates the SubtleCrypto::wrapKey method to match the latest spec: https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey. It also refers to the latest Editor's Draft to a certain degree: https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-wrapKey.
  2. It implements wrapKey operations of the following algorithms: AES-KW.
  3. It also replaces JSSubtleCrypto* with auto in all promise functions.

Tests: crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-private.html

crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-public.html
crypto/subtle/aes-kw-import-key-wrap-raw-key.html
crypto/subtle/aes-kw-wrap-key-malformed-parameters.html
crypto/subtle/rsa-oaep-import-key-wrap-jwk-oct-key.html
crypto/subtle/wrapKey-malformed-parameters.html
crypto/workers/subtle/aes-cbc-import-key-wrap-key.html
crypto/workers/subtle/aes-kw-import-key-wrap-key.html
crypto/workers/subtle/rsa-oaep-import-key-wrap-key.html

  • bindings/js/JSSubtleCryptoCustom.cpp:

(WebCore::normalizeCryptoAlgorithmParameters):
(WebCore::supportExportKeyThrow):
(WebCore::jsSubtleCryptoFunctionEncryptPromise):
(WebCore::jsSubtleCryptoFunctionDecryptPromise):
(WebCore::jsSubtleCryptoFunctionExportKeyPromise):
(WebCore::jsSubtleCryptoFunctionWrapKeyPromise):
(WebCore::JSSubtleCrypto::wrapKey):

  • crypto/CryptoAlgorithm.cpp:

(WebCore::CryptoAlgorithm::wrapKey):

  • crypto/CryptoAlgorithm.h:
  • crypto/SubtleCrypto.idl:
  • crypto/algorithms/CryptoAlgorithmAES_KW.cpp:

(WebCore::CryptoAlgorithmAES_KW::wrapKey):

  • crypto/algorithms/CryptoAlgorithmAES_KW.h:
  • crypto/gnutls/CryptoAlgorithmAES_KWGnuTLS.cpp:

(WebCore::CryptoAlgorithmAES_KW::platformWrapKey):

  • crypto/mac/CryptoAlgorithmAES_KWMac.cpp:

(WebCore::wrapKeyAES_KW):
(WebCore::CryptoAlgorithmAES_KW::platformWrapKey):
(WebCore::CryptoAlgorithmAES_KW::platformEncrypt):

LayoutTests:

  • crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-private-expected.txt: Added.
  • crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-private.html: Added.
  • crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-public-expected.txt: Added.
  • crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-public.html: Added.
  • crypto/subtle/aes-kw-import-key-wrap-raw-key-expected.txt: Added.
  • crypto/subtle/aes-kw-import-key-wrap-raw-key.html: Added.
  • crypto/subtle/aes-kw-wrap-key-malformed-parameters-expected.txt: Added.
  • crypto/subtle/aes-kw-wrap-key-malformed-parameters.html: Added.
  • crypto/subtle/rsa-oaep-import-key-wrap-jwk-oct-key-expected.txt: Added.
  • crypto/subtle/rsa-oaep-import-key-wrap-jwk-oct-key.html: Added.
  • crypto/subtle/wrapKey-malformed-parameters-expected.txt: Added.
  • crypto/subtle/wrapKey-malformed-parameters.html: Added.
  • crypto/workers/subtle/aes-cbc-import-key-wrap-key-expected.txt: Added.
  • crypto/workers/subtle/aes-cbc-import-key-wrap-key.html: Added.
  • crypto/workers/subtle/aes-kw-import-key-wrap-key-expected.txt: Added.
  • crypto/workers/subtle/aes-kw-import-key-wrap-key.html: Added.
  • crypto/workers/subtle/resources/aes-cbc-import-key-wrap-key.js: Added.
  • crypto/workers/subtle/resources/aes-kw-import-key-wrap-key.js: Added.
  • crypto/workers/subtle/resources/rsa-oaep-import-key-wrap-key.js: Added.
  • crypto/workers/subtle/rsa-oaep-import-key-wrap-key-expected.txt: Added.
  • crypto/workers/subtle/rsa-oaep-import-key-wrap-key.html: Added.
Location:
trunk
Files:
21 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r209154 r209155  
     12016-11-30  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        Update SubtleCrypto::wrapKey to match the latest spec
     4        https://bugs.webkit.org/show_bug.cgi?id=164746
     5        <rdar://problem/29258160>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        * crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-private-expected.txt: Added.
     10        * crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-private.html: Added.
     11        * crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-public-expected.txt: Added.
     12        * crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-public.html: Added.
     13        * crypto/subtle/aes-kw-import-key-wrap-raw-key-expected.txt: Added.
     14        * crypto/subtle/aes-kw-import-key-wrap-raw-key.html: Added.
     15        * crypto/subtle/aes-kw-wrap-key-malformed-parameters-expected.txt: Added.
     16        * crypto/subtle/aes-kw-wrap-key-malformed-parameters.html: Added.
     17        * crypto/subtle/rsa-oaep-import-key-wrap-jwk-oct-key-expected.txt: Added.
     18        * crypto/subtle/rsa-oaep-import-key-wrap-jwk-oct-key.html: Added.
     19        * crypto/subtle/wrapKey-malformed-parameters-expected.txt: Added.
     20        * crypto/subtle/wrapKey-malformed-parameters.html: Added.
     21        * crypto/workers/subtle/aes-cbc-import-key-wrap-key-expected.txt: Added.
     22        * crypto/workers/subtle/aes-cbc-import-key-wrap-key.html: Added.
     23        * crypto/workers/subtle/aes-kw-import-key-wrap-key-expected.txt: Added.
     24        * crypto/workers/subtle/aes-kw-import-key-wrap-key.html: Added.
     25        * crypto/workers/subtle/resources/aes-cbc-import-key-wrap-key.js: Added.
     26        * crypto/workers/subtle/resources/aes-kw-import-key-wrap-key.js: Added.
     27        * crypto/workers/subtle/resources/rsa-oaep-import-key-wrap-key.js: Added.
     28        * crypto/workers/subtle/rsa-oaep-import-key-wrap-key-expected.txt: Added.
     29        * crypto/workers/subtle/rsa-oaep-import-key-wrap-key.html: Added.
     30
    1312016-11-30  Joseph Pecoraro  <pecoraro@apple.com>
    232
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r209150 r209155  
     12016-11-30  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        Update SubtleCrypto::wrapKey to match the latest spec
     4        https://bugs.webkit.org/show_bug.cgi?id=164746
     5        <rdar://problem/29258160>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        * WebCryptoAPI/idlharness-expected.txt:
     10
    1112016-11-30  Jiewen Tan  <jiewen_tan@apple.com>
    212
  • trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt

    r209150 r209155  
    6464PASS SubtleCrypto interface: crypto.subtle must inherit property "exportKey" with the proper type (9)
    6565PASS SubtleCrypto interface: calling exportKey(KeyFormat,CryptoKey) on crypto.subtle with too few arguments must throw TypeError
    66 FAIL SubtleCrypto interface: crypto.subtle must inherit property "wrapKey" with the proper type (10) assert_inherits: property "wrapKey" not found in prototype chain
    67 FAIL SubtleCrypto interface: calling wrapKey(KeyFormat,CryptoKey,CryptoKey,AlgorithmIdentifier) on crypto.subtle with too few arguments must throw TypeError assert_inherits: property "wrapKey" not found in prototype chain
     66PASS SubtleCrypto interface: crypto.subtle must inherit property "wrapKey" with the proper type (10)
     67PASS SubtleCrypto interface: calling wrapKey(KeyFormat,CryptoKey,CryptoKey,AlgorithmIdentifier) on crypto.subtle with too few arguments must throw TypeError
    6868FAIL SubtleCrypto interface: crypto.subtle must inherit property "unwrapKey" with the proper type (11) assert_inherits: property "unwrapKey" not found in prototype chain
    6969FAIL SubtleCrypto interface: calling unwrapKey(KeyFormat,BufferSource,CryptoKey,AlgorithmIdentifier,AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_inherits: property "unwrapKey" not found in prototype chain
  • trunk/Source/WebCore/ChangeLog

    r209153 r209155  
     12016-11-30  Jiewen Tan  <jiewen_tan@apple.com>
     2
     3        Update SubtleCrypto::wrapKey to match the latest spec
     4        https://bugs.webkit.org/show_bug.cgi?id=164746
     5        <rdar://problem/29258160>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        This patch does following few things:
     10        1. It updates the SubtleCrypto::wrapKey method to match the latest spec:
     11           https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey.
     12           It also refers to the latest Editor's Draft to a certain degree:
     13           https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-wrapKey.
     14        2. It implements wrapKey operations of the following algorithms: AES-KW.
     15        3. It also replaces JSSubtleCrypto* with auto in all promise functions.
     16
     17        Tests: crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-private.html
     18               crypto/subtle/aes-cbc-import-key-wrap-jwk-rsa-key-public.html
     19               crypto/subtle/aes-kw-import-key-wrap-raw-key.html
     20               crypto/subtle/aes-kw-wrap-key-malformed-parameters.html
     21               crypto/subtle/rsa-oaep-import-key-wrap-jwk-oct-key.html
     22               crypto/subtle/wrapKey-malformed-parameters.html
     23               crypto/workers/subtle/aes-cbc-import-key-wrap-key.html
     24               crypto/workers/subtle/aes-kw-import-key-wrap-key.html
     25               crypto/workers/subtle/rsa-oaep-import-key-wrap-key.html
     26
     27        * bindings/js/JSSubtleCryptoCustom.cpp:
     28        (WebCore::normalizeCryptoAlgorithmParameters):
     29        (WebCore::supportExportKeyThrow):
     30        (WebCore::jsSubtleCryptoFunctionEncryptPromise):
     31        (WebCore::jsSubtleCryptoFunctionDecryptPromise):
     32        (WebCore::jsSubtleCryptoFunctionExportKeyPromise):
     33        (WebCore::jsSubtleCryptoFunctionWrapKeyPromise):
     34        (WebCore::JSSubtleCrypto::wrapKey):
     35        * crypto/CryptoAlgorithm.cpp:
     36        (WebCore::CryptoAlgorithm::wrapKey):
     37        * crypto/CryptoAlgorithm.h:
     38        * crypto/SubtleCrypto.idl:
     39        * crypto/algorithms/CryptoAlgorithmAES_KW.cpp:
     40        (WebCore::CryptoAlgorithmAES_KW::wrapKey):
     41        * crypto/algorithms/CryptoAlgorithmAES_KW.h:
     42        * crypto/gnutls/CryptoAlgorithmAES_KWGnuTLS.cpp:
     43        (WebCore::CryptoAlgorithmAES_KW::platformWrapKey):
     44        * crypto/mac/CryptoAlgorithmAES_KWMac.cpp:
     45        (WebCore::wrapKeyAES_KW):
     46        (WebCore::CryptoAlgorithmAES_KW::platformWrapKey):
     47        (WebCore::CryptoAlgorithmAES_KW::platformEncrypt):
     48
    1492016-11-29  Sam Weinig  <sam@webkit.org>
    250
  • trunk/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp

    r209150 r209155  
    4747#include <runtime/IteratorOperations.h>
    4848#include <runtime/JSArray.h>
     49#include <runtime/JSONObject.h>
    4950
    5051using namespace JSC;
     
    6061    GenerateKey,
    6162    ImportKey,
     63    WrapKey,
    6264};
    6365
     
    219221                break;
    220222            }
     223            default:
     224                setDOMException(&state, NOT_SUPPORTED_ERR);
     225                return nullptr;
     226            }
     227            break;
     228        case Operations::WrapKey:
     229            switch (*identifier) {
     230            case CryptoAlgorithmIdentifier::AES_KW:
     231                result = std::make_unique<CryptoAlgorithmParameters>(params);
     232                break;
    221233            default:
    222234                setDOMException(&state, NOT_SUPPORTED_ERR);
     
    431443}
    432444
    433 static void jsSubtleCryptoFunctionEncryptPromise(ExecState& state, Ref<DeferredPromise>&& promise)
    434 {
    435     VM& vm = state.vm();
    436     auto scope = DECLARE_THROW_SCOPE(vm);
    437 
    438     if (UNLIKELY(state.argumentCount() < 3)) {
    439         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
    440         return;
    441     }
    442 
    443     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Encrypt);
    444     RETURN_IF_EXCEPTION(scope, void());
    445 
    446     auto key = toCryptoKey(state, state.uncheckedArgument(1));
    447     RETURN_IF_EXCEPTION(scope, void());
    448 
    449     auto data = toVector(state, state.uncheckedArgument(2));
    450     RETURN_IF_EXCEPTION(scope, void());
    451 
    452     if (params->identifier != key->algorithmIdentifier()) {
    453         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
    454         return;
    455     }
    456 
    457     if (!key->allows(CryptoKeyUsageEncrypt)) {
    458         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support encryption"));
    459         return;
    460     }
    461 
    462     auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
    463     RETURN_IF_EXCEPTION(scope, void());
    464 
    465     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& cipherText) mutable {
    466         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), cipherText.data(), cipherText.size());
    467         return;
    468     };
    469     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
    470         rejectWithException(WTFMove(capturedPromise), ec);
    471     };
    472 
    473     JSSubtleCrypto* subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
    474     ASSERT(subtle);
    475     algorithm->encrypt(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
    476 }
    477 
    478 static void jsSubtleCryptoFunctionDecryptPromise(ExecState& state, Ref<DeferredPromise>&& promise)
    479 {
    480     VM& vm = state.vm();
    481     auto scope = DECLARE_THROW_SCOPE(vm);
    482 
    483     if (UNLIKELY(state.argumentCount() < 3)) {
    484         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
    485         return;
    486     }
    487 
    488     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Decrypt);
    489     RETURN_IF_EXCEPTION(scope, void());
    490 
    491     auto key = toCryptoKey(state, state.uncheckedArgument(1));
    492     RETURN_IF_EXCEPTION(scope, void());
    493 
    494     auto data = toVector(state, state.uncheckedArgument(2));
    495     RETURN_IF_EXCEPTION(scope, void());
    496 
    497     if (params->identifier != key->algorithmIdentifier()) {
    498         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
    499         return;
    500     }
    501 
    502     if (!key->allows(CryptoKeyUsageDecrypt)) {
    503         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support decryption"));
    504         return;
    505     }
    506 
    507     auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
    508     RETURN_IF_EXCEPTION(scope, void());
    509 
    510     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& plainText) mutable {
    511         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), plainText.data(), plainText.size());
    512         return;
    513     };
    514     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
    515         rejectWithException(WTFMove(capturedPromise), ec);
    516     };
    517 
    518     JSSubtleCrypto* subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
    519     ASSERT(subtle);
    520     algorithm->decrypt(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
    521 }
    522 
    523 static void jsSubtleCryptoFunctionSignPromise(ExecState& state, Ref<DeferredPromise>&& promise)
    524 {
    525     VM& vm = state.vm();
    526     auto scope = DECLARE_THROW_SCOPE(vm);
    527 
    528     if (UNLIKELY(state.argumentCount() < 3)) {
    529         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
    530         return;
    531     }
    532 
    533     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Sign);
    534     RETURN_IF_EXCEPTION(scope, void());
    535 
    536     auto key = toCryptoKey(state, state.uncheckedArgument(1));
    537     RETURN_IF_EXCEPTION(scope, void());
    538 
    539     auto data = toVector(state, state.uncheckedArgument(2));
    540     RETURN_IF_EXCEPTION(scope, void());
    541 
    542     if (params->identifier != key->algorithmIdentifier()) {
    543         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
    544         return;
    545     }
    546 
    547     if (!key->allows(CryptoKeyUsageSign)) {
    548         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support signing"));
    549         return;
    550     }
    551 
    552     auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
    553     RETURN_IF_EXCEPTION(scope, void());
    554 
    555     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& signature) mutable {
    556         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), signature.data(), signature.size());
    557         return;
    558     };
    559     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
    560         rejectWithException(WTFMove(capturedPromise), ec);
    561     };
    562 
    563     JSSubtleCrypto* subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
    564     ASSERT(subtle);
    565     algorithm->sign(key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
    566 }
    567 
    568 static void jsSubtleCryptoFunctionVerifyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
    569 {
    570     VM& vm = state.vm();
    571     auto scope = DECLARE_THROW_SCOPE(vm);
    572 
    573     if (UNLIKELY(state.argumentCount() < 4)) {
    574         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
    575         return;
    576     }
    577 
    578     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Verify);
    579     RETURN_IF_EXCEPTION(scope, void());
    580 
    581     auto key = toCryptoKey(state, state.uncheckedArgument(1));
    582     RETURN_IF_EXCEPTION(scope, void());
    583 
    584     auto signature = toVector(state, state.uncheckedArgument(2));
    585     RETURN_IF_EXCEPTION(scope, void());
    586 
    587     auto data = toVector(state, state.uncheckedArgument(3));
    588     RETURN_IF_EXCEPTION(scope, void());
    589 
    590     if (params->identifier != key->algorithmIdentifier()) {
    591         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
    592         return;
    593     }
    594 
    595     if (!key->allows(CryptoKeyUsageVerify)) {
    596         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support verification"));
    597         return;
    598     }
    599 
    600     auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
    601     RETURN_IF_EXCEPTION(scope, void());
    602 
    603     auto callback = [capturedPromise = promise.copyRef()](bool result) mutable {
    604         capturedPromise->resolve(result);
    605         return;
    606     };
    607     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
    608         rejectWithException(WTFMove(capturedPromise), ec);
    609     };
    610 
    611     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
    612     ASSERT(subtle);
    613     algorithm->verify(key.releaseNonNull(), WTFMove(signature), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
    614 }
    615 
    616 static void jsSubtleCryptoFunctionGenerateKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
    617 {
    618     VM& vm = state.vm();
    619     auto scope = DECLARE_THROW_SCOPE(vm);
    620 
    621     if (UNLIKELY(state.argumentCount() < 3)) {
    622         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
    623         return;
    624     }
    625 
    626     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::GenerateKey);
    627     RETURN_IF_EXCEPTION(scope, void());
    628 
    629     auto extractable = state.uncheckedArgument(1).toBoolean(&state);
    630     RETURN_IF_EXCEPTION(scope, void());
    631 
    632     auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(2));
    633     RETURN_IF_EXCEPTION(scope, void());
    634 
    635     auto algorithm = createAlgorithm(state, params->identifier);
    636     RETURN_IF_EXCEPTION(scope, void());
    637 
    638     auto callback = [capturedPromise = promise.copyRef()](CryptoKey* key, CryptoKeyPair* keyPair) mutable {
    639         ASSERT(key || keyPair);
    640         ASSERT(!key || !keyPair);
    641         if (key) {
    642             if ((key->type() == CryptoKeyType::Private || key->type() == CryptoKeyType::Secret) && !key->usagesBitmap()) {
    643                 rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
    644                 return;
    645             }
    646             capturedPromise->resolve(key);
    647         } else {
    648             if (!keyPair->privateKey()->usagesBitmap()) {
    649                 rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
    650                 return;
    651             }
    652             capturedPromise->resolve(keyPair);
    653         }
    654     };
    655     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
    656         rejectWithException(WTFMove(capturedPromise), ec);
    657     };
    658 
    659     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously
    660     // regardless what kind of keys it produces: https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey
    661     // That's simply not efficient for AES and HMAC keys. Therefore, we perform it as an async task conditionally.
    662     algorithm->generateKey(*params, extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state));
    663 }
    664 
    665 static void jsSubtleCryptoFunctionImportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
    666 {
    667     VM& vm = state.vm();
    668     auto scope = DECLARE_THROW_SCOPE(vm);
    669 
    670     if (UNLIKELY(state.argumentCount() < 5)) {
    671         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
    672         return;
    673     }
    674 
    675     auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
    676     RETURN_IF_EXCEPTION(scope, void());
    677 
    678     auto keyData = toKeyData(state, format, state.uncheckedArgument(1));
    679     RETURN_IF_EXCEPTION(scope, void());
    680 
    681     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(2), Operations::ImportKey);
    682     RETURN_IF_EXCEPTION(scope, void());
    683 
    684     auto extractable = state.uncheckedArgument(3).toBoolean(&state);
    685     RETURN_IF_EXCEPTION(scope, void());
    686 
    687     auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(4));
    688     RETURN_IF_EXCEPTION(scope, void());
    689 
    690     auto algorithm = createAlgorithm(state, params->identifier);
    691     RETURN_IF_EXCEPTION(scope, void());
    692 
    693     auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable {
    694         if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
    695             rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
    696             return;
    697         }
    698         capturedPromise->resolve(key);
    699     };
    700     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
    701         rejectWithException(WTFMove(capturedPromise), ec);
    702     };
    703 
    704     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
    705     // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey
    706     // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
    707     algorithm->importKey(format, WTFMove(keyData), WTFMove(params), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback));
    708 }
    709 
    710 static void jsSubtleCryptoFunctionExportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
    711 {
    712     VM& vm = state.vm();
    713     auto scope = DECLARE_THROW_SCOPE(vm);
    714 
    715     if (UNLIKELY(state.argumentCount() < 2)) {
    716         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
    717         return;
    718     }
    719 
    720     auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
    721     RETURN_IF_EXCEPTION(scope, void());
    722 
    723     auto key = toCryptoKey(state, state.uncheckedArgument(1));
    724     RETURN_IF_EXCEPTION(scope, void());
    725 
    726     switch (key->algorithmIdentifier()) {
     445static void supportExportKeyThrow(ExecState& state, CryptoAlgorithmIdentifier identifier)
     446{
     447    switch (identifier) {
    727448    case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
    728449    case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
     
    736457    case CryptoAlgorithmIdentifier::AES_KW:
    737458    case CryptoAlgorithmIdentifier::HMAC:
    738         break;
     459        return;
    739460    default:
    740         promise->reject(NOT_SUPPORTED_ERR, ASCIILiteral("The operation is not supported"));
    741         return;
    742     }
     461        setDOMException(&state, NOT_SUPPORTED_ERR);
     462    }
     463}
     464
     465static void jsSubtleCryptoFunctionEncryptPromise(ExecState& state, Ref<DeferredPromise>&& promise)
     466{
     467    VM& vm = state.vm();
     468    auto scope = DECLARE_THROW_SCOPE(vm);
     469
     470    if (UNLIKELY(state.argumentCount() < 3)) {
     471        promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
     472        return;
     473    }
     474
     475    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Encrypt);
     476    RETURN_IF_EXCEPTION(scope, void());
     477
     478    auto key = toCryptoKey(state, state.uncheckedArgument(1));
     479    RETURN_IF_EXCEPTION(scope, void());
     480
     481    auto data = toVector(state, state.uncheckedArgument(2));
     482    RETURN_IF_EXCEPTION(scope, void());
     483
     484    if (params->identifier != key->algorithmIdentifier()) {
     485        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
     486        return;
     487    }
     488
     489    if (!key->allows(CryptoKeyUsageEncrypt)) {
     490        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support encryption"));
     491        return;
     492    }
     493
     494    auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
     495    RETURN_IF_EXCEPTION(scope, void());
     496
     497    auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& cipherText) mutable {
     498        fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), cipherText.data(), cipherText.size());
     499        return;
     500    };
     501    auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
     502        rejectWithException(WTFMove(capturedPromise), ec);
     503    };
     504
     505    auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
     506    ASSERT(subtle);
     507    algorithm->encrypt(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
     508}
     509
     510static void jsSubtleCryptoFunctionDecryptPromise(ExecState& state, Ref<DeferredPromise>&& promise)
     511{
     512    VM& vm = state.vm();
     513    auto scope = DECLARE_THROW_SCOPE(vm);
     514
     515    if (UNLIKELY(state.argumentCount() < 3)) {
     516        promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
     517        return;
     518    }
     519
     520    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Decrypt);
     521    RETURN_IF_EXCEPTION(scope, void());
     522
     523    auto key = toCryptoKey(state, state.uncheckedArgument(1));
     524    RETURN_IF_EXCEPTION(scope, void());
     525
     526    auto data = toVector(state, state.uncheckedArgument(2));
     527    RETURN_IF_EXCEPTION(scope, void());
     528
     529    if (params->identifier != key->algorithmIdentifier()) {
     530        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
     531        return;
     532    }
     533
     534    if (!key->allows(CryptoKeyUsageDecrypt)) {
     535        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support decryption"));
     536        return;
     537    }
     538
     539    auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
     540    RETURN_IF_EXCEPTION(scope, void());
     541
     542    auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& plainText) mutable {
     543        fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), plainText.data(), plainText.size());
     544        return;
     545    };
     546    auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
     547        rejectWithException(WTFMove(capturedPromise), ec);
     548    };
     549
     550    auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
     551    ASSERT(subtle);
     552    algorithm->decrypt(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
     553}
     554
     555static void jsSubtleCryptoFunctionSignPromise(ExecState& state, Ref<DeferredPromise>&& promise)
     556{
     557    VM& vm = state.vm();
     558    auto scope = DECLARE_THROW_SCOPE(vm);
     559
     560    if (UNLIKELY(state.argumentCount() < 3)) {
     561        promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
     562        return;
     563    }
     564
     565    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Sign);
     566    RETURN_IF_EXCEPTION(scope, void());
     567
     568    auto key = toCryptoKey(state, state.uncheckedArgument(1));
     569    RETURN_IF_EXCEPTION(scope, void());
     570
     571    auto data = toVector(state, state.uncheckedArgument(2));
     572    RETURN_IF_EXCEPTION(scope, void());
     573
     574    if (params->identifier != key->algorithmIdentifier()) {
     575        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
     576        return;
     577    }
     578
     579    if (!key->allows(CryptoKeyUsageSign)) {
     580        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support signing"));
     581        return;
     582    }
     583
     584    auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
     585    RETURN_IF_EXCEPTION(scope, void());
     586
     587    auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& signature) mutable {
     588        fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), signature.data(), signature.size());
     589        return;
     590    };
     591    auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
     592        rejectWithException(WTFMove(capturedPromise), ec);
     593    };
     594
     595    JSSubtleCrypto* subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
     596    ASSERT(subtle);
     597    algorithm->sign(key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
     598}
     599
     600static void jsSubtleCryptoFunctionVerifyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
     601{
     602    VM& vm = state.vm();
     603    auto scope = DECLARE_THROW_SCOPE(vm);
     604
     605    if (UNLIKELY(state.argumentCount() < 4)) {
     606        promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
     607        return;
     608    }
     609
     610    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Verify);
     611    RETURN_IF_EXCEPTION(scope, void());
     612
     613    auto key = toCryptoKey(state, state.uncheckedArgument(1));
     614    RETURN_IF_EXCEPTION(scope, void());
     615
     616    auto signature = toVector(state, state.uncheckedArgument(2));
     617    RETURN_IF_EXCEPTION(scope, void());
     618
     619    auto data = toVector(state, state.uncheckedArgument(3));
     620    RETURN_IF_EXCEPTION(scope, void());
     621
     622    if (params->identifier != key->algorithmIdentifier()) {
     623        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
     624        return;
     625    }
     626
     627    if (!key->allows(CryptoKeyUsageVerify)) {
     628        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support verification"));
     629        return;
     630    }
     631
     632    auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
     633    RETURN_IF_EXCEPTION(scope, void());
     634
     635    auto callback = [capturedPromise = promise.copyRef()](bool result) mutable {
     636        capturedPromise->resolve(result);
     637        return;
     638    };
     639    auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
     640        rejectWithException(WTFMove(capturedPromise), ec);
     641    };
     642
     643    auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
     644    ASSERT(subtle);
     645    algorithm->verify(key.releaseNonNull(), WTFMove(signature), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
     646}
     647
     648static void jsSubtleCryptoFunctionGenerateKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
     649{
     650    VM& vm = state.vm();
     651    auto scope = DECLARE_THROW_SCOPE(vm);
     652
     653    if (UNLIKELY(state.argumentCount() < 3)) {
     654        promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
     655        return;
     656    }
     657
     658    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::GenerateKey);
     659    RETURN_IF_EXCEPTION(scope, void());
     660
     661    auto extractable = state.uncheckedArgument(1).toBoolean(&state);
     662    RETURN_IF_EXCEPTION(scope, void());
     663
     664    auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(2));
     665    RETURN_IF_EXCEPTION(scope, void());
     666
     667    auto algorithm = createAlgorithm(state, params->identifier);
     668    RETURN_IF_EXCEPTION(scope, void());
     669
     670    auto callback = [capturedPromise = promise.copyRef()](CryptoKey* key, CryptoKeyPair* keyPair) mutable {
     671        ASSERT(key || keyPair);
     672        ASSERT(!key || !keyPair);
     673        if (key) {
     674            if ((key->type() == CryptoKeyType::Private || key->type() == CryptoKeyType::Secret) && !key->usagesBitmap()) {
     675                rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
     676                return;
     677            }
     678            capturedPromise->resolve(key);
     679        } else {
     680            if (!keyPair->privateKey()->usagesBitmap()) {
     681                rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
     682                return;
     683            }
     684            capturedPromise->resolve(keyPair);
     685        }
     686    };
     687    auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
     688        rejectWithException(WTFMove(capturedPromise), ec);
     689    };
     690
     691    // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously
     692    // regardless what kind of keys it produces: https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey
     693    // That's simply not efficient for AES and HMAC keys. Therefore, we perform it as an async task conditionally.
     694    algorithm->generateKey(*params, extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state));
     695}
     696
     697static void jsSubtleCryptoFunctionImportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
     698{
     699    VM& vm = state.vm();
     700    auto scope = DECLARE_THROW_SCOPE(vm);
     701
     702    if (UNLIKELY(state.argumentCount() < 5)) {
     703        promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
     704        return;
     705    }
     706
     707    auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
     708    RETURN_IF_EXCEPTION(scope, void());
     709
     710    auto keyData = toKeyData(state, format, state.uncheckedArgument(1));
     711    RETURN_IF_EXCEPTION(scope, void());
     712
     713    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(2), Operations::ImportKey);
     714    RETURN_IF_EXCEPTION(scope, void());
     715
     716    auto extractable = state.uncheckedArgument(3).toBoolean(&state);
     717    RETURN_IF_EXCEPTION(scope, void());
     718
     719    auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(4));
     720    RETURN_IF_EXCEPTION(scope, void());
     721
     722    auto algorithm = createAlgorithm(state, params->identifier);
     723    RETURN_IF_EXCEPTION(scope, void());
     724
     725    auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable {
     726        if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
     727            rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
     728            return;
     729        }
     730        capturedPromise->resolve(key);
     731    };
     732    auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
     733        rejectWithException(WTFMove(capturedPromise), ec);
     734    };
     735
     736    // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
     737    // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey
     738    // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
     739    algorithm->importKey(format, WTFMove(keyData), WTFMove(params), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback));
     740}
     741
     742static void jsSubtleCryptoFunctionExportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
     743{
     744    VM& vm = state.vm();
     745    auto scope = DECLARE_THROW_SCOPE(vm);
     746
     747    if (UNLIKELY(state.argumentCount() < 2)) {
     748        promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
     749        return;
     750    }
     751
     752    auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
     753    RETURN_IF_EXCEPTION(scope, void());
     754
     755    auto key = toCryptoKey(state, state.uncheckedArgument(1));
     756    RETURN_IF_EXCEPTION(scope, void());
     757
     758    supportExportKeyThrow(state, key->algorithmIdentifier());
     759    RETURN_IF_EXCEPTION(scope, void());
    743760
    744761    if (!key->extractable()) {
     
    775792}
    776793
     794static void jsSubtleCryptoFunctionWrapKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
     795{
     796    VM& vm = state.vm();
     797    auto scope = DECLARE_THROW_SCOPE(vm);
     798
     799    if (UNLIKELY(state.argumentCount() < 4)) {
     800        promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
     801        return;
     802    }
     803
     804    auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
     805    RETURN_IF_EXCEPTION(scope, void());
     806
     807    auto key = toCryptoKey(state, state.uncheckedArgument(1));
     808    RETURN_IF_EXCEPTION(scope, void());
     809
     810    auto wrappingKey = toCryptoKey(state, state.uncheckedArgument(2));
     811    RETURN_IF_EXCEPTION(scope, void());
     812
     813    auto catchScope = DECLARE_CATCH_SCOPE(vm);
     814    bool isEncryption = false;
     815    auto wrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::WrapKey);
     816    if (catchScope.exception()) {
     817        catchScope.clearException();
     818        wrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::Encrypt);
     819        RETURN_IF_EXCEPTION(scope, void());
     820        isEncryption = true;
     821    }
     822
     823    if (wrapParams->identifier != wrappingKey->algorithmIdentifier()) {
     824        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Wrapping CryptoKey doesn't match AlgorithmIdentifier"));
     825        return;
     826    }
     827
     828    if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) {
     829        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Wrapping CryptoKey doesn't support wrapKey operation"));
     830        return;
     831    }
     832
     833    supportExportKeyThrow(state, key->algorithmIdentifier());
     834    RETURN_IF_EXCEPTION(scope, void());
     835
     836    if (!key->extractable()) {
     837        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("The CryptoKey is nonextractable"));
     838        return;
     839    }
     840
     841    auto exportAlgorithm = createAlgorithm(state, key->algorithmIdentifier());
     842    RETURN_IF_EXCEPTION(scope, void());
     843
     844    auto wrapAlgorithm = createAlgorithm(state, wrappingKey->algorithmIdentifier());
     845    RETURN_IF_EXCEPTION(scope, void());
     846
     847    auto context = scriptExecutionContextFromExecState(&state);
     848
     849    auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
     850    ASSERT(subtle);
     851    auto& workQueue = subtle->wrapped().workQueue();
     852
     853    auto callback = [promise = promise.copyRef(), wrapAlgorithm, wrappingKey = WTFMove(wrappingKey), wrapParams = WTFMove(wrapParams), isEncryption, context, &workQueue](SubtleCrypto::KeyFormat format, KeyData&& key) mutable {
     854        Vector<uint8_t> bytes;
     855        switch (format) {
     856        case SubtleCrypto::KeyFormat::Spki:
     857        case SubtleCrypto::KeyFormat::Pkcs8:
     858        case SubtleCrypto::KeyFormat::Raw:
     859            bytes = WTF::get<Vector<uint8_t>>(key);
     860            break;
     861        case SubtleCrypto::KeyFormat::Jwk: {
     862            auto jwk = toJSValueFromJsonWebKey(*(promise->globalObject()), WTFMove(WTF::get<JsonWebKey>(key)));
     863            String jwkString = JSONStringify(promise->globalObject()->globalExec(), jwk, 0);
     864            CString jwkUtf8String = jwkString.utf8(StrictConversion);
     865            bytes.append(jwkUtf8String.data(), jwkUtf8String.length());
     866        }
     867        }
     868
     869        auto callback = [promise = promise.copyRef()](const Vector<uint8_t>& wrappedKey) mutable {
     870            fulfillPromiseWithArrayBuffer(WTFMove(promise), wrappedKey.data(), wrappedKey.size());
     871            return;
     872        };
     873        auto exceptionCallback = [promise = WTFMove(promise)](ExceptionCode ec) mutable {
     874            rejectWithException(WTFMove(promise), ec);
     875        };
     876
     877        if (!isEncryption) {
     878            // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
     879            // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey
     880            // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
     881            wrapAlgorithm->wrapKey(wrappingKey.releaseNonNull(), WTFMove(bytes), WTFMove(callback), WTFMove(exceptionCallback));
     882            return;
     883        }
     884        wrapAlgorithm->encrypt(WTFMove(wrapParams), wrappingKey.releaseNonNull(), WTFMove(bytes), WTFMove(callback), WTFMove(exceptionCallback), *context, workQueue);
     885    };
     886    auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
     887        rejectWithException(WTFMove(capturedPromise), ec);
     888    };
     889
     890    exportAlgorithm->exportKey(format, key.releaseNonNull(), WTFMove(callback), WTFMove(exceptionCallback));
     891}
     892
    777893JSValue JSSubtleCrypto::encrypt(ExecState& state)
    778894{
     
    810926}
    811927
     928JSValue JSSubtleCrypto::wrapKey(ExecState& state)
     929{
     930    return callPromiseFunction<jsSubtleCryptoFunctionWrapKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
     931}
     932
    812933} // namespace WebCore
    813934
  • trunk/Source/WebCore/crypto/CryptoAlgorithm.cpp

    r209150 r209155  
    6868}
    6969
     70void CryptoAlgorithm::wrapKey(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&& exceptionCallback)
     71{
     72    exceptionCallback(NOT_SUPPORTED_ERR);
     73}
     74
    7075ExceptionOr<void> CryptoAlgorithm::encrypt(const CryptoAlgorithmParametersDeprecated&, const CryptoKey&, const CryptoOperationData&, VectorCallback&&, VoidCallback&&)
    7176{
  • trunk/Source/WebCore/crypto/CryptoAlgorithm.h

    r209150 r209155  
    7272    virtual void importKey(SubtleCrypto::KeyFormat, KeyData&&, const std::unique_ptr<CryptoAlgorithmParameters>&&, bool extractable, CryptoKeyUsageBitmap, KeyCallback&&, ExceptionCallback&&);
    7373    virtual void exportKey(SubtleCrypto::KeyFormat, Ref<CryptoKey>&&, KeyDataCallback&&, ExceptionCallback&&);
     74    virtual void wrapKey(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&);
    7475
    7576    // The following will be deprecated.
  • trunk/Source/WebCore/crypto/SubtleCrypto.idl

    r209150 r209155  
    4040    [Custom] Promise<CryptoKey> importKey(KeyFormat format, (BufferSource or JsonWebKey) keyData, AlgorithmIdentifier algorithm, boolen extractable, sequence<CryptoKeyUsage> keyUsages);
    4141    [Custom] Promise<any> exportKey(KeyFormat format, CryptoKey key);
     42    [Custom] Promise<any> wrapKey(KeyFormat format, CryptoKey key, CryptoKey wrappingKey, AlgorithmIdentifier wrapAlgorithm);
    4243};
  • trunk/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_KW.cpp

    r209077 r209155  
    159159}
    160160
     161void CryptoAlgorithmAES_KW::wrapKey(Ref<CryptoKey>&& key, Vector<uint8_t>&& data, VectorCallback&& callback, ExceptionCallback&& exceptionCallback)
     162{
     163    if (data.size() % 8) {
     164        exceptionCallback(OperationError);
     165        return;
     166    }
     167    platformWrapKey(WTFMove(key), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback));
     168}
     169
    161170ExceptionOr<void> CryptoAlgorithmAES_KW::encryptForWrapKey(const CryptoAlgorithmParametersDeprecated&, const CryptoKey& key, const CryptoOperationData& data, VectorCallback&& callback, VoidCallback&& failureCallback)
    162171{
  • trunk/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_KW.h

    r209077 r209155  
    4747    void importKey(SubtleCrypto::KeyFormat, KeyData&&, const std::unique_ptr<CryptoAlgorithmParameters>&&, bool extractable, CryptoKeyUsageBitmap, KeyCallback&&, ExceptionCallback&&) final;
    4848    void exportKey(SubtleCrypto::KeyFormat, Ref<CryptoKey>&&, KeyDataCallback&&, ExceptionCallback&&) final;
     49    void wrapKey(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&) final;
    4950
    5051    ExceptionOr<void> encryptForWrapKey(const CryptoAlgorithmParametersDeprecated&, const CryptoKey&, const CryptoOperationData&, VectorCallback&&, VoidCallback&& failureCallback) final;
     
    5455
    5556    bool keyAlgorithmMatches(const CryptoKey&) const;
     57    void platformWrapKey(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&);
    5658    ExceptionOr<void> platformEncrypt(const CryptoKeyAES&, const CryptoOperationData&, VectorCallback&&, VoidCallback&& failureCallback);
    5759    ExceptionOr<void> platformDecrypt(const CryptoKeyAES&, const CryptoOperationData&, VectorCallback&&, VoidCallback&& failureCallback);
  • trunk/Source/WebCore/crypto/gnutls/CryptoAlgorithmAES_KWGnuTLS.cpp

    r208669 r209155  
    3434namespace WebCore {
    3535
     36void CryptoAlgorithmAES_KW::platformWrapKey(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&)
     37{
     38    notImplemented();
     39}
     40
    3641ExceptionOr<void> CryptoAlgorithmAES_KW::platformEncrypt(const CryptoKeyAES&, const CryptoOperationData&, VectorCallback&&, VoidCallback&&)
    3742{
  • trunk/Source/WebCore/crypto/mac/CryptoAlgorithmAES_KWMac.cpp

    r208669 r209155  
    3535namespace WebCore {
    3636
     37// FIXME: We should change data to Vector<uint8_t> type once WebKitSubtleCrypto is deprecated.
     38// https://bugs.webkit.org/show_bug.cgi?id=164939
     39static ExceptionOr<Vector<uint8_t>> wrapKeyAES_KW(const Vector<uint8_t>& key, const uint8_t* data, size_t dataLength)
     40{
     41    Vector<uint8_t> result(CCSymmetricWrappedSize(kCCWRAPAES, dataLength));
     42    size_t resultSize = result.size();
     43    if (CCSymmetricKeyWrap(kCCWRAPAES, CCrfc3394_iv, CCrfc3394_ivLen, key.data(), key.size(), data, dataLength, result.data(), &resultSize))
     44        return Exception { OperationError };
     45
     46    result.shrink(resultSize);
     47    return WTFMove(result);
     48}
     49
     50void CryptoAlgorithmAES_KW::platformWrapKey(Ref<CryptoKey>&& key, Vector<uint8_t>&& data, VectorCallback&& callback, ExceptionCallback&& exceptionCallback)
     51{
     52    auto& aesKey = downcast<CryptoKeyAES>(key.get());
     53    auto result = wrapKeyAES_KW(aesKey.key(), data.data(), data.size());
     54    if (result.hasException()) {
     55        exceptionCallback(result.releaseException().code());
     56        return;
     57    }
     58    callback(result.releaseReturnValue());
     59}
     60
    3761ExceptionOr<void> CryptoAlgorithmAES_KW::platformEncrypt(const CryptoKeyAES& key, const CryptoOperationData& data, VectorCallback&& callback, VoidCallback&& failureCallback)
    3862{
     
    4468    }
    4569
    46     Vector<uint8_t> result(CCSymmetricWrappedSize(kCCWRAPAES, data.second));
    47     size_t resultSize = result.size();
    48     int status = CCSymmetricKeyWrap(kCCWRAPAES, CCrfc3394_iv, CCrfc3394_ivLen, key.key().data(), key.key().size(), data.first, data.second, result.data(), &resultSize);
    49     if (status) {
     70    auto result = wrapKeyAES_KW(key.key(), data.first, data.second);
     71    if (result.hasException()) {
    5072        failureCallback();
    5173        return { };
    5274    }
    53     result.shrink(resultSize);
    54     callback(result);
     75    callback(result.releaseReturnValue());
    5576    return { };
    5677}
Note: See TracChangeset for help on using the changeset viewer.