[WebIDL] Remove some unnecessary specialization for enum types
[WebKit.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 "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 "ScriptState.h"
54 #include <runtime/Error.h>
55 #include <runtime/JSArray.h>
56 #include <runtime/JSONObject.h>
57
58 using namespace JSC;
59
60 namespace WebCore {
61
62 enum class Operations {
63     Encrypt,
64     Decrypt,
65     Sign,
66     Verify,
67     Digest,
68     GenerateKey,
69     DeriveBits,
70     ImportKey,
71     WrapKey,
72     UnwrapKey,
73     GetKeyLength
74 };
75
76 static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParameters(ExecState&, JSValue, Operations);
77
78 static CryptoAlgorithmIdentifier toHashIdentifier(ExecState& state, JSValue value)
79 {
80     VM& vm = state.vm();
81     auto scope = DECLARE_THROW_SCOPE(vm);
82
83     auto digestParams = normalizeCryptoAlgorithmParameters(state, value, Operations::Digest);
84     RETURN_IF_EXCEPTION(scope, { });
85     return digestParams->identifier;
86 }
87
88 static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParameters(ExecState& state, JSValue value, Operations operation)
89 {
90     VM& vm = state.vm();
91     auto scope = DECLARE_THROW_SCOPE(vm);
92
93     if (value.isString()) {
94         JSObject* newParams = constructEmptyObject(&state);
95         newParams->putDirect(vm, Identifier::fromString(&vm, "name"), value);
96         return normalizeCryptoAlgorithmParameters(state, newParams, operation);
97     }
98
99     if (value.isObject()) {
100         auto params = convertDictionary<CryptoAlgorithmParameters>(state, value);
101         RETURN_IF_EXCEPTION(scope, nullptr);
102
103         auto identifier = CryptoAlgorithmRegistry::singleton().identifier(params.name);
104         if (UNLIKELY(!identifier)) {
105             throwNotSupportedError(state, scope);
106             return nullptr;
107         }
108
109         std::unique_ptr<CryptoAlgorithmParameters> result;
110         switch (operation) {
111         case Operations::Encrypt:
112         case Operations::Decrypt:
113             switch (*identifier) {
114             case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
115                 result = std::make_unique<CryptoAlgorithmParameters>(params);
116                 break;
117             case CryptoAlgorithmIdentifier::RSA_OAEP: {
118                 auto params = convertDictionary<CryptoAlgorithmRsaOaepParams>(state, value);
119                 RETURN_IF_EXCEPTION(scope, nullptr);
120                 result = std::make_unique<CryptoAlgorithmRsaOaepParams>(params);
121                 break;
122             }
123             case CryptoAlgorithmIdentifier::AES_CBC:
124             case CryptoAlgorithmIdentifier::AES_CFB: {
125                 auto params = convertDictionary<CryptoAlgorithmAesCbcCfbParams>(state, value);
126                 RETURN_IF_EXCEPTION(scope, nullptr);
127                 result = std::make_unique<CryptoAlgorithmAesCbcCfbParams>(params);
128                 break;
129             }
130             case CryptoAlgorithmIdentifier::AES_CTR: {
131                 auto params = convertDictionary<CryptoAlgorithmAesCtrParams>(state, value);
132                 RETURN_IF_EXCEPTION(scope, nullptr);
133                 result = std::make_unique<CryptoAlgorithmAesCtrParams>(params);
134                 break;
135             }
136             case CryptoAlgorithmIdentifier::AES_GCM: {
137                 auto params = convertDictionary<CryptoAlgorithmAesGcmParams>(state, value);
138                 RETURN_IF_EXCEPTION(scope, nullptr);
139                 result = std::make_unique<CryptoAlgorithmAesGcmParams>(params);
140                 break;
141             }
142             default:
143                 throwNotSupportedError(state, scope);
144                 return nullptr;
145             }
146             break;
147         case Operations::Sign:
148         case Operations::Verify:
149             switch (*identifier) {
150             case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
151             case CryptoAlgorithmIdentifier::HMAC:
152                 result = std::make_unique<CryptoAlgorithmParameters>(params);
153                 break;
154             case CryptoAlgorithmIdentifier::ECDSA: {
155                 auto params = convertDictionary<CryptoAlgorithmEcdsaParams>(state, value);
156                 RETURN_IF_EXCEPTION(scope, nullptr);
157                 params.hashIdentifier = toHashIdentifier(state, params.hash);
158                 RETURN_IF_EXCEPTION(scope, nullptr);
159                 result = std::make_unique<CryptoAlgorithmEcdsaParams>(params);
160                 break;
161
162             }
163             default:
164                 throwNotSupportedError(state, scope);
165                 return nullptr;
166             }
167             break;
168         case Operations::Digest:
169             switch (*identifier) {
170             case CryptoAlgorithmIdentifier::SHA_1:
171             case CryptoAlgorithmIdentifier::SHA_224:
172             case CryptoAlgorithmIdentifier::SHA_256:
173             case CryptoAlgorithmIdentifier::SHA_384:
174             case CryptoAlgorithmIdentifier::SHA_512:
175                 result = std::make_unique<CryptoAlgorithmParameters>(params);
176                 break;
177             default:
178                 throwNotSupportedError(state, scope);
179                 return nullptr;
180             }
181             break;
182         case Operations::GenerateKey:
183             switch (*identifier) {
184             case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: {
185                 auto params = convertDictionary<CryptoAlgorithmRsaKeyGenParams>(state, value);
186                 RETURN_IF_EXCEPTION(scope, nullptr);
187                 result = std::make_unique<CryptoAlgorithmRsaKeyGenParams>(params);
188                 break;
189             }
190             case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
191             case CryptoAlgorithmIdentifier::RSA_PSS:
192             case CryptoAlgorithmIdentifier::RSA_OAEP: {
193                 auto params = convertDictionary<CryptoAlgorithmRsaHashedKeyGenParams>(state, value);
194                 RETURN_IF_EXCEPTION(scope, nullptr);
195                 params.hashIdentifier = toHashIdentifier(state, params.hash);
196                 RETURN_IF_EXCEPTION(scope, nullptr);
197                 result = std::make_unique<CryptoAlgorithmRsaHashedKeyGenParams>(params);
198                 break;
199             }
200             case CryptoAlgorithmIdentifier::AES_CTR:
201             case CryptoAlgorithmIdentifier::AES_CBC:
202             case CryptoAlgorithmIdentifier::AES_CMAC:
203             case CryptoAlgorithmIdentifier::AES_GCM:
204             case CryptoAlgorithmIdentifier::AES_CFB:
205             case CryptoAlgorithmIdentifier::AES_KW: {
206                 auto params = convertDictionary<CryptoAlgorithmAesKeyParams>(state, value);
207                 RETURN_IF_EXCEPTION(scope, nullptr);
208                 result = std::make_unique<CryptoAlgorithmAesKeyParams>(params);
209                 break;
210             }
211             case CryptoAlgorithmIdentifier::HMAC: {
212                 auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value);
213                 RETURN_IF_EXCEPTION(scope, nullptr);
214                 params.hashIdentifier = toHashIdentifier(state, params.hash);
215                 RETURN_IF_EXCEPTION(scope, nullptr);
216                 result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
217                 break;
218             }
219             case CryptoAlgorithmIdentifier::ECDSA:
220             case CryptoAlgorithmIdentifier::ECDH: {
221                 auto params = convertDictionary<CryptoAlgorithmEcKeyParams>(state, value);
222                 RETURN_IF_EXCEPTION(scope, nullptr);
223                 result = std::make_unique<CryptoAlgorithmEcKeyParams>(params);
224                 break;
225             }
226             default:
227                 throwNotSupportedError(state, scope);
228                 return nullptr;
229             }
230             break;
231         case Operations::DeriveBits:
232             switch (*identifier) {
233             case CryptoAlgorithmIdentifier::ECDH: {
234                 // Remove this hack once https://bugs.webkit.org/show_bug.cgi?id=169333 is fixed.
235                 JSValue nameValue = value.getObject()->get(&state, Identifier::fromString(&state, "name"));
236                 JSValue publicValue = value.getObject()->get(&state, Identifier::fromString(&state, "public"));
237                 JSObject* newValue = constructEmptyObject(&state);
238                 newValue->putDirect(vm, Identifier::fromString(&vm, "name"), nameValue);
239                 newValue->putDirect(vm, Identifier::fromString(&vm, "publicKey"), publicValue);
240
241                 auto params = convertDictionary<CryptoAlgorithmEcdhKeyDeriveParams>(state, newValue);
242                 RETURN_IF_EXCEPTION(scope, nullptr);
243                 result = std::make_unique<CryptoAlgorithmEcdhKeyDeriveParams>(params);
244                 break;
245             }
246             case CryptoAlgorithmIdentifier::HKDF: {
247                 auto params = convertDictionary<CryptoAlgorithmHkdfParams>(state, value);
248                 RETURN_IF_EXCEPTION(scope, nullptr);
249                 params.hashIdentifier = toHashIdentifier(state, params.hash);
250                 RETURN_IF_EXCEPTION(scope, nullptr);
251                 result = std::make_unique<CryptoAlgorithmHkdfParams>(params);
252                 break;
253             }
254             case CryptoAlgorithmIdentifier::PBKDF2: {
255                 auto params = convertDictionary<CryptoAlgorithmPbkdf2Params>(state, value);
256                 RETURN_IF_EXCEPTION(scope, nullptr);
257                 params.hashIdentifier = toHashIdentifier(state, params.hash);
258                 RETURN_IF_EXCEPTION(scope, nullptr);
259                 result = std::make_unique<CryptoAlgorithmPbkdf2Params>(params);
260                 break;
261             }
262             default:
263                 throwNotSupportedError(state, scope);
264                 return nullptr;
265             }
266             break;
267         case Operations::ImportKey:
268             switch (*identifier) {
269             case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
270                 result = std::make_unique<CryptoAlgorithmParameters>(params);
271                 break;
272             case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
273             case CryptoAlgorithmIdentifier::RSA_PSS:
274             case CryptoAlgorithmIdentifier::RSA_OAEP: {
275                 auto params = convertDictionary<CryptoAlgorithmRsaHashedImportParams>(state, value);
276                 RETURN_IF_EXCEPTION(scope, nullptr);
277                 params.hashIdentifier = toHashIdentifier(state, params.hash);
278                 RETURN_IF_EXCEPTION(scope, nullptr);
279                 result = std::make_unique<CryptoAlgorithmRsaHashedImportParams>(params);
280                 break;
281             }
282             case CryptoAlgorithmIdentifier::AES_CTR:
283             case CryptoAlgorithmIdentifier::AES_CBC:
284             case CryptoAlgorithmIdentifier::AES_CMAC:
285             case CryptoAlgorithmIdentifier::AES_GCM:
286             case CryptoAlgorithmIdentifier::AES_CFB:
287             case CryptoAlgorithmIdentifier::AES_KW:
288                 result = std::make_unique<CryptoAlgorithmParameters>(params);
289                 break;
290             case CryptoAlgorithmIdentifier::HMAC: {
291                 auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value);
292                 RETURN_IF_EXCEPTION(scope, nullptr);
293                 params.hashIdentifier = toHashIdentifier(state, params.hash);
294                 RETURN_IF_EXCEPTION(scope, nullptr);
295                 result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
296                 break;
297             }
298             case CryptoAlgorithmIdentifier::ECDSA:
299             case CryptoAlgorithmIdentifier::ECDH: {
300                 auto params = convertDictionary<CryptoAlgorithmEcKeyParams>(state, value);
301                 RETURN_IF_EXCEPTION(scope, nullptr);
302                 result = std::make_unique<CryptoAlgorithmEcKeyParams>(params);
303                 break;
304             }
305             case CryptoAlgorithmIdentifier::HKDF:
306             case CryptoAlgorithmIdentifier::PBKDF2:
307                 result = std::make_unique<CryptoAlgorithmParameters>(params);
308                 break;
309             default:
310                 throwNotSupportedError(state, scope);
311                 return nullptr;
312             }
313             break;
314         case Operations::WrapKey:
315         case Operations::UnwrapKey:
316             switch (*identifier) {
317             case CryptoAlgorithmIdentifier::AES_KW:
318                 result = std::make_unique<CryptoAlgorithmParameters>(params);
319                 break;
320             default:
321                 throwNotSupportedError(state, scope);
322                 return nullptr;
323             }
324             break;
325         case Operations::GetKeyLength:
326             switch (*identifier) {
327             case CryptoAlgorithmIdentifier::AES_CTR:
328             case CryptoAlgorithmIdentifier::AES_CBC:
329             case CryptoAlgorithmIdentifier::AES_CMAC:
330             case CryptoAlgorithmIdentifier::AES_GCM:
331             case CryptoAlgorithmIdentifier::AES_CFB:
332             case CryptoAlgorithmIdentifier::AES_KW: {
333                 auto params = convertDictionary<CryptoAlgorithmAesKeyParams>(state, value);
334                 RETURN_IF_EXCEPTION(scope, nullptr);
335                 result = std::make_unique<CryptoAlgorithmAesKeyParams>(params);
336                 break;
337             }
338             case CryptoAlgorithmIdentifier::HMAC: {
339                 auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value);
340                 RETURN_IF_EXCEPTION(scope, nullptr);
341                 params.hashIdentifier = toHashIdentifier(state, params.hash);
342                 RETURN_IF_EXCEPTION(scope, nullptr);
343                 result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params);
344                 break;
345             }
346             case CryptoAlgorithmIdentifier::HKDF:
347             case CryptoAlgorithmIdentifier::PBKDF2:
348                 result = std::make_unique<CryptoAlgorithmParameters>(params);
349                 break;
350             default:
351                 throwNotSupportedError(state, scope);
352                 return nullptr;
353             }
354             break;
355         default:
356             ASSERT_NOT_REACHED();
357             return nullptr;
358         }
359
360         result->identifier = *identifier;
361         return result;
362     }
363
364     throwTypeError(&state, scope, ASCIILiteral("Invalid AlgorithmIdentifier"));
365     return nullptr;
366 }
367
368 static CryptoKeyUsageBitmap toCryptoKeyUsageBitmap(CryptoKeyUsage usage)
369 {
370     switch (usage) {
371     case CryptoKeyUsage::Encrypt:
372         return CryptoKeyUsageEncrypt;
373     case CryptoKeyUsage::Decrypt:
374         return CryptoKeyUsageDecrypt;
375     case CryptoKeyUsage::Sign:
376         return CryptoKeyUsageSign;
377     case CryptoKeyUsage::Verify:
378         return CryptoKeyUsageVerify;
379     case CryptoKeyUsage::DeriveKey:
380         return CryptoKeyUsageDeriveKey;
381     case CryptoKeyUsage::DeriveBits:
382         return CryptoKeyUsageDeriveBits;
383     case CryptoKeyUsage::WrapKey:
384         return CryptoKeyUsageWrapKey;
385     case CryptoKeyUsage::UnwrapKey:
386         return CryptoKeyUsageUnwrapKey;
387     }
388
389     ASSERT_NOT_REACHED();
390     return 0;
391 }
392
393 static CryptoKeyUsageBitmap cryptoKeyUsageBitmapFromJSValue(ExecState& state, JSValue value)
394 {
395     VM& vm = state.vm();
396     auto scope = DECLARE_THROW_SCOPE(vm);
397
398     CryptoKeyUsageBitmap result = 0;
399     auto usages = convert<IDLSequence<IDLEnumeration<CryptoKeyUsage>>>(state, value);
400     RETURN_IF_EXCEPTION(scope, 0);
401     // Maybe we shouldn't silently bypass duplicated usages?
402     for (auto usage : usages)
403         result |= toCryptoKeyUsageBitmap(usage);
404
405     return result;
406 }
407
408 // Maybe we want more specific error messages?
409 static void rejectWithException(Ref<DeferredPromise>&& passedPromise, ExceptionCode ec)
410 {
411     switch (ec) {
412     case NOT_SUPPORTED_ERR:
413         passedPromise->reject(ec, ASCIILiteral("The algorithm is not supported"));
414         return;
415     case SYNTAX_ERR:
416         passedPromise->reject(ec, ASCIILiteral("A required parameter was missing or out-of-range"));
417         return;
418     case INVALID_STATE_ERR:
419         passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the current state of the provided key"));
420         return;
421     case INVALID_ACCESS_ERR:
422         passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the provided key"));
423         return;
424     case UnknownError:
425         passedPromise->reject(ec, ASCIILiteral("The operation failed for an unknown transient reason (e.g. out of memory)"));
426         return;
427     case DataError:
428         passedPromise->reject(ec, ASCIILiteral("Data provided to an operation does not meet requirements"));
429         return;
430     case OperationError:
431         passedPromise->reject(ec, ASCIILiteral("The operation failed for an operation-specific reason"));
432         return;
433     }
434     ASSERT_NOT_REACHED();
435 }
436
437 static KeyData toKeyData(ExecState& state, SubtleCrypto::KeyFormat format, JSValue value)
438 {
439     VM& vm = state.vm();
440     auto scope = DECLARE_THROW_SCOPE(vm);
441
442     KeyData result;
443     switch (format) {
444     case SubtleCrypto::KeyFormat::Spki:
445     case SubtleCrypto::KeyFormat::Pkcs8:
446     case SubtleCrypto::KeyFormat::Raw: {
447         BufferSource bufferSource = convert<IDLBufferSource>(state, value);
448         RETURN_IF_EXCEPTION(scope, result);
449         Vector<uint8_t> vector;
450         vector.append(bufferSource.data(), bufferSource.length());
451         result = WTFMove(vector);
452         return result;
453     }
454     case SubtleCrypto::KeyFormat::Jwk: {
455         result = convertDictionary<JsonWebKey>(state, value);
456         RETURN_IF_EXCEPTION(scope, result);
457         CryptoKeyUsageBitmap usages = 0;
458         if (WTF::get<JsonWebKey>(result).key_ops) {
459             // Maybe we shouldn't silently bypass duplicated usages?
460             for (auto usage : WTF::get<JsonWebKey>(result).key_ops.value())
461                 usages |= toCryptoKeyUsageBitmap(usage);
462         }
463         WTF::get<JsonWebKey>(result).usages = usages;
464         return result;
465     }
466     }
467     ASSERT_NOT_REACHED();
468     return result;
469 }
470
471 static RefPtr<CryptoKey> toCryptoKey(ExecState& state, JSValue value)
472 {
473     VM& vm = state.vm();
474     auto scope = DECLARE_THROW_SCOPE(vm);
475
476     RefPtr<CryptoKey> result = JSCryptoKey::toWrapped(vm, value);
477     if (!result) {
478         throwTypeError(&state, scope, ASCIILiteral("Invalid CryptoKey"));
479         return nullptr;
480     }
481     return result;
482 }
483
484 static Vector<uint8_t> toVector(ExecState& state, JSValue value)
485 {
486     VM& vm = state.vm();
487     auto scope = DECLARE_THROW_SCOPE(vm);
488
489     BufferSource data = convert<IDLBufferSource>(state, value);
490     RETURN_IF_EXCEPTION(scope, { });
491     Vector<uint8_t> dataVector;
492     dataVector.append(data.data(), data.length());
493
494     return dataVector;
495 }
496
497 static void supportExportKeyThrow(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier identifier)
498 {
499     switch (identifier) {
500     case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
501     case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
502     case CryptoAlgorithmIdentifier::RSA_PSS:
503     case CryptoAlgorithmIdentifier::RSA_OAEP:
504     case CryptoAlgorithmIdentifier::AES_CTR:
505     case CryptoAlgorithmIdentifier::AES_CBC:
506     case CryptoAlgorithmIdentifier::AES_CMAC:
507     case CryptoAlgorithmIdentifier::AES_GCM:
508     case CryptoAlgorithmIdentifier::AES_CFB:
509     case CryptoAlgorithmIdentifier::AES_KW:
510     case CryptoAlgorithmIdentifier::HMAC:
511     case CryptoAlgorithmIdentifier::ECDSA:
512     case CryptoAlgorithmIdentifier::ECDH:
513         return;
514     default:
515         throwNotSupportedError(state, scope);
516     }
517 }
518
519 static void jsSubtleCryptoFunctionEncryptPromise(ExecState& state, Ref<DeferredPromise>&& promise)
520 {
521     VM& vm = state.vm();
522     auto scope = DECLARE_THROW_SCOPE(vm);
523
524     if (UNLIKELY(state.argumentCount() < 3)) {
525         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
526         return;
527     }
528
529     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Encrypt);
530     RETURN_IF_EXCEPTION(scope, void());
531
532     auto key = toCryptoKey(state, state.uncheckedArgument(1));
533     RETURN_IF_EXCEPTION(scope, void());
534
535     auto data = toVector(state, state.uncheckedArgument(2));
536     RETURN_IF_EXCEPTION(scope, void());
537
538     if (params->identifier != key->algorithmIdentifier()) {
539         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
540         return;
541     }
542
543     if (!key->allows(CryptoKeyUsageEncrypt)) {
544         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support encryption"));
545         return;
546     }
547
548     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier());
549     if (UNLIKELY(!algorithm)) {
550         throwNotSupportedError(state, scope);
551         return;
552     }
553
554     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& cipherText) mutable {
555         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), cipherText.data(), cipherText.size());
556     };
557     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
558         rejectWithException(WTFMove(capturedPromise), ec);
559     };
560
561     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
562     ASSERT(subtle);
563     algorithm->encrypt(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
564 }
565
566 static void jsSubtleCryptoFunctionDecryptPromise(ExecState& state, Ref<DeferredPromise>&& promise)
567 {
568     VM& vm = state.vm();
569     auto scope = DECLARE_THROW_SCOPE(vm);
570
571     if (UNLIKELY(state.argumentCount() < 3)) {
572         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
573         return;
574     }
575
576     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Decrypt);
577     RETURN_IF_EXCEPTION(scope, void());
578
579     auto key = toCryptoKey(state, state.uncheckedArgument(1));
580     RETURN_IF_EXCEPTION(scope, void());
581
582     auto data = toVector(state, state.uncheckedArgument(2));
583     RETURN_IF_EXCEPTION(scope, void());
584
585     if (params->identifier != key->algorithmIdentifier()) {
586         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
587         return;
588     }
589
590     if (!key->allows(CryptoKeyUsageDecrypt)) {
591         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support decryption"));
592         return;
593     }
594
595     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier());
596     if (UNLIKELY(!algorithm)) {
597         throwNotSupportedError(state, scope);
598         return;
599     }
600
601     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& plainText) mutable {
602         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), plainText.data(), plainText.size());
603     };
604     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
605         rejectWithException(WTFMove(capturedPromise), ec);
606     };
607
608     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
609     ASSERT(subtle);
610     algorithm->decrypt(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
611 }
612
613 static void jsSubtleCryptoFunctionSignPromise(ExecState& state, Ref<DeferredPromise>&& promise)
614 {
615     VM& vm = state.vm();
616     auto scope = DECLARE_THROW_SCOPE(vm);
617
618     if (UNLIKELY(state.argumentCount() < 3)) {
619         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
620         return;
621     }
622
623     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Sign);
624     RETURN_IF_EXCEPTION(scope, void());
625
626     auto key = toCryptoKey(state, state.uncheckedArgument(1));
627     RETURN_IF_EXCEPTION(scope, void());
628
629     auto data = toVector(state, state.uncheckedArgument(2));
630     RETURN_IF_EXCEPTION(scope, void());
631
632     if (params->identifier != key->algorithmIdentifier()) {
633         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
634         return;
635     }
636
637     if (!key->allows(CryptoKeyUsageSign)) {
638         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support signing"));
639         return;
640     }
641
642     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier());
643     if (UNLIKELY(!algorithm)) {
644         throwNotSupportedError(state, scope);
645         return;
646     }
647
648     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& signature) mutable {
649         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), signature.data(), signature.size());
650     };
651     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
652         rejectWithException(WTFMove(capturedPromise), ec);
653     };
654
655     JSSubtleCrypto* subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
656     ASSERT(subtle);
657     algorithm->sign(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
658 }
659
660 static void jsSubtleCryptoFunctionVerifyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
661 {
662     VM& vm = state.vm();
663     auto scope = DECLARE_THROW_SCOPE(vm);
664
665     if (UNLIKELY(state.argumentCount() < 4)) {
666         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
667         return;
668     }
669
670     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Verify);
671     RETURN_IF_EXCEPTION(scope, void());
672
673     auto key = toCryptoKey(state, state.uncheckedArgument(1));
674     RETURN_IF_EXCEPTION(scope, void());
675
676     auto signature = toVector(state, state.uncheckedArgument(2));
677     RETURN_IF_EXCEPTION(scope, void());
678
679     auto data = toVector(state, state.uncheckedArgument(3));
680     RETURN_IF_EXCEPTION(scope, void());
681
682     if (params->identifier != key->algorithmIdentifier()) {
683         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
684         return;
685     }
686
687     if (!key->allows(CryptoKeyUsageVerify)) {
688         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support verification"));
689         return;
690     }
691
692     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier());
693     if (UNLIKELY(!algorithm)) {
694         throwNotSupportedError(state, scope);
695         return;
696     }
697
698     auto callback = [capturedPromise = promise.copyRef()](bool result) mutable {
699         capturedPromise->resolve<IDLBoolean>(result);
700     };
701     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
702         rejectWithException(WTFMove(capturedPromise), ec);
703     };
704
705     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
706     ASSERT(subtle);
707     algorithm->verify(WTFMove(params), key.releaseNonNull(), WTFMove(signature), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
708 }
709
710 static void jsSubtleCryptoFunctionDigestPromise(ExecState& state, Ref<DeferredPromise>&& promise)
711 {
712     VM& vm = state.vm();
713     auto scope = DECLARE_THROW_SCOPE(vm);
714
715     if (UNLIKELY(state.argumentCount() < 2)) {
716         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
717         return;
718     }
719
720     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Digest);
721     RETURN_IF_EXCEPTION(scope, void());
722
723     auto data = toVector(state, state.uncheckedArgument(1));
724     RETURN_IF_EXCEPTION(scope, void());
725
726     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
727     if (UNLIKELY(!algorithm)) {
728         throwNotSupportedError(state, scope);
729         return;
730     }
731
732     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& digest) mutable {
733         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), digest.data(), digest.size());
734     };
735     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
736         rejectWithException(WTFMove(capturedPromise), ec);
737     };
738
739     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
740     ASSERT(subtle);
741     algorithm->digest(WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
742 }
743
744 static void jsSubtleCryptoFunctionGenerateKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
745 {
746     VM& vm = state.vm();
747     auto scope = DECLARE_THROW_SCOPE(vm);
748
749     if (UNLIKELY(state.argumentCount() < 3)) {
750         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
751         return;
752     }
753
754     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::GenerateKey);
755     RETURN_IF_EXCEPTION(scope, void());
756
757     auto extractable = state.uncheckedArgument(1).toBoolean(&state);
758     RETURN_IF_EXCEPTION(scope, void());
759
760     auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(2));
761     RETURN_IF_EXCEPTION(scope, void());
762
763     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
764     if (UNLIKELY(!algorithm)) {
765         throwNotSupportedError(state, scope);
766         return;
767     }
768
769     auto callback = [capturedPromise = promise.copyRef()](KeyOrKeyPair&& keyOrKeyPair) mutable {
770         WTF::switchOn(keyOrKeyPair,
771             [&capturedPromise] (RefPtr<CryptoKey>& key) {
772                 if ((key->type() == CryptoKeyType::Private || key->type() == CryptoKeyType::Secret) && !key->usagesBitmap()) {
773                     rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
774                     return;
775                 }
776                 capturedPromise->resolve<IDLInterface<CryptoKey>>(*key);
777             },
778             [&capturedPromise] (CryptoKeyPair& keyPair) {
779                 if (!keyPair.privateKey->usagesBitmap()) {
780                     rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
781                     return;
782                 }
783                 capturedPromise->resolve<IDLDictionary<CryptoKeyPair>>(keyPair);
784             }
785         );
786     };
787     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
788         rejectWithException(WTFMove(capturedPromise), ec);
789     };
790
791     // The 26 January 2017 version of the specification suggests we should perform the following task asynchronously
792     // regardless what kind of keys it produces: https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey
793     // That's simply not efficient for AES, HMAC and EC keys. Therefore, we perform it as an async task only for RSA keys.
794     algorithm->generateKey(*params, extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state));
795 }
796
797 static void jsSubtleCryptoFunctionDeriveKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
798 {
799     VM& vm = state.vm();
800     auto scope = DECLARE_THROW_SCOPE(vm);
801
802     if (UNLIKELY(state.argumentCount() < 5)) {
803         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
804         return;
805     }
806
807     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::DeriveBits);
808     RETURN_IF_EXCEPTION(scope, void());
809
810     auto baseKey = toCryptoKey(state, state.uncheckedArgument(1));
811     RETURN_IF_EXCEPTION(scope, void());
812
813     auto importParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(2), Operations::ImportKey);
814     RETURN_IF_EXCEPTION(scope, void());
815
816     auto getLengthParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(2), Operations::GetKeyLength);
817     RETURN_IF_EXCEPTION(scope, void());
818
819     auto extractable = state.uncheckedArgument(3).toBoolean(&state);
820     RETURN_IF_EXCEPTION(scope, void());
821
822     auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(4));
823     RETURN_IF_EXCEPTION(scope, void());
824
825     if (params->identifier != baseKey->algorithmIdentifier()) {
826         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
827         return;
828     }
829
830     if (!baseKey->allows(CryptoKeyUsageDeriveKey)) {
831         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support CryptoKey derivation"));
832         return;
833     }
834
835     auto getLengthAlgorithm = CryptoAlgorithmRegistry::singleton().create(getLengthParams->identifier);
836     if (UNLIKELY(!getLengthAlgorithm)) {
837         throwNotSupportedError(state, scope);
838         return;
839     }
840     auto result = getLengthAlgorithm->getKeyLength(*getLengthParams);
841     if (result.hasException()) {
842         promise->reject(result.releaseException().code(), ASCIILiteral("Cannot get key length from derivedKeyType"));
843         return;
844     }
845     size_t length = result.releaseReturnValue();
846
847     auto importAlgorithm = CryptoAlgorithmRegistry::singleton().create(importParams->identifier);
848     if (UNLIKELY(!importAlgorithm)) {
849         throwNotSupportedError(state, scope);
850         return;
851     }
852
853     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
854     if (UNLIKELY(!algorithm)) {
855         throwNotSupportedError(state, scope);
856         return;
857     }
858
859     auto callback = [promise = promise.copyRef(), importAlgorithm, importParams = WTFMove(importParams), extractable, keyUsages](const Vector<uint8_t>& derivedKey) mutable {
860         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=169395
861         KeyData data = derivedKey;
862         auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable {
863             if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
864                 rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
865                 return;
866             }
867             capturedPromise->resolve<IDLInterface<CryptoKey>>(key);
868         };
869         auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
870             rejectWithException(WTFMove(capturedPromise), ec);
871         };
872
873         importAlgorithm->importKey(SubtleCrypto::KeyFormat::Raw, WTFMove(data), WTFMove(importParams), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback));
874     };
875     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
876         rejectWithException(WTFMove(capturedPromise), ec);
877     };
878
879     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
880     ASSERT(subtle);
881     algorithm->deriveBits(WTFMove(params), baseKey.releaseNonNull(), length, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
882 }
883
884 static void jsSubtleCryptoFunctionDeriveBitsPromise(ExecState& state, Ref<DeferredPromise>&& promise)
885 {
886     VM& vm = state.vm();
887     auto scope = DECLARE_THROW_SCOPE(vm);
888
889     if (UNLIKELY(state.argumentCount() < 3)) {
890         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
891         return;
892     }
893
894     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::DeriveBits);
895     RETURN_IF_EXCEPTION(scope, void());
896
897     auto baseKey = toCryptoKey(state, state.uncheckedArgument(1));
898     RETURN_IF_EXCEPTION(scope, void());
899
900     auto length = convert<IDLUnsignedLong>(state, state.uncheckedArgument(2));
901     RETURN_IF_EXCEPTION(scope, void());
902
903     if (params->identifier != baseKey->algorithmIdentifier()) {
904         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
905         return;
906     }
907
908     if (!baseKey->allows(CryptoKeyUsageDeriveBits)) {
909         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support bits derivation"));
910         return;
911     }
912
913     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
914     if (UNLIKELY(!algorithm)) {
915         throwNotSupportedError(state, scope);
916         return;
917     }
918
919     auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& derivedKey) mutable {
920         fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), derivedKey.data(), derivedKey.size());
921     };
922     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
923         rejectWithException(WTFMove(capturedPromise), ec);
924     };
925
926     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
927     ASSERT(subtle);
928     algorithm->deriveBits(WTFMove(params), baseKey.releaseNonNull(), length, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
929 }
930
931 static void jsSubtleCryptoFunctionImportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
932 {
933     VM& vm = state.vm();
934     auto scope = DECLARE_THROW_SCOPE(vm);
935
936     if (UNLIKELY(state.argumentCount() < 5)) {
937         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
938         return;
939     }
940
941     auto format = convert<IDLEnumeration<SubtleCrypto::KeyFormat>>(state, state.uncheckedArgument(0));
942     RETURN_IF_EXCEPTION(scope, void());
943
944     auto keyData = toKeyData(state, format, state.uncheckedArgument(1));
945     RETURN_IF_EXCEPTION(scope, void());
946
947     auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(2), Operations::ImportKey);
948     RETURN_IF_EXCEPTION(scope, void());
949
950     auto extractable = state.uncheckedArgument(3).toBoolean(&state);
951     RETURN_IF_EXCEPTION(scope, void());
952
953     auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(4));
954     RETURN_IF_EXCEPTION(scope, void());
955
956     auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
957     if (UNLIKELY(!algorithm)) {
958         throwNotSupportedError(state, scope);
959         return;
960     }
961
962     auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable {
963         if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
964             rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR);
965             return;
966         }
967         capturedPromise->resolve<IDLInterface<CryptoKey>>(key);
968     };
969     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
970         rejectWithException(WTFMove(capturedPromise), ec);
971     };
972
973     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
974     // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey
975     // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
976     algorithm->importKey(format, WTFMove(keyData), WTFMove(params), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback));
977 }
978
979 static void jsSubtleCryptoFunctionExportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
980 {
981     VM& vm = state.vm();
982     auto scope = DECLARE_THROW_SCOPE(vm);
983
984     if (UNLIKELY(state.argumentCount() < 2)) {
985         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
986         return;
987     }
988
989     auto format = convert<IDLEnumeration<SubtleCrypto::KeyFormat>>(state, state.uncheckedArgument(0));
990     RETURN_IF_EXCEPTION(scope, void());
991
992     auto key = toCryptoKey(state, state.uncheckedArgument(1));
993     RETURN_IF_EXCEPTION(scope, void());
994
995     supportExportKeyThrow(state, scope, key->algorithmIdentifier());
996     RETURN_IF_EXCEPTION(scope, void());
997
998     if (!key->extractable()) {
999         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("The CryptoKey is nonextractable"));
1000         return;
1001     }
1002
1003     auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier());
1004     if (UNLIKELY(!algorithm)) {
1005         throwNotSupportedError(state, scope);
1006         return;
1007     }
1008
1009     auto callback = [capturedPromise = promise.copyRef()](SubtleCrypto::KeyFormat format, KeyData&& key) mutable {
1010         switch (format) {
1011         case SubtleCrypto::KeyFormat::Spki:
1012         case SubtleCrypto::KeyFormat::Pkcs8:
1013         case SubtleCrypto::KeyFormat::Raw: {
1014             Vector<uint8_t>& rawKey = WTF::get<Vector<uint8_t>>(key);
1015             fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), rawKey.data(), rawKey.size());
1016             return;
1017         }
1018         case SubtleCrypto::KeyFormat::Jwk:
1019             capturedPromise->resolve<IDLDictionary<JsonWebKey>>(WTFMove(WTF::get<JsonWebKey>(key)));
1020             return;
1021         }
1022         ASSERT_NOT_REACHED();
1023     };
1024     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
1025         rejectWithException(WTFMove(capturedPromise), ec);
1026     };
1027
1028     // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
1029     // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey
1030     // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
1031     algorithm->exportKey(format, key.releaseNonNull(), WTFMove(callback), WTFMove(exceptionCallback));
1032 }
1033
1034 static void jsSubtleCryptoFunctionWrapKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
1035 {
1036     VM& vm = state.vm();
1037     auto scope = DECLARE_THROW_SCOPE(vm);
1038
1039     if (UNLIKELY(state.argumentCount() < 4)) {
1040         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
1041         return;
1042     }
1043
1044     auto format = convert<IDLEnumeration<SubtleCrypto::KeyFormat>>(state, state.uncheckedArgument(0));
1045     RETURN_IF_EXCEPTION(scope, void());
1046
1047     auto key = toCryptoKey(state, state.uncheckedArgument(1));
1048     RETURN_IF_EXCEPTION(scope, void());
1049
1050     auto wrappingKey = toCryptoKey(state, state.uncheckedArgument(2));
1051     RETURN_IF_EXCEPTION(scope, void());
1052
1053     auto catchScope = DECLARE_CATCH_SCOPE(vm);
1054     bool isEncryption = false;
1055     auto wrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::WrapKey);
1056     if (catchScope.exception()) {
1057         catchScope.clearException();
1058         wrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::Encrypt);
1059         RETURN_IF_EXCEPTION(scope, void());
1060         isEncryption = true;
1061     }
1062
1063     if (wrapParams->identifier != wrappingKey->algorithmIdentifier()) {
1064         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Wrapping CryptoKey doesn't match AlgorithmIdentifier"));
1065         return;
1066     }
1067
1068     if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) {
1069         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Wrapping CryptoKey doesn't support wrapKey operation"));
1070         return;
1071     }
1072
1073     supportExportKeyThrow(state, scope, key->algorithmIdentifier());
1074     RETURN_IF_EXCEPTION(scope, void());
1075
1076     if (!key->extractable()) {
1077         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("The CryptoKey is nonextractable"));
1078         return;
1079     }
1080
1081     auto exportAlgorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier());
1082     if (UNLIKELY(!exportAlgorithm)) {
1083         throwNotSupportedError(state, scope);
1084         return;
1085     }
1086
1087     auto wrapAlgorithm = CryptoAlgorithmRegistry::singleton().create(wrappingKey->algorithmIdentifier());
1088     if (UNLIKELY(!wrapAlgorithm)) {
1089         throwNotSupportedError(state, scope);
1090         return;
1091     }
1092
1093     auto context = scriptExecutionContextFromExecState(&state);
1094
1095     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
1096     ASSERT(subtle);
1097     auto& workQueue = subtle->wrapped().workQueue();
1098
1099     auto callback = [promise = promise.copyRef(), wrapAlgorithm, wrappingKey = WTFMove(wrappingKey), wrapParams = WTFMove(wrapParams), isEncryption, context, &workQueue](SubtleCrypto::KeyFormat format, KeyData&& key) mutable {
1100         Vector<uint8_t> bytes;
1101         switch (format) {
1102         case SubtleCrypto::KeyFormat::Spki:
1103         case SubtleCrypto::KeyFormat::Pkcs8:
1104         case SubtleCrypto::KeyFormat::Raw:
1105             bytes = WTF::get<Vector<uint8_t>>(key);
1106             break;
1107         case SubtleCrypto::KeyFormat::Jwk: {
1108             auto jwk = toJS<IDLDictionary<JsonWebKey>>(*(promise->globalObject()->globalExec()), *(promise->globalObject()), WTFMove(WTF::get<JsonWebKey>(key)));
1109             String jwkString = JSONStringify(promise->globalObject()->globalExec(), jwk, 0);
1110             CString jwkUtf8String = jwkString.utf8(StrictConversion);
1111             bytes.append(jwkUtf8String.data(), jwkUtf8String.length());
1112         }
1113         }
1114
1115         auto callback = [promise = promise.copyRef()](const Vector<uint8_t>& wrappedKey) mutable {
1116             fulfillPromiseWithArrayBuffer(WTFMove(promise), wrappedKey.data(), wrappedKey.size());
1117             return;
1118         };
1119         auto exceptionCallback = [promise = WTFMove(promise)](ExceptionCode ec) mutable {
1120             rejectWithException(WTFMove(promise), ec);
1121         };
1122
1123         if (!isEncryption) {
1124             // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
1125             // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey
1126             // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
1127             wrapAlgorithm->wrapKey(wrappingKey.releaseNonNull(), WTFMove(bytes), WTFMove(callback), WTFMove(exceptionCallback));
1128             return;
1129         }
1130         // The following operation should be performed asynchronously.
1131         wrapAlgorithm->encrypt(WTFMove(wrapParams), wrappingKey.releaseNonNull(), WTFMove(bytes), WTFMove(callback), WTFMove(exceptionCallback), *context, workQueue);
1132     };
1133     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
1134         rejectWithException(WTFMove(capturedPromise), ec);
1135     };
1136
1137     // The following operation should be performed synchronously.
1138     exportAlgorithm->exportKey(format, key.releaseNonNull(), WTFMove(callback), WTFMove(exceptionCallback));
1139 }
1140
1141 static void jsSubtleCryptoFunctionUnwrapKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
1142 {
1143     VM& vm = state.vm();
1144     auto scope = DECLARE_THROW_SCOPE(vm);
1145
1146     if (UNLIKELY(state.argumentCount() < 7)) {
1147         promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
1148         return;
1149     }
1150
1151     auto format = convert<IDLEnumeration<SubtleCrypto::KeyFormat>>(state, state.uncheckedArgument(0));
1152     RETURN_IF_EXCEPTION(scope, void());
1153
1154     auto wrappedKey = toVector(state, state.uncheckedArgument(1));
1155     RETURN_IF_EXCEPTION(scope, void());
1156
1157     auto unwrappingKey = toCryptoKey(state, state.uncheckedArgument(2));
1158     RETURN_IF_EXCEPTION(scope, void());
1159
1160     auto catchScope = DECLARE_CATCH_SCOPE(vm);
1161     bool isDecryption = false;
1162     auto unwrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::UnwrapKey);
1163     if (catchScope.exception()) {
1164         catchScope.clearException();
1165         unwrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::Decrypt);
1166         RETURN_IF_EXCEPTION(scope, void());
1167         isDecryption = true;
1168     }
1169
1170     auto unwrappedKeyAlgorithm = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(4), Operations::ImportKey);
1171     RETURN_IF_EXCEPTION(scope, void());
1172
1173     auto extractable = state.uncheckedArgument(5).toBoolean(&state);
1174     RETURN_IF_EXCEPTION(scope, void());
1175
1176     auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(6));
1177     RETURN_IF_EXCEPTION(scope, void());
1178
1179     if (unwrapParams->identifier != unwrappingKey->algorithmIdentifier()) {
1180         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Unwrapping CryptoKey doesn't match unwrap AlgorithmIdentifier"));
1181         return;
1182     }
1183
1184     if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) {
1185         promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Unwrapping CryptoKey doesn't support unwrapKey operation"));
1186         return;
1187     }
1188
1189     auto importAlgorithm = CryptoAlgorithmRegistry::singleton().create(unwrappedKeyAlgorithm->identifier);
1190     if (UNLIKELY(!importAlgorithm)) {
1191         throwNotSupportedError(state, scope);
1192         return;
1193     }
1194
1195     auto unwrapAlgorithm = CryptoAlgorithmRegistry::singleton().create(unwrappingKey->algorithmIdentifier());
1196     if (UNLIKELY(!unwrapAlgorithm)) {
1197         throwNotSupportedError(state, scope);
1198         return;
1199     }
1200
1201     auto callback = [promise = promise.copyRef(), format, importAlgorithm, unwrappedKeyAlgorithm = WTFMove(unwrappedKeyAlgorithm), extractable, keyUsages](const Vector<uint8_t>& bytes) mutable {
1202         ExecState& state = *(promise->globalObject()->globalExec());
1203         VM& vm = state.vm();
1204         auto scope = DECLARE_THROW_SCOPE(vm);
1205
1206         KeyData keyData;
1207         switch (format) {
1208         case SubtleCrypto::KeyFormat::Spki:
1209         case SubtleCrypto::KeyFormat::Pkcs8:
1210         case SubtleCrypto::KeyFormat::Raw:
1211             keyData = bytes;
1212             break;
1213         case SubtleCrypto::KeyFormat::Jwk: {
1214             String jwkString(reinterpret_cast_ptr<const char*>(bytes.data()), bytes.size());
1215             JSC::JSLockHolder locker(vm);
1216             auto jwk = JSONParse(&state, jwkString);
1217             if (!jwk) {
1218                 promise->reject(DataError, ASCIILiteral("WrappedKey cannot be converted to a JSON object"));
1219                 return;
1220             }
1221             keyData = toKeyData(state, format, jwk);
1222             RETURN_IF_EXCEPTION(scope, void());
1223         }
1224         }
1225
1226         auto callback = [promise = promise.copyRef()](CryptoKey& key) mutable {
1227             if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) {
1228                 rejectWithException(WTFMove(promise), SYNTAX_ERR);
1229                 return;
1230             }
1231             promise->resolve<IDLInterface<CryptoKey>>(key);
1232         };
1233         auto exceptionCallback = [promise = WTFMove(promise)](ExceptionCode ec) mutable {
1234             rejectWithException(WTFMove(promise), ec);
1235         };
1236
1237         // The following operation should be performed synchronously.
1238         importAlgorithm->importKey(format, WTFMove(keyData), WTFMove(unwrappedKeyAlgorithm), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback));
1239     };
1240     auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
1241         rejectWithException(WTFMove(capturedPromise), ec);
1242     };
1243
1244     if (!isDecryption) {
1245         // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously:
1246         // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-unwrapKey
1247         // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously.
1248         unwrapAlgorithm->unwrapKey(unwrappingKey.releaseNonNull(), WTFMove(wrappedKey), WTFMove(callback), WTFMove(exceptionCallback));
1249         return;
1250     }
1251     auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
1252     ASSERT(subtle);
1253     // The following operation should be performed asynchronously.
1254     unwrapAlgorithm->decrypt(WTFMove(unwrapParams), unwrappingKey.releaseNonNull(), WTFMove(wrappedKey), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
1255 }
1256
1257 JSValue JSSubtleCrypto::encrypt(ExecState& state)
1258 {
1259     return callPromiseFunction<jsSubtleCryptoFunctionEncryptPromise, PromiseExecutionScope::WindowOrWorker>(state);
1260 }
1261
1262 JSValue JSSubtleCrypto::decrypt(ExecState& state)
1263 {
1264     return callPromiseFunction<jsSubtleCryptoFunctionDecryptPromise, PromiseExecutionScope::WindowOrWorker>(state);
1265 }
1266
1267 JSValue JSSubtleCrypto::sign(ExecState& state)
1268 {
1269     return callPromiseFunction<jsSubtleCryptoFunctionSignPromise, PromiseExecutionScope::WindowOrWorker>(state);
1270 }
1271
1272 JSValue JSSubtleCrypto::verify(ExecState& state)
1273 {
1274     return callPromiseFunction<jsSubtleCryptoFunctionVerifyPromise, PromiseExecutionScope::WindowOrWorker>(state);
1275 }
1276
1277 JSValue JSSubtleCrypto::digest(ExecState& state)
1278 {
1279     return callPromiseFunction<jsSubtleCryptoFunctionDigestPromise, PromiseExecutionScope::WindowOrWorker>(state);
1280 }
1281
1282
1283 JSValue JSSubtleCrypto::generateKey(ExecState& state)
1284 {
1285     return callPromiseFunction<jsSubtleCryptoFunctionGenerateKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
1286 }
1287
1288 JSValue JSSubtleCrypto::deriveKey(ExecState& state)
1289 {
1290     return callPromiseFunction<jsSubtleCryptoFunctionDeriveKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
1291 }
1292
1293 JSValue JSSubtleCrypto::deriveBits(ExecState& state)
1294 {
1295     return callPromiseFunction<jsSubtleCryptoFunctionDeriveBitsPromise, PromiseExecutionScope::WindowOrWorker>(state);
1296 }
1297
1298 JSValue JSSubtleCrypto::importKey(ExecState& state)
1299 {
1300     return callPromiseFunction<jsSubtleCryptoFunctionImportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
1301 }
1302
1303 JSValue JSSubtleCrypto::exportKey(ExecState& state)
1304 {
1305     return callPromiseFunction<jsSubtleCryptoFunctionExportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
1306 }
1307
1308 JSValue JSSubtleCrypto::wrapKey(ExecState& state)
1309 {
1310     return callPromiseFunction<jsSubtleCryptoFunctionWrapKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
1311 }
1312
1313 JSValue JSSubtleCrypto::unwrapKey(ExecState& state)
1314 {
1315     return callPromiseFunction<jsSubtleCryptoFunctionUnwrapKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
1316 }
1317
1318 } // namespace WebCore
1319
1320 #endif