2 * Copyright (C) 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "JSSubtleCrypto.h"
29 #if ENABLE(SUBTLE_CRYPTO)
31 #include "CryptoAlgorithm.h"
32 #include "CryptoAlgorithmRegistry.h"
33 #include "JSAesCbcParams.h"
34 #include "JSAesKeyGenParams.h"
35 #include "JSCryptoAlgorithmParameters.h"
36 #include "JSCryptoKey.h"
37 #include "JSCryptoKeyPair.h"
38 #include "JSDOMPromise.h"
39 #include "JSHmacKeyParams.h"
40 #include "JSJsonWebKey.h"
41 #include "JSRsaHashedImportParams.h"
42 #include "JSRsaHashedKeyGenParams.h"
43 #include "JSRsaKeyGenParams.h"
44 #include "JSRsaOaepParams.h"
45 #include "ScriptState.h"
46 #include <runtime/Error.h>
47 #include <runtime/IteratorOperations.h>
48 #include <runtime/JSArray.h>
54 enum class Operations {
61 static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParameters(ExecState&, JSValue, Operations);
63 static CryptoAlgorithmIdentifier toHashIdentifier(ExecState& state, JSValue value)
66 auto scope = DECLARE_THROW_SCOPE(vm);
68 auto digestParams = normalizeCryptoAlgorithmParameters(state, value, Operations::Digest);
69 RETURN_IF_EXCEPTION(scope, { });
70 return digestParams->identifier;
73 static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParameters(ExecState& state, JSValue value, Operations operation)
76 auto scope = DECLARE_THROW_SCOPE(vm);
78 if (value.isString()) {
79 JSObject* newParams = constructEmptyObject(&state);
80 newParams->putDirect(vm, Identifier::fromString(&vm, "name"), value);
81 return normalizeCryptoAlgorithmParameters(state, newParams, operation);
84 if (value.isObject()) {
85 auto params = convertDictionary<CryptoAlgorithmParameters>(state, value);
86 RETURN_IF_EXCEPTION(scope, nullptr);
88 auto identifier = CryptoAlgorithmRegistry::singleton().identifier(params.name);
90 setDOMException(&state, NOT_SUPPORTED_ERR);
94 std::unique_ptr<CryptoAlgorithmParameters> result;
96 case Operations::Encrypt:
97 switch (*identifier) {
98 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
99 result = std::make_unique<CryptoAlgorithmParameters>(params);
101 case CryptoAlgorithmIdentifier::RSA_OAEP: {
102 auto params = convertDictionary<CryptoAlgorithmRsaOaepParams>(state, value);
103 RETURN_IF_EXCEPTION(scope, nullptr);
104 result = std::make_unique<CryptoAlgorithmRsaOaepParams>(params);
107 case CryptoAlgorithmIdentifier::AES_CBC: {
108 auto params = convertDictionary<CryptoAlgorithmAesCbcParams>(state, value);
109 RETURN_IF_EXCEPTION(scope, nullptr);
110 result = std::make_unique<CryptoAlgorithmAesCbcParams>(params);
114 setDOMException(&state, NOT_SUPPORTED_ERR);
118 case Operations::Digest:
119 switch (*identifier) {
120 case CryptoAlgorithmIdentifier::SHA_1:
121 case CryptoAlgorithmIdentifier::SHA_224:
122 case CryptoAlgorithmIdentifier::SHA_256:
123 case CryptoAlgorithmIdentifier::SHA_384:
124 case CryptoAlgorithmIdentifier::SHA_512:
125 result = std::make_unique<CryptoAlgorithmParameters>(params);
128 setDOMException(&state, NOT_SUPPORTED_ERR);
132 case Operations::GenerateKey:
133 switch (*identifier) {
134 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: {
135 auto params = convertDictionary<CryptoAlgorithmRsaKeyGenParams>(state, value);
136 RETURN_IF_EXCEPTION(scope, nullptr);
137 result = std::make_unique<CryptoAlgorithmRsaKeyGenParams>(params);
140 case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
141 case CryptoAlgorithmIdentifier::RSA_PSS:
142 case CryptoAlgorithmIdentifier::RSA_OAEP: {
143 auto params = convertDictionary<CryptoAlgorithmRsaHashedKeyGenParams>(state, value);
144 RETURN_IF_EXCEPTION(scope, nullptr);
145 params.hashIdentifier = toHashIdentifier(state, params.hash);
146 RETURN_IF_EXCEPTION(scope, nullptr);
147 result = std::make_unique<CryptoAlgorithmRsaHashedKeyGenParams>(params);
150 case CryptoAlgorithmIdentifier::AES_CTR:
151 case CryptoAlgorithmIdentifier::AES_CBC:
152 case CryptoAlgorithmIdentifier::AES_CMAC:
153 case CryptoAlgorithmIdentifier::AES_GCM:
154 case CryptoAlgorithmIdentifier::AES_CFB:
155 case CryptoAlgorithmIdentifier::AES_KW: {
156 auto params = convertDictionary<CryptoAlgorithmAesKeyGenParams>(state, value);
157 RETURN_IF_EXCEPTION(scope, nullptr);
158 result = std::make_unique<CryptoAlgorithmAesKeyGenParams>(params);
161 case CryptoAlgorithmIdentifier::HMAC: {
162 auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value);
163 RETURN_IF_EXCEPTION(scope, nullptr);
164 params.hashIdentifier = toHashIdentifier(state, params.hash);
165 RETURN_IF_EXCEPTION(scope, nullptr);
166 result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
170 setDOMException(&state, NOT_SUPPORTED_ERR);
174 case Operations::ImportKey:
175 switch (*identifier) {
176 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
177 result = std::make_unique<CryptoAlgorithmParameters>(params);
179 case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
180 case CryptoAlgorithmIdentifier::RSA_PSS:
181 case CryptoAlgorithmIdentifier::RSA_OAEP: {
182 auto params = convertDictionary<CryptoAlgorithmRsaHashedImportParams>(state, value);
183 RETURN_IF_EXCEPTION(scope, nullptr);
184 params.hashIdentifier = toHashIdentifier(state, params.hash);
185 RETURN_IF_EXCEPTION(scope, nullptr);
186 result = std::make_unique<CryptoAlgorithmRsaHashedImportParams>(params);
189 case CryptoAlgorithmIdentifier::AES_CTR:
190 case CryptoAlgorithmIdentifier::AES_CBC:
191 case CryptoAlgorithmIdentifier::AES_CMAC:
192 case CryptoAlgorithmIdentifier::AES_GCM:
193 case CryptoAlgorithmIdentifier::AES_CFB:
194 case CryptoAlgorithmIdentifier::AES_KW:
195 result = std::make_unique<CryptoAlgorithmParameters>(params);
197 case CryptoAlgorithmIdentifier::HMAC: {
198 auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value);
199 RETURN_IF_EXCEPTION(scope, nullptr);
200 params.hashIdentifier = toHashIdentifier(state, params.hash);
201 RETURN_IF_EXCEPTION(scope, nullptr);
202 result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
206 setDOMException(&state, NOT_SUPPORTED_ERR);
211 ASSERT_NOT_REACHED();
215 result->identifier = *identifier;
219 throwTypeError(&state, scope, ASCIILiteral("Invalid AlgorithmIdentifier"));
223 static CryptoKeyUsageBitmap toCryptoKeyUsageBitmap(CryptoKeyUsage usage)
226 case CryptoKeyUsage::Encrypt:
227 return CryptoKeyUsageEncrypt;
228 case CryptoKeyUsage::Decrypt:
229 return CryptoKeyUsageDecrypt;
230 case CryptoKeyUsage::Sign:
231 return CryptoKeyUsageSign;
232 case CryptoKeyUsage::Verify:
233 return CryptoKeyUsageVerify;
234 case CryptoKeyUsage::DeriveKey:
235 return CryptoKeyUsageDeriveKey;
236 case CryptoKeyUsage::DeriveBits:
237 return CryptoKeyUsageDeriveBits;
238 case CryptoKeyUsage::WrapKey:
239 return CryptoKeyUsageWrapKey;
240 case CryptoKeyUsage::UnwrapKey:
241 return CryptoKeyUsageUnwrapKey;
244 ASSERT_NOT_REACHED();
248 static CryptoKeyUsageBitmap cryptoKeyUsageBitmapFromJSValue(ExecState& state, JSValue value)
251 auto scope = DECLARE_THROW_SCOPE(vm);
253 CryptoKeyUsageBitmap result = 0;
254 auto usages = convert<IDLSequence<IDLEnumeration<CryptoKeyUsage>>>(state, value);
255 RETURN_IF_EXCEPTION(scope, 0);
256 // Maybe we shouldn't silently bypass duplicated usages?
257 for (auto usage : usages)
258 result |= toCryptoKeyUsageBitmap(usage);
263 static RefPtr<CryptoAlgorithm> createAlgorithm(ExecState& state, CryptoAlgorithmIdentifier identifier)
265 auto result = CryptoAlgorithmRegistry::singleton().create(identifier);
267 setDOMException(&state, NOT_SUPPORTED_ERR);
271 // Maybe we want more specific error messages?
272 static void rejectWithException(Ref<DeferredPromise>&& passedPromise, ExceptionCode ec)
275 case NOT_SUPPORTED_ERR:
276 passedPromise->reject(ec, ASCIILiteral("The algorithm is not supported"));
279 passedPromise->reject(ec, ASCIILiteral("A required parameter was missing or out-of-range"));
281 case INVALID_STATE_ERR:
282 passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the current state of the provided key"));
284 case INVALID_ACCESS_ERR:
285 passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the provided key"));
288 passedPromise->reject(ec, ASCIILiteral("The operation failed for an unknown transient reason (e.g. out of memory)"));
291 passedPromise->reject(ec, ASCIILiteral("Data provided to an operation does not meet requirements"));
294 passedPromise->reject(ec, ASCIILiteral("The operation failed for an operation-specific reason"));
297 ASSERT_NOT_REACHED();
300 static KeyData toKeyData(ExecState& state, SubtleCrypto::KeyFormat format, JSValue value)
303 auto scope = DECLARE_THROW_SCOPE(vm);
307 case SubtleCrypto::KeyFormat::Spki:
308 case SubtleCrypto::KeyFormat::Pkcs8:
309 setDOMException(&state, NOT_SUPPORTED_ERR);
311 case SubtleCrypto::KeyFormat::Raw: {
312 BufferSource bufferSource = convert<IDLBufferSource>(state, value);
313 RETURN_IF_EXCEPTION(scope, result);
314 Vector<uint8_t> vector;
315 vector.append(bufferSource.data(), bufferSource.length());
316 result = WTFMove(vector);
319 case SubtleCrypto::KeyFormat::Jwk: {
320 result = convertDictionary<JsonWebKey>(state, value);
321 RETURN_IF_EXCEPTION(scope, result);
322 CryptoKeyUsageBitmap usages = 0;
323 if (WTF::get<JsonWebKey>(result).key_ops) {
324 // Maybe we shouldn't silently bypass duplicated usages?
325 for (auto usage : WTF::get<JsonWebKey>(result).key_ops.value())
326 usages |= toCryptoKeyUsageBitmap(usage);
328 WTF::get<JsonWebKey>(result).usages = usages;
332 ASSERT_NOT_REACHED();
336 // FIXME: We should get rid of this once https://bugs.webkit.org/show_bug.cgi?id=163711 is fixed.
337 static JSValue toJSValueFromJsonWebKey(JSDOMGlobalObject& globalObject, JsonWebKey&& key)
339 ExecState& state = *globalObject.globalExec();
342 auto* result = constructEmptyObject(&state);
343 result->putDirect(vm, Identifier::fromString(&vm, "kty"), toJS<IDLDOMString>(state, key.kty));
345 result->putDirect(vm, Identifier::fromString(&vm, "use"), toJS<IDLDOMString>(state, key.use.value()));
347 result->putDirect(vm, Identifier::fromString(&vm, "key_ops"), toJS<IDLSequence<IDLEnumeration<CryptoKeyUsage>>>(state, globalObject, key.key_ops.value()));
349 result->putDirect(vm, Identifier::fromString(&vm, "alg"), toJS<IDLDOMString>(state, key.alg.value()));
351 result->putDirect(vm, Identifier::fromString(&vm, "ext"), toJS<IDLBoolean>(state, key.ext.value()));
353 result->putDirect(vm, Identifier::fromString(&vm, "crv"), toJS<IDLDOMString>(state, key.crv.value()));
355 result->putDirect(vm, Identifier::fromString(&vm, "x"), toJS<IDLDOMString>(state, key.x.value()));
357 result->putDirect(vm, Identifier::fromString(&vm, "y"), toJS<IDLDOMString>(state, key.y.value()));
359 result->putDirect(vm, Identifier::fromString(&vm, "d"), toJS<IDLDOMString>(state, key.d.value()));
361 result->putDirect(vm, Identifier::fromString(&vm, "n"), toJS<IDLDOMString>(state, key.n.value()));
363 result->putDirect(vm, Identifier::fromString(&vm, "e"), toJS<IDLDOMString>(state, key.e.value()));
365 result->putDirect(vm, Identifier::fromString(&vm, "p"), toJS<IDLDOMString>(state, key.p.value()));
367 result->putDirect(vm, Identifier::fromString(&vm, "q"), toJS<IDLDOMString>(state, key.q.value()));
369 result->putDirect(vm, Identifier::fromString(&vm, "dp"), toJS<IDLDOMString>(state, key.dp.value()));
371 result->putDirect(vm, Identifier::fromString(&vm, "dq"), toJS<IDLDOMString>(state, key.dq.value()));
373 result->putDirect(vm, Identifier::fromString(&vm, "qi"), toJS<IDLDOMString>(state, key.qi.value()));
375 MarkedArgumentBuffer list;
376 for (auto& value : key.oth.value()) {
377 auto* info = constructEmptyObject(&state);
378 info->putDirect(vm, Identifier::fromString(&vm, "r"), toJS<IDLDOMString>(state, value.r));
379 info->putDirect(vm, Identifier::fromString(&vm, "d"), toJS<IDLDOMString>(state, value.d));
380 info->putDirect(vm, Identifier::fromString(&vm, "t"), toJS<IDLDOMString>(state, value.t));
383 result->putDirect(vm, Identifier::fromString(&vm, "oth"), constructArray(&state, static_cast<Structure*>(nullptr), list));
386 result->putDirect(vm, Identifier::fromString(&vm, "k"), toJS<IDLDOMString>(state, key.k.value()));
391 static void jsSubtleCryptoFunctionEncryptPromise(ExecState& state, Ref<DeferredPromise>&& promise)
394 auto scope = DECLARE_THROW_SCOPE(vm);
396 if (UNLIKELY(state.argumentCount() < 3)) {
397 promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
401 auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Encrypt);
402 RETURN_IF_EXCEPTION(scope, void());
404 RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(state.uncheckedArgument(1));
406 promise->reject(TypeError, ASCIILiteral("Invalid CryptoKey"));
410 BufferSource data = convert<IDLBufferSource>(state, state.uncheckedArgument(2));
411 RETURN_IF_EXCEPTION(scope, void());
412 Vector<uint8_t> dataVector;
413 dataVector.append(data.data(), data.length());
415 if (params->identifier != key->algorithmIdentifier()) {
416 promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
420 if (!key->allows(CryptoKeyUsageEncrypt)) {
421 promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support encryption"));
425 auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
426 RETURN_IF_EXCEPTION(scope, void());
428 auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& cipherText) mutable {
429 fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), cipherText.data(), cipherText.size());
432 auto exceptionCallback = [capturedPromise = promise.copyRef()](ExceptionCode ec) mutable {
433 rejectWithException(WTFMove(capturedPromise), ec);
436 JSSubtleCrypto* subtle = jsDynamicDowncast<JSSubtleCrypto*>(state.thisValue());
438 algorithm->encrypt(WTFMove(params), key.releaseNonNull(), WTFMove(dataVector), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
441 static void jsSubtleCryptoFunctionGenerateKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
444 auto scope = DECLARE_THROW_SCOPE(vm);
446 if (UNLIKELY(state.argumentCount() < 3)) {
447 promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
451 auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::GenerateKey);
452 RETURN_IF_EXCEPTION(scope, void());
454 auto extractable = state.uncheckedArgument(1).toBoolean(&state);
455 RETURN_IF_EXCEPTION(scope, void());
457 auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(2));
458 RETURN_IF_EXCEPTION(scope, void());
460 auto algorithm = createAlgorithm(state, params->identifier);
461 RETURN_IF_EXCEPTION(scope, void());
463 auto callback = [capturedPromise = promise.copyRef()](CryptoKey* key, CryptoKeyPair* keyPair) mutable {
464 ASSERT(key || keyPair);
465 ASSERT(!key || !keyPair);
467 if ((key->type() == CryptoKeyType::Private || key->type() == CryptoKeyType::Secret) && !key->usagesBitmap()) {
468 rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
471 capturedPromise->resolve(key);
473 if (!keyPair->privateKey()->usagesBitmap()) {
474 rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
477 capturedPromise->resolve(keyPair);
480 auto exceptionCallback = [capturedPromise = promise.copyRef()](ExceptionCode ec) mutable {
481 rejectWithException(WTFMove(capturedPromise), ec);
484 // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously
485 // regardless what kind of keys it produces: https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey
486 // That's simply not efficient for AES and HMAC keys. Therefore, we perform it as an async task conditionally.
487 algorithm->generateKey(WTFMove(params), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state));
490 static void jsSubtleCryptoFunctionImportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
493 auto scope = DECLARE_THROW_SCOPE(vm);
495 if (UNLIKELY(state.argumentCount() < 5)) {
496 promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
500 auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
501 RETURN_IF_EXCEPTION(scope, void());
503 auto keyData = toKeyData(state, format, state.uncheckedArgument(1));
504 RETURN_IF_EXCEPTION(scope, void());
506 auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(2), Operations::ImportKey);
507 RETURN_IF_EXCEPTION(scope, void());
509 auto extractable = state.uncheckedArgument(3).toBoolean(&state);
510 RETURN_IF_EXCEPTION(scope, void());
512 auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(4));
513 RETURN_IF_EXCEPTION(scope, void());
515 auto algorithm = createAlgorithm(state, params->identifier);
516 RETURN_IF_EXCEPTION(scope, void());
518 auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable {
519 if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
520 rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
523 capturedPromise->resolve(key);
525 auto exceptionCallback = [capturedPromise = promise.copyRef()](ExceptionCode ec) mutable {
526 rejectWithException(WTFMove(capturedPromise), ec);
529 // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
530 // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey
531 // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
532 algorithm->importKey(format, WTFMove(keyData), WTFMove(params), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback));
535 static void jsSubtleCryptoFunctionExportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
538 auto scope = DECLARE_THROW_SCOPE(vm);
540 if (UNLIKELY(state.argumentCount() < 2)) {
541 promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
545 auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
546 RETURN_IF_EXCEPTION(scope, void());
548 RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(state.uncheckedArgument(1));
550 promise->reject(TypeError, ASCIILiteral("Invalid CryptoKey"));
554 switch (key->algorithmIdentifier()) {
555 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
556 case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
557 case CryptoAlgorithmIdentifier::RSA_PSS:
558 case CryptoAlgorithmIdentifier::RSA_OAEP:
559 case CryptoAlgorithmIdentifier::AES_CTR:
560 case CryptoAlgorithmIdentifier::AES_CBC:
561 case CryptoAlgorithmIdentifier::AES_CMAC:
562 case CryptoAlgorithmIdentifier::AES_GCM:
563 case CryptoAlgorithmIdentifier::AES_CFB:
564 case CryptoAlgorithmIdentifier::AES_KW:
565 case CryptoAlgorithmIdentifier::HMAC:
568 promise->reject(NOT_SUPPORTED_ERR, ASCIILiteral("The operation is not supported"));
572 if (!key->extractable()) {
573 promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("The CryptoKey is nonextractable"));
577 auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
578 RETURN_IF_EXCEPTION(scope, void());
580 auto callback = [capturedPromise = promise.copyRef()](SubtleCrypto::KeyFormat format, KeyData&& key) mutable {
582 case SubtleCrypto::KeyFormat::Spki:
583 case SubtleCrypto::KeyFormat::Pkcs8:
584 case SubtleCrypto::KeyFormat::Raw: {
585 Vector<uint8_t>& rawKey = WTF::get<Vector<uint8_t>>(key);
586 fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), rawKey.data(), rawKey.size());
589 case SubtleCrypto::KeyFormat::Jwk:
590 capturedPromise->resolve(toJSValueFromJsonWebKey(*(capturedPromise->globalObject()), WTFMove(WTF::get<JsonWebKey>(key))));
593 ASSERT_NOT_REACHED();
595 auto exceptionCallback = [capturedPromise = promise.copyRef()](ExceptionCode ec) mutable {
596 rejectWithException(WTFMove(capturedPromise), ec);
599 // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
600 // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey
601 // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
602 algorithm->exportKey(format, key.releaseNonNull(), WTFMove(callback), WTFMove(exceptionCallback));
605 JSValue JSSubtleCrypto::encrypt(ExecState& state)
607 return callPromiseFunction<jsSubtleCryptoFunctionEncryptPromise, PromiseExecutionScope::WindowOrWorker>(state);
610 JSValue JSSubtleCrypto::generateKey(ExecState& state)
612 return callPromiseFunction<jsSubtleCryptoFunctionGenerateKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
615 JSValue JSSubtleCrypto::importKey(ExecState& state)
617 return callPromiseFunction<jsSubtleCryptoFunctionImportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
620 JSValue JSSubtleCrypto::exportKey(ExecState& state)
622 return callPromiseFunction<jsSubtleCryptoFunctionExportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
625 } // namespace WebCore