JSValue JSWebKitSubtleCrypto::verify(ExecState& state)
{
    VM& vm = state.vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    if (state.argumentCount() < 4)
        return throwException(&state, scope, createNotEnoughArgumentsError(&state));

    auto algorithm = createAlgorithmFromJSValue(state, state.uncheckedArgument(0));
    ASSERT(scope.exception() || algorithm);
    if (!algorithm)
        return jsUndefined();

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForVerify(&state, algorithm->identifier(), state.uncheckedArgument(0));
    ASSERT(scope.exception() || parameters);
    if (!parameters)
        return jsUndefined();

    RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(state.uncheckedArgument(1));
    if (!key)
        return throwTypeError(&state, scope);

    if (!key->allows(CryptoKeyUsageVerify)) {
        wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'verify'"));
        setDOMException(&state, NOT_SUPPORTED_ERR);
        return jsUndefined();
    }

    CryptoOperationData signature;
    auto success = cryptoOperationDataFromJSValue(&state, state.uncheckedArgument(2), signature);
    ASSERT(scope.exception() || success);
    if (!success)
        return jsUndefined();

    CryptoOperationData data;
    success = cryptoOperationDataFromJSValue(&state, state.uncheckedArgument(3), data);
    ASSERT(scope.exception() || success);
    if (!success)
        return jsUndefined();

    RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow());
    auto promise = wrapper->promise();
    auto successCallback = [wrapper](bool result) mutable {
        wrapper->resolve(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper->reject(nullptr);
    };

    auto result = algorithm->verify(*parameters, *key, signature, data, WTFMove(successCallback), WTFMove(failureCallback));
    if (result.hasException()) {
        propagateException(state, scope, result.releaseException());
        return { };
    }

    return promise;
}
示例#2
0
JSValue JSSubtleCrypto::verify(ExecState* exec)
{
    if (exec->argumentCount() < 4)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
    if (!algorithm) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForVerify(exec, algorithm->identifier(), exec->uncheckedArgument(0));
    if (!parameters) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(exec->uncheckedArgument(1));
    if (!key)
        return throwTypeError(exec);

    if (!key->allows(CryptoKeyUsageVerify)) {
        m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'verify'"));
        setDOMException(exec, NOT_SUPPORTED_ERR);
        return jsUndefined();
    }

    CryptoOperationData signature;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), signature)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    CryptoOperationData data;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(3), data)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    auto successCallback = [wrapper](bool result) mutable {
        wrapper.resolve(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper.reject(nullptr);
    };

    ExceptionCode ec = 0;
    algorithm->verify(*parameters, *key, signature, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
    if (ec) {
        setDOMException(exec, ec);
        return jsUndefined();
    }

    return promiseDeferred->promise();
}
JSValue JSWebKitSubtleCrypto::digest(ExecState& state)
{
    VM& vm = state.vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    if (state.argumentCount() < 2)
        return throwException(&state, scope, createNotEnoughArgumentsError(&state));

    auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0));
    RETURN_IF_EXCEPTION(scope, { });

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(state, scope, algorithm->identifier(), state.uncheckedArgument(0));
    RETURN_IF_EXCEPTION(scope, { });

    auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(1));
    RETURN_IF_EXCEPTION(scope, { });

    RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow());
    auto promise = wrapper->promise();
    auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
        fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), result.data(), result.size());
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper->reject(); // FIXME: This should reject with an Exception.
    };

    auto result = algorithm->digest(*parameters, data, WTFMove(successCallback), WTFMove(failureCallback));
    if (result.hasException()) {
        propagateException(state, scope, result.releaseException());
        return { };
    }

    return promise;
}
static RefPtr<CryptoAlgorithmParameters> createRsaOaepParams(ExecState* exec, JSValue value)
{
    if (!value.isObject()) {
        throwTypeError(exec);
        return nullptr;
    }

    JSDictionary jsDictionary(exec, value.getObject());
    auto result = adoptRef(*new CryptoAlgorithmRsaOaepParams);

    if (!getHashAlgorithm(jsDictionary, result->hash, HashRequirement::Required)) {
        ASSERT(exec->hadException());
        return nullptr;
    }

    JSValue labelValue = getProperty(exec, value.getObject(), "label");
    if (exec->hadException())
        return nullptr;

    result->hasLabel = !labelValue.isUndefinedOrNull();
    if (!result->hasLabel)
        return WTFMove(result);

    CryptoOperationData labelData;
    if (!cryptoOperationDataFromJSValue(exec, labelValue, labelData)) {
        ASSERT(exec->hadException());
        return nullptr;
    }

    result->label.append(labelData.first, labelData.second);

    return WTFMove(result);
}
static RefPtr<CryptoAlgorithmParameters> createAesCbcParams(ExecState* exec, JSValue value)
{
    if (!value.isObject()) {
        throwTypeError(exec);
        return nullptr;
    }

    JSValue iv = getProperty(exec, value.getObject(), "iv");
    if (exec->hadException())
        return nullptr;

    auto result = adoptRef(*new CryptoAlgorithmAesCbcParams);

    CryptoOperationData ivData;
    if (!cryptoOperationDataFromJSValue(exec, iv, ivData)) {
        ASSERT(exec->hadException());
        return nullptr;
    }

    if (ivData.second != 16) {
        exec->vm().throwException(exec, createError(exec, "AES-CBC initialization data must be 16 bytes"));
        return nullptr;
    }

    memcpy(result->iv.data(), ivData.first, ivData.second);

    return WTFMove(result);
}
JSValue JSWebKitSubtleCrypto::verify(ExecState& state)
{
    VM& vm = state.vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    if (state.argumentCount() < 4)
        return throwException(&state, scope, createNotEnoughArgumentsError(&state));

    auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0));
    RETURN_IF_EXCEPTION(scope, { });

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForVerify(state, scope, algorithm->identifier(), state.uncheckedArgument(0));
    RETURN_IF_EXCEPTION(scope, { });

    RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1));
    if (!key)
        return throwTypeError(&state, scope);

    if (!key->allows(CryptoKeyUsageVerify)) {
        wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'verify'"));
        throwNotSupportedError(state, scope);
        return jsUndefined();
    }

    auto signature = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(2));
    RETURN_IF_EXCEPTION(scope, { });

    auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(3));
    RETURN_IF_EXCEPTION(scope, { });

    RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow());
    auto promise = wrapper->promise();
    auto successCallback = [wrapper](bool result) mutable {
        wrapper->resolve<IDLBoolean>(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper->reject(); // FIXME: This should reject with an Exception.
    };

    auto result = algorithm->verify(*parameters, *key, signature, data, WTFMove(successCallback), WTFMove(failureCallback));
    if (result.hasException()) {
        propagateException(state, scope, result.releaseException());
        return { };
    }

    return promise;
}
JSValue JSWebKitSubtleCrypto::importKey(ExecState& state)
{
    VM& vm = state.vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    if (state.argumentCount() < 3)
        return throwException(&state, scope, createNotEnoughArgumentsError(&state));

    auto keyFormat = cryptoKeyFormatFromJSValue(state, scope, state.uncheckedArgument(0));
    RETURN_IF_EXCEPTION(scope, { });

    auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(1));
    RETURN_IF_EXCEPTION(scope, { });

    RefPtr<CryptoAlgorithm> algorithm;
    RefPtr<CryptoAlgorithmParametersDeprecated> parameters;
    if (!state.uncheckedArgument(2).isNull()) {
        algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(2));
        RETURN_IF_EXCEPTION(scope, { });

        parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(state, scope, algorithm->identifier(), state.uncheckedArgument(2));
        RETURN_IF_EXCEPTION(scope, { });
    }

    bool extractable = state.argument(3).toBoolean(&state);
    RETURN_IF_EXCEPTION(scope, JSValue());

    CryptoKeyUsageBitmap keyUsages = 0;
    if (state.argumentCount() >= 5) {
        keyUsages = cryptoKeyUsagesFromJSValue(state, scope, state.uncheckedArgument(4));
        RETURN_IF_EXCEPTION(scope, { });
    }

    RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow());
    auto promise = wrapper->promise();
    auto successCallback = [wrapper](CryptoKey& result) mutable {
        wrapper->resolve<IDLInterface<CryptoKey>>(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper->reject(); // FIXME: This should reject with an Exception.
    };

    WebCore::importKey(state, keyFormat, data, WTFMove(algorithm), WTFMove(parameters), extractable, keyUsages, WTFMove(successCallback), WTFMove(failureCallback));
    RETURN_IF_EXCEPTION(scope, JSValue());

    return promise;
}
示例#8
0
JSValue JSSubtleCrypto::digest(ExecState* exec)
{
    if (exec->argumentCount() < 2)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
    if (!algorithm) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(exec, algorithm->identifier(), exec->uncheckedArgument(0));
    if (!parameters) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    CryptoOperationData data;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
        wrapper.resolve(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper.reject(nullptr);
    };

    ExceptionCode ec = 0;
    algorithm->digest(*parameters, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
    if (ec) {
        setDOMException(exec, ec);
        return jsUndefined();
    }

    return promiseDeferred->promise();
}
示例#9
0
JSValue JSSubtleCrypto::unwrapKey(ExecState* exec)
{
    if (exec->argumentCount() < 5)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    CryptoKeyFormat keyFormat;
    if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    CryptoOperationData wrappedKeyData;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), wrappedKeyData)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    RefPtr<CryptoKey> unwrappingKey = JSCryptoKey::toWrapped(exec->uncheckedArgument(2));
    if (!unwrappingKey)
        return throwTypeError(exec);

    if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) {
        m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'unwrapKey'"));
        setDOMException(exec, NOT_SUPPORTED_ERR);
        return jsUndefined();
    }

    std::unique_ptr<CryptoAlgorithm> unwrapAlgorithm;
    std::unique_ptr<CryptoAlgorithmParameters> unwrapAlgorithmParameters;
    unwrapAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3));
    if (!unwrapAlgorithm) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }
    unwrapAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(exec, unwrapAlgorithm->identifier(), exec->uncheckedArgument(3));
    if (!unwrapAlgorithmParameters) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    std::unique_ptr<CryptoAlgorithm> unwrappedKeyAlgorithm;
    std::unique_ptr<CryptoAlgorithmParameters> unwrappedKeyAlgorithmParameters;
    if (!exec->uncheckedArgument(4).isNull()) {
        unwrappedKeyAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(4));
        if (!unwrappedKeyAlgorithm) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
        unwrappedKeyAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, unwrappedKeyAlgorithm->identifier(), exec->uncheckedArgument(4));
        if (!unwrappedKeyAlgorithmParameters) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    bool extractable = false;
    if (exec->argumentCount() >= 6) {
        extractable = exec->uncheckedArgument(5).toBoolean(exec);
        if (exec->hadException())
            return jsUndefined();
    }

    CryptoKeyUsage keyUsages = 0;
    if (exec->argumentCount() >= 7) {
        if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(6), keyUsages)) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    Strong<JSDOMGlobalObject> domGlobalObject(exec->vm(), globalObject());

    CryptoAlgorithm* unwrappedKeyAlgorithmPtr = unwrappedKeyAlgorithm.release();
    CryptoAlgorithmParameters* unwrappedKeyAlgorithmParametersPtr = unwrappedKeyAlgorithmParameters.release();

    auto decryptSuccessCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, wrapper](const Vector<uint8_t>& result) mutable {
        auto importSuccessCallback = [wrapper](CryptoKey& key) mutable {
            wrapper.resolve(&key);
        };
        auto importFailureCallback = [wrapper]() mutable {
            wrapper.reject(nullptr);
        };
        ExecState* exec = domGlobalObject->globalExec();
        WebCore::importKey(exec, keyFormat, std::make_pair(result.data(), result.size()), std::unique_ptr<CryptoAlgorithm>(unwrappedKeyAlgorithmPtr), std::unique_ptr<CryptoAlgorithmParameters>(unwrappedKeyAlgorithmParametersPtr), extractable, keyUsages, WTF::move(importSuccessCallback), WTF::move(importFailureCallback));
        if (exec->hadException()) {
            // FIXME: Report exception details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
            exec->clearException();
            importFailureCallback();
        }
    };

    auto decryptFailureCallback = [wrapper, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr]() mutable {
        delete unwrappedKeyAlgorithmPtr;
        delete unwrappedKeyAlgorithmParametersPtr;
        wrapper.reject(nullptr);
    };

    ExceptionCode ec = 0;
    unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, WTF::move(decryptSuccessCallback), WTF::move(decryptFailureCallback), ec);
    if (ec) {
        delete unwrappedKeyAlgorithmPtr;
        delete unwrappedKeyAlgorithmParametersPtr;
        setDOMException(exec, ec);
        return jsUndefined();
    }

    return promiseDeferred->promise();
}
示例#10
0
JSValue JSSubtleCrypto::importKey(ExecState* exec)
{
    if (exec->argumentCount() < 3)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    CryptoKeyFormat keyFormat;
    if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    CryptoOperationData data;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    std::unique_ptr<CryptoAlgorithm> algorithm;
    std::unique_ptr<CryptoAlgorithmParameters> parameters;
    if (!exec->uncheckedArgument(2).isNull()) {
        algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(2));
        if (!algorithm) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
        parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, algorithm->identifier(), exec->uncheckedArgument(2));
        if (!parameters) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    bool extractable = false;
    if (exec->argumentCount() >= 4) {
        extractable = exec->uncheckedArgument(3).toBoolean(exec);
        if (exec->hadException())
            return jsUndefined();
    }

    CryptoKeyUsage keyUsages = 0;
    if (exec->argumentCount() >= 5) {
        if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(4), keyUsages)) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    auto successCallback = [wrapper](CryptoKey& result) mutable {
        wrapper.resolve(&result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper.reject(nullptr);
    };

    WebCore::importKey(exec, keyFormat, data, WTF::move(algorithm), WTF::move(parameters), extractable, keyUsages, WTF::move(successCallback), WTF::move(failureCallback));
    if (exec->hadException())
        return jsUndefined();

    return promiseDeferred->promise();
}
JSValue JSWebKitSubtleCrypto::unwrapKey(ExecState& state)
{
    VM& vm = state.vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    if (state.argumentCount() < 5)
        return throwException(&state, scope, createNotEnoughArgumentsError(&state));

    auto keyFormat = cryptoKeyFormatFromJSValue(state, scope, state.uncheckedArgument(0));
    RETURN_IF_EXCEPTION(scope, { });

    auto wrappedKeyData = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(1));
    RETURN_IF_EXCEPTION(scope, { });

    RefPtr<CryptoKey> unwrappingKey = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(2));
    if (!unwrappingKey)
        return throwTypeError(&state, scope);

    if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) {
        wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'unwrapKey'"));
        throwNotSupportedError(state, scope);
        return jsUndefined();
    }

    auto unwrapAlgorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(3));
    RETURN_IF_EXCEPTION(scope, { });

    auto unwrapAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(state, scope, unwrapAlgorithm->identifier(), state.uncheckedArgument(3));
    RETURN_IF_EXCEPTION(scope, { });

    RefPtr<CryptoAlgorithm> unwrappedKeyAlgorithm;
    RefPtr<CryptoAlgorithmParametersDeprecated> unwrappedKeyAlgorithmParameters;
    if (!state.uncheckedArgument(4).isNull()) {
        unwrappedKeyAlgorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(4));
        RETURN_IF_EXCEPTION(scope, { });

        unwrappedKeyAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(state, scope, unwrappedKeyAlgorithm->identifier(), state.uncheckedArgument(4));
        RETURN_IF_EXCEPTION(scope, { });
    }

    bool extractable = state.argument(5).toBoolean(&state);
    RETURN_IF_EXCEPTION(scope, { });

    CryptoKeyUsageBitmap keyUsages = 0;
    if (state.argumentCount() >= 7) {
        keyUsages = cryptoKeyUsagesFromJSValue(state, scope, state.uncheckedArgument(6));
        RETURN_IF_EXCEPTION(scope, { });
    }

    RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow());
    auto promise = wrapper->promise();
    Strong<JSDOMGlobalObject> domGlobalObject(state.vm(), globalObject());

    auto decryptSuccessCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithm, unwrappedKeyAlgorithmParameters, extractable, keyUsages, wrapper](const Vector<uint8_t>& result) mutable {
        auto importSuccessCallback = [wrapper](CryptoKey& key) mutable {
            wrapper->resolve<IDLInterface<CryptoKey>>(key);
        };
        auto importFailureCallback = [wrapper]() mutable {
            wrapper->reject(); // FIXME: This should reject with an Exception.
        };

        VM& vm = domGlobalObject->vm();
        auto scope = DECLARE_CATCH_SCOPE(vm);

        ExecState& state = *domGlobalObject->globalExec();
        WebCore::importKey(state, keyFormat, std::make_pair(result.data(), result.size()), unwrappedKeyAlgorithm, unwrappedKeyAlgorithmParameters, extractable, keyUsages, WTFMove(importSuccessCallback), WTFMove(importFailureCallback));
        if (UNLIKELY(scope.exception())) {
            // FIXME: Report exception details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
            scope.clearException();
            wrapper->reject(); // FIXME: This should reject with an Exception.
        }
    };

    auto decryptFailureCallback = [wrapper]() mutable {
        wrapper->reject(); // FIXME: This should reject with an Exception.
    };

    auto result = unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, WTFMove(decryptSuccessCallback), WTFMove(decryptFailureCallback));
    if (result.hasException()) {
        propagateException(state, scope, result.releaseException());
        return { };
    }

    return promise;
}
JSValue JSWebKitSubtleCrypto::importKey(ExecState& state)
{
    VM& vm = state.vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    if (state.argumentCount() < 3)
        return throwException(&state, scope, createNotEnoughArgumentsError(&state));

    CryptoKeyFormat keyFormat;
    auto success = cryptoKeyFormatFromJSValue(state, state.argument(0), keyFormat);
    ASSERT(scope.exception() || success);
    if (!success)
        return jsUndefined();

    CryptoOperationData data;
    success = cryptoOperationDataFromJSValue(&state, state.uncheckedArgument(1), data);
    ASSERT(scope.exception() || success);
    if (!success)
        return jsUndefined();

    RefPtr<CryptoAlgorithm> algorithm;
    RefPtr<CryptoAlgorithmParametersDeprecated> parameters;
    if (!state.uncheckedArgument(2).isNull()) {
        algorithm = createAlgorithmFromJSValue(state, state.uncheckedArgument(2));
        ASSERT(scope.exception() || algorithm);
        if (!algorithm)
            return jsUndefined();

        parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(&state, algorithm->identifier(), state.uncheckedArgument(2));
        ASSERT(scope.exception() || parameters);
        if (!parameters)
            return jsUndefined();
    }

    bool extractable = false;
    if (state.argumentCount() >= 4) {
        extractable = state.uncheckedArgument(3).toBoolean(&state);
        RETURN_IF_EXCEPTION(scope, JSValue());
    }

    CryptoKeyUsageBitmap keyUsages = 0;
    if (state.argumentCount() >= 5) {
        auto success = cryptoKeyUsagesFromJSValue(state, state.argument(4), keyUsages);
        ASSERT(scope.exception() || success);
        if (!success)
            return jsUndefined();
    }

    RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow());
    auto promise = wrapper->promise();
    auto successCallback = [wrapper](CryptoKey& result) mutable {
        wrapper->resolve(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper->reject(nullptr);
    };

    WebCore::importKey(state, keyFormat, data, WTFMove(algorithm), WTFMove(parameters), extractable, keyUsages, WTFMove(successCallback), WTFMove(failureCallback));
    RETURN_IF_EXCEPTION(scope, JSValue());

    return promise;
}