f405a03df6e301ee806acc86872631e6bdb489d8
[WebKit.git] / Source / WebCore / bindings / js / JSSubtleCryptoCustom.cpp
1 /*
2  * Copyright (C) 2013 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 "CryptoAlgorithmParameters.h"
33 #include "CryptoAlgorithmRegistry.h"
34 #include "CryptoKeyData.h"
35 #include "CryptoKeySerializationRaw.h"
36 #include "Document.h"
37 #include "ExceptionCode.h"
38 #include "JSCryptoAlgorithmDictionary.h"
39 #include "JSCryptoKeySerializationJWK.h"
40 #include "JSCryptoOperationData.h"
41 #include "JSDOMPromise.h"
42 #include <runtime/Error.h>
43
44 using namespace JSC;
45
46 namespace WebCore {
47
48 enum class CryptoKeyFormat {
49     // An unformatted sequence of bytes. Intended for secret keys.
50     Raw,
51
52     // The DER encoding of the PrivateKeyInfo structure from RFC 5208.
53     PKCS8,
54
55     // The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280.
56     SPKI,
57
58     // The key is represented as JSON according to the JSON Web Key format.
59     JWK
60 };
61
62 static std::unique_ptr<CryptoAlgorithm> createAlgorithmFromJSValue(ExecState* exec, JSValue value)
63 {
64     CryptoAlgorithmIdentifier algorithmIdentifier;
65     if (!JSCryptoAlgorithmDictionary::getAlgorithmIdentifier(exec, value, algorithmIdentifier)) {
66         ASSERT(exec->hadException());
67         return nullptr;
68     }
69
70     auto result = CryptoAlgorithmRegistry::shared().create(algorithmIdentifier);
71     if (!result)
72         setDOMException(exec, NOT_SUPPORTED_ERR);
73     return result;
74 }
75
76 static bool cryptoKeyFormatFromJSValue(ExecState* exec, JSValue value, CryptoKeyFormat& result)
77 {
78     String keyFormatString = value.toString(exec)->value(exec);
79     if (exec->hadException())
80         return false;
81     if (keyFormatString == "raw")
82         result = CryptoKeyFormat::Raw;
83     else if (keyFormatString == "pkcs8")
84         result = CryptoKeyFormat::PKCS8;
85     else if (keyFormatString == "spki")
86         result = CryptoKeyFormat::SPKI;
87     else if (keyFormatString == "jwk")
88         result = CryptoKeyFormat::JWK;
89     else {
90         throwTypeError(exec, "Unknown key format");
91         return false;
92     }
93     return true;
94 }
95
96 static bool cryptoKeyUsagesFromJSValue(ExecState* exec, JSValue value, CryptoKeyUsage& result)
97 {
98     if (!isJSArray(value)) {
99         throwTypeError(exec);
100         return false;
101     }
102
103     result = 0;
104
105     JSArray* array = asArray(value);
106     for (size_t i = 0; i < array->length(); ++i) {
107         JSValue element = array->getIndex(exec, i);
108         String usageString = element.toString(exec)->value(exec);
109         if (exec->hadException())
110             return false;
111         if (usageString == "encrypt")
112             result |= CryptoKeyUsageEncrypt;
113         else if (usageString == "decrypt")
114             result |= CryptoKeyUsageDecrypt;
115         else if (usageString == "sign")
116             result |= CryptoKeyUsageSign;
117         else if (usageString == "verify")
118             result |= CryptoKeyUsageVerify;
119         else if (usageString == "deriveKey")
120             result |= CryptoKeyUsageDeriveKey;
121         else if (usageString == "deriveBits")
122             result |= CryptoKeyUsageDeriveBits;
123         else if (usageString == "wrapKey")
124             result |= CryptoKeyUsageWrapKey;
125         else if (usageString == "unwrapKey")
126             result |= CryptoKeyUsageUnwrapKey;
127     }
128     return true;
129 }
130
131 JSValue JSSubtleCrypto::encrypt(ExecState* exec)
132 {
133     if (exec->argumentCount() < 3)
134         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
135
136     auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
137     if (!algorithm) {
138         ASSERT(exec->hadException());
139         return jsUndefined();
140     }
141
142     auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(exec, algorithm->identifier(), exec->uncheckedArgument(0));
143     if (!parameters) {
144         ASSERT(exec->hadException());
145         return jsUndefined();
146     }
147
148     RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
149     if (!key)
150         return throwTypeError(exec);
151
152     if (!key->allows(CryptoKeyUsageEncrypt)) {
153         m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'encrypt'"));
154         setDOMException(exec, NOT_SUPPORTED_ERR);
155         return jsUndefined();
156     }
157
158     CryptoOperationData data;
159     if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), data)) {
160         ASSERT(exec->hadException());
161         return jsUndefined();
162     }
163
164     
165     DeferredWrapper wrapper(exec, globalObject());
166     auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
167         wrapper.resolve(result);
168     };
169     auto failureCallback = [wrapper]() mutable {
170         wrapper.reject(nullptr);
171     };
172
173     ExceptionCode ec = 0;
174     algorithm->encrypt(*parameters, *key, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
175     if (ec) {
176         setDOMException(exec, ec);
177         return jsUndefined();
178     }
179
180     return wrapper.promise();
181 }
182
183 JSValue JSSubtleCrypto::decrypt(ExecState* exec)
184 {
185     if (exec->argumentCount() < 3)
186         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
187
188     auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
189     if (!algorithm) {
190         ASSERT(exec->hadException());
191         return jsUndefined();
192     }
193
194     auto parameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(exec, algorithm->identifier(), exec->uncheckedArgument(0));
195     if (!parameters) {
196         ASSERT(exec->hadException());
197         return jsUndefined();
198     }
199
200     RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
201     if (!key)
202         return throwTypeError(exec);
203
204     if (!key->allows(CryptoKeyUsageDecrypt)) {
205         m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'decrypt'"));
206         setDOMException(exec, NOT_SUPPORTED_ERR);
207         return jsUndefined();
208     }
209
210     CryptoOperationData data;
211     if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), data)) {
212         ASSERT(exec->hadException());
213         return jsUndefined();
214     }
215
216     DeferredWrapper wrapper(exec, globalObject());
217     auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
218         wrapper.resolve(result);
219     };
220     auto failureCallback = [wrapper]() mutable {
221         wrapper.reject(nullptr);
222     };
223
224     ExceptionCode ec = 0;
225     algorithm->decrypt(*parameters, *key, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
226     if (ec) {
227         setDOMException(exec, ec);
228         return jsUndefined();
229     }
230
231     return wrapper.promise();
232 }
233
234 JSValue JSSubtleCrypto::sign(ExecState* exec)
235 {
236     if (exec->argumentCount() < 3)
237         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
238
239     auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
240     if (!algorithm) {
241         ASSERT(exec->hadException());
242         return jsUndefined();
243     }
244
245     auto parameters = JSCryptoAlgorithmDictionary::createParametersForSign(exec, algorithm->identifier(), exec->uncheckedArgument(0));
246     if (!parameters) {
247         ASSERT(exec->hadException());
248         return jsUndefined();
249     }
250
251     RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
252     if (!key)
253         return throwTypeError(exec);
254
255     if (!key->allows(CryptoKeyUsageSign)) {
256         m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'sign'"));
257         setDOMException(exec, NOT_SUPPORTED_ERR);
258         return jsUndefined();
259     }
260
261     CryptoOperationData data;
262     if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), data)) {
263         ASSERT(exec->hadException());
264         return jsUndefined();
265     }
266
267     DeferredWrapper wrapper(exec, globalObject());
268     auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
269         wrapper.resolve(result);
270     };
271     auto failureCallback = [wrapper]() mutable {
272         wrapper.reject(nullptr);
273     };
274
275     ExceptionCode ec = 0;
276     algorithm->sign(*parameters, *key, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
277     if (ec) {
278         setDOMException(exec, ec);
279         return jsUndefined();
280     }
281
282     return wrapper.promise();
283 }
284
285 JSValue JSSubtleCrypto::verify(ExecState* exec)
286 {
287     if (exec->argumentCount() < 4)
288         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
289
290     auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
291     if (!algorithm) {
292         ASSERT(exec->hadException());
293         return jsUndefined();
294     }
295
296     auto parameters = JSCryptoAlgorithmDictionary::createParametersForVerify(exec, algorithm->identifier(), exec->uncheckedArgument(0));
297     if (!parameters) {
298         ASSERT(exec->hadException());
299         return jsUndefined();
300     }
301
302     RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
303     if (!key)
304         return throwTypeError(exec);
305
306     if (!key->allows(CryptoKeyUsageVerify)) {
307         m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'verify'"));
308         setDOMException(exec, NOT_SUPPORTED_ERR);
309         return jsUndefined();
310     }
311
312     CryptoOperationData signature;
313     if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), signature)) {
314         ASSERT(exec->hadException());
315         return jsUndefined();
316     }
317
318     CryptoOperationData data;
319     if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(3), data)) {
320         ASSERT(exec->hadException());
321         return jsUndefined();
322     }
323
324     DeferredWrapper wrapper(exec, globalObject());
325     auto successCallback = [wrapper](bool result) mutable {
326         wrapper.resolve(result);
327     };
328     auto failureCallback = [wrapper]() mutable {
329         wrapper.reject(nullptr);
330     };
331
332     ExceptionCode ec = 0;
333     algorithm->verify(*parameters, *key, signature, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
334     if (ec) {
335         setDOMException(exec, ec);
336         return jsUndefined();
337     }
338
339     return wrapper.promise();
340 }
341
342 JSValue JSSubtleCrypto::digest(ExecState* exec)
343 {
344     if (exec->argumentCount() < 2)
345         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
346
347     auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
348     if (!algorithm) {
349         ASSERT(exec->hadException());
350         return jsUndefined();
351     }
352
353     auto parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(exec, algorithm->identifier(), exec->uncheckedArgument(0));
354     if (!parameters) {
355         ASSERT(exec->hadException());
356         return jsUndefined();
357     }
358
359     CryptoOperationData data;
360     if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
361         ASSERT(exec->hadException());
362         return jsUndefined();
363     }
364
365     DeferredWrapper wrapper(exec, globalObject());
366     auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
367         wrapper.resolve(result);
368     };
369     auto failureCallback = [wrapper]() mutable {
370         wrapper.reject(nullptr);
371     };
372
373     ExceptionCode ec = 0;
374     algorithm->digest(*parameters, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
375     if (ec) {
376         setDOMException(exec, ec);
377         return jsUndefined();
378     }
379
380     return wrapper.promise();
381 }
382
383 JSValue JSSubtleCrypto::generateKey(ExecState* exec)
384 {
385     if (exec->argumentCount() < 1)
386         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
387
388     auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
389     if (!algorithm) {
390         ASSERT(exec->hadException());
391         return jsUndefined();
392     }
393
394     auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(exec, algorithm->identifier(), exec->uncheckedArgument(0));
395     if (!parameters) {
396         ASSERT(exec->hadException());
397         return jsUndefined();
398     }
399
400     bool extractable = false;
401     if (exec->argumentCount() >= 2) {
402         extractable = exec->uncheckedArgument(1).toBoolean(exec);
403         if (exec->hadException())
404             return jsUndefined();
405     }
406
407     CryptoKeyUsage keyUsages = 0;
408     if (exec->argumentCount() >= 3) {
409         if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(2), keyUsages)) {
410             ASSERT(exec->hadException());
411             return jsUndefined();
412         }
413     }
414
415     DeferredWrapper wrapper(exec, globalObject());
416     auto successCallback = [wrapper](CryptoKey* key, CryptoKeyPair* keyPair) mutable {
417         ASSERT(key || keyPair);
418         ASSERT(!key || !keyPair);
419         if (key)
420             wrapper.resolve(key);
421         else
422             wrapper.resolve(keyPair);
423     };
424     auto failureCallback = [wrapper]() mutable {
425         wrapper.reject(nullptr);
426     };
427
428     ExceptionCode ec = 0;
429     algorithm->generateKey(*parameters, extractable, keyUsages, WTF::move(successCallback), WTF::move(failureCallback), ec);
430     if (ec) {
431         setDOMException(exec, ec);
432         return jsUndefined();
433     }
434
435     return wrapper.promise();
436 }
437
438 static void importKey(ExecState* exec, CryptoKeyFormat keyFormat, CryptoOperationData data, CryptoAlgorithm* algorithmPtr, CryptoAlgorithmParameters* parametersPtr, bool extractable, CryptoKeyUsage keyUsages, CryptoAlgorithm::KeyCallback callback, CryptoAlgorithm::VoidCallback failureCallback)
439 {
440     std::unique_ptr<CryptoAlgorithm> algorithm(algorithmPtr);
441     std::unique_ptr<CryptoAlgorithmParameters> parameters(parametersPtr);
442
443     std::unique_ptr<CryptoKeySerialization> keySerialization;
444     switch (keyFormat) {
445     case CryptoKeyFormat::Raw:
446         keySerialization = CryptoKeySerializationRaw::create(data);
447         break;
448     case CryptoKeyFormat::JWK: {
449         String jwkString = String::fromUTF8(data.first, data.second);
450         if (jwkString.isNull()) {
451             throwTypeError(exec, "JWK JSON serialization is not valid UTF-8");
452             return;
453         }
454         keySerialization = JSCryptoKeySerializationJWK::create(exec, jwkString);
455         if (exec->hadException())
456             return;
457         break;
458     }
459     default:
460         throwTypeError(exec, "Unsupported key format for import");
461         return;
462     }
463
464     ASSERT(keySerialization);
465
466     if (!keySerialization->reconcileAlgorithm(algorithm, parameters)) {
467         if (!exec->hadException())
468             throwTypeError(exec, "Algorithm specified in key is not compatible with one passed to importKey as argument");
469         return;
470     }
471     if (exec->hadException())
472         return;
473
474     if (!algorithm) {
475         throwTypeError(exec, "Neither key nor function argument has crypto algorithm specified");
476         return;
477     }
478     ASSERT(parameters);
479
480     keySerialization->reconcileExtractable(extractable);
481     if (exec->hadException())
482         return;
483
484     keySerialization->reconcileUsages(keyUsages);
485     if (exec->hadException())
486         return;
487
488     auto keyData = keySerialization->keyData();
489     if (exec->hadException())
490         return;
491
492     ExceptionCode ec = 0;
493     algorithm->importKey(*parameters, *keyData, extractable, keyUsages, WTF::move(callback), WTF::move(failureCallback), ec);
494     if (ec)
495         setDOMException(exec, ec);
496 }
497
498 JSValue JSSubtleCrypto::importKey(ExecState* exec)
499 {
500     if (exec->argumentCount() < 3)
501         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
502
503     CryptoKeyFormat keyFormat;
504     if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
505         ASSERT(exec->hadException());
506         return jsUndefined();
507     }
508
509     CryptoOperationData data;
510     if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
511         ASSERT(exec->hadException());
512         return jsUndefined();
513     }
514
515     std::unique_ptr<CryptoAlgorithm> algorithm;
516     std::unique_ptr<CryptoAlgorithmParameters> parameters;
517     if (!exec->uncheckedArgument(2).isNull()) {
518         algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(2));
519         if (!algorithm) {
520             ASSERT(exec->hadException());
521             return jsUndefined();
522         }
523         parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, algorithm->identifier(), exec->uncheckedArgument(2));
524         if (!parameters) {
525             ASSERT(exec->hadException());
526             return jsUndefined();
527         }
528     }
529
530     bool extractable = false;
531     if (exec->argumentCount() >= 4) {
532         extractable = exec->uncheckedArgument(3).toBoolean(exec);
533         if (exec->hadException())
534             return jsUndefined();
535     }
536
537     CryptoKeyUsage keyUsages = 0;
538     if (exec->argumentCount() >= 5) {
539         if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(4), keyUsages)) {
540             ASSERT(exec->hadException());
541             return jsUndefined();
542         }
543     }
544
545     DeferredWrapper wrapper(exec, globalObject());
546     auto successCallback = [wrapper](CryptoKey& result) mutable {
547         wrapper.resolve(&result);
548     };
549     auto failureCallback = [wrapper]() mutable {
550         wrapper.reject(nullptr);
551     };
552
553     WebCore::importKey(exec, keyFormat, data, algorithm.release(), parameters.release(), extractable, keyUsages, WTF::move(successCallback), WTF::move(failureCallback));
554     if (exec->hadException())
555         return jsUndefined();
556
557     return wrapper.promise();
558 }
559
560 static void exportKey(ExecState* exec, CryptoKeyFormat keyFormat, const CryptoKey& key, CryptoAlgorithm::VectorCallback callback, CryptoAlgorithm::VoidCallback failureCallback)
561 {
562     if (!key.extractable()) {
563         throwTypeError(exec, "Key is not extractable");
564         return;
565     }
566
567     switch (keyFormat) {
568     case CryptoKeyFormat::Raw: {
569         Vector<uint8_t> result;
570         if (CryptoKeySerializationRaw::serialize(key, result))
571             callback(result);
572         else
573             failureCallback();
574         break;
575     }
576     case CryptoKeyFormat::JWK: {
577         String result = JSCryptoKeySerializationJWK::serialize(exec, key);
578         if (exec->hadException())
579             return;
580         CString utf8String = result.utf8(StrictConversion);
581         Vector<uint8_t> resultBuffer;
582         resultBuffer.append(utf8String.data(), utf8String.length());
583         callback(resultBuffer);
584         break;
585     }
586     default:
587         throwTypeError(exec, "Unsupported key format for export");
588         break;
589     }
590 }
591
592 JSValue JSSubtleCrypto::exportKey(ExecState* exec)
593 {
594     if (exec->argumentCount() < 2)
595         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
596
597     CryptoKeyFormat keyFormat;
598     if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
599         ASSERT(exec->hadException());
600         return jsUndefined();
601     }
602
603     RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
604     if (!key)
605         return throwTypeError(exec);
606
607     DeferredWrapper wrapper(exec, globalObject());
608     auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
609         wrapper.resolve(result);
610     };
611     auto failureCallback = [wrapper]() mutable {
612         wrapper.reject(nullptr);
613     };
614
615     WebCore::exportKey(exec, keyFormat, *key, WTF::move(successCallback), WTF::move(failureCallback));
616     if (exec->hadException())
617         return jsUndefined();
618
619     return wrapper.promise();
620 }
621
622 JSValue JSSubtleCrypto::wrapKey(ExecState* exec)
623 {
624     if (exec->argumentCount() < 4)
625         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
626
627     CryptoKeyFormat keyFormat;
628     if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
629         ASSERT(exec->hadException());
630         return jsUndefined();
631     }
632
633     RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
634     if (!key)
635         return throwTypeError(exec);
636
637     RefPtr<CryptoKey> wrappingKey = toCryptoKey(exec->uncheckedArgument(2));
638     if (!key)
639         return throwTypeError(exec);
640
641     if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) {
642         m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'wrapKey'"));
643         setDOMException(exec, NOT_SUPPORTED_ERR);
644         return jsUndefined();
645     }
646
647     auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3));
648     if (!algorithm) {
649         ASSERT(exec->hadException());
650         return jsUndefined();
651     }
652
653     auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(exec, algorithm->identifier(), exec->uncheckedArgument(3));
654     if (!parameters) {
655         ASSERT(exec->hadException());
656         return jsUndefined();
657     }
658
659     DeferredWrapper wrapper(exec, globalObject());
660
661     CryptoAlgorithm* algorithmPtr = algorithm.release();
662     CryptoAlgorithmParameters* parametersPtr = parameters.release();
663
664     auto exportSuccessCallback = [keyFormat, algorithmPtr, parametersPtr, wrappingKey, wrapper](const Vector<uint8_t>& exportedKeyData) mutable {
665         auto encryptSuccessCallback = [wrapper, algorithmPtr, parametersPtr](const Vector<uint8_t>& encryptedData) mutable {
666             delete algorithmPtr;
667             delete parametersPtr;
668             wrapper.resolve(encryptedData);
669         };
670         auto encryptFailureCallback = [wrapper, algorithmPtr, parametersPtr]() mutable {
671             delete algorithmPtr;
672             delete parametersPtr;
673             wrapper.reject(nullptr);
674         };
675         ExceptionCode ec = 0;
676         algorithmPtr->encryptForWrapKey(*parametersPtr, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), WTF::move(encryptSuccessCallback), WTF::move(encryptFailureCallback), ec);
677         if (ec) {
678             // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
679             encryptFailureCallback();
680         }
681     };
682
683     auto exportFailureCallback = [wrapper, algorithmPtr, parametersPtr]() mutable {
684         delete algorithmPtr;
685         delete parametersPtr;
686         wrapper.reject(nullptr);
687     };
688
689     ExceptionCode ec = 0;
690     WebCore::exportKey(exec, keyFormat, *key, WTF::move(exportSuccessCallback), WTF::move(exportFailureCallback));
691     if (ec) {
692         setDOMException(exec, ec);
693         return jsUndefined();
694     }
695
696     return wrapper.promise();
697 }
698
699 JSValue JSSubtleCrypto::unwrapKey(ExecState* exec)
700 {
701     if (exec->argumentCount() < 5)
702         return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
703
704     CryptoKeyFormat keyFormat;
705     if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
706         ASSERT(exec->hadException());
707         return jsUndefined();
708     }
709
710     CryptoOperationData wrappedKeyData;
711     if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), wrappedKeyData)) {
712         ASSERT(exec->hadException());
713         return jsUndefined();
714     }
715
716     RefPtr<CryptoKey> unwrappingKey = toCryptoKey(exec->uncheckedArgument(2));
717     if (!unwrappingKey)
718         return throwTypeError(exec);
719
720     if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) {
721         m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'unwrapKey'"));
722         setDOMException(exec, NOT_SUPPORTED_ERR);
723         return jsUndefined();
724     }
725
726     std::unique_ptr<CryptoAlgorithm> unwrapAlgorithm;
727     std::unique_ptr<CryptoAlgorithmParameters> unwrapAlgorithmParameters;
728     unwrapAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3));
729     if (!unwrapAlgorithm) {
730         ASSERT(exec->hadException());
731         return jsUndefined();
732     }
733     unwrapAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(exec, unwrapAlgorithm->identifier(), exec->uncheckedArgument(3));
734     if (!unwrapAlgorithmParameters) {
735         ASSERT(exec->hadException());
736         return jsUndefined();
737     }
738
739     std::unique_ptr<CryptoAlgorithm> unwrappedKeyAlgorithm;
740     std::unique_ptr<CryptoAlgorithmParameters> unwrappedKeyAlgorithmParameters;
741     if (!exec->uncheckedArgument(4).isNull()) {
742         unwrappedKeyAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(4));
743         if (!unwrappedKeyAlgorithm) {
744             ASSERT(exec->hadException());
745             return jsUndefined();
746         }
747         unwrappedKeyAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, unwrappedKeyAlgorithm->identifier(), exec->uncheckedArgument(4));
748         if (!unwrappedKeyAlgorithmParameters) {
749             ASSERT(exec->hadException());
750             return jsUndefined();
751         }
752     }
753
754     bool extractable = false;
755     if (exec->argumentCount() >= 6) {
756         extractable = exec->uncheckedArgument(5).toBoolean(exec);
757         if (exec->hadException())
758             return jsUndefined();
759     }
760
761     CryptoKeyUsage keyUsages = 0;
762     if (exec->argumentCount() >= 7) {
763         if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(6), keyUsages)) {
764             ASSERT(exec->hadException());
765             return jsUndefined();
766         }
767     }
768
769     DeferredWrapper wrapper(exec, globalObject());
770     Strong<JSDOMGlobalObject> domGlobalObject(exec->vm(), globalObject());
771
772     CryptoAlgorithm* unwrappedKeyAlgorithmPtr = unwrappedKeyAlgorithm.release();
773     CryptoAlgorithmParameters* unwrappedKeyAlgorithmParametersPtr = unwrappedKeyAlgorithmParameters.release();
774
775     auto decryptSuccessCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, wrapper](const Vector<uint8_t>& result) mutable {
776         auto importSuccessCallback = [wrapper](CryptoKey& key) mutable {
777             wrapper.resolve(&key);
778         };
779         auto importFailureCallback = [wrapper]() mutable {
780             wrapper.reject(nullptr);
781         };
782         ExecState* exec = domGlobalObject->globalExec();
783         WebCore::importKey(exec, keyFormat, std::make_pair(result.data(), result.size()), unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, WTF::move(importSuccessCallback), WTF::move(importFailureCallback));
784         if (exec->hadException()) {
785             // FIXME: Report exception details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
786             exec->clearException();
787             importFailureCallback();
788         }
789     };
790
791     auto decryptFailureCallback = [wrapper, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr]() mutable {
792         delete unwrappedKeyAlgorithmPtr;
793         delete unwrappedKeyAlgorithmParametersPtr;
794         wrapper.reject(nullptr);
795     };
796
797     ExceptionCode ec = 0;
798     unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, WTF::move(decryptSuccessCallback), WTF::move(decryptFailureCallback), ec);
799     if (ec) {
800         setDOMException(exec, ec);
801         return jsUndefined();
802     }
803
804     return wrapper.promise();
805 }
806
807 } // namespace WebCore
808
809 #endif