27b1bed23e6380493d31fa2f88d3185938c2c616
[WebKit-https.git] / Source / WebCore / bindings / js / JSSubtleCryptoCustom.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "JSSubtleCrypto.h"
28
29 #if ENABLE(SUBTLE_CRYPTO)
30
31 #include "CryptoAlgorithm.h"
32 #include "CryptoAlgorithmRegistry.h"
33 #include "JSAesKeyGenParams.h"
34 #include "JSCryptoAlgorithmParameters.h"
35 #include "JSCryptoKey.h"
36 #include "JSCryptoKeyPair.h"
37 #include "JSDOMPromise.h"
38 #include "JSHmacKeyParams.h"
39 #include "JSJsonWebKey.h"
40 #include "JSRsaHashedImportParams.h"
41 #include "JSRsaHashedKeyGenParams.h"
42 #include "JSRsaKeyGenParams.h"
43 #include "ScriptState.h"
44 #include <runtime/Error.h>
45 #include <runtime/IteratorOperations.h>
46 #include <runtime/JSArray.h>
47
48 using namespace JSC;
49
50 namespace WebCore {
51
52 enum class Operations {
53     Digest,
54     GenerateKey,
55     ImportKey,
56 };
57
58 static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParameters(ExecState&, JSValue, Operations);
59
60 static CryptoAlgorithmIdentifier toHashIdentifier(ExecState& state, JSValue value)
61 {
62     VM& vm = state.vm();
63     auto scope = DECLARE_THROW_SCOPE(vm);
64
65     auto digestParams = normalizeCryptoAlgorithmParameters(state, value, Operations::Digest);
66     RETURN_IF_EXCEPTION(scope, { });
67     return digestParams->identifier;
68 }
69
70 static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParameters(ExecState& state, JSValue value, Operations operation)
71 {
72     VM& vm = state.vm();
73     auto scope = DECLARE_THROW_SCOPE(vm);
74
75     if (value.isString()) {
76         JSObject* newParams = constructEmptyObject(&state);
77         newParams->putDirect(vm, Identifier::fromString(&vm, "name"), value);
78         return normalizeCryptoAlgorithmParameters(state, newParams, operation);
79     }
80
81     if (value.isObject()) {
82         auto params = convertDictionary<CryptoAlgorithmParameters>(state, value);
83         RETURN_IF_EXCEPTION(scope, nullptr);
84
85         auto identifier = CryptoAlgorithmRegistry::singleton().identifier(params.name);
86         if (!identifier) {
87             setDOMException(&state, NOT_SUPPORTED_ERR);
88             return nullptr;
89         }
90
91         std::unique_ptr<CryptoAlgorithmParameters> result;
92         switch (operation) {
93         case Operations::Digest:
94             switch (*identifier) {
95             case CryptoAlgorithmIdentifier::SHA_1:
96             case CryptoAlgorithmIdentifier::SHA_224:
97             case CryptoAlgorithmIdentifier::SHA_256:
98             case CryptoAlgorithmIdentifier::SHA_384:
99             case CryptoAlgorithmIdentifier::SHA_512:
100                 result = std::make_unique<CryptoAlgorithmParameters>(params);
101                 break;
102             default:
103                 setDOMException(&state, NOT_SUPPORTED_ERR);
104                 return nullptr;
105             }
106             break;
107         case Operations::GenerateKey:
108             switch (*identifier) {
109             case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: {
110                 auto params = convertDictionary<CryptoAlgorithmRsaKeyGenParams>(state, value);
111                 RETURN_IF_EXCEPTION(scope, nullptr);
112                 result = std::make_unique<CryptoAlgorithmRsaKeyGenParams>(params);
113                 break;
114             }
115             case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
116             case CryptoAlgorithmIdentifier::RSA_PSS:
117             case CryptoAlgorithmIdentifier::RSA_OAEP: {
118                 auto params = convertDictionary<CryptoAlgorithmRsaHashedKeyGenParams>(state, value);
119                 RETURN_IF_EXCEPTION(scope, nullptr);
120                 params.hashIdentifier = toHashIdentifier(state, params.hash);
121                 RETURN_IF_EXCEPTION(scope, nullptr);
122                 result = std::make_unique<CryptoAlgorithmRsaHashedKeyGenParams>(params);
123                 break;
124             }
125             case CryptoAlgorithmIdentifier::AES_CTR:
126             case CryptoAlgorithmIdentifier::AES_CBC:
127             case CryptoAlgorithmIdentifier::AES_CMAC:
128             case CryptoAlgorithmIdentifier::AES_GCM:
129             case CryptoAlgorithmIdentifier::AES_CFB:
130             case CryptoAlgorithmIdentifier::AES_KW: {
131                 auto params = convertDictionary<CryptoAlgorithmAesKeyGenParams>(state, value);
132                 RETURN_IF_EXCEPTION(scope, nullptr);
133                 result = std::make_unique<CryptoAlgorithmAesKeyGenParams>(params);
134                 break;
135             }
136             case CryptoAlgorithmIdentifier::HMAC: {
137                 auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value);
138                 RETURN_IF_EXCEPTION(scope, nullptr);
139                 params.hashIdentifier = toHashIdentifier(state, params.hash);
140                 RETURN_IF_EXCEPTION(scope, nullptr);
141                 result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
142                 break;
143             }
144             default:
145                 setDOMException(&state, NOT_SUPPORTED_ERR);
146                 return nullptr;
147             }
148             break;
149         case Operations::ImportKey:
150             switch (*identifier) {
151             case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
152                 result = std::make_unique<CryptoAlgorithmParameters>(params);
153                 break;
154             case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
155             case CryptoAlgorithmIdentifier::RSA_PSS:
156             case CryptoAlgorithmIdentifier::RSA_OAEP: {
157                 auto params = convertDictionary<CryptoAlgorithmRsaHashedImportParams>(state, value);
158                 RETURN_IF_EXCEPTION(scope, nullptr);
159                 params.hashIdentifier = toHashIdentifier(state, params.hash);
160                 RETURN_IF_EXCEPTION(scope, nullptr);
161                 result = std::make_unique<CryptoAlgorithmRsaHashedImportParams>(params);
162                 break;
163             }
164             case CryptoAlgorithmIdentifier::AES_CTR:
165             case CryptoAlgorithmIdentifier::AES_CBC:
166             case CryptoAlgorithmIdentifier::AES_CMAC:
167             case CryptoAlgorithmIdentifier::AES_GCM:
168             case CryptoAlgorithmIdentifier::AES_CFB:
169             case CryptoAlgorithmIdentifier::AES_KW:
170                 result = std::make_unique<CryptoAlgorithmParameters>(params);
171                 break;
172             case CryptoAlgorithmIdentifier::HMAC: {
173                 auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value);
174                 RETURN_IF_EXCEPTION(scope, nullptr);
175                 params.hashIdentifier = toHashIdentifier(state, params.hash);
176                 RETURN_IF_EXCEPTION(scope, nullptr);
177                 result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
178                 break;
179             }
180             default:
181                 setDOMException(&state, NOT_SUPPORTED_ERR);
182                 return nullptr;
183             }
184             break;
185         default:
186             ASSERT_NOT_REACHED();
187             return nullptr;
188         }
189
190         result->identifier = *identifier;
191         return result;
192     }
193
194     throwTypeError(&state, scope, ASCIILiteral("Invalid AlgorithmIdentifier"));
195     return nullptr;
196 }
197
198 static CryptoKeyUsageBitmap toCryptoKeyUsageBitmap(CryptoKeyUsage usage)
199 {
200     switch (usage) {
201     case CryptoKeyUsage::Encrypt:
202         return CryptoKeyUsageEncrypt;
203     case CryptoKeyUsage::Decrypt:
204         return CryptoKeyUsageDecrypt;
205     case CryptoKeyUsage::Sign:
206         return CryptoKeyUsageSign;
207     case CryptoKeyUsage::Verify:
208         return CryptoKeyUsageVerify;
209     case CryptoKeyUsage::DeriveKey:
210         return CryptoKeyUsageDeriveKey;
211     case CryptoKeyUsage::DeriveBits:
212         return CryptoKeyUsageDeriveBits;
213     case CryptoKeyUsage::WrapKey:
214         return CryptoKeyUsageWrapKey;
215     case CryptoKeyUsage::UnwrapKey:
216         return CryptoKeyUsageUnwrapKey;
217     }
218
219     ASSERT_NOT_REACHED();
220     return 0;
221 }
222
223 static CryptoKeyUsageBitmap cryptoKeyUsageBitmapFromJSValue(ExecState& state, JSValue value)
224 {
225     VM& vm = state.vm();
226     auto scope = DECLARE_THROW_SCOPE(vm);
227
228     CryptoKeyUsageBitmap result = 0;
229     auto usages = convert<IDLSequence<IDLEnumeration<CryptoKeyUsage>>>(state, value);
230     RETURN_IF_EXCEPTION(scope, 0);
231     // Maybe we shouldn't silently bypass duplicated usages?
232     for (auto usage : usages)
233         result |= toCryptoKeyUsageBitmap(usage);
234
235     return result;
236 }
237
238 static RefPtr<CryptoAlgorithm> createAlgorithm(ExecState& state, CryptoAlgorithmIdentifier identifier)
239 {
240     auto result = CryptoAlgorithmRegistry::singleton().create(identifier);
241     if (!result)
242         setDOMException(&state, NOT_SUPPORTED_ERR);
243     return result;
244 }
245
246 // Maybe we want more specific error messages?
247 static void rejectWithException(Ref<DeferredPromise>&& passedPromise, ExceptionCode ec)
248 {
249     switch (ec) {
250     case NOT_SUPPORTED_ERR:
251         passedPromise->reject(ec, ASCIILiteral("The algorithm is not supported"));
252         return;
253     case SYNTAX_ERR:
254         passedPromise->reject(ec, ASCIILiteral("A required parameter was missing or out-of-range"));
255         return;
256     case INVALID_STATE_ERR:
257         passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the current state of the provided key"));
258         return;
259     case INVALID_ACCESS_ERR:
260         passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the provided key"));
261         return;
262     case UnknownError:
263         passedPromise->reject(ec, ASCIILiteral("The operation failed for an unknown transient reason (e.g. out of memory)"));
264         return;
265     case DataError:
266         passedPromise->reject(ec, ASCIILiteral("Data provided to an operation does not meet requirements"));
267         return;
268     case OperationError:
269         passedPromise->reject(ec, ASCIILiteral("The operation failed for an operation-specific reason"));
270         return;
271     }
272     ASSERT_NOT_REACHED();
273 }
274
275 static KeyData toKeyData(ExecState& state, SubtleCrypto::KeyFormat format, JSValue value)
276 {
277     VM& vm = state.vm();
278     auto scope = DECLARE_THROW_SCOPE(vm);
279
280     KeyData result;
281     switch (format) {
282     case SubtleCrypto::KeyFormat::Spki:
283     case SubtleCrypto::KeyFormat::Pkcs8:
284         setDOMException(&state, NOT_SUPPORTED_ERR);
285         return result;
286     case SubtleCrypto::KeyFormat::Raw: {
287         BufferSource bufferSource = convert<IDLBufferSource>(state, value);
288         RETURN_IF_EXCEPTION(scope, result);
289         Vector<uint8_t> vector;
290         vector.append(bufferSource.data(), bufferSource.length());
291         result = WTFMove(vector);
292         return result;
293     }
294     case SubtleCrypto::KeyFormat::Jwk: {
295         result = convertDictionary<JsonWebKey>(state, value);
296         RETURN_IF_EXCEPTION(scope, result);
297         CryptoKeyUsageBitmap usages = 0;
298         if (WTF::get<JsonWebKey>(result).key_ops) {
299             // Maybe we shouldn't silently bypass duplicated usages?
300             for (auto usage : WTF::get<JsonWebKey>(result).key_ops.value())
301                 usages |= toCryptoKeyUsageBitmap(usage);
302         }
303         WTF::get<JsonWebKey>(result).usages = usages;
304         return result;
305     }
306     }
307     ASSERT_NOT_REACHED();
308     return result;
309 }
310
311 // FIXME: We should get rid of this once https://bugs.webkit.org/show_bug.cgi?id=163711 is fixed.
312 static JSValue toJSValueFromJsonWebKey(JSDOMGlobalObject& globalObject, JsonWebKey&& key)
313 {
314     ExecState& state = *globalObject.globalExec();
315     VM& vm = state.vm();
316
317     auto* result = constructEmptyObject(&state);
318     result->putDirect(vm, Identifier::fromString(&vm, "kty"), toJS<IDLDOMString>(state, key.kty));
319     if (key.use)
320         result->putDirect(vm, Identifier::fromString(&vm, "use"), toJS<IDLDOMString>(state, key.use.value()));
321     if (key.key_ops)
322         result->putDirect(vm, Identifier::fromString(&vm, "key_ops"), toJS<IDLSequence<IDLEnumeration<CryptoKeyUsage>>>(state, globalObject, key.key_ops.value()));
323     if (key.alg)
324         result->putDirect(vm, Identifier::fromString(&vm, "alg"), toJS<IDLDOMString>(state, key.alg.value()));
325     if (key.ext)
326         result->putDirect(vm, Identifier::fromString(&vm, "ext"), toJS<IDLBoolean>(state, key.ext.value()));
327     if (key.crv)
328         result->putDirect(vm, Identifier::fromString(&vm, "crv"), toJS<IDLDOMString>(state, key.crv.value()));
329     if (key.x)
330         result->putDirect(vm, Identifier::fromString(&vm, "x"), toJS<IDLDOMString>(state, key.x.value()));
331     if (key.y)
332         result->putDirect(vm, Identifier::fromString(&vm, "y"), toJS<IDLDOMString>(state, key.y.value()));
333     if (key.d)
334         result->putDirect(vm, Identifier::fromString(&vm, "d"), toJS<IDLDOMString>(state, key.d.value()));
335     if (key.n)
336         result->putDirect(vm, Identifier::fromString(&vm, "n"), toJS<IDLDOMString>(state, key.n.value()));
337     if (key.e)
338         result->putDirect(vm, Identifier::fromString(&vm, "e"), toJS<IDLDOMString>(state, key.e.value()));
339     if (key.p)
340         result->putDirect(vm, Identifier::fromString(&vm, "p"), toJS<IDLDOMString>(state, key.p.value()));
341     if (key.q)
342         result->putDirect(vm, Identifier::fromString(&vm, "q"), toJS<IDLDOMString>(state, key.q.value()));
343     if (key.dp)
344         result->putDirect(vm, Identifier::fromString(&vm, "dp"), toJS<IDLDOMString>(state, key.dp.value()));
345     if (key.dq)
346         result->putDirect(vm, Identifier::fromString(&vm, "dq"), toJS<IDLDOMString>(state, key.dq.value()));
347     if (key.qi)
348         result->putDirect(vm, Identifier::fromString(&vm, "qi"), toJS<IDLDOMString>(state, key.qi.value()));
349     if (key.oth) {
350         MarkedArgumentBuffer list;
351         for (auto& value : key.oth.value()) {
352             auto* info = constructEmptyObject(&state);
353             info->putDirect(vm, Identifier::fromString(&vm, "r"), toJS<IDLDOMString>(state, value.r));
354             info->putDirect(vm, Identifier::fromString(&vm, "d"), toJS<IDLDOMString>(state, value.d));
355             info->putDirect(vm, Identifier::fromString(&vm, "t"), toJS<IDLDOMString>(state, value.t));
356             list.append(info);
357         }
358         result->putDirect(vm, Identifier::fromString(&vm, "oth"), constructArray(&state, static_cast<Structure*>(nullptr), list));
359     }
360     if (key.k)
361         result->putDirect(vm, Identifier::fromString(&vm, "k"), toJS<IDLDOMString>(state, key.k.value()));
362
363     return result;
364 }
365
366 static void jsSubtleCryptoFunctionGenerateKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
367 {
368     VM& vm = state.vm();
369     auto scope = DECLARE_THROW_SCOPE(vm);
370
371     if (UNLIKELY(state.argumentCount() < 3)) {
372         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
373         return;
374     }
375
376     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::GenerateKey);
377     RETURN_IF_EXCEPTION(scope, void());
378
379     auto extractable = state.uncheckedArgument(1).toBoolean(&state);
380     RETURN_IF_EXCEPTION(scope, void());
381
382     auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(2));
383     RETURN_IF_EXCEPTION(scope, void());
384
385     auto algorithm = createAlgorithm(state, params->identifier);
386     RETURN_IF_EXCEPTION(scope, void());
387
388     auto callback = [capturedPromise = promise.copyRef()](CryptoKey* key, CryptoKeyPair* keyPair) mutable {
389         ASSERT(key || keyPair);
390         ASSERT(!key || !keyPair);
391         if (key) {
392             if ((key->type() == CryptoKeyType::Private || key->type() == CryptoKeyType::Secret) && !key->usagesBitmap()) {
393                 rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
394                 return;
395             }
396             capturedPromise->resolve(key);
397         } else {
398             if (!keyPair->privateKey()->usagesBitmap()) {
399                 rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
400                 return;
401             }
402             capturedPromise->resolve(keyPair);
403         }
404     };
405     auto exceptionCallback = [capturedPromise =  promise.copyRef()](ExceptionCode ec) mutable {
406         rejectWithException(WTFMove(capturedPromise), ec);
407     };
408
409     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously
410     // regardless what kind of keys it produces: https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey
411     // That's simply not efficient for AES and HMAC keys. Therefore, we perform it as an async task conditionally.
412     algorithm->generateKey(WTFMove(params), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state));
413 }
414
415 static void jsSubtleCryptoFunctionImportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
416 {
417     VM& vm = state.vm();
418     auto scope = DECLARE_THROW_SCOPE(vm);
419
420     if (UNLIKELY(state.argumentCount() < 5)) {
421         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
422         return;
423     }
424
425     auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
426     RETURN_IF_EXCEPTION(scope, void());
427
428     auto keyData = toKeyData(state, format, state.uncheckedArgument(1));
429     RETURN_IF_EXCEPTION(scope, void());
430
431     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(2), Operations::ImportKey);
432     RETURN_IF_EXCEPTION(scope, void());
433
434     auto extractable = state.uncheckedArgument(3).toBoolean(&state);
435     RETURN_IF_EXCEPTION(scope, void());
436
437     auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(4));
438     RETURN_IF_EXCEPTION(scope, void());
439
440     auto algorithm = createAlgorithm(state, params->identifier);
441     RETURN_IF_EXCEPTION(scope, void());
442
443     auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable {
444         if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
445             rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
446             return;
447         }
448         capturedPromise->resolve(key);
449     };
450     auto exceptionCallback = [capturedPromise =  promise.copyRef()](ExceptionCode ec) mutable {
451         rejectWithException(WTFMove(capturedPromise), ec);
452     };
453
454     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
455     // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey
456     // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
457     algorithm->importKey(format, WTFMove(keyData), WTFMove(params), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback));
458 }
459
460 static void jsSubtleCryptoFunctionExportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
461 {
462     VM& vm = state.vm();
463     auto scope = DECLARE_THROW_SCOPE(vm);
464
465     if (UNLIKELY(state.argumentCount() < 2)) {
466         promise->reject<JSValue>(createNotEnoughArgumentsError(&state));
467         return;
468     }
469
470     auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0));
471     RETURN_IF_EXCEPTION(scope, void());
472
473     RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(state.uncheckedArgument(1));
474     if (!key) {
475         promise->reject(TypeError, ASCIILiteral("Invalid CryptoKey"));
476         return;
477     }
478
479     switch (key->algorithmIdentifier()) {
480     case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
481     case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
482     case CryptoAlgorithmIdentifier::RSA_PSS:
483     case CryptoAlgorithmIdentifier::RSA_OAEP:
484     case CryptoAlgorithmIdentifier::AES_CTR:
485     case CryptoAlgorithmIdentifier::AES_CBC:
486     case CryptoAlgorithmIdentifier::AES_CMAC:
487     case CryptoAlgorithmIdentifier::AES_GCM:
488     case CryptoAlgorithmIdentifier::AES_CFB:
489     case CryptoAlgorithmIdentifier::AES_KW:
490     case CryptoAlgorithmIdentifier::HMAC:
491         break;
492     default:
493         promise->reject(NOT_SUPPORTED_ERR, ASCIILiteral("The operation is not supported"));
494         return;
495     }
496
497     if (!key->extractable()) {
498         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("The CryptoKey is nonextractable"));
499         return;
500     }
501
502     auto algorithm = createAlgorithm(state, key->algorithmIdentifier());
503     RETURN_IF_EXCEPTION(scope, void());
504
505     auto callback = [capturedPromise = promise.copyRef()](SubtleCrypto::KeyFormat format, KeyData&& key) mutable {
506         switch (format) {
507         case SubtleCrypto::KeyFormat::Spki:
508         case SubtleCrypto::KeyFormat::Pkcs8:
509         case SubtleCrypto::KeyFormat::Raw: {
510             Vector<uint8_t>& rawKey = WTF::get<Vector<uint8_t>>(key);
511             fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), rawKey.data(), rawKey.size());
512             return;
513         }
514         case SubtleCrypto::KeyFormat::Jwk:
515             capturedPromise->resolve(toJSValueFromJsonWebKey(*(capturedPromise->globalObject()), WTFMove(WTF::get<JsonWebKey>(key))));
516             return;
517         }
518         ASSERT_NOT_REACHED();
519     };
520     auto exceptionCallback = [capturedPromise =  promise.copyRef()](ExceptionCode ec) mutable {
521         rejectWithException(WTFMove(capturedPromise), ec);
522     };
523
524     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
525     // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey
526     // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
527     algorithm->exportKey(format, WTFMove(key), WTFMove(callback), WTFMove(exceptionCallback));
528 }
529
530 JSValue JSSubtleCrypto::generateKey(ExecState& state)
531 {
532     return callPromiseFunction<jsSubtleCryptoFunctionGenerateKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
533 }
534
535 JSValue JSSubtleCrypto::importKey(ExecState& state)
536 {
537     return callPromiseFunction<jsSubtleCryptoFunctionImportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
538 }
539
540 JSValue JSSubtleCrypto::exportKey(ExecState& state)
541 {
542     return callPromiseFunction<jsSubtleCryptoFunctionExportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
543 }
544
545 } // namespace WebCore
546
547 #endif