• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "modules/crypto/SubtleCrypto.h"
33 
34 #include "bindings/v8/Dictionary.h"
35 #include "bindings/v8/ExceptionState.h"
36 #include "core/dom/ExceptionCode.h"
37 #include "modules/crypto/CryptoResultImpl.h"
38 #include "modules/crypto/Key.h"
39 #include "modules/crypto/NormalizeAlgorithm.h"
40 #include "public/platform/Platform.h"
41 #include "public/platform/WebCrypto.h"
42 #include "public/platform/WebCryptoAlgorithm.h"
43 #include "wtf/ArrayBufferView.h"
44 
45 namespace WebCore {
46 
47 // FIXME: asynchronous completion of CryptoResult. Need to re-enter the
48 //        v8::Context before trying to fulfill the promise, and enable test.
49 
50 namespace {
51 
startCryptoOperation(const Dictionary & rawAlgorithm,Key * key,AlgorithmOperation operationType,ArrayBufferView * signature,ArrayBufferView * dataBuffer,ExceptionState & exceptionState)52 ScriptPromise startCryptoOperation(const Dictionary& rawAlgorithm, Key* key, AlgorithmOperation operationType, ArrayBufferView* signature, ArrayBufferView* dataBuffer, ExceptionState& exceptionState)
53 {
54     bool requiresKey = operationType != Digest;
55 
56     // Seems like the generated bindings should take care of these however it
57     // currently doesn't. See also http://crbugh.com/264520
58     if (requiresKey && !key) {
59         exceptionState.throwTypeError("Invalid key argument");
60         return ScriptPromise();
61     }
62     if (operationType == Verify && !signature) {
63         exceptionState.throwTypeError("Invalid signature argument");
64         return ScriptPromise();
65     }
66     if (!dataBuffer) {
67         exceptionState.throwTypeError("Invalid dataBuffer argument");
68         return ScriptPromise();
69     }
70 
71     blink::WebCryptoAlgorithm algorithm;
72     if (!normalizeAlgorithm(rawAlgorithm, operationType, algorithm, exceptionState))
73         return ScriptPromise();
74 
75     if (requiresKey && !key->canBeUsedForAlgorithm(algorithm, operationType, exceptionState))
76         return ScriptPromise();
77 
78     const unsigned char* data = static_cast<const unsigned char*>(dataBuffer->baseAddress());
79     unsigned dataSize = dataBuffer->byteLength();
80 
81     ScriptPromise promise = ScriptPromise::createPending();
82     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
83 
84     switch (operationType) {
85     case Encrypt:
86         blink::Platform::current()->crypto()->encrypt(algorithm, key->key(), data, dataSize, result->result());
87         break;
88     case Decrypt:
89         blink::Platform::current()->crypto()->decrypt(algorithm, key->key(), data, dataSize, result->result());
90         break;
91     case Sign:
92         blink::Platform::current()->crypto()->sign(algorithm, key->key(), data, dataSize, result->result());
93         break;
94     case Verify:
95         blink::Platform::current()->crypto()->verifySignature(algorithm, key->key(), reinterpret_cast<const unsigned char*>(signature->baseAddress()), signature->byteLength(), data, dataSize, result->result());
96         break;
97     case Digest:
98         blink::Platform::current()->crypto()->digest(algorithm, data, dataSize, result->result());
99         break;
100     default:
101         ASSERT_NOT_REACHED();
102         return ScriptPromise();
103     }
104 
105     return promise;
106 }
107 
108 } // namespace
109 
SubtleCrypto()110 SubtleCrypto::SubtleCrypto()
111 {
112     ScriptWrappable::init(this);
113 }
114 
encrypt(const Dictionary & rawAlgorithm,Key * key,ArrayBufferView * data,ExceptionState & exceptionState)115 ScriptPromise SubtleCrypto::encrypt(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* data, ExceptionState& exceptionState)
116 {
117     return startCryptoOperation(rawAlgorithm, key, Encrypt, 0, data, exceptionState);
118 }
119 
decrypt(const Dictionary & rawAlgorithm,Key * key,ArrayBufferView * data,ExceptionState & exceptionState)120 ScriptPromise SubtleCrypto::decrypt(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* data, ExceptionState& exceptionState)
121 {
122     return startCryptoOperation(rawAlgorithm, key, Decrypt, 0, data, exceptionState);
123 }
124 
sign(const Dictionary & rawAlgorithm,Key * key,ArrayBufferView * data,ExceptionState & exceptionState)125 ScriptPromise SubtleCrypto::sign(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* data, ExceptionState& exceptionState)
126 {
127     return startCryptoOperation(rawAlgorithm, key, Sign, 0, data, exceptionState);
128 }
129 
verifySignature(const Dictionary & rawAlgorithm,Key * key,ArrayBufferView * signature,ArrayBufferView * data,ExceptionState & exceptionState)130 ScriptPromise SubtleCrypto::verifySignature(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* signature, ArrayBufferView* data, ExceptionState& exceptionState)
131 {
132     return startCryptoOperation(rawAlgorithm, key, Verify, signature, data, exceptionState);
133 }
134 
digest(const Dictionary & rawAlgorithm,ArrayBufferView * data,ExceptionState & exceptionState)135 ScriptPromise SubtleCrypto::digest(const Dictionary& rawAlgorithm, ArrayBufferView* data, ExceptionState& exceptionState)
136 {
137     return startCryptoOperation(rawAlgorithm, 0, Digest, 0, data, exceptionState);
138 }
139 
generateKey(const Dictionary & rawAlgorithm,bool extractable,const Vector<String> & rawKeyUsages,ExceptionState & exceptionState)140 ScriptPromise SubtleCrypto::generateKey(const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& exceptionState)
141 {
142     blink::WebCryptoKeyUsageMask keyUsages;
143     if (!Key::parseUsageMask(rawKeyUsages, keyUsages, exceptionState))
144         return ScriptPromise();
145 
146     blink::WebCryptoAlgorithm algorithm;
147     if (!normalizeAlgorithm(rawAlgorithm, GenerateKey, algorithm, exceptionState))
148         return ScriptPromise();
149 
150     ScriptPromise promise = ScriptPromise::createPending();
151     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
152     blink::Platform::current()->crypto()->generateKey(algorithm, extractable, keyUsages, result->result());
153     return promise;
154 }
155 
importKey(const String & rawFormat,ArrayBufferView * keyData,const Dictionary & rawAlgorithm,bool extractable,const Vector<String> & rawKeyUsages,ExceptionState & exceptionState)156 ScriptPromise SubtleCrypto::importKey(const String& rawFormat, ArrayBufferView* keyData, const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& exceptionState)
157 {
158     blink::WebCryptoKeyFormat format;
159     if (!Key::parseFormat(rawFormat, format, exceptionState))
160         return ScriptPromise();
161 
162     if (!keyData) {
163         exceptionState.throwTypeError("Invalid keyData argument");
164         return ScriptPromise();
165     }
166 
167     blink::WebCryptoKeyUsageMask keyUsages;
168     if (!Key::parseUsageMask(rawKeyUsages, keyUsages, exceptionState))
169         return ScriptPromise();
170 
171     // The algorithm is optional.
172     blink::WebCryptoAlgorithm algorithm;
173     if (!rawAlgorithm.isUndefinedOrNull() && !normalizeAlgorithm(rawAlgorithm, ImportKey, algorithm, exceptionState))
174         return ScriptPromise();
175 
176     const unsigned char* keyDataBytes = static_cast<unsigned char*>(keyData->baseAddress());
177 
178     ScriptPromise promise = ScriptPromise::createPending();
179     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
180     blink::Platform::current()->crypto()->importKey(format, keyDataBytes, keyData->byteLength(), algorithm, extractable, keyUsages, result->result());
181     return promise;
182 }
183 
exportKey(const String & rawFormat,Key * key,ExceptionState & exceptionState)184 ScriptPromise SubtleCrypto::exportKey(const String& rawFormat, Key* key, ExceptionState& exceptionState)
185 {
186     blink::WebCryptoKeyFormat format;
187     if (!Key::parseFormat(rawFormat, format, exceptionState))
188         return ScriptPromise();
189 
190     if (!key) {
191         exceptionState.throwTypeError("Invalid key argument");
192         return ScriptPromise();
193     }
194 
195     if (!key->extractable()) {
196         exceptionState.throwDOMException(NotSupportedError, "key is not extractable");
197         return ScriptPromise();
198     }
199 
200     ScriptPromise promise = ScriptPromise::createPending();
201     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
202     blink::Platform::current()->crypto()->exportKey(format, key->key(), result->result());
203     return promise;
204 }
205 
wrapKey(const String & rawFormat,Key * key,Key * wrappingKey,const Dictionary & rawWrapAlgorithm,ExceptionState & exceptionState)206 ScriptPromise SubtleCrypto::wrapKey(const String& rawFormat, Key* key, Key* wrappingKey, const Dictionary& rawWrapAlgorithm, ExceptionState& exceptionState)
207 {
208     blink::WebCryptoKeyFormat format;
209     if (!Key::parseFormat(rawFormat, format, exceptionState))
210         return ScriptPromise();
211 
212     if (!key) {
213         exceptionState.throwTypeError("Invalid key argument");
214         return ScriptPromise();
215     }
216 
217     if (!wrappingKey) {
218         exceptionState.throwTypeError("Invalid wrappingKey argument");
219         return ScriptPromise();
220     }
221 
222     blink::WebCryptoAlgorithm wrapAlgorithm;
223     if (!normalizeAlgorithm(rawWrapAlgorithm, WrapKey, wrapAlgorithm, exceptionState))
224         return ScriptPromise();
225 
226     if (!key->extractable()) {
227         exceptionState.throwDOMException(NotSupportedError, "key is not extractable");
228         return ScriptPromise();
229     }
230 
231     if (!wrappingKey->canBeUsedForAlgorithm(wrapAlgorithm, WrapKey, exceptionState))
232         return ScriptPromise();
233 
234     ScriptPromise promise = ScriptPromise::createPending();
235     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
236     blink::Platform::current()->crypto()->wrapKey(format, key->key(), wrappingKey->key(), wrapAlgorithm, result->result());
237     return promise;
238 }
239 
unwrapKey(const String & rawFormat,ArrayBufferView * wrappedKey,Key * unwrappingKey,const Dictionary & rawUnwrapAlgorithm,const Dictionary & rawUnwrappedKeyAlgorithm,bool extractable,const Vector<String> & rawKeyUsages,ExceptionState & exceptionState)240 ScriptPromise SubtleCrypto::unwrapKey(const String& rawFormat, ArrayBufferView* wrappedKey, Key* unwrappingKey, const Dictionary& rawUnwrapAlgorithm, const Dictionary& rawUnwrappedKeyAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& exceptionState)
241 {
242     blink::WebCryptoKeyFormat format;
243     if (!Key::parseFormat(rawFormat, format, exceptionState))
244         return ScriptPromise();
245 
246     if (!wrappedKey) {
247         exceptionState.throwTypeError("Invalid wrappedKey argument");
248         return ScriptPromise();
249     }
250 
251     if (!unwrappingKey) {
252         exceptionState.throwTypeError("Invalid unwrappingKey argument");
253         return ScriptPromise();
254     }
255 
256     blink::WebCryptoAlgorithm unwrapAlgorithm;
257     if (!normalizeAlgorithm(rawUnwrapAlgorithm, UnwrapKey, unwrapAlgorithm, exceptionState))
258         return ScriptPromise();
259 
260     // The unwrappedKeyAlgorithm is optional.
261     blink::WebCryptoAlgorithm unwrappedKeyAlgorithm;
262     if (!rawUnwrappedKeyAlgorithm.isUndefinedOrNull() && !normalizeAlgorithm(rawUnwrappedKeyAlgorithm, ImportKey, unwrappedKeyAlgorithm, exceptionState))
263         return ScriptPromise();
264 
265     blink::WebCryptoKeyUsageMask keyUsages;
266     if (!Key::parseUsageMask(rawKeyUsages, keyUsages, exceptionState))
267         return ScriptPromise();
268 
269     if (!unwrappingKey->canBeUsedForAlgorithm(unwrapAlgorithm, UnwrapKey, exceptionState))
270         return ScriptPromise();
271 
272     const unsigned char* wrappedKeyData = static_cast<const unsigned char*>(wrappedKey->baseAddress());
273     unsigned wrappedKeyDataSize = wrappedKey->byteLength();
274 
275     ScriptPromise promise = ScriptPromise::createPending();
276     RefPtr<CryptoResultImpl> result = CryptoResultImpl::create(promise);
277     blink::Platform::current()->crypto()->unwrapKey(format, wrappedKeyData, wrappedKeyDataSize, unwrappingKey->key(), unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages, result->result());
278     return promise;
279 }
280 
281 
282 } // namespace WebCore
283