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; }
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::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; }
JSValue JSWebKitSubtleCrypto::wrapKey(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (state.argumentCount() < 4) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto keyFormat = cryptoKeyFormatFromJSValue(state, scope, state.uncheckedArgument(0)); RETURN_IF_EXCEPTION(scope, { }); RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1)); if (!key) return throwTypeError(&state, scope); RefPtr<CryptoKey> wrappingKey = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(2)); if (!key) return throwTypeError(&state, scope); if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) { wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'wrapKey'")); throwNotSupportedError(state, scope); return jsUndefined(); } auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(3)); RETURN_IF_EXCEPTION(scope, { }); auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(state, scope, algorithm->identifier(), state.uncheckedArgument(3)); RETURN_IF_EXCEPTION(scope, { }); RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); auto promise = wrapper->promise(); auto exportSuccessCallback = [keyFormat, algorithm, parameters, wrappingKey, wrapper](const Vector<uint8_t>& exportedKeyData) mutable { auto encryptSuccessCallback = [wrapper](const Vector<uint8_t>& encryptedData) mutable { fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), encryptedData.data(), encryptedData.size()); }; auto encryptFailureCallback = [wrapper]() mutable { wrapper->reject(); // FIXME: This should reject with an Exception. }; auto result = algorithm->encryptForWrapKey(*parameters, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), WTFMove(encryptSuccessCallback), WTFMove(encryptFailureCallback)); if (result.hasException()) { // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions. wrapper->reject(); // FIXME: This should reject with an Exception. } }; auto exportFailureCallback = [wrapper]() mutable { wrapper->reject(); // FIXME: This should reject with an Exception. }; WebCore::exportKey(state, keyFormat, *key, WTFMove(exportSuccessCallback), WTFMove(exportFailureCallback)); return promise; }
JSValue JSSubtleCrypto::generateKey(ExecState* exec) { if (exec->argumentCount() < 1) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0)); if (!algorithm) { ASSERT(exec->hadException()); return jsUndefined(); } auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(exec, algorithm->identifier(), exec->uncheckedArgument(0)); if (!parameters) { ASSERT(exec->hadException()); return jsUndefined(); } bool extractable = false; if (exec->argumentCount() >= 2) { extractable = exec->uncheckedArgument(1).toBoolean(exec); if (exec->hadException()) return jsUndefined(); } CryptoKeyUsage keyUsages = 0; if (exec->argumentCount() >= 3) { if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(2), keyUsages)) { ASSERT(exec->hadException()); return jsUndefined(); } } JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); auto successCallback = [wrapper](CryptoKey* key, CryptoKeyPair* keyPair) mutable { ASSERT(key || keyPair); ASSERT(!key || !keyPair); if (key) wrapper.resolve(key); else wrapper.resolve(keyPair); }; auto failureCallback = [wrapper]() mutable { wrapper.reject(nullptr); }; ExceptionCode ec = 0; algorithm->generateKey(*parameters, extractable, keyUsages, WTF::move(successCallback), WTF::move(failureCallback), ec); if (ec) { setDOMException(exec, ec); return jsUndefined(); } return promiseDeferred->promise(); }
JSValue JSWebKitSubtleCrypto::generateKey(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (state.argumentCount() < 1) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto algorithm = createAlgorithmFromJSValue(state, state.uncheckedArgument(0)); ASSERT(scope.exception() || algorithm); if (!algorithm) return jsUndefined(); auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(&state, algorithm->identifier(), state.uncheckedArgument(0)); ASSERT(scope.exception() || parameters); if (!parameters) return jsUndefined(); bool extractable = false; if (state.argumentCount() >= 2) { extractable = state.uncheckedArgument(1).toBoolean(&state); RETURN_IF_EXCEPTION(scope, JSValue()); } CryptoKeyUsageBitmap keyUsages = 0; if (state.argumentCount() >= 3) { auto success = cryptoKeyUsagesFromJSValue(state, state.argument(2), keyUsages); ASSERT(scope.exception() || success); if (!success) return jsUndefined(); } RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); auto promise = wrapper->promise(); auto successCallback = [wrapper](CryptoKey* key, CryptoKeyPair* keyPair) mutable { ASSERT(key || keyPair); ASSERT(!key || !keyPair); if (key) wrapper->resolve(key); else wrapper->resolve(keyPair); }; auto failureCallback = [wrapper]() mutable { wrapper->reject(nullptr); }; auto result = algorithm->generateKey(*parameters, extractable, keyUsages, WTFMove(successCallback), WTFMove(failureCallback), *scriptExecutionContextFromExecState(&state)); 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; }
JSValue JSWebKitSubtleCrypto::generateKey(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (state.argumentCount() < 1) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); RETURN_IF_EXCEPTION(scope, { }); auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); RETURN_IF_EXCEPTION(scope, { }); bool extractable = state.argument(1).toBoolean(&state); RETURN_IF_EXCEPTION(scope, { }); CryptoKeyUsageBitmap keyUsages = 0; if (state.argumentCount() >= 3) { keyUsages = cryptoKeyUsagesFromJSValue(state, scope, state.uncheckedArgument(2)); RETURN_IF_EXCEPTION(scope, { }); } RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); auto promise = wrapper->promise(); auto successCallback = [wrapper](KeyOrKeyPair&& keyOrKeyPair) mutable { WTF::switchOn(keyOrKeyPair, [&wrapper] (RefPtr<CryptoKey>& key) { wrapper->resolve<IDLInterface<CryptoKey>>(*key); }, [&wrapper] (CryptoKeyPair& keyPair) { wrapper->resolve<IDLDictionary<CryptoKeyPair>>(keyPair); } ); }; auto failureCallback = [wrapper]() mutable { wrapper->reject(); // FIXME: This should reject with an Exception. }; auto result = algorithm->generateKey(*parameters, extractable, keyUsages, WTFMove(successCallback), WTFMove(failureCallback), *scriptExecutionContextFromExecState(&state)); if (result.hasException()) { propagateException(state, scope, result.releaseException()); return { }; } return promise; }
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 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(); }
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(); }
JSValue JSSubtleCrypto::wrapKey(ExecState* exec) { if (exec->argumentCount() < 4) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); CryptoKeyFormat keyFormat; if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) { ASSERT(exec->hadException()); return jsUndefined(); } RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(exec->uncheckedArgument(1)); if (!key) return throwTypeError(exec); RefPtr<CryptoKey> wrappingKey = JSCryptoKey::toWrapped(exec->uncheckedArgument(2)); if (!key) return throwTypeError(exec); if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) { m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'wrapKey'")); setDOMException(exec, NOT_SUPPORTED_ERR); return jsUndefined(); } auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3)); if (!algorithm) { ASSERT(exec->hadException()); return jsUndefined(); } auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(exec, algorithm->identifier(), exec->uncheckedArgument(3)); if (!parameters) { ASSERT(exec->hadException()); return jsUndefined(); } JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); CryptoAlgorithm* algorithmPtr = algorithm.release(); CryptoAlgorithmParameters* parametersPtr = parameters.release(); auto exportSuccessCallback = [keyFormat, algorithmPtr, parametersPtr, wrappingKey, wrapper](const Vector<uint8_t>& exportedKeyData) mutable { auto encryptSuccessCallback = [wrapper, algorithmPtr, parametersPtr](const Vector<uint8_t>& encryptedData) mutable { delete algorithmPtr; delete parametersPtr; wrapper.resolve(encryptedData); }; auto encryptFailureCallback = [wrapper, algorithmPtr, parametersPtr]() mutable { delete algorithmPtr; delete parametersPtr; wrapper.reject(nullptr); }; ExceptionCode ec = 0; algorithmPtr->encryptForWrapKey(*parametersPtr, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), WTF::move(encryptSuccessCallback), WTF::move(encryptFailureCallback), ec); if (ec) { // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions. encryptFailureCallback(); } }; auto exportFailureCallback = [wrapper, algorithmPtr, parametersPtr]() mutable { delete algorithmPtr; delete parametersPtr; wrapper.reject(nullptr); }; ExceptionCode ec = 0; WebCore::exportKey(exec, keyFormat, *key, WTF::move(exportSuccessCallback), WTF::move(exportFailureCallback)); if (ec) { delete algorithmPtr; delete parametersPtr; setDOMException(exec, ec); return jsUndefined(); } return promiseDeferred->promise(); }
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; }