Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / crypto / SubtleCrypto.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 "SubtleCrypto.h"
28
29 #if ENABLE(SUBTLE_CRYPTO)
30
31 #include "CryptoAlgorithm.h"
32 #include "CryptoAlgorithmRegistry.h"
33 #include "JSAesCbcCfbParams.h"
34 #include "JSAesCtrParams.h"
35 #include "JSAesGcmParams.h"
36 #include "JSAesKeyParams.h"
37 #include "JSCryptoAlgorithmParameters.h"
38 #include "JSCryptoKey.h"
39 #include "JSCryptoKeyPair.h"
40 #include "JSDOMPromiseDeferred.h"
41 #include "JSDOMWrapper.h"
42 #include "JSEcKeyParams.h"
43 #include "JSEcdhKeyDeriveParams.h"
44 #include "JSEcdsaParams.h"
45 #include "JSHkdfParams.h"
46 #include "JSHmacKeyParams.h"
47 #include "JSJsonWebKey.h"
48 #include "JSPbkdf2Params.h"
49 #include "JSRsaHashedImportParams.h"
50 #include "JSRsaHashedKeyGenParams.h"
51 #include "JSRsaKeyGenParams.h"
52 #include "JSRsaOaepParams.h"
53 #include "JSRsaPssParams.h"
54 #include <runtime/JSONObject.h>
55
56
57 namespace WebCore {
58 using namespace JSC;
59
60 SubtleCrypto::SubtleCrypto(ScriptExecutionContext& context)
61     : ContextDestructionObserver(&context)
62     , m_workQueue(WorkQueue::create("com.apple.WebKit.CryptoQueue"))
63 {
64 }
65
66 SubtleCrypto::~SubtleCrypto() = default;
67
68 enum class Operations {
69     Encrypt,
70     Decrypt,
71     Sign,
72     Verify,
73     Digest,
74     GenerateKey,
75     DeriveBits,
76     ImportKey,
77     WrapKey,
78     UnwrapKey,
79     GetKeyLength
80 };
81
82 static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAlgorithmParameters(ExecState&, WebCore::SubtleCrypto::AlgorithmIdentifier, Operations);
83
84 static ExceptionOr<CryptoAlgorithmIdentifier> toHashIdentifier(ExecState& state, SubtleCrypto::AlgorithmIdentifier algorithmIdentifier)
85 {
86     auto digestParams = normalizeCryptoAlgorithmParameters(state, algorithmIdentifier, Operations::Digest);
87     if (digestParams.hasException())
88         return digestParams.releaseException();
89     return digestParams.returnValue()->identifier;
90 }
91
92 static ExceptionOr<std::unique_ptr<CryptoAlgorithmParameters>> normalizeCryptoAlgorithmParameters(ExecState& state, SubtleCrypto::AlgorithmIdentifier algorithmIdentifier, Operations operation)
93 {
94     VM& vm = state.vm();
95     auto scope = DECLARE_THROW_SCOPE(vm);
96
97     if (WTF::holds_alternative<String>(algorithmIdentifier)) {
98         auto newParams = Strong<JSObject>(vm, constructEmptyObject(&state));
99         newParams->putDirect(vm, Identifier::fromString(&vm, "name"), jsString(&state, WTF::get<String>(algorithmIdentifier)));
100         
101         return normalizeCryptoAlgorithmParameters(state, newParams, operation);
102     }
103
104     auto& value = WTF::get<JSC::Strong<JSC::JSObject>>(algorithmIdentifier);
105
106     auto params = convertDictionary<CryptoAlgorithmParameters>(state, value.get());
107     RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
108
109     auto identifier = CryptoAlgorithmRegistry::singleton().identifier(params.name);
110     if (UNLIKELY(!identifier))
111         return Exception { NotSupportedError };
112
113     std::unique_ptr<CryptoAlgorithmParameters> result;
114     switch (operation) {
115     case Operations::Encrypt:
116     case Operations::Decrypt:
117         switch (*identifier) {
118         case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
119             result = std::make_unique<CryptoAlgorithmParameters>(params);
120             break;
121         case CryptoAlgorithmIdentifier::RSA_OAEP: {
122             auto params = convertDictionary<CryptoAlgorithmRsaOaepParams>(state, value.get());
123             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
124             result = std::make_unique<CryptoAlgorithmRsaOaepParams>(params);
125             break;
126         }
127         case CryptoAlgorithmIdentifier::AES_CBC:
128         case CryptoAlgorithmIdentifier::AES_CFB: {
129             auto params = convertDictionary<CryptoAlgorithmAesCbcCfbParams>(state, value.get());
130             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
131             result = std::make_unique<CryptoAlgorithmAesCbcCfbParams>(params);
132             break;
133         }
134         case CryptoAlgorithmIdentifier::AES_CTR: {
135             auto params = convertDictionary<CryptoAlgorithmAesCtrParams>(state, value.get());
136             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
137             result = std::make_unique<CryptoAlgorithmAesCtrParams>(params);
138             break;
139         }
140         case CryptoAlgorithmIdentifier::AES_GCM: {
141             auto params = convertDictionary<CryptoAlgorithmAesGcmParams>(state, value.get());
142             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
143             result = std::make_unique<CryptoAlgorithmAesGcmParams>(params);
144             break;
145         }
146         default:
147             return Exception { NotSupportedError };
148         }
149         break;
150     case Operations::Sign:
151     case Operations::Verify:
152         switch (*identifier) {
153         case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
154         case CryptoAlgorithmIdentifier::HMAC:
155             result = std::make_unique<CryptoAlgorithmParameters>(params);
156             break;
157         case CryptoAlgorithmIdentifier::ECDSA: {
158             auto params = convertDictionary<CryptoAlgorithmEcdsaParams>(state, value.get());
159             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
160             auto hashIdentifier = toHashIdentifier(state, params.hash);
161             if (hashIdentifier.hasException())
162                 return hashIdentifier.releaseException();
163             params.hashIdentifier = hashIdentifier.releaseReturnValue();
164             result = std::make_unique<CryptoAlgorithmEcdsaParams>(params);
165             break;
166         }
167         case CryptoAlgorithmIdentifier::RSA_PSS: {
168             auto params = convertDictionary<CryptoAlgorithmRsaPssParams>(state, value.get());
169             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
170             result = std::make_unique<CryptoAlgorithmRsaPssParams>(params);
171             break;
172         }
173         default:
174             return Exception { NotSupportedError };
175         }
176         break;
177     case Operations::Digest:
178         switch (*identifier) {
179         case CryptoAlgorithmIdentifier::SHA_1:
180         case CryptoAlgorithmIdentifier::SHA_224:
181         case CryptoAlgorithmIdentifier::SHA_256:
182         case CryptoAlgorithmIdentifier::SHA_384:
183         case CryptoAlgorithmIdentifier::SHA_512:
184             result = std::make_unique<CryptoAlgorithmParameters>(params);
185             break;
186         default:
187             return Exception { NotSupportedError };
188         }
189         break;
190     case Operations::GenerateKey:
191         switch (*identifier) {
192         case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: {
193             auto params = convertDictionary<CryptoAlgorithmRsaKeyGenParams>(state, value.get());
194             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
195             result = std::make_unique<CryptoAlgorithmRsaKeyGenParams>(params);
196             break;
197         }
198         case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
199         case CryptoAlgorithmIdentifier::RSA_PSS:
200         case CryptoAlgorithmIdentifier::RSA_OAEP: {
201             auto params = convertDictionary<CryptoAlgorithmRsaHashedKeyGenParams>(state, value.get());
202             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
203             auto hashIdentifier = toHashIdentifier(state, params.hash);
204             if (hashIdentifier.hasException())
205                 return hashIdentifier.releaseException();
206             params.hashIdentifier = hashIdentifier.releaseReturnValue();
207             result = std::make_unique<CryptoAlgorithmRsaHashedKeyGenParams>(params);
208             break;
209         }
210         case CryptoAlgorithmIdentifier::AES_CTR:
211         case CryptoAlgorithmIdentifier::AES_CBC:
212         case CryptoAlgorithmIdentifier::AES_GCM:
213         case CryptoAlgorithmIdentifier::AES_CFB:
214         case CryptoAlgorithmIdentifier::AES_KW: {
215             auto params = convertDictionary<CryptoAlgorithmAesKeyParams>(state, value.get());
216             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
217             result = std::make_unique<CryptoAlgorithmAesKeyParams>(params);
218             break;
219         }
220         case CryptoAlgorithmIdentifier::HMAC: {
221             auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value.get());
222             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
223             auto hashIdentifier = toHashIdentifier(state, params.hash);
224             if (hashIdentifier.hasException())
225                 return hashIdentifier.releaseException();
226             params.hashIdentifier = hashIdentifier.releaseReturnValue();
227             result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
228             break;
229         }
230         case CryptoAlgorithmIdentifier::ECDSA:
231         case CryptoAlgorithmIdentifier::ECDH: {
232             auto params = convertDictionary<CryptoAlgorithmEcKeyParams>(state, value.get());
233             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
234             result = std::make_unique<CryptoAlgorithmEcKeyParams>(params);
235             break;
236         }
237         default:
238             return Exception { NotSupportedError };
239         }
240         break;
241     case Operations::DeriveBits:
242         switch (*identifier) {
243         case CryptoAlgorithmIdentifier::ECDH: {
244             // Remove this hack once https://bugs.webkit.org/show_bug.cgi?id=169333 is fixed.
245             JSValue nameValue = value.get()->get(&state, Identifier::fromString(&state, "name"));
246             JSValue publicValue = value.get()->get(&state, Identifier::fromString(&state, "public"));
247             JSObject* newValue = constructEmptyObject(&state);
248             newValue->putDirect(vm, Identifier::fromString(&vm, "name"), nameValue);
249             newValue->putDirect(vm, Identifier::fromString(&vm, "publicKey"), publicValue);
250
251             auto params = convertDictionary<CryptoAlgorithmEcdhKeyDeriveParams>(state, newValue);
252             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
253             result = std::make_unique<CryptoAlgorithmEcdhKeyDeriveParams>(params);
254             break;
255         }
256         case CryptoAlgorithmIdentifier::HKDF: {
257             auto params = convertDictionary<CryptoAlgorithmHkdfParams>(state, value.get());
258             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
259             auto hashIdentifier = toHashIdentifier(state, params.hash);
260             if (hashIdentifier.hasException())
261                 return hashIdentifier.releaseException();
262             params.hashIdentifier = hashIdentifier.releaseReturnValue();
263             result = std::make_unique<CryptoAlgorithmHkdfParams>(params);
264             break;
265         }
266         case CryptoAlgorithmIdentifier::PBKDF2: {
267             auto params = convertDictionary<CryptoAlgorithmPbkdf2Params>(state, value.get());
268             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
269             auto hashIdentifier = toHashIdentifier(state, params.hash);
270             if (hashIdentifier.hasException())
271                 return hashIdentifier.releaseException();
272             params.hashIdentifier = hashIdentifier.releaseReturnValue();
273             result = std::make_unique<CryptoAlgorithmPbkdf2Params>(params);
274             break;
275         }
276         default:
277             return Exception { NotSupportedError };
278         }
279         break;
280     case Operations::ImportKey:
281         switch (*identifier) {
282         case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
283             result = std::make_unique<CryptoAlgorithmParameters>(params);
284             break;
285         case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
286         case CryptoAlgorithmIdentifier::RSA_PSS:
287         case CryptoAlgorithmIdentifier::RSA_OAEP: {
288             auto params = convertDictionary<CryptoAlgorithmRsaHashedImportParams>(state, value.get());
289             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
290             auto hashIdentifier = toHashIdentifier(state, params.hash);
291             if (hashIdentifier.hasException())
292                 return hashIdentifier.releaseException();
293             params.hashIdentifier = hashIdentifier.releaseReturnValue();
294             result = std::make_unique<CryptoAlgorithmRsaHashedImportParams>(params);
295             break;
296         }
297         case CryptoAlgorithmIdentifier::AES_CTR:
298         case CryptoAlgorithmIdentifier::AES_CBC:
299         case CryptoAlgorithmIdentifier::AES_GCM:
300         case CryptoAlgorithmIdentifier::AES_CFB:
301         case CryptoAlgorithmIdentifier::AES_KW:
302             result = std::make_unique<CryptoAlgorithmParameters>(params);
303             break;
304         case CryptoAlgorithmIdentifier::HMAC: {
305             auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value.get());
306             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
307             auto hashIdentifier = toHashIdentifier(state, params.hash);
308             if (hashIdentifier.hasException())
309                 return hashIdentifier.releaseException();
310             params.hashIdentifier = hashIdentifier.releaseReturnValue();
311             result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
312             break;
313         }
314         case CryptoAlgorithmIdentifier::ECDSA:
315         case CryptoAlgorithmIdentifier::ECDH: {
316             auto params = convertDictionary<CryptoAlgorithmEcKeyParams>(state, value.get());
317             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
318             result = std::make_unique<CryptoAlgorithmEcKeyParams>(params);
319             break;
320         }
321         case CryptoAlgorithmIdentifier::HKDF:
322         case CryptoAlgorithmIdentifier::PBKDF2:
323             result = std::make_unique<CryptoAlgorithmParameters>(params);
324             break;
325         default:
326             return Exception { NotSupportedError };
327         }
328         break;
329     case Operations::WrapKey:
330     case Operations::UnwrapKey:
331         switch (*identifier) {
332         case CryptoAlgorithmIdentifier::AES_KW:
333             result = std::make_unique<CryptoAlgorithmParameters>(params);
334             break;
335         default:
336             return Exception { NotSupportedError };
337         }
338         break;
339     case Operations::GetKeyLength:
340         switch (*identifier) {
341         case CryptoAlgorithmIdentifier::AES_CTR:
342         case CryptoAlgorithmIdentifier::AES_CBC:
343         case CryptoAlgorithmIdentifier::AES_GCM:
344         case CryptoAlgorithmIdentifier::AES_CFB:
345         case CryptoAlgorithmIdentifier::AES_KW: {
346             auto params = convertDictionary<CryptoAlgorithmAesKeyParams>(state, value.get());
347             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
348             result = std::make_unique<CryptoAlgorithmAesKeyParams>(params);
349             break;
350         }
351         case CryptoAlgorithmIdentifier::HMAC: {
352             auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value.get());
353             RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });
354             auto hashIdentifier = toHashIdentifier(state, params.hash);
355             if (hashIdentifier.hasException())
356                 return hashIdentifier.releaseException();
357             params.hashIdentifier = hashIdentifier.releaseReturnValue();
358             result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
359             break;
360         }
361         case CryptoAlgorithmIdentifier::HKDF:
362         case CryptoAlgorithmIdentifier::PBKDF2:
363             result = std::make_unique<CryptoAlgorithmParameters>(params);
364             break;
365         default:
366             return Exception { NotSupportedError };
367         }
368         break;
369     }
370
371     result->identifier = *identifier;
372     return WTFMove(result);
373 }
374
375 static CryptoKeyUsageBitmap toCryptoKeyUsageBitmap(CryptoKeyUsage usage)
376 {
377     switch (usage) {
378     case CryptoKeyUsage::Encrypt:
379         return CryptoKeyUsageEncrypt;
380     case CryptoKeyUsage::Decrypt:
381         return CryptoKeyUsageDecrypt;
382     case CryptoKeyUsage::Sign:
383         return CryptoKeyUsageSign;
384     case CryptoKeyUsage::Verify:
385         return CryptoKeyUsageVerify;
386     case CryptoKeyUsage::DeriveKey:
387         return CryptoKeyUsageDeriveKey;
388     case CryptoKeyUsage::DeriveBits:
389         return CryptoKeyUsageDeriveBits;
390     case CryptoKeyUsage::WrapKey:
391         return CryptoKeyUsageWrapKey;
392     case CryptoKeyUsage::UnwrapKey:
393         return CryptoKeyUsageUnwrapKey;
394     }
395
396     RELEASE_ASSERT_NOT_REACHED();
397 }
398
399 static CryptoKeyUsageBitmap toCryptoKeyUsageBitmap(const Vector<CryptoKeyUsage>& usages)
400 {
401     CryptoKeyUsageBitmap result = 0;
402     // Maybe we shouldn't silently bypass duplicated usages?
403     for (auto usage : usages)
404         result |= toCryptoKeyUsageBitmap(usage);
405
406     return result;
407 }
408
409 // Maybe we want more specific error messages?
410 static void rejectWithException(Ref<DeferredPromise>&& passedPromise, ExceptionCode ec)
411 {
412     switch (ec) {
413     case NotSupportedError:
414         passedPromise->reject(ec, ASCIILiteral("The algorithm is not supported"));
415         return;
416     case SyntaxError:
417         passedPromise->reject(ec, ASCIILiteral("A required parameter was missing or out-of-range"));
418         return;
419     case InvalidStateError:
420         passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the current state of the provided key"));
421         return;
422     case InvalidAccessError:
423         passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the provided key"));
424         return;
425     case UnknownError:
426         passedPromise->reject(ec, ASCIILiteral("The operation failed for an unknown transient reason (e.g. out of memory)"));
427         return;
428     case DataError:
429         passedPromise->reject(ec, ASCIILiteral("Data provided to an operation does not meet requirements"));
430         return;
431     case OperationError:
432         passedPromise->reject(ec, ASCIILiteral("The operation failed for an operation-specific reason"));
433         return;
434     default:
435         break;
436     }
437     ASSERT_NOT_REACHED();
438 }
439
440 static void normalizeJsonWebKey(JsonWebKey& webKey)
441 {
442     // Maybe we shouldn't silently bypass duplicated usages?
443     webKey.usages = webKey.key_ops ? toCryptoKeyUsageBitmap(webKey.key_ops.value()) : 0;
444 }
445
446 // FIXME: This returns an std::optional<KeyData> and takes a promise, rather than returning an
447 // ExceptionOr<KeyData> and letting the caller handle the promise, to work around an issue where
448 // Variant types (which KeyData is) in ExceptionOr<> cause compile issues on some platforms. This
449 // should be resolved by adopting a standards compliant std::variant (see https://webkit.org/b/175583)
450 static std::optional<KeyData> toKeyData(SubtleCrypto::KeyFormat format, SubtleCrypto::KeyDataVariant&& keyDataVariant, Ref<DeferredPromise>& promise)
451 {
452     switch (format) {
453     case SubtleCrypto::KeyFormat::Spki:
454     case SubtleCrypto::KeyFormat::Pkcs8:
455     case SubtleCrypto::KeyFormat::Raw:
456         return WTF::switchOn(keyDataVariant,
457             [&promise] (JsonWebKey&) -> std::optional<KeyData> {
458                 promise->reject(Exception { TypeError });
459                 return std::nullopt;
460             },
461             [] (auto& bufferSource) -> std::optional<KeyData> {
462                 Vector<uint8_t> result;
463                 result.append(static_cast<const uint8_t*>(bufferSource->data()), bufferSource->byteLength());
464                 return KeyData { result };
465             }
466         );
467     case SubtleCrypto::KeyFormat::Jwk:
468         return WTF::switchOn(keyDataVariant,
469             [] (JsonWebKey& webKey) -> std::optional<KeyData> {
470                 normalizeJsonWebKey(webKey);
471                 return KeyData { webKey };
472             },
473             [&promise] (auto&) -> std::optional<KeyData> {
474                 promise->reject(Exception { TypeError });
475                 return std::nullopt;
476             }
477         );
478     }
479
480     RELEASE_ASSERT_NOT_REACHED();
481 }
482
483 static Vector<uint8_t> copyToVector(BufferSource&& data)
484 {
485     Vector<uint8_t> dataVector;
486     dataVector.append(data.data(), data.length());
487     return dataVector;
488 }
489
490 static bool isSupportedExportKey(CryptoAlgorithmIdentifier identifier)
491 {
492     switch (identifier) {
493     case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
494     case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
495     case CryptoAlgorithmIdentifier::RSA_PSS:
496     case CryptoAlgorithmIdentifier::RSA_OAEP:
497     case CryptoAlgorithmIdentifier::AES_CTR:
498     case CryptoAlgorithmIdentifier::AES_CBC:
499     case CryptoAlgorithmIdentifier::AES_GCM:
500     case CryptoAlgorithmIdentifier::AES_CFB:
501     case CryptoAlgorithmIdentifier::AES_KW:
502     case CryptoAlgorithmIdentifier::HMAC:
503     case CryptoAlgorithmIdentifier::ECDSA:
504     case CryptoAlgorithmIdentifier::ECDH:
505         return true;
506     default:
507         return false;
508     }
509 }
510
511
512 // MARK: - Exposed functions.
513
514 void SubtleCrypto::encrypt(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, CryptoKey& key, BufferSource&& dataBufferSource, Ref<DeferredPromise>&& promise)
515 {
516     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::Encrypt);
517     if (paramsOrException.hasException()) {
518         promise->reject(paramsOrException.releaseException());
519         return;
520     }
521     auto params = paramsOrException.releaseReturnValue();
522
523     auto data = copyToVector(WTFMove(dataBufferSource));
524
525     if (params->identifier != key.algorithmIdentifier()) {
526         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
527         return;
528     }
529
530     if (!key.allows(CryptoKeyUsageEncrypt)) {
531         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't support encryption"));
532         return;
533     }
534
535     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key.algorithmIdentifier());
536
537     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& cipherText) mutable {
538         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), cipherText.data(), cipherText.size());
539     };
540     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
541         rejectWithException(WTFMove(capturedPromise), ec);
542     };
543
544     algorithm->encrypt(WTFMove(params), key, WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext(), m_workQueue);
545 }
546
547 void SubtleCrypto::decrypt(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, CryptoKey& key, BufferSource&& dataBufferSource, Ref<DeferredPromise>&& promise)
548 {
549     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::Decrypt);
550     if (paramsOrException.hasException()) {
551         promise->reject(paramsOrException.releaseException());
552         return;
553     }
554     auto params = paramsOrException.releaseReturnValue();
555
556     auto data = copyToVector(WTFMove(dataBufferSource));
557
558     if (params->identifier != key.algorithmIdentifier()) {
559         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
560         return;
561     }
562
563     if (!key.allows(CryptoKeyUsageDecrypt)) {
564         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't support decryption"));
565         return;
566     }
567
568     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key.algorithmIdentifier());
569
570     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& plainText) mutable {
571         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), plainText.data(), plainText.size());
572     };
573     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
574         rejectWithException(WTFMove(capturedPromise), ec);
575     };
576
577     algorithm->decrypt(WTFMove(params), key, WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext(), m_workQueue);
578 }
579
580 void SubtleCrypto::sign(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, CryptoKey& key, BufferSource&& dataBufferSource, Ref<DeferredPromise>&& promise)
581 {
582     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::Sign);
583     if (paramsOrException.hasException()) {
584         promise->reject(paramsOrException.releaseException());
585         return;
586     }
587     auto params = paramsOrException.releaseReturnValue();
588
589     auto data = copyToVector(WTFMove(dataBufferSource));
590
591     if (params->identifier != key.algorithmIdentifier()) {
592         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
593         return;
594     }
595
596     if (!key.allows(CryptoKeyUsageSign)) {
597         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't support signing"));
598         return;
599     }
600
601     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key.algorithmIdentifier());
602
603     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& signature) mutable {
604         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), signature.data(), signature.size());
605     };
606     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
607         rejectWithException(WTFMove(capturedPromise), ec);
608     };
609
610     algorithm->sign(WTFMove(params), key, WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext(), m_workQueue);
611 }
612
613 void SubtleCrypto::verify(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, CryptoKey& key, BufferSource&& signatureBufferSource, BufferSource&& dataBufferSource, Ref<DeferredPromise>&& promise)
614 {
615     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::Verify);
616     if (paramsOrException.hasException()) {
617         promise->reject(paramsOrException.releaseException());
618         return;
619     }
620     auto params = paramsOrException.releaseReturnValue();
621
622     auto signature = copyToVector(WTFMove(signatureBufferSource));
623     auto data = copyToVector(WTFMove(dataBufferSource));
624
625     if (params->identifier != key.algorithmIdentifier()) {
626         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
627         return;
628     }
629
630     if (!key.allows(CryptoKeyUsageVerify)) {
631         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't support verification"));
632         return;
633     }
634
635     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key.algorithmIdentifier());
636     
637     auto callback = [capturedPromise = promise.copyRef()](bool result) mutable {
638         capturedPromise->resolve<IDLBoolean>(result);
639     };
640     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
641         rejectWithException(WTFMove(capturedPromise), ec);
642     };
643
644     algorithm->verify(WTFMove(params), key, WTFMove(signature), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext(), m_workQueue);
645 }
646
647 void SubtleCrypto::digest(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, BufferSource&& dataBufferSource, Ref<DeferredPromise>&& promise)
648 {
649     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::Digest);
650     if (paramsOrException.hasException()) {
651         promise->reject(paramsOrException.releaseException());
652         return;
653     }
654     auto params = paramsOrException.releaseReturnValue();
655
656     auto data = copyToVector(WTFMove(dataBufferSource));
657
658     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
659     
660     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& digest) mutable {
661         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), digest.data(), digest.size());
662     };
663     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
664         rejectWithException(WTFMove(capturedPromise), ec);
665     };
666
667     algorithm->digest(WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext(), m_workQueue);
668 }
669
670 void SubtleCrypto::generateKey(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, bool extractable, Vector<CryptoKeyUsage>&& keyUsages, Ref<DeferredPromise>&& promise)
671 {
672     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::GenerateKey);
673     if (paramsOrException.hasException()) {
674         promise->reject(paramsOrException.releaseException());
675         return;
676     }
677     auto params = paramsOrException.releaseReturnValue();
678
679     auto keyUsagesBitmap = toCryptoKeyUsageBitmap(keyUsages);
680
681     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
682
683     auto callback = [capturedPromise = promise.copyRef()](KeyOrKeyPair&& keyOrKeyPair) mutable {
684         WTF::switchOn(keyOrKeyPair,
685             [&capturedPromise] (RefPtr<CryptoKey>& key) {
686                 if ((key->type() == CryptoKeyType::Private || key->type() == CryptoKeyType::Secret) && !key->usagesBitmap()) {
687                     rejectWithException(WTFMove(capturedPromise), SyntaxError);
688                     return;
689                 }
690                 capturedPromise->resolve<IDLInterface<CryptoKey>>(*key);
691             },
692             [&capturedPromise] (CryptoKeyPair& keyPair) {
693                 if (!keyPair.privateKey->usagesBitmap()) {
694                     rejectWithException(WTFMove(capturedPromise), SyntaxError);
695                     return;
696                 }
697                 capturedPromise->resolve<IDLDictionary<CryptoKeyPair>>(keyPair);
698             }
699         );
700     };
701     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
702         rejectWithException(WTFMove(capturedPromise), ec);
703     };
704
705     // The 26 January 2017 version of the specification suggests we should perform the following task asynchronously
706     // regardless what kind of keys it produces: https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey
707     // That's simply not efficient for AES, HMAC and EC keys. Therefore, we perform it as an async task only for RSA keys.
708     algorithm->generateKey(*params, extractable, keyUsagesBitmap, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext());
709 }
710
711 void SubtleCrypto::deriveKey(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, CryptoKey& baseKey, AlgorithmIdentifier&& derivedKeyType, bool extractable, Vector<CryptoKeyUsage>&& keyUsages, Ref<DeferredPromise>&& promise)
712 {
713     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::DeriveBits);
714     if (paramsOrException.hasException()) {
715         promise->reject(paramsOrException.releaseException());
716         return;
717     }
718     auto params = paramsOrException.releaseReturnValue();
719
720     auto importParamsOrException = normalizeCryptoAlgorithmParameters(state, derivedKeyType, Operations::ImportKey);
721     if (importParamsOrException.hasException()) {
722         promise->reject(importParamsOrException.releaseException());
723         return;
724     }
725     auto importParams = importParamsOrException.releaseReturnValue();
726
727     auto getLengthParamsOrException = normalizeCryptoAlgorithmParameters(state, derivedKeyType, Operations::GetKeyLength);
728     if (getLengthParamsOrException.hasException()) {
729         promise->reject(getLengthParamsOrException.releaseException());
730         return;
731     }
732     auto getLengthParams = getLengthParamsOrException.releaseReturnValue();
733
734     auto keyUsagesBitmap = toCryptoKeyUsageBitmap(keyUsages);
735
736     if (params->identifier != baseKey.algorithmIdentifier()) {
737         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
738         return;
739     }
740
741     if (!baseKey.allows(CryptoKeyUsageDeriveKey)) {
742         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't support CryptoKey derivation"));
743         return;
744     }
745
746     auto getLengthAlgorithm = CryptoAlgorithmRegistry::singleton().create(getLengthParams->identifier);
747
748     auto result = getLengthAlgorithm->getKeyLength(*getLengthParams);
749     if (result.hasException()) {
750         promise->reject(result.releaseException().code(), ASCIILiteral("Cannot get key length from derivedKeyType"));
751         return;
752     }
753     size_t length = result.releaseReturnValue();
754
755     auto importAlgorithm = CryptoAlgorithmRegistry::singleton().create(importParams->identifier);
756     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
757
758     auto callback = [promise = promise.copyRef(), importAlgorithm, importParams = WTFMove(importParams), extractable, keyUsagesBitmap](const Vector<uint8_t>& derivedKey) mutable {
759         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=169395
760         KeyData data = derivedKey;
761         auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable {
762             if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
763                 rejectWithException(WTFMove(capturedPromise), SyntaxError);
764                 return;
765             }
766             capturedPromise->resolve<IDLInterface<CryptoKey>>(key);
767         };
768         auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
769             rejectWithException(WTFMove(capturedPromise), ec);
770         };
771
772         importAlgorithm->importKey(SubtleCrypto::KeyFormat::Raw, WTFMove(data), WTFMove(importParams), extractable, keyUsagesBitmap, WTFMove(callback), WTFMove(exceptionCallback));
773     };
774     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
775         rejectWithException(WTFMove(capturedPromise), ec);
776     };
777
778     algorithm->deriveBits(WTFMove(params), baseKey, length, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext(), m_workQueue);
779 }
780
781 void SubtleCrypto::deriveBits(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, CryptoKey& baseKey, unsigned length, Ref<DeferredPromise>&& promise)
782 {
783     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::DeriveBits);
784     if (paramsOrException.hasException()) {
785         promise->reject(paramsOrException.releaseException());
786         return;
787     }
788     auto params = paramsOrException.releaseReturnValue();
789
790     if (params->identifier != baseKey.algorithmIdentifier()) {
791         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
792         return;
793     }
794
795     if (!baseKey.allows(CryptoKeyUsageDeriveBits)) {
796         promise->reject(InvalidAccessError, ASCIILiteral("CryptoKey doesn't support bits derivation"));
797         return;
798     }
799
800     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
801
802     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& derivedKey) mutable {
803         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), derivedKey.data(), derivedKey.size());
804     };
805     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
806         rejectWithException(WTFMove(capturedPromise), ec);
807     };
808
809     algorithm->deriveBits(WTFMove(params), baseKey, length, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext(), m_workQueue);
810 }
811
812 void SubtleCrypto::importKey(JSC::ExecState& state, KeyFormat format, KeyDataVariant&& keyDataVariant, AlgorithmIdentifier&& algorithmIdentifier, bool extractable, Vector<CryptoKeyUsage>&& keyUsages, Ref<DeferredPromise>&& promise)
813 {
814     auto paramsOrException = normalizeCryptoAlgorithmParameters(state, WTFMove(algorithmIdentifier), Operations::ImportKey);
815     if (paramsOrException.hasException()) {
816         promise->reject(paramsOrException.releaseException());
817         return;
818     }
819     auto params = paramsOrException.releaseReturnValue();
820
821     auto keyDataOrNull = toKeyData(format, WTFMove(keyDataVariant), promise);
822     if (!keyDataOrNull) {
823         // When toKeyData, it means the promise has been rejected, and we should return.
824         return;
825     }
826
827     auto keyData = *keyDataOrNull;
828     auto keyUsagesBitmap = toCryptoKeyUsageBitmap(keyUsages);
829
830     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
831
832     auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable {
833         if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
834             rejectWithException(WTFMove(capturedPromise), SyntaxError);
835             return;
836         }
837         capturedPromise->resolve<IDLInterface<CryptoKey>>(key);
838     };
839     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
840         rejectWithException(WTFMove(capturedPromise), ec);
841     };
842
843     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
844     // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey
845     // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
846     algorithm->importKey(format, WTFMove(keyData), WTFMove(params), extractable, keyUsagesBitmap, WTFMove(callback), WTFMove(exceptionCallback));
847 }
848
849 void SubtleCrypto::exportKey(KeyFormat format, CryptoKey& key, Ref<DeferredPromise>&& promise)
850 {
851     if (!isSupportedExportKey(key.algorithmIdentifier())) {
852         promise->reject(Exception { NotSupportedError });
853         return;
854     }
855
856     if (!key.extractable()) {
857         promise->reject(InvalidAccessError, ASCIILiteral("The CryptoKey is nonextractable"));
858         return;
859     }
860
861     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key.algorithmIdentifier());
862
863     auto callback = [capturedPromise = promise.copyRef()](SubtleCrypto::KeyFormat format, KeyData&& key) mutable {
864         switch (format) {
865         case SubtleCrypto::KeyFormat::Spki:
866         case SubtleCrypto::KeyFormat::Pkcs8:
867         case SubtleCrypto::KeyFormat::Raw: {
868             Vector<uint8_t>& rawKey = WTF::get<Vector<uint8_t>>(key);
869             fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), rawKey.data(), rawKey.size());
870             return;
871         }
872         case SubtleCrypto::KeyFormat::Jwk:
873             capturedPromise->resolve<IDLDictionary<JsonWebKey>>(WTFMove(WTF::get<JsonWebKey>(key)));
874             return;
875         }
876         ASSERT_NOT_REACHED();
877     };
878     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
879         rejectWithException(WTFMove(capturedPromise), ec);
880     };
881
882     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
883     // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey
884     // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
885     algorithm->exportKey(format, key, WTFMove(callback), WTFMove(exceptionCallback));
886 }
887
888 void SubtleCrypto::wrapKey(JSC::ExecState& state, KeyFormat format, CryptoKey& key, CryptoKey& wrappingKey, AlgorithmIdentifier&& wrapAlgorithmIdentifier, Ref<DeferredPromise>&& promise)
889 {
890     bool isEncryption = false;
891
892     auto wrapParamsOrException = normalizeCryptoAlgorithmParameters(state, wrapAlgorithmIdentifier, Operations::WrapKey);
893     if (wrapParamsOrException.hasException()) {
894         ASSERT(wrapParamsOrException.exception().code() != ExistingExceptionError);
895
896         wrapParamsOrException = normalizeCryptoAlgorithmParameters(state, wrapAlgorithmIdentifier, Operations::Encrypt);
897         if (wrapParamsOrException.hasException()) {
898             promise->reject(wrapParamsOrException.releaseException());
899             return;
900         }
901
902         isEncryption = true;
903     }
904     auto wrapParams = wrapParamsOrException.releaseReturnValue();
905
906     if (wrapParams->identifier != wrappingKey.algorithmIdentifier()) {
907         promise->reject(InvalidAccessError, ASCIILiteral("Wrapping CryptoKey doesn't match AlgorithmIdentifier"));
908         return;
909     }
910
911     if (!wrappingKey.allows(CryptoKeyUsageWrapKey)) {
912         promise->reject(InvalidAccessError, ASCIILiteral("Wrapping CryptoKey doesn't support wrapKey operation"));
913         return;
914     }
915
916     if (!isSupportedExportKey(key.algorithmIdentifier())) {
917         promise->reject(Exception { NotSupportedError });
918         return;
919     }
920
921     if (!key.extractable()) {
922         promise->reject(InvalidAccessError, ASCIILiteral("The CryptoKey is nonextractable"));
923         return;
924     }
925
926     auto exportAlgorithm = CryptoAlgorithmRegistry::singleton().create(key.algorithmIdentifier());
927     auto wrapAlgorithm = CryptoAlgorithmRegistry::singleton().create(wrappingKey.algorithmIdentifier());
928
929     auto context = scriptExecutionContext();
930
931     auto callback = [promise = promise.copyRef(), wrapAlgorithm, wrappingKey = makeRef(wrappingKey), wrapParams = WTFMove(wrapParams), isEncryption, context, workQueue = m_workQueue.copyRef()](SubtleCrypto::KeyFormat format, KeyData&& key) mutable {
932         Vector<uint8_t> bytes;
933         switch (format) {
934         case SubtleCrypto::KeyFormat::Spki:
935         case SubtleCrypto::KeyFormat::Pkcs8:
936         case SubtleCrypto::KeyFormat::Raw:
937             bytes = WTF::get<Vector<uint8_t>>(key);
938             break;
939         case SubtleCrypto::KeyFormat::Jwk: {
940             // FIXME: Converting to JS just to JSON-Stringify seems inefficient. We should find a way to go directly from the struct to JSON.
941             auto jwk = toJS<IDLDictionary<JsonWebKey>>(*(promise->globalObject()->globalExec()), *(promise->globalObject()), WTFMove(WTF::get<JsonWebKey>(key)));
942             String jwkString = JSONStringify(promise->globalObject()->globalExec(), jwk, 0);
943             CString jwkUtf8String = jwkString.utf8(StrictConversion);
944             bytes.append(jwkUtf8String.data(), jwkUtf8String.length());
945         }
946         }
947
948         auto callback = [promise = promise.copyRef()](const Vector<uint8_t>& wrappedKey) mutable {
949             fulfillPromiseWithArrayBuffer(WTFMove(promise), wrappedKey.data(), wrappedKey.size());
950             return;
951         };
952         auto exceptionCallback = [promise = WTFMove(promise)](ExceptionCode ec) mutable {
953             rejectWithException(WTFMove(promise), ec);
954         };
955
956         if (!isEncryption) {
957             // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
958             // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey
959             // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
960             wrapAlgorithm->wrapKey(wrappingKey.get(), WTFMove(bytes), WTFMove(callback), WTFMove(exceptionCallback));
961             return;
962         }
963         // The following operation should be performed asynchronously.
964         wrapAlgorithm->encrypt(WTFMove(wrapParams), WTFMove(wrappingKey), WTFMove(bytes), WTFMove(callback), WTFMove(exceptionCallback), *context, workQueue);
965     };
966     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
967         rejectWithException(WTFMove(capturedPromise), ec);
968     };
969
970     // The following operation should be performed synchronously.
971     exportAlgorithm->exportKey(format, key, WTFMove(callback), WTFMove(exceptionCallback));
972 }
973
974 void SubtleCrypto::unwrapKey(JSC::ExecState& state, KeyFormat format, BufferSource&& wrappedKeyBufferSource, CryptoKey& unwrappingKey, AlgorithmIdentifier&& unwrapAlgorithmIdentifier, AlgorithmIdentifier&& unwrappedKeyAlgorithmIdentifier, bool extractable, Vector<CryptoKeyUsage>&& keyUsages, Ref<DeferredPromise>&& promise)
975 {
976     auto wrappedKey = copyToVector(WTFMove(wrappedKeyBufferSource));
977
978     bool isDecryption = false;
979
980     auto unwrapParamsOrException = normalizeCryptoAlgorithmParameters(state, unwrapAlgorithmIdentifier, Operations::UnwrapKey);
981     if (unwrapParamsOrException.hasException()) {
982         ASSERT(unwrapParamsOrException.exception().code() != ExistingExceptionError);
983
984         unwrapParamsOrException = normalizeCryptoAlgorithmParameters(state, unwrapAlgorithmIdentifier, Operations::Decrypt);
985         if (unwrapParamsOrException.hasException()) {
986             promise->reject(unwrapParamsOrException.releaseException());
987             return;
988         }
989
990         isDecryption = true;
991     }
992     auto unwrapParams = unwrapParamsOrException.releaseReturnValue();
993
994     auto unwrappedKeyAlgorithmOrException = normalizeCryptoAlgorithmParameters(state, unwrappedKeyAlgorithmIdentifier, Operations::ImportKey);
995     if (unwrappedKeyAlgorithmOrException.hasException()) {
996         promise->reject(unwrappedKeyAlgorithmOrException.releaseException());
997         return;
998     }
999     auto unwrappedKeyAlgorithm = unwrappedKeyAlgorithmOrException.releaseReturnValue();
1000
1001     auto keyUsagesBitmap = toCryptoKeyUsageBitmap(keyUsages);
1002
1003     if (unwrapParams->identifier != unwrappingKey.algorithmIdentifier()) {
1004         promise->reject(InvalidAccessError, ASCIILiteral("Unwrapping CryptoKey doesn't match unwrap AlgorithmIdentifier"));
1005         return;
1006     }
1007
1008     if (!unwrappingKey.allows(CryptoKeyUsageUnwrapKey)) {
1009         promise->reject(InvalidAccessError, ASCIILiteral("Unwrapping CryptoKey doesn't support unwrapKey operation"));
1010         return;
1011     }
1012
1013     auto importAlgorithm = CryptoAlgorithmRegistry::singleton().create(unwrappedKeyAlgorithm->identifier);
1014     if (UNLIKELY(!importAlgorithm)) {
1015         promise->reject(Exception { NotSupportedError });
1016         return;
1017     }
1018
1019     auto unwrapAlgorithm = CryptoAlgorithmRegistry::singleton().create(unwrappingKey.algorithmIdentifier());
1020     if (UNLIKELY(!unwrapAlgorithm)) {
1021         promise->reject(Exception { NotSupportedError });
1022         return;
1023     }
1024
1025     auto callback = [promise = promise.copyRef(), format, importAlgorithm, unwrappedKeyAlgorithm = WTFMove(unwrappedKeyAlgorithm), extractable, keyUsagesBitmap](const Vector<uint8_t>& bytes) mutable {
1026         KeyData keyData;
1027         switch (format) {
1028         case SubtleCrypto::KeyFormat::Spki:
1029         case SubtleCrypto::KeyFormat::Pkcs8:
1030         case SubtleCrypto::KeyFormat::Raw:
1031             keyData = bytes;
1032             break;
1033         case SubtleCrypto::KeyFormat::Jwk: {
1034             auto& state = *(promise->globalObject()->globalExec());
1035             auto& vm = state.vm();
1036             auto scope = DECLARE_THROW_SCOPE(vm);
1037
1038             String jwkString(reinterpret_cast_ptr<const char*>(bytes.data()), bytes.size());
1039             JSLockHolder locker(vm);
1040             auto jwkObject = JSONParse(&state, jwkString);
1041             if (!jwkObject) {
1042                 promise->reject(DataError, ASCIILiteral("WrappedKey cannot be converted to a JSON object"));
1043                 return;
1044             }
1045             auto jwk = convert<IDLDictionary<JsonWebKey>>(state, jwkObject);
1046             RETURN_IF_EXCEPTION(scope, void());
1047             normalizeJsonWebKey(jwk);
1048
1049             keyData = jwk;
1050             break;
1051         }
1052         }
1053
1054         auto callback = [promise = promise.copyRef()](CryptoKey& key) mutable {
1055             if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
1056                 rejectWithException(WTFMove(promise), SyntaxError);
1057                 return;
1058             }
1059             promise->resolve<IDLInterface<CryptoKey>>(key);
1060         };
1061         auto exceptionCallback = [promise = WTFMove(promise)](ExceptionCode ec) mutable {
1062             rejectWithException(WTFMove(promise), ec);
1063         };
1064
1065         // The following operation should be performed synchronously.
1066         importAlgorithm->importKey(format, WTFMove(keyData), WTFMove(unwrappedKeyAlgorithm), extractable, keyUsagesBitmap, WTFMove(callback), WTFMove(exceptionCallback));
1067     };
1068     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
1069         rejectWithException(WTFMove(capturedPromise), ec);
1070     };
1071
1072     if (!isDecryption) {
1073         // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
1074         // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-unwrapKey
1075         // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
1076         unwrapAlgorithm->unwrapKey(unwrappingKey, WTFMove(wrappedKey), WTFMove(callback), WTFMove(exceptionCallback));
1077         return;
1078     }
1079
1080     unwrapAlgorithm->decrypt(WTFMove(unwrapParams), unwrappingKey, WTFMove(wrappedKey), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContext(), m_workQueue);
1081 }
1082
1083 }
1084
1085 #endif