OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/child/webcrypto/webcrypto_impl.h" | 5 #include "content/child/webcrypto/webcrypto_impl.h" |
6 | 6 |
7 #include "base/bind.h" | |
8 #include "base/lazy_instance.h" | |
9 #include "base/location.h" | |
7 #include "base/logging.h" | 10 #include "base/logging.h" |
8 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/task_runner.h" | |
14 #include "base/thread_task_runner_handle.h" | |
15 #include "base/threading/sequenced_worker_pool.h" | |
16 #include "base/threading/worker_pool.h" | |
9 #include "content/child/webcrypto/crypto_data.h" | 17 #include "content/child/webcrypto/crypto_data.h" |
10 #include "content/child/webcrypto/shared_crypto.h" | 18 #include "content/child/webcrypto/shared_crypto.h" |
11 #include "content/child/webcrypto/status.h" | 19 #include "content/child/webcrypto/status.h" |
12 #include "content/child/webcrypto/webcrypto_util.h" | 20 #include "content/child/webcrypto/webcrypto_util.h" |
21 #include "content/child/worker_thread_task_runner.h" | |
13 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | 22 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" |
14 #include "third_party/WebKit/public/platform/WebString.h" | 23 #include "third_party/WebKit/public/platform/WebString.h" |
15 | 24 |
16 namespace content { | 25 namespace content { |
17 | 26 |
18 using webcrypto::Status; | 27 using webcrypto::Status; |
19 | 28 |
20 namespace { | 29 namespace { |
21 | 30 |
31 // --------------------- | |
32 // Threading | |
33 // --------------------- | |
34 // | |
35 // WebCrypto operations can be slow. For instance generating an RSA key can | |
36 // takes hundreds of milliseconds. | |
Ryan Sleevi
2014/04/18 00:51:26
"hundreds of milliseconds to several seconds" (eg:
eroman
2014/04/18 18:45:56
Done.
| |
37 // | |
38 // Moreover the underlying crypto libraries are not threadsafe when operating | |
39 // on the same key. | |
40 // | |
41 // The strategy used here is to run a sequenced worker pool for all WebCrypto | |
42 // operations. This pool (of 1 threads) is also used by requests started from | |
43 // blink Web Workers. | |
Ryan Sleevi
2014/04/18 00:51:26
s/blink/Blink/
| |
44 // | |
45 // A few notes to keep in mind: | |
46 // | |
47 // * PostTaskAndReply() cannot be used for two reasons: | |
48 // | |
49 // (1) Blink Web Worker threads do not have an associated message loop so | |
50 // construction of the reply callback will crash. | |
51 // | |
52 // (2) PostTaskAndReply() handles failure posting the reply by leaking the | |
53 // callback, rather than destroying it. In the case of Web Workers this | |
54 // condition is reachable via normal execution, since Web Workers can | |
55 // be stopped before the WebCrypto operation has finished. A policy of | |
56 // leaking would therefore be problematic. | |
57 // | |
58 // * blink::WebArrayBuffer is NOT threadsafe, and should therefore be allocated | |
59 // on the target blink thread. | |
60 // | |
61 // TODO(eroman): Is there any way around this? Copying the result between | |
62 // threads is silly. | |
63 // | |
64 // * WebCryptoAlgorithm and WebCryptoKey are threadsafe (however the key's | |
65 // handle() which wraps an NSS/OpenSSL type may not be, and should only be | |
Ryan Sleevi
2014/04/18 00:51:26
s/handle() /handle(), /
s/type may/type, may/
eroman
2014/04/18 18:45:56
Done.
| |
66 // used from the webcrypto thread). | |
67 // | |
68 // * blink::WebCryptoResult is NOT threadsafe and should only be operated on | |
69 // the target blink thread. | |
Ryan Sleevi
2014/04/18 00:51:26
s/blink/Blink/
| |
70 // | |
71 // TODO(eroman): In the current design the WebCryptoResult object may be | |
72 // destroyed from the webcrypto worker pool if the blink worker | |
Ryan Sleevi
2014/04/18 00:51:26
s/blink/Blink/
| |
73 // thread has vanished by the time the operation completes. This | |
74 // requires further investigation since WebCryptoResult itself is | |
75 // not thread safe... However if the worker thread has been | |
76 // stopped then the potential for races seems limited. | |
77 class CryptoThreadPool { | |
78 public: | |
79 CryptoThreadPool() | |
80 : worker_pool_(new base::SequencedWorkerPool(1, "WebCrypto")), | |
81 task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( | |
82 worker_pool_->GetSequenceToken(), | |
83 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {} | |
84 | |
85 static bool PostTask(const tracked_objects::Location& from_here, | |
86 const base::Closure& task); | |
87 | |
88 private: | |
89 scoped_refptr<base::SequencedWorkerPool> worker_pool_; | |
90 scoped_refptr<base::SequencedTaskRunner> task_runner_; | |
91 }; | |
92 | |
93 base::LazyInstance<CryptoThreadPool> crypto_thread_pool = | |
Ryan Sleevi
2014/04/18 00:51:26
LeakyLazyInstance
eroman
2014/04/18 18:45:56
Done.
| |
94 LAZY_INSTANCE_INITIALIZER; | |
95 | |
96 bool CryptoThreadPool::PostTask(const tracked_objects::Location& from_here, | |
97 const base::Closure& task) { | |
98 return crypto_thread_pool.Get().task_runner_->PostTask(from_here, task); | |
99 } | |
100 | |
101 const char kFailedPostingToThreadPool[] = | |
102 "Failed posting to crypto worker pool"; | |
103 | |
22 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { | 104 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { |
23 DCHECK(status.IsError()); | 105 DCHECK(status.IsError()); |
24 if (status.HasErrorDetails()) | 106 if (status.HasErrorDetails()) |
25 result->completeWithError(blink::WebString::fromUTF8(status.ToString())); | 107 result->completeWithError(blink::WebString::fromUTF8(status.ToString())); |
26 else | 108 else |
27 result->completeWithError(); | 109 result->completeWithError(); |
28 } | 110 } |
29 | 111 |
112 void CompleteWithBuffer(const Status& status, | |
113 const std::vector<uint8>& buffer, | |
114 blink::WebCryptoResult* result) { | |
115 if (status.IsError()) | |
116 CompleteWithError(status, result); | |
117 else { | |
Ryan Sleevi
2014/04/18 00:51:26
use braces on 115 and 117 to match 117
eroman
2014/04/18 18:45:56
Done.
| |
118 if (buffer.size() > UINT_MAX) { | |
119 // WebArrayBuffers have a smaller range than std::vector<>, so | |
120 // theoretically this could overflow. | |
121 CompleteWithError(Status::ErrorUnexpected(), result); | |
122 } else { | |
123 result->completeWithBuffer(webcrypto::Uint8VectorStart(buffer), | |
124 buffer.size()); | |
125 } | |
126 } | |
127 } | |
128 | |
129 void CompleteWithKey(const Status& status, | |
130 const blink::WebCryptoKey& key, | |
131 blink::WebCryptoResult* result) { | |
132 if (status.IsError()) | |
133 CompleteWithError(status, result); | |
134 else { | |
135 result->completeWithKey(key); | |
136 } | |
Ryan Sleevi
2014/04/18 00:51:26
inconsistent braces. Brace ALL the things or brace
eroman
2014/04/18 18:45:56
Done.
I agree.
Not sure how this happened, proba
| |
137 } | |
138 | |
30 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { | 139 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { |
31 // TODO(padolph): include all other asymmetric algorithms once they are | 140 // TODO(padolph): include all other asymmetric algorithms once they are |
32 // defined, e.g. EC and DH. | 141 // defined, e.g. EC and DH. |
33 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 142 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
34 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | 143 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || |
35 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); | 144 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); |
36 } | 145 } |
37 | 146 |
147 // Blink WebWorker threads do not have an associated task runner. | |
148 scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() { | |
149 if (base::ThreadTaskRunnerHandle::IsSet()) | |
150 return base::ThreadTaskRunnerHandle::Get(); | |
151 return WorkerThreadTaskRunner::current(); | |
152 } | |
Ryan Sleevi
2014/04/18 00:51:26
This comment and this function do not make sense i
eroman
2014/04/18 18:45:56
Changed the comment to hopefully clarify things:
| |
153 | |
154 // -------------------------------------------------------------------- | |
155 // State | |
156 // -------------------------------------------------------------------- | |
157 // | |
158 // Explicit state classes are used rather than base::Bind(). This is done | |
159 // both for clarity, but also to avoid extraneous allocations for things | |
160 // like passing buffers and result objects between threads. | |
161 // | |
162 // BaseState is the base class common to all of the async operations, and | |
163 // keeps track of the thread to complete on, the error state, and the | |
164 // callback into blink. | |
165 // | |
166 // Ownership of the State object is passed between the crypto thread and the | |
167 // Blink thread. Under normal completion it is destroyed on the Blink thread. | |
168 // However it may also be destroyed on the crypto thread if the Blink thread | |
169 // has vanished (which can happen for blink web worker threads). | |
170 | |
171 struct BaseState { | |
172 explicit BaseState(const blink::WebCryptoResult& result) | |
173 : origin_thread(GetCurrentBlinkThread()), result(result) {} | |
174 | |
175 scoped_refptr<base::TaskRunner> origin_thread; | |
176 | |
177 webcrypto::Status status; | |
178 blink::WebCryptoResult result; | |
179 | |
180 protected: | |
181 // Since there is no virtual destructor, must not delete directly as a | |
182 // BaseState. | |
183 ~BaseState() {} | |
184 }; | |
185 | |
186 struct EncryptState : public BaseState { | |
187 EncryptState(const blink::WebCryptoAlgorithm& algorithm, | |
188 const blink::WebCryptoKey& key, | |
189 const unsigned char* data, | |
190 unsigned int data_size, | |
191 const blink::WebCryptoResult& result) | |
192 : BaseState(result), | |
193 algorithm(algorithm), | |
194 key(key), | |
195 data(data, data + data_size) {} | |
196 | |
197 const blink::WebCryptoAlgorithm algorithm; | |
198 const blink::WebCryptoKey key; | |
199 const std::vector<uint8> data; | |
200 | |
201 std::vector<uint8> buffer; | |
202 }; | |
203 | |
204 typedef EncryptState DecryptState; | |
205 typedef EncryptState DigestState; | |
206 | |
207 struct GenerateKeyState : public BaseState { | |
208 GenerateKeyState(const blink::WebCryptoAlgorithm& algorithm, | |
209 bool extractable, | |
210 blink::WebCryptoKeyUsageMask usage_mask, | |
211 const blink::WebCryptoResult& result) | |
212 : BaseState(result), | |
213 algorithm(algorithm), | |
214 extractable(extractable), | |
215 usage_mask(usage_mask), | |
216 public_key(blink::WebCryptoKey::createNull()), | |
217 private_key(blink::WebCryptoKey::createNull()), | |
218 is_asymetric(false) {} | |
219 | |
220 const blink::WebCryptoAlgorithm algorithm; | |
221 const bool extractable; | |
222 const blink::WebCryptoKeyUsageMask usage_mask; | |
223 | |
224 // If |is_asymetric| is false, then |public_key| is understood to mean the | |
Ryan Sleevi
2014/04/18 00:51:26
asymmetric
eroman
2014/04/18 18:45:56
Done throughout.
| |
225 // symmetric key, and |private_key| is unused. | |
226 blink::WebCryptoKey public_key; | |
227 blink::WebCryptoKey private_key; | |
228 bool is_asymetric; | |
Ryan Sleevi
2014/04/18 00:51:26
asymmetric
| |
229 }; | |
230 | |
231 struct ImportKeyState : public BaseState { | |
232 ImportKeyState(blink::WebCryptoKeyFormat format, | |
233 const unsigned char* key_data, | |
234 unsigned int key_data_size, | |
235 const blink::WebCryptoAlgorithm& algorithm, | |
236 bool extractable, | |
237 blink::WebCryptoKeyUsageMask usage_mask, | |
238 const blink::WebCryptoResult& result) | |
239 : BaseState(result), | |
240 format(format), | |
241 key_data(key_data, key_data + key_data_size), | |
242 algorithm(algorithm), | |
243 extractable(extractable), | |
244 usage_mask(usage_mask), | |
245 key(blink::WebCryptoKey::createNull()) {} | |
246 | |
247 const blink::WebCryptoKeyFormat format; | |
248 const std::vector<uint8> key_data; | |
249 const blink::WebCryptoAlgorithm algorithm; | |
250 const bool extractable; | |
251 const blink::WebCryptoKeyUsageMask usage_mask; | |
252 | |
253 blink::WebCryptoKey key; | |
254 }; | |
255 | |
256 struct ExportKeyState : public BaseState { | |
257 ExportKeyState(blink::WebCryptoKeyFormat format, | |
258 const blink::WebCryptoKey& key, | |
259 const blink::WebCryptoResult& result) | |
260 : BaseState(result), format(format), key(key) {} | |
261 | |
262 const blink::WebCryptoKeyFormat format; | |
263 const blink::WebCryptoKey key; | |
264 | |
265 std::vector<uint8> buffer; | |
266 }; | |
267 | |
268 typedef EncryptState SignState; | |
269 | |
270 struct VerifySignatureState : public BaseState { | |
271 VerifySignatureState(const blink::WebCryptoAlgorithm& algorithm, | |
272 const blink::WebCryptoKey& key, | |
273 const unsigned char* signature, | |
274 unsigned int signature_size, | |
275 const unsigned char* data, | |
276 unsigned int data_size, | |
277 const blink::WebCryptoResult& result) | |
278 : BaseState(result), | |
279 algorithm(algorithm), | |
280 key(key), | |
281 signature(signature, signature + signature_size), | |
282 data(data, data + data_size), | |
283 verify_result(false) {} | |
284 | |
285 const blink::WebCryptoAlgorithm algorithm; | |
286 const blink::WebCryptoKey key; | |
287 const std::vector<uint8> signature; | |
288 const std::vector<uint8> data; | |
289 | |
290 bool verify_result; | |
291 }; | |
292 | |
293 struct WrapKeyState : public BaseState { | |
294 WrapKeyState(blink::WebCryptoKeyFormat format, | |
295 const blink::WebCryptoKey& key, | |
296 const blink::WebCryptoKey& wrapping_key, | |
297 const blink::WebCryptoAlgorithm& wrap_algorithm, | |
298 const blink::WebCryptoResult& result) | |
299 : BaseState(result), | |
300 format(format), | |
301 key(key), | |
302 wrapping_key(wrapping_key), | |
303 wrap_algorithm(wrap_algorithm) {} | |
304 | |
305 const blink::WebCryptoKeyFormat format; | |
306 const blink::WebCryptoKey key; | |
307 const blink::WebCryptoKey wrapping_key; | |
308 const blink::WebCryptoAlgorithm wrap_algorithm; | |
309 | |
310 std::vector<uint8> buffer; | |
311 }; | |
312 | |
313 struct UnwrapKeyState : public BaseState { | |
314 UnwrapKeyState(blink::WebCryptoKeyFormat format, | |
315 const unsigned char* wrapped_key, | |
316 unsigned wrapped_key_size, | |
317 const blink::WebCryptoKey& wrapping_key, | |
318 const blink::WebCryptoAlgorithm& unwrap_algorithm, | |
319 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, | |
320 bool extractable, | |
321 blink::WebCryptoKeyUsageMask usages, | |
322 const blink::WebCryptoResult& result) | |
323 : BaseState(result), | |
324 format(format), | |
325 wrapped_key(wrapped_key, wrapped_key + wrapped_key_size), | |
326 wrapping_key(wrapping_key), | |
327 unwrap_algorithm(unwrap_algorithm), | |
328 unwrapped_key_algorithm(unwrapped_key_algorithm), | |
329 extractable(extractable), | |
330 usages(usages), | |
331 unwrapped_key(blink::WebCryptoKey::createNull()) {} | |
332 | |
333 const blink::WebCryptoKeyFormat format; | |
334 const std::vector<uint8> wrapped_key; | |
335 const blink::WebCryptoKey wrapping_key; | |
336 const blink::WebCryptoAlgorithm unwrap_algorithm; | |
337 const blink::WebCryptoAlgorithm unwrapped_key_algorithm; | |
338 const bool extractable; | |
339 const blink::WebCryptoKeyUsageMask usages; | |
340 | |
341 blink::WebCryptoKey unwrapped_key; | |
342 }; | |
343 | |
344 // -------------------------------------------------------------------- | |
345 // Wrapper functions | |
346 // -------------------------------------------------------------------- | |
347 // | |
348 // * The methods named Do*() run on the crypto thread. | |
349 // * The methods named Do*Reply() run on the target Blink thread | |
350 | |
351 void DoEncryptReply(scoped_ptr<EncryptState> state) { | |
352 CompleteWithBuffer(state->status, state->buffer, &state->result); | |
353 } | |
354 | |
355 void DoEncrypt(scoped_ptr<EncryptState> state) { | |
356 state->status = webcrypto::Encrypt(state->algorithm, | |
357 state->key, | |
358 webcrypto::CryptoData(state->data), | |
359 &state->buffer); | |
360 state->origin_thread->PostTask(FROM_HERE, | |
361 base::Bind(DoEncryptReply, Passed(&state))); | |
362 } | |
363 | |
364 void DoDecryptReply(scoped_ptr<DecryptState> state) { | |
365 CompleteWithBuffer(state->status, state->buffer, &state->result); | |
366 } | |
367 | |
368 void DoDecrypt(scoped_ptr<DecryptState> state) { | |
369 state->status = webcrypto::Decrypt(state->algorithm, | |
370 state->key, | |
371 webcrypto::CryptoData(state->data), | |
372 &state->buffer); | |
373 state->origin_thread->PostTask(FROM_HERE, | |
374 base::Bind(DoDecryptReply, Passed(&state))); | |
375 } | |
376 | |
377 void DoDigestReply(scoped_ptr<DigestState> state) { | |
378 CompleteWithBuffer(state->status, state->buffer, &state->result); | |
379 } | |
380 | |
381 void DoDigest(scoped_ptr<DigestState> state) { | |
382 state->status = webcrypto::Digest( | |
383 state->algorithm, webcrypto::CryptoData(state->data), &state->buffer); | |
384 state->origin_thread->PostTask(FROM_HERE, | |
385 base::Bind(DoDigestReply, Passed(&state))); | |
386 } | |
387 | |
388 void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) { | |
389 if (state->status.IsError()) { | |
390 CompleteWithError(state->status, &state->result); | |
Ryan Sleevi
2014/04/18 00:51:26
Why do you allow CompleteWithError() here and in D
eroman
2014/04/18 18:45:56
Agreed. Done
| |
391 } else { | |
392 if (state->is_asymetric) | |
393 state->result.completeWithKeyPair(state->public_key, state->private_key); | |
394 else | |
395 state->result.completeWithKey(state->public_key); | |
396 } | |
397 } | |
398 | |
399 void DoGenerateKey(scoped_ptr<GenerateKeyState> state) { | |
400 state->is_asymetric = IsAlgorithmAsymmetric(state->algorithm); | |
401 if (state->is_asymetric) { | |
402 state->status = webcrypto::GenerateKeyPair(state->algorithm, | |
403 state->extractable, | |
404 state->usage_mask, | |
405 &state->public_key, | |
406 &state->private_key); | |
407 | |
408 DCHECK(state->public_key.handle()); | |
409 DCHECK(state->private_key.handle()); | |
410 DCHECK_EQ(state->algorithm.id(), state->public_key.algorithm().id()); | |
411 DCHECK_EQ(state->algorithm.id(), state->private_key.algorithm().id()); | |
412 DCHECK_EQ(true, state->public_key.extractable()); | |
413 DCHECK_EQ(state->extractable, state->private_key.extractable()); | |
414 DCHECK_EQ(state->usage_mask, state->public_key.usages()); | |
415 DCHECK_EQ(state->usage_mask, state->private_key.usages()); | |
416 } else { | |
417 blink::WebCryptoKey* key = &state->public_key; | |
418 | |
419 state->status = webcrypto::GenerateSecretKey( | |
420 state->algorithm, state->extractable, state->usage_mask, key); | |
421 | |
422 DCHECK(key->handle()); | |
423 DCHECK_EQ(state->algorithm.id(), key->algorithm().id()); | |
424 DCHECK_EQ(state->extractable, key->extractable()); | |
425 DCHECK_EQ(state->usage_mask, key->usages()); | |
426 } | |
427 | |
428 state->origin_thread->PostTask( | |
429 FROM_HERE, base::Bind(DoGenerateKeyReply, Passed(&state))); | |
430 } | |
431 | |
432 void DoImportKeyReply(scoped_ptr<ImportKeyState> state) { | |
433 CompleteWithKey(state->status, state->key, &state->result); | |
434 } | |
435 | |
436 void DoImportKey(scoped_ptr<ImportKeyState> state) { | |
437 state->status = webcrypto::ImportKey(state->format, | |
438 webcrypto::CryptoData(state->key_data), | |
439 state->algorithm, | |
440 state->extractable, | |
441 state->usage_mask, | |
442 &state->key); | |
443 DCHECK(state->key.handle()); | |
444 DCHECK(!state->key.algorithm().isNull()); | |
445 DCHECK_EQ(state->extractable, state->key.extractable()); | |
446 | |
447 state->origin_thread->PostTask(FROM_HERE, | |
448 base::Bind(DoImportKeyReply, Passed(&state))); | |
449 } | |
450 | |
451 void DoExportKeyReply(scoped_ptr<ExportKeyState> state) { | |
452 CompleteWithBuffer(state->status, state->buffer, &state->result); | |
453 } | |
454 | |
455 void DoExportKey(scoped_ptr<ExportKeyState> state) { | |
456 state->status = | |
457 webcrypto::ExportKey(state->format, state->key, &state->buffer); | |
458 state->origin_thread->PostTask(FROM_HERE, | |
459 base::Bind(DoExportKeyReply, Passed(&state))); | |
460 } | |
461 | |
462 void DoSignReply(scoped_ptr<SignState> state) { | |
463 CompleteWithBuffer(state->status, state->buffer, &state->result); | |
464 } | |
465 | |
466 void DoSign(scoped_ptr<SignState> state) { | |
467 state->status = webcrypto::Sign(state->algorithm, | |
468 state->key, | |
469 webcrypto::CryptoData(state->data), | |
470 &state->buffer); | |
471 | |
472 state->origin_thread->PostTask(FROM_HERE, | |
473 base::Bind(DoSignReply, Passed(&state))); | |
474 } | |
475 | |
476 void DoVerifyReply(scoped_ptr<VerifySignatureState> state) { | |
477 if (state->status.IsError()) { | |
478 CompleteWithError(state->status, &state->result); | |
479 } else { | |
480 state->result.completeWithBoolean(state->verify_result); | |
481 } | |
482 } | |
483 | |
484 void DoVerify(scoped_ptr<VerifySignatureState> state) { | |
485 state->status = | |
486 webcrypto::VerifySignature(state->algorithm, | |
487 state->key, | |
488 webcrypto::CryptoData(state->signature), | |
489 webcrypto::CryptoData(state->data), | |
490 &state->verify_result); | |
491 | |
492 state->origin_thread->PostTask(FROM_HERE, | |
493 base::Bind(DoVerifyReply, Passed(&state))); | |
494 } | |
495 | |
496 void DoWrapKeyReply(scoped_ptr<WrapKeyState> state) { | |
497 CompleteWithBuffer(state->status, state->buffer, &state->result); | |
498 } | |
499 | |
500 void DoWrapKey(scoped_ptr<WrapKeyState> state) { | |
501 // TODO(eroman): The parameter ordering of webcrypto::WrapKey() is | |
502 // inconsistent with that of blink::WebCrypto::wrapKey(). | |
503 state->status = webcrypto::WrapKey(state->format, | |
504 state->wrapping_key, | |
505 state->key, | |
506 state->wrap_algorithm, | |
507 &state->buffer); | |
508 | |
509 state->origin_thread->PostTask(FROM_HERE, | |
510 base::Bind(DoWrapKeyReply, Passed(&state))); | |
511 } | |
512 | |
513 void DoUnwrapKeyReply(scoped_ptr<UnwrapKeyState> state) { | |
514 CompleteWithKey(state->status, state->unwrapped_key, &state->result); | |
515 } | |
516 | |
517 void DoUnwrapKey(scoped_ptr<UnwrapKeyState> state) { | |
518 state->status = | |
519 webcrypto::UnwrapKey(state->format, | |
520 webcrypto::CryptoData(state->wrapped_key), | |
521 state->wrapping_key, | |
522 state->unwrap_algorithm, | |
523 state->unwrapped_key_algorithm, | |
524 state->extractable, | |
525 state->usages, | |
526 &state->unwrapped_key); | |
527 | |
528 state->origin_thread->PostTask(FROM_HERE, | |
529 base::Bind(DoUnwrapKeyReply, Passed(&state))); | |
530 } | |
531 | |
38 } // namespace | 532 } // namespace |
39 | 533 |
40 WebCryptoImpl::WebCryptoImpl() { webcrypto::Init(); } | 534 WebCryptoImpl::WebCryptoImpl() { |
41 | 535 webcrypto::Init(); |
42 WebCryptoImpl::~WebCryptoImpl() {} | 536 } |
537 | |
538 WebCryptoImpl::~WebCryptoImpl() { | |
539 } | |
43 | 540 |
44 void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm, | 541 void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm, |
45 const blink::WebCryptoKey& key, | 542 const blink::WebCryptoKey& key, |
46 const unsigned char* data, | 543 const unsigned char* data, |
47 unsigned int data_size, | 544 unsigned int data_size, |
48 blink::WebCryptoResult result) { | 545 blink::WebCryptoResult result) { |
49 DCHECK(!algorithm.isNull()); | 546 DCHECK(!algorithm.isNull()); |
50 blink::WebArrayBuffer buffer; | 547 |
51 Status status = webcrypto::Encrypt( | 548 scoped_ptr<EncryptState> state( |
52 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); | 549 new EncryptState(algorithm, key, data, data_size, result)); |
53 if (status.IsError()) | 550 if (!CryptoThreadPool::PostTask(FROM_HERE, |
54 CompleteWithError(status, &result); | 551 base::Bind(DoEncrypt, Passed(&state)))) { |
55 else | 552 result.completeWithError(kFailedPostingToThreadPool); |
56 result.completeWithBuffer(buffer); | 553 } |
57 } | 554 } |
58 | 555 |
59 void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, | 556 void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, |
60 const blink::WebCryptoKey& key, | 557 const blink::WebCryptoKey& key, |
61 const unsigned char* data, | 558 const unsigned char* data, |
62 unsigned int data_size, | 559 unsigned int data_size, |
63 blink::WebCryptoResult result) { | 560 blink::WebCryptoResult result) { |
64 DCHECK(!algorithm.isNull()); | 561 DCHECK(!algorithm.isNull()); |
65 blink::WebArrayBuffer buffer; | 562 |
66 Status status = webcrypto::Decrypt( | 563 scoped_ptr<DecryptState> state( |
67 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); | 564 new DecryptState(algorithm, key, data, data_size, result)); |
68 if (status.IsError()) | 565 if (!CryptoThreadPool::PostTask(FROM_HERE, |
69 CompleteWithError(status, &result); | 566 base::Bind(DoDecrypt, Passed(&state)))) { |
70 else | 567 result.completeWithError(kFailedPostingToThreadPool); |
71 result.completeWithBuffer(buffer); | 568 } |
72 } | 569 } |
73 | 570 |
74 void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, | 571 void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, |
75 const unsigned char* data, | 572 const unsigned char* data, |
76 unsigned int data_size, | 573 unsigned int data_size, |
77 blink::WebCryptoResult result) { | 574 blink::WebCryptoResult result) { |
78 DCHECK(!algorithm.isNull()); | 575 DCHECK(!algorithm.isNull()); |
79 blink::WebArrayBuffer buffer; | 576 |
80 Status status = webcrypto::Digest( | 577 scoped_ptr<DigestState> state(new DigestState( |
81 algorithm, webcrypto::CryptoData(data, data_size), &buffer); | 578 algorithm, blink::WebCryptoKey::createNull(), data, data_size, result)); |
82 if (status.IsError()) | 579 if (!CryptoThreadPool::PostTask(FROM_HERE, |
83 CompleteWithError(status, &result); | 580 base::Bind(DoDigest, Passed(&state)))) { |
84 else | 581 result.completeWithError(kFailedPostingToThreadPool); |
85 result.completeWithBuffer(buffer); | 582 } |
86 } | 583 } |
87 | 584 |
88 void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, | 585 void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, |
89 bool extractable, | 586 bool extractable, |
90 blink::WebCryptoKeyUsageMask usage_mask, | 587 blink::WebCryptoKeyUsageMask usage_mask, |
91 blink::WebCryptoResult result) { | 588 blink::WebCryptoResult result) { |
92 DCHECK(!algorithm.isNull()); | 589 DCHECK(!algorithm.isNull()); |
93 if (IsAlgorithmAsymmetric(algorithm)) { | 590 |
94 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); | 591 scoped_ptr<GenerateKeyState> state( |
95 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); | 592 new GenerateKeyState(algorithm, extractable, usage_mask, result)); |
96 Status status = webcrypto::GenerateKeyPair( | 593 if (!CryptoThreadPool::PostTask(FROM_HERE, |
97 algorithm, extractable, usage_mask, &public_key, &private_key); | 594 base::Bind(DoGenerateKey, Passed(&state)))) { |
98 if (status.IsError()) { | 595 result.completeWithError(kFailedPostingToThreadPool); |
99 CompleteWithError(status, &result); | |
100 } else { | |
101 DCHECK(public_key.handle()); | |
102 DCHECK(private_key.handle()); | |
103 DCHECK_EQ(algorithm.id(), public_key.algorithm().id()); | |
104 DCHECK_EQ(algorithm.id(), private_key.algorithm().id()); | |
105 DCHECK_EQ(true, public_key.extractable()); | |
106 DCHECK_EQ(extractable, private_key.extractable()); | |
107 DCHECK_EQ(usage_mask, public_key.usages()); | |
108 DCHECK_EQ(usage_mask, private_key.usages()); | |
109 result.completeWithKeyPair(public_key, private_key); | |
110 } | |
111 } else { | |
112 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | |
113 Status status = | |
114 webcrypto::GenerateSecretKey(algorithm, extractable, usage_mask, &key); | |
115 if (status.IsError()) { | |
116 CompleteWithError(status, &result); | |
117 } else { | |
118 DCHECK(key.handle()); | |
119 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
120 DCHECK_EQ(extractable, key.extractable()); | |
121 DCHECK_EQ(usage_mask, key.usages()); | |
122 result.completeWithKey(key); | |
123 } | |
124 } | 596 } |
125 } | 597 } |
126 | 598 |
127 void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format, | 599 void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format, |
128 const unsigned char* key_data, | 600 const unsigned char* key_data, |
129 unsigned int key_data_size, | 601 unsigned int key_data_size, |
130 const blink::WebCryptoAlgorithm& algorithm, | 602 const blink::WebCryptoAlgorithm& algorithm, |
131 bool extractable, | 603 bool extractable, |
132 blink::WebCryptoKeyUsageMask usage_mask, | 604 blink::WebCryptoKeyUsageMask usage_mask, |
133 blink::WebCryptoResult result) { | 605 blink::WebCryptoResult result) { |
134 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 606 scoped_ptr<ImportKeyState> state(new ImportKeyState(format, |
135 Status status = | 607 key_data, |
136 webcrypto::ImportKey(format, | 608 key_data_size, |
137 webcrypto::CryptoData(key_data, key_data_size), | 609 algorithm, |
138 algorithm, | 610 extractable, |
139 extractable, | 611 usage_mask, |
140 usage_mask, | 612 result)); |
141 &key); | 613 if (!CryptoThreadPool::PostTask(FROM_HERE, |
142 if (status.IsError()) { | 614 base::Bind(DoImportKey, Passed(&state)))) { |
143 CompleteWithError(status, &result); | 615 result.completeWithError(kFailedPostingToThreadPool); |
144 } else { | |
145 DCHECK(key.handle()); | |
146 DCHECK(!key.algorithm().isNull()); | |
147 DCHECK_EQ(extractable, key.extractable()); | |
148 result.completeWithKey(key); | |
149 } | 616 } |
150 } | 617 } |
151 | 618 |
152 void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format, | 619 void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format, |
153 const blink::WebCryptoKey& key, | 620 const blink::WebCryptoKey& key, |
154 blink::WebCryptoResult result) { | 621 blink::WebCryptoResult result) { |
155 blink::WebArrayBuffer buffer; | 622 scoped_ptr<ExportKeyState> state(new ExportKeyState(format, key, result)); |
156 Status status = webcrypto::ExportKey(format, key, &buffer); | 623 if (!CryptoThreadPool::PostTask(FROM_HERE, |
157 if (status.IsError()) | 624 base::Bind(DoExportKey, Passed(&state)))) { |
158 CompleteWithError(status, &result); | 625 result.completeWithError(kFailedPostingToThreadPool); |
159 else | 626 } |
160 result.completeWithBuffer(buffer); | |
161 } | 627 } |
162 | 628 |
163 void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, | 629 void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, |
164 const blink::WebCryptoKey& key, | 630 const blink::WebCryptoKey& key, |
165 const unsigned char* data, | 631 const unsigned char* data, |
166 unsigned int data_size, | 632 unsigned int data_size, |
167 blink::WebCryptoResult result) { | 633 blink::WebCryptoResult result) { |
168 DCHECK(!algorithm.isNull()); | 634 scoped_ptr<SignState> state( |
169 blink::WebArrayBuffer buffer; | 635 new SignState(algorithm, key, data, data_size, result)); |
170 Status status = webcrypto::Sign( | 636 if (!CryptoThreadPool::PostTask(FROM_HERE, |
171 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); | 637 base::Bind(DoSign, Passed(&state)))) { |
172 if (status.IsError()) | 638 result.completeWithError(kFailedPostingToThreadPool); |
173 CompleteWithError(status, &result); | 639 } |
174 else | |
175 result.completeWithBuffer(buffer); | |
176 } | 640 } |
177 | 641 |
178 void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm, | 642 void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm, |
179 const blink::WebCryptoKey& key, | 643 const blink::WebCryptoKey& key, |
180 const unsigned char* signature, | 644 const unsigned char* signature, |
181 unsigned int signature_size, | 645 unsigned int signature_size, |
182 const unsigned char* data, | 646 const unsigned char* data, |
183 unsigned int data_size, | 647 unsigned int data_size, |
184 blink::WebCryptoResult result) { | 648 blink::WebCryptoResult result) { |
185 DCHECK(!algorithm.isNull()); | 649 scoped_ptr<VerifySignatureState> state(new VerifySignatureState( |
186 bool signature_match = false; | 650 algorithm, key, signature, signature_size, data, data_size, result)); |
187 Status status = webcrypto::VerifySignature( | 651 if (!CryptoThreadPool::PostTask(FROM_HERE, |
188 algorithm, | 652 base::Bind(DoVerify, Passed(&state)))) { |
189 key, | 653 result.completeWithError(kFailedPostingToThreadPool); |
190 webcrypto::CryptoData(signature, signature_size), | 654 } |
191 webcrypto::CryptoData(data, data_size), | |
192 &signature_match); | |
193 if (status.IsError()) | |
194 CompleteWithError(status, &result); | |
195 else | |
196 result.completeWithBoolean(signature_match); | |
197 } | 655 } |
198 | 656 |
199 void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format, | 657 void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format, |
200 const blink::WebCryptoKey& key, | 658 const blink::WebCryptoKey& key, |
201 const blink::WebCryptoKey& wrapping_key, | 659 const blink::WebCryptoKey& wrapping_key, |
202 const blink::WebCryptoAlgorithm& wrap_algorithm, | 660 const blink::WebCryptoAlgorithm& wrap_algorithm, |
203 blink::WebCryptoResult result) { | 661 blink::WebCryptoResult result) { |
204 blink::WebArrayBuffer buffer; | 662 scoped_ptr<WrapKeyState> state( |
205 // TODO(eroman): Use the same parameter ordering. | 663 new WrapKeyState(format, key, wrapping_key, wrap_algorithm, result)); |
206 Status status = webcrypto::WrapKey( | 664 if (!CryptoThreadPool::PostTask(FROM_HERE, |
207 format, wrapping_key, key, wrap_algorithm, &buffer); | 665 base::Bind(DoWrapKey, Passed(&state)))) { |
208 if (status.IsError()) | 666 result.completeWithError(kFailedPostingToThreadPool); |
209 CompleteWithError(status, &result); | 667 } |
210 else | |
211 result.completeWithBuffer(buffer); | |
212 } | 668 } |
213 | 669 |
214 void WebCryptoImpl::unwrapKey( | 670 void WebCryptoImpl::unwrapKey( |
215 blink::WebCryptoKeyFormat format, | 671 blink::WebCryptoKeyFormat format, |
216 const unsigned char* wrapped_key, | 672 const unsigned char* wrapped_key, |
217 unsigned wrapped_key_size, | 673 unsigned wrapped_key_size, |
218 const blink::WebCryptoKey& wrapping_key, | 674 const blink::WebCryptoKey& wrapping_key, |
219 const blink::WebCryptoAlgorithm& unwrap_algorithm, | 675 const blink::WebCryptoAlgorithm& unwrap_algorithm, |
220 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, | 676 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, |
221 bool extractable, | 677 bool extractable, |
222 blink::WebCryptoKeyUsageMask usages, | 678 blink::WebCryptoKeyUsageMask usages, |
223 blink::WebCryptoResult result) { | 679 blink::WebCryptoResult result) { |
224 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 680 scoped_ptr<UnwrapKeyState> state(new UnwrapKeyState(format, |
225 Status status = | 681 wrapped_key, |
226 webcrypto::UnwrapKey(format, | 682 wrapped_key_size, |
227 webcrypto::CryptoData(wrapped_key, wrapped_key_size), | 683 wrapping_key, |
228 wrapping_key, | 684 unwrap_algorithm, |
229 unwrap_algorithm, | 685 unwrapped_key_algorithm, |
230 unwrapped_key_algorithm, | 686 extractable, |
231 extractable, | 687 usages, |
232 usages, | 688 result)); |
233 &key); | 689 if (!CryptoThreadPool::PostTask(FROM_HERE, |
234 if (status.IsError()) | 690 base::Bind(DoUnwrapKey, Passed(&state)))) { |
235 CompleteWithError(status, &result); | 691 result.completeWithError(kFailedPostingToThreadPool); |
236 else | 692 } |
237 result.completeWithKey(key); | |
238 } | |
239 | |
240 bool WebCryptoImpl::digestSynchronous( | |
241 const blink::WebCryptoAlgorithmId algorithm_id, | |
242 const unsigned char* data, | |
243 unsigned int data_size, | |
244 blink::WebArrayBuffer& result) { | |
245 blink::WebCryptoAlgorithm algorithm = | |
246 blink::WebCryptoAlgorithm::adoptParamsAndCreate(algorithm_id, NULL); | |
247 return (webcrypto::Digest( | |
248 algorithm, webcrypto::CryptoData(data, data_size), &result)) | |
249 .IsSuccess(); | |
250 } | 693 } |
251 | 694 |
252 blink::WebCryptoDigestor* WebCryptoImpl::createDigestor( | 695 blink::WebCryptoDigestor* WebCryptoImpl::createDigestor( |
253 blink::WebCryptoAlgorithmId algorithm_id) { | 696 blink::WebCryptoAlgorithmId algorithm_id) { |
254 return webcrypto::CreateDigestor(algorithm_id).release(); | 697 return webcrypto::CreateDigestor(algorithm_id).release(); |
255 } | 698 } |
256 | 699 |
257 bool WebCryptoImpl::deserializeKeyForClone( | 700 bool WebCryptoImpl::deserializeKeyForClone( |
258 const blink::WebCryptoKeyAlgorithm& algorithm, | 701 const blink::WebCryptoKeyAlgorithm& algorithm, |
259 blink::WebCryptoKeyType type, | 702 blink::WebCryptoKeyType type, |
260 bool extractable, | 703 bool extractable, |
261 blink::WebCryptoKeyUsageMask usages, | 704 blink::WebCryptoKeyUsageMask usages, |
262 const unsigned char* key_data, | 705 const unsigned char* key_data, |
263 unsigned key_data_size, | 706 unsigned key_data_size, |
264 blink::WebCryptoKey& key) { | 707 blink::WebCryptoKey& key) { |
265 Status status = webcrypto::DeserializeKeyForClone( | 708 // TODO(eroman): Rather than do the import immediately on the current thread, |
709 // it could defer to the crypto thread. | |
710 return webcrypto::DeserializeKeyForClone( | |
266 algorithm, | 711 algorithm, |
267 type, | 712 type, |
268 extractable, | 713 extractable, |
269 usages, | 714 usages, |
270 webcrypto::CryptoData(key_data, key_data_size), | 715 webcrypto::CryptoData(key_data, key_data_size), |
271 &key); | 716 &key); |
272 return status.IsSuccess(); | |
273 } | 717 } |
274 | 718 |
275 bool WebCryptoImpl::serializeKeyForClone( | 719 bool WebCryptoImpl::serializeKeyForClone( |
276 const blink::WebCryptoKey& key, | 720 const blink::WebCryptoKey& key, |
277 blink::WebVector<unsigned char>& key_data) { | 721 blink::WebVector<unsigned char>& key_data) { |
278 Status status = webcrypto::SerializeKeyForClone(key, &key_data); | 722 return webcrypto::SerializeKeyForClone(key, &key_data); |
279 return status.IsSuccess(); | |
280 } | 723 } |
281 | 724 |
282 } // namespace content | 725 } // namespace content |
OLD | NEW |