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