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 // take hundreds of milliseconds to several seconds. | |
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. | |
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 | |
66 // used from the webcrypto thread). | |
67 // | |
68 // * blink::WebCryptoResult is not threadsafe and should only be operated on | |
69 // the target Blink thread. HOWEVER, it is safe to delete it from any thread. | |
70 // This can happen if by the time the operation has completed in the crypto | |
71 // worker pool, the Blink worker thread that initiated the request is gone. | |
72 // Posting back to the origin thread will fail, and the WebCryptoResult will | |
73 // be deleted while running in the crypto worker pool. | |
74 class CryptoThreadPool { | |
75 public: | |
76 CryptoThreadPool() | |
77 : worker_pool_(new base::SequencedWorkerPool(1, "WebCrypto")), | |
78 task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( | |
79 worker_pool_->GetSequenceToken(), | |
80 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {} | |
81 | |
82 static bool PostTask(const tracked_objects::Location& from_here, | |
83 const base::Closure& task); | |
84 | |
85 private: | |
86 scoped_refptr<base::SequencedWorkerPool> worker_pool_; | |
87 scoped_refptr<base::SequencedTaskRunner> task_runner_; | |
88 }; | |
89 | |
90 base::LazyInstance<CryptoThreadPool>::Leaky crypto_thread_pool = | |
91 LAZY_INSTANCE_INITIALIZER; | |
92 | |
93 bool CryptoThreadPool::PostTask(const tracked_objects::Location& from_here, | |
94 const base::Closure& task) { | |
95 return crypto_thread_pool.Get().task_runner_->PostTask(from_here, task); | |
96 } | |
97 | |
22 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { | 98 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { |
23 DCHECK(status.IsError()); | 99 DCHECK(status.IsError()); |
24 | 100 |
25 #if defined(WEBCRYPTO_HAS_ERROR_TYPE) | 101 #if defined(WEBCRYPTO_HAS_ERROR_TYPE) |
26 result->completeWithError(status.error_type(), | 102 result->completeWithError(status.error_type(), |
27 blink::WebString::fromUTF8(status.error_details())); | 103 blink::WebString::fromUTF8(status.error_details())); |
28 #else | 104 #else |
29 // TODO(eroman): Delete once Blink changes have rolled into Chromium. | 105 // TODO(eroman): Delete once Blink changes have rolled into Chromium. |
30 if (!status.error_details().empty()) | 106 if (!status.error_details().empty()) |
31 result->completeWithError( | 107 result->completeWithError( |
32 blink::WebString::fromUTF8(status.error_details())); | 108 blink::WebString::fromUTF8(status.error_details())); |
33 else | 109 else |
34 result->completeWithError(); | 110 result->completeWithError(); |
35 #endif | 111 #endif |
36 } | 112 } |
37 | 113 |
114 // Runs |work_func(state)| (on the crypto pool), and then posts a task back to | |
115 // the origin thread to run |reply_callback|. | |
116 template <typename State> | |
117 void DoTaskThenPostReply(Status (*work_func)(State*), | |
118 State* state, | |
119 const base::Closure& reply_callback) { | |
120 state->status = work_func(state); | |
121 state->origin_thread->PostTask(FROM_HERE, reply_callback); | |
122 } | |
123 | |
124 // Handles any errors. If there was no error, then calls |reply_func(state)| (on | |
125 // the origin thread). | |
126 template <typename State> | |
127 void DoHandleErrorsAndReply(void (*reply_func)(State*), | |
128 scoped_ptr<State> state) { | |
129 if (state->status.IsError()) | |
130 CompleteWithError(state->status, &state->result); | |
131 else | |
132 reply_func(state.get()); | |
133 } | |
134 | |
135 // Posts a task to the crypto thread pool. Once that is done, posts a task back | |
136 // to the origin thread to run the reply. | |
137 // | |
138 // * work_func -- Function pointer to be run on the crypto thread pool. Should | |
139 // return a Status object indicating success, and can stash any | |
140 // results into the state parameter. | |
141 // * reply_func -- Function pointer to be run on the origin thread. Note this | |
142 // is | |
143 // ONLY CALLED ON SUCCESS. If work_func returned an error, then | |
144 // this will not be called. | |
145 // * state -- Holds the state that is passed between threads. | |
146 template <typename State> | |
147 void PostToCryptoThreadAndReply(const tracked_objects::Location& from_here, | |
148 Status (*work_func)(State*), | |
149 void (*reply_func)(State*), | |
150 scoped_ptr<State> state) { | |
151 base::Closure reply_callback = | |
152 base::Bind(&DoHandleErrorsAndReply<State>, reply_func, Passed(&state)); | |
153 if (!CryptoThreadPool::PostTask(FROM_HERE, | |
154 base::Bind(&DoTaskThenPostReply<State>, | |
155 work_func, | |
156 state.get(), | |
157 reply_callback))) { | |
158 #if defined(WEBCRYPTO_HAS_ERROR_TYPE) | |
159 state->result.completeWithError(blink::WebCryptoErrorTypeOperation, | |
160 "Failed posting to crypto worker pool"); | |
161 #else | |
162 state->result->completeWithError("Failed posting to crypto worker pool"); | |
163 #endif | |
164 } | |
165 } | |
Ryan Sleevi
2014/04/29 20:16:00
Not LGTM. I don't like this co-opting of function
eroman
2014/04/29 22:24:52
Ok I can do that. I thought the new way was superi
| |
166 | |
167 void CompleteWithBuffer(const std::vector<uint8>& buffer, | |
168 blink::WebCryptoResult* result) { | |
169 if (buffer.size() > UINT_MAX) { | |
170 // WebArrayBuffers have a smaller range than std::vector<>, so | |
171 // theoretically this could overflow. | |
172 CompleteWithError(Status::ErrorUnexpected(), result); | |
173 } else { | |
174 result->completeWithBuffer(webcrypto::Uint8VectorStart(buffer), | |
175 buffer.size()); | |
176 } | |
177 } | |
178 | |
38 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { | 179 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { |
39 // TODO(padolph): include all other asymmetric algorithms once they are | 180 // TODO(padolph): include all other asymmetric algorithms once they are |
40 // defined, e.g. EC and DH. | 181 // defined, e.g. EC and DH. |
41 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 182 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
42 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | 183 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || |
43 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); | 184 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); |
44 } | 185 } |
45 | 186 |
187 // Gets a task runner for the current thread. The current thread is either: | |
188 // | |
189 // * The main Blink thread | |
190 // * A Blink web worker thread | |
191 // | |
192 // A different mechanism is needed for posting to these threads. The main | |
193 // thread has an associated message loop and can simply use | |
194 // base::ThreadTaskRunnerHandle. Whereas the web worker threads are managed by | |
195 // Blink and need to be indirected through WorkerThreadTaskRunner. | |
196 scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() { | |
197 if (base::ThreadTaskRunnerHandle::IsSet()) | |
198 return base::ThreadTaskRunnerHandle::Get(); | |
199 return WorkerThreadTaskRunner::current(); | |
200 } | |
201 | |
202 // -------------------------------------------------------------------- | |
203 // State | |
204 // -------------------------------------------------------------------- | |
205 // | |
206 // Explicit state classes are used rather than base::Bind(). This is done | |
207 // both for clarity, but also to avoid extraneous allocations for things | |
208 // like passing buffers and result objects between threads. | |
209 // | |
210 // BaseState is the base class common to all of the async operations, and | |
211 // keeps track of the thread to complete on, the error state, and the | |
212 // callback into Blink. | |
213 // | |
214 // Ownership of the State object is passed between the crypto thread and the | |
215 // Blink thread. Under normal completion it is destroyed on the Blink thread. | |
216 // However it may also be destroyed on the crypto thread if the Blink thread | |
217 // has vanished (which can happen for Blink web worker threads). | |
218 | |
219 struct BaseState { | |
220 explicit BaseState(const blink::WebCryptoResult& result) | |
221 : origin_thread(GetCurrentBlinkThread()), result(result) {} | |
222 | |
223 scoped_refptr<base::TaskRunner> origin_thread; | |
224 | |
225 webcrypto::Status status; | |
226 blink::WebCryptoResult result; | |
227 | |
228 protected: | |
229 // Since there is no virtual destructor, must not delete directly as a | |
230 // BaseState. | |
231 ~BaseState() {} | |
232 }; | |
233 | |
234 struct EncryptState : public BaseState { | |
235 EncryptState(const blink::WebCryptoAlgorithm& algorithm, | |
236 const blink::WebCryptoKey& key, | |
237 const unsigned char* data, | |
238 unsigned int data_size, | |
239 const blink::WebCryptoResult& result) | |
240 : BaseState(result), | |
241 algorithm(algorithm), | |
242 key(key), | |
243 data(data, data + data_size) {} | |
244 | |
245 const blink::WebCryptoAlgorithm algorithm; | |
246 const blink::WebCryptoKey key; | |
247 const std::vector<uint8> data; | |
248 | |
249 std::vector<uint8> buffer; | |
250 }; | |
251 | |
252 typedef EncryptState DecryptState; | |
253 typedef EncryptState DigestState; | |
254 | |
255 struct GenerateKeyState : public BaseState { | |
256 GenerateKeyState(const blink::WebCryptoAlgorithm& algorithm, | |
257 bool extractable, | |
258 blink::WebCryptoKeyUsageMask usage_mask, | |
259 const blink::WebCryptoResult& result) | |
260 : BaseState(result), | |
261 algorithm(algorithm), | |
262 extractable(extractable), | |
263 usage_mask(usage_mask), | |
264 public_key(blink::WebCryptoKey::createNull()), | |
265 private_key(blink::WebCryptoKey::createNull()), | |
266 is_asymmetric(false) {} | |
267 | |
268 const blink::WebCryptoAlgorithm algorithm; | |
269 const bool extractable; | |
270 const blink::WebCryptoKeyUsageMask usage_mask; | |
271 | |
272 // If |is_asymmetric| is false, then |public_key| is understood to mean the | |
273 // symmetric key, and |private_key| is unused. | |
274 blink::WebCryptoKey public_key; | |
275 blink::WebCryptoKey private_key; | |
276 bool is_asymmetric; | |
277 }; | |
278 | |
279 struct ImportKeyState : public BaseState { | |
280 ImportKeyState(blink::WebCryptoKeyFormat format, | |
281 const unsigned char* key_data, | |
282 unsigned int key_data_size, | |
283 const blink::WebCryptoAlgorithm& algorithm, | |
284 bool extractable, | |
285 blink::WebCryptoKeyUsageMask usage_mask, | |
286 const blink::WebCryptoResult& result) | |
287 : BaseState(result), | |
288 format(format), | |
289 key_data(key_data, key_data + key_data_size), | |
290 algorithm(algorithm), | |
291 extractable(extractable), | |
292 usage_mask(usage_mask), | |
293 key(blink::WebCryptoKey::createNull()) {} | |
294 | |
295 const blink::WebCryptoKeyFormat format; | |
296 const std::vector<uint8> key_data; | |
297 const blink::WebCryptoAlgorithm algorithm; | |
298 const bool extractable; | |
299 const blink::WebCryptoKeyUsageMask usage_mask; | |
300 | |
301 blink::WebCryptoKey key; | |
302 }; | |
303 | |
304 struct ExportKeyState : public BaseState { | |
305 ExportKeyState(blink::WebCryptoKeyFormat format, | |
306 const blink::WebCryptoKey& key, | |
307 const blink::WebCryptoResult& result) | |
308 : BaseState(result), format(format), key(key) {} | |
309 | |
310 const blink::WebCryptoKeyFormat format; | |
311 const blink::WebCryptoKey key; | |
312 | |
313 std::vector<uint8> buffer; | |
314 }; | |
315 | |
316 typedef EncryptState SignState; | |
317 | |
318 struct VerifySignatureState : public BaseState { | |
319 VerifySignatureState(const blink::WebCryptoAlgorithm& algorithm, | |
320 const blink::WebCryptoKey& key, | |
321 const unsigned char* signature, | |
322 unsigned int signature_size, | |
323 const unsigned char* data, | |
324 unsigned int data_size, | |
325 const blink::WebCryptoResult& result) | |
326 : BaseState(result), | |
327 algorithm(algorithm), | |
328 key(key), | |
329 signature(signature, signature + signature_size), | |
330 data(data, data + data_size), | |
331 verify_result(false) {} | |
332 | |
333 const blink::WebCryptoAlgorithm algorithm; | |
334 const blink::WebCryptoKey key; | |
335 const std::vector<uint8> signature; | |
336 const std::vector<uint8> data; | |
337 | |
338 bool verify_result; | |
339 }; | |
340 | |
341 struct WrapKeyState : public BaseState { | |
342 WrapKeyState(blink::WebCryptoKeyFormat format, | |
343 const blink::WebCryptoKey& key, | |
344 const blink::WebCryptoKey& wrapping_key, | |
345 const blink::WebCryptoAlgorithm& wrap_algorithm, | |
346 const blink::WebCryptoResult& result) | |
347 : BaseState(result), | |
348 format(format), | |
349 key(key), | |
350 wrapping_key(wrapping_key), | |
351 wrap_algorithm(wrap_algorithm) {} | |
352 | |
353 const blink::WebCryptoKeyFormat format; | |
354 const blink::WebCryptoKey key; | |
355 const blink::WebCryptoKey wrapping_key; | |
356 const blink::WebCryptoAlgorithm wrap_algorithm; | |
357 | |
358 std::vector<uint8> buffer; | |
359 }; | |
360 | |
361 struct UnwrapKeyState : public BaseState { | |
362 UnwrapKeyState(blink::WebCryptoKeyFormat format, | |
363 const unsigned char* wrapped_key, | |
364 unsigned wrapped_key_size, | |
365 const blink::WebCryptoKey& wrapping_key, | |
366 const blink::WebCryptoAlgorithm& unwrap_algorithm, | |
367 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, | |
368 bool extractable, | |
369 blink::WebCryptoKeyUsageMask usages, | |
370 const blink::WebCryptoResult& result) | |
371 : BaseState(result), | |
372 format(format), | |
373 wrapped_key(wrapped_key, wrapped_key + wrapped_key_size), | |
374 wrapping_key(wrapping_key), | |
375 unwrap_algorithm(unwrap_algorithm), | |
376 unwrapped_key_algorithm(unwrapped_key_algorithm), | |
377 extractable(extractable), | |
378 usages(usages), | |
379 unwrapped_key(blink::WebCryptoKey::createNull()) {} | |
380 | |
381 const blink::WebCryptoKeyFormat format; | |
382 const std::vector<uint8> wrapped_key; | |
383 const blink::WebCryptoKey wrapping_key; | |
384 const blink::WebCryptoAlgorithm unwrap_algorithm; | |
385 const blink::WebCryptoAlgorithm unwrapped_key_algorithm; | |
386 const bool extractable; | |
387 const blink::WebCryptoKeyUsageMask usages; | |
388 | |
389 blink::WebCryptoKey unwrapped_key; | |
390 }; | |
391 | |
392 // -------------------------------------------------------------------- | |
393 // Wrapper functions | |
394 // -------------------------------------------------------------------- | |
395 // | |
396 // * The methods named Do*() run on the crypto thread. | |
397 // * The methods named Do*Reply() run on the target Blink thread | |
398 | |
399 template <typename State> | |
400 void DoReplyWithBuffer(State* state) { | |
401 CompleteWithBuffer(state->buffer, &state->result); | |
402 } | |
403 | |
404 Status DoEncrypt(EncryptState* state) { | |
405 return webcrypto::Encrypt(state->algorithm, | |
406 state->key, | |
407 webcrypto::CryptoData(state->data), | |
408 &state->buffer); | |
409 } | |
410 | |
411 Status DoDecrypt(DecryptState* state) { | |
412 return webcrypto::Decrypt(state->algorithm, | |
413 state->key, | |
414 webcrypto::CryptoData(state->data), | |
415 &state->buffer); | |
416 } | |
417 | |
418 Status DoDigest(DigestState* state) { | |
419 return webcrypto::Digest( | |
420 state->algorithm, webcrypto::CryptoData(state->data), &state->buffer); | |
421 } | |
422 | |
423 void DoGenerateKeyReply(GenerateKeyState* state) { | |
424 if (state->is_asymmetric) | |
425 state->result.completeWithKeyPair(state->public_key, state->private_key); | |
426 else | |
427 state->result.completeWithKey(state->public_key); | |
428 } | |
429 | |
430 Status DoGenerateKey(GenerateKeyState* state) { | |
431 state->is_asymmetric = IsAlgorithmAsymmetric(state->algorithm); | |
432 if (state->is_asymmetric) { | |
433 Status status = webcrypto::GenerateKeyPair(state->algorithm, | |
434 state->extractable, | |
435 state->usage_mask, | |
436 &state->public_key, | |
437 &state->private_key); | |
438 | |
439 if (status.IsSuccess()) { | |
440 DCHECK(state->public_key.handle()); | |
441 DCHECK(state->private_key.handle()); | |
442 DCHECK_EQ(state->algorithm.id(), state->public_key.algorithm().id()); | |
443 DCHECK_EQ(state->algorithm.id(), state->private_key.algorithm().id()); | |
444 DCHECK_EQ(true, state->public_key.extractable()); | |
445 DCHECK_EQ(state->extractable, state->private_key.extractable()); | |
446 DCHECK_EQ(state->usage_mask, state->public_key.usages()); | |
447 DCHECK_EQ(state->usage_mask, state->private_key.usages()); | |
448 } | |
449 | |
450 return status; | |
451 } | |
452 | |
453 blink::WebCryptoKey* key = &state->public_key; | |
454 | |
455 Status status = webcrypto::GenerateSecretKey( | |
456 state->algorithm, state->extractable, state->usage_mask, key); | |
457 | |
458 if (status.IsSuccess()) { | |
459 DCHECK(key->handle()); | |
460 DCHECK_EQ(state->algorithm.id(), key->algorithm().id()); | |
461 DCHECK_EQ(state->extractable, key->extractable()); | |
462 DCHECK_EQ(state->usage_mask, key->usages()); | |
463 } | |
464 | |
465 return status; | |
466 } | |
467 | |
468 void DoImportKeyReply(ImportKeyState* state) { | |
469 state->result.completeWithKey(state->key); | |
470 } | |
471 | |
472 Status DoImportKey(ImportKeyState* state) { | |
473 Status status = webcrypto::ImportKey(state->format, | |
474 webcrypto::CryptoData(state->key_data), | |
475 state->algorithm, | |
476 state->extractable, | |
477 state->usage_mask, | |
478 &state->key); | |
479 if (status.IsSuccess()) { | |
480 DCHECK(state->key.handle()); | |
481 DCHECK(!state->key.algorithm().isNull()); | |
482 DCHECK_EQ(state->extractable, state->key.extractable()); | |
483 } | |
484 | |
485 return status; | |
486 } | |
487 | |
488 Status DoExportKey(ExportKeyState* state) { | |
489 return webcrypto::ExportKey(state->format, state->key, &state->buffer); | |
490 } | |
491 | |
492 Status DoSign(SignState* state) { | |
493 return webcrypto::Sign(state->algorithm, | |
494 state->key, | |
495 webcrypto::CryptoData(state->data), | |
496 &state->buffer); | |
497 } | |
498 | |
499 void DoVerifyReply(VerifySignatureState* state) { | |
500 state->result.completeWithBoolean(state->verify_result); | |
501 } | |
502 | |
503 Status DoVerify(VerifySignatureState* state) { | |
504 return webcrypto::VerifySignature(state->algorithm, | |
505 state->key, | |
506 webcrypto::CryptoData(state->signature), | |
507 webcrypto::CryptoData(state->data), | |
508 &state->verify_result); | |
509 } | |
510 | |
511 Status DoWrapKey(WrapKeyState* state) { | |
512 // TODO(eroman): The parameter ordering of webcrypto::WrapKey() is | |
513 // inconsistent with that of blink::WebCrypto::wrapKey(). | |
514 return webcrypto::WrapKey(state->format, | |
515 state->wrapping_key, | |
516 state->key, | |
517 state->wrap_algorithm, | |
518 &state->buffer); | |
519 } | |
520 | |
521 void DoUnwrapKeyReply(UnwrapKeyState* state) { | |
522 state->result.completeWithKey(state->unwrapped_key); | |
523 } | |
524 | |
525 Status DoUnwrapKey(UnwrapKeyState* state) { | |
526 return webcrypto::UnwrapKey(state->format, | |
527 webcrypto::CryptoData(state->wrapped_key), | |
528 state->wrapping_key, | |
529 state->unwrap_algorithm, | |
530 state->unwrapped_key_algorithm, | |
531 state->extractable, | |
532 state->usages, | |
533 &state->unwrapped_key); | |
534 } | |
535 | |
46 } // namespace | 536 } // namespace |
47 | 537 |
48 WebCryptoImpl::WebCryptoImpl() { webcrypto::Init(); } | 538 WebCryptoImpl::WebCryptoImpl() { |
49 | 539 webcrypto::Init(); |
50 WebCryptoImpl::~WebCryptoImpl() {} | 540 } |
541 | |
542 WebCryptoImpl::~WebCryptoImpl() { | |
543 } | |
51 | 544 |
52 void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm, | 545 void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm, |
53 const blink::WebCryptoKey& key, | 546 const blink::WebCryptoKey& key, |
54 const unsigned char* data, | 547 const unsigned char* data, |
55 unsigned int data_size, | 548 unsigned int data_size, |
56 blink::WebCryptoResult result) { | 549 blink::WebCryptoResult result) { |
57 DCHECK(!algorithm.isNull()); | 550 scoped_ptr<EncryptState> state( |
58 blink::WebArrayBuffer buffer; | 551 new EncryptState(algorithm, key, data, data_size, result)); |
59 Status status = webcrypto::Encrypt( | 552 PostToCryptoThreadAndReply( |
60 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); | 553 FROM_HERE, &DoEncrypt, &DoReplyWithBuffer<EncryptState>, state.Pass()); |
61 if (status.IsError()) | |
62 CompleteWithError(status, &result); | |
63 else | |
64 result.completeWithBuffer(buffer); | |
65 } | 554 } |
66 | 555 |
67 void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, | 556 void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, |
68 const blink::WebCryptoKey& key, | 557 const blink::WebCryptoKey& key, |
69 const unsigned char* data, | 558 const unsigned char* data, |
70 unsigned int data_size, | 559 unsigned int data_size, |
71 blink::WebCryptoResult result) { | 560 blink::WebCryptoResult result) { |
72 DCHECK(!algorithm.isNull()); | 561 scoped_ptr<DecryptState> state( |
73 blink::WebArrayBuffer buffer; | 562 new DecryptState(algorithm, key, data, data_size, result)); |
74 Status status = webcrypto::Decrypt( | 563 PostToCryptoThreadAndReply( |
75 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); | 564 FROM_HERE, &DoDecrypt, &DoReplyWithBuffer<DecryptState>, state.Pass()); |
76 if (status.IsError()) | |
77 CompleteWithError(status, &result); | |
78 else | |
79 result.completeWithBuffer(buffer); | |
80 } | 565 } |
81 | 566 |
82 void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, | 567 void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, |
83 const unsigned char* data, | 568 const unsigned char* data, |
84 unsigned int data_size, | 569 unsigned int data_size, |
85 blink::WebCryptoResult result) { | 570 blink::WebCryptoResult result) { |
86 DCHECK(!algorithm.isNull()); | 571 scoped_ptr<DigestState> state(new DigestState( |
87 blink::WebArrayBuffer buffer; | 572 algorithm, blink::WebCryptoKey::createNull(), data, data_size, result)); |
88 Status status = webcrypto::Digest( | 573 PostToCryptoThreadAndReply( |
89 algorithm, webcrypto::CryptoData(data, data_size), &buffer); | 574 FROM_HERE, &DoDigest, &DoReplyWithBuffer<DigestState>, state.Pass()); |
90 if (status.IsError()) | |
91 CompleteWithError(status, &result); | |
92 else | |
93 result.completeWithBuffer(buffer); | |
94 } | 575 } |
95 | 576 |
96 void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, | 577 void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, |
97 bool extractable, | 578 bool extractable, |
98 blink::WebCryptoKeyUsageMask usage_mask, | 579 blink::WebCryptoKeyUsageMask usage_mask, |
99 blink::WebCryptoResult result) { | 580 blink::WebCryptoResult result) { |
100 DCHECK(!algorithm.isNull()); | 581 scoped_ptr<GenerateKeyState> state( |
101 if (IsAlgorithmAsymmetric(algorithm)) { | 582 new GenerateKeyState(algorithm, extractable, usage_mask, result)); |
102 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); | 583 PostToCryptoThreadAndReply( |
103 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); | 584 FROM_HERE, &DoGenerateKey, &DoGenerateKeyReply, state.Pass()); |
104 Status status = webcrypto::GenerateKeyPair( | |
105 algorithm, extractable, usage_mask, &public_key, &private_key); | |
106 if (status.IsError()) { | |
107 CompleteWithError(status, &result); | |
108 } else { | |
109 DCHECK(public_key.handle()); | |
110 DCHECK(private_key.handle()); | |
111 DCHECK_EQ(algorithm.id(), public_key.algorithm().id()); | |
112 DCHECK_EQ(algorithm.id(), private_key.algorithm().id()); | |
113 DCHECK_EQ(true, public_key.extractable()); | |
114 DCHECK_EQ(extractable, private_key.extractable()); | |
115 DCHECK_EQ(usage_mask, public_key.usages()); | |
116 DCHECK_EQ(usage_mask, private_key.usages()); | |
117 result.completeWithKeyPair(public_key, private_key); | |
118 } | |
119 } else { | |
120 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | |
121 Status status = | |
122 webcrypto::GenerateSecretKey(algorithm, extractable, usage_mask, &key); | |
123 if (status.IsError()) { | |
124 CompleteWithError(status, &result); | |
125 } else { | |
126 DCHECK(key.handle()); | |
127 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
128 DCHECK_EQ(extractable, key.extractable()); | |
129 DCHECK_EQ(usage_mask, key.usages()); | |
130 result.completeWithKey(key); | |
131 } | |
132 } | |
133 } | 585 } |
134 | 586 |
135 void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format, | 587 void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format, |
136 const unsigned char* key_data, | 588 const unsigned char* key_data, |
137 unsigned int key_data_size, | 589 unsigned int key_data_size, |
138 const blink::WebCryptoAlgorithm& algorithm, | 590 const blink::WebCryptoAlgorithm& algorithm, |
139 bool extractable, | 591 bool extractable, |
140 blink::WebCryptoKeyUsageMask usage_mask, | 592 blink::WebCryptoKeyUsageMask usage_mask, |
141 blink::WebCryptoResult result) { | 593 blink::WebCryptoResult result) { |
142 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 594 scoped_ptr<ImportKeyState> state(new ImportKeyState(format, |
143 Status status = | 595 key_data, |
144 webcrypto::ImportKey(format, | 596 key_data_size, |
145 webcrypto::CryptoData(key_data, key_data_size), | 597 algorithm, |
146 algorithm, | 598 extractable, |
147 extractable, | 599 usage_mask, |
148 usage_mask, | 600 result)); |
149 &key); | 601 PostToCryptoThreadAndReply( |
150 if (status.IsError()) { | 602 FROM_HERE, &DoImportKey, &DoImportKeyReply, state.Pass()); |
151 CompleteWithError(status, &result); | |
152 } else { | |
153 DCHECK(key.handle()); | |
154 DCHECK(!key.algorithm().isNull()); | |
155 DCHECK_EQ(extractable, key.extractable()); | |
156 result.completeWithKey(key); | |
157 } | |
158 } | 603 } |
159 | 604 |
160 void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format, | 605 void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format, |
161 const blink::WebCryptoKey& key, | 606 const blink::WebCryptoKey& key, |
162 blink::WebCryptoResult result) { | 607 blink::WebCryptoResult result) { |
163 blink::WebArrayBuffer buffer; | 608 scoped_ptr<ExportKeyState> state(new ExportKeyState(format, key, result)); |
164 Status status = webcrypto::ExportKey(format, key, &buffer); | 609 PostToCryptoThreadAndReply(FROM_HERE, |
165 if (status.IsError()) | 610 &DoExportKey, |
166 CompleteWithError(status, &result); | 611 &DoReplyWithBuffer<ExportKeyState>, |
167 else | 612 state.Pass()); |
168 result.completeWithBuffer(buffer); | |
169 } | 613 } |
170 | 614 |
171 void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, | 615 void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, |
172 const blink::WebCryptoKey& key, | 616 const blink::WebCryptoKey& key, |
173 const unsigned char* data, | 617 const unsigned char* data, |
174 unsigned int data_size, | 618 unsigned int data_size, |
175 blink::WebCryptoResult result) { | 619 blink::WebCryptoResult result) { |
176 DCHECK(!algorithm.isNull()); | 620 scoped_ptr<SignState> state( |
177 blink::WebArrayBuffer buffer; | 621 new SignState(algorithm, key, data, data_size, result)); |
178 Status status = webcrypto::Sign( | 622 PostToCryptoThreadAndReply( |
179 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); | 623 FROM_HERE, &DoSign, &DoReplyWithBuffer<SignState>, state.Pass()); |
180 if (status.IsError()) | |
181 CompleteWithError(status, &result); | |
182 else | |
183 result.completeWithBuffer(buffer); | |
184 } | 624 } |
185 | 625 |
186 void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm, | 626 void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm, |
187 const blink::WebCryptoKey& key, | 627 const blink::WebCryptoKey& key, |
188 const unsigned char* signature, | 628 const unsigned char* signature, |
189 unsigned int signature_size, | 629 unsigned int signature_size, |
190 const unsigned char* data, | 630 const unsigned char* data, |
191 unsigned int data_size, | 631 unsigned int data_size, |
192 blink::WebCryptoResult result) { | 632 blink::WebCryptoResult result) { |
193 DCHECK(!algorithm.isNull()); | 633 scoped_ptr<VerifySignatureState> state(new VerifySignatureState( |
194 bool signature_match = false; | 634 algorithm, key, signature, signature_size, data, data_size, result)); |
195 Status status = webcrypto::VerifySignature( | 635 PostToCryptoThreadAndReply( |
196 algorithm, | 636 FROM_HERE, &DoVerify, &DoVerifyReply, state.Pass()); |
197 key, | |
198 webcrypto::CryptoData(signature, signature_size), | |
199 webcrypto::CryptoData(data, data_size), | |
200 &signature_match); | |
201 if (status.IsError()) | |
202 CompleteWithError(status, &result); | |
203 else | |
204 result.completeWithBoolean(signature_match); | |
205 } | 637 } |
206 | 638 |
207 void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format, | 639 void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format, |
208 const blink::WebCryptoKey& key, | 640 const blink::WebCryptoKey& key, |
209 const blink::WebCryptoKey& wrapping_key, | 641 const blink::WebCryptoKey& wrapping_key, |
210 const blink::WebCryptoAlgorithm& wrap_algorithm, | 642 const blink::WebCryptoAlgorithm& wrap_algorithm, |
211 blink::WebCryptoResult result) { | 643 blink::WebCryptoResult result) { |
212 blink::WebArrayBuffer buffer; | 644 scoped_ptr<WrapKeyState> state( |
213 // TODO(eroman): Use the same parameter ordering. | 645 new WrapKeyState(format, key, wrapping_key, wrap_algorithm, result)); |
214 Status status = webcrypto::WrapKey( | 646 PostToCryptoThreadAndReply( |
215 format, wrapping_key, key, wrap_algorithm, &buffer); | 647 FROM_HERE, &DoWrapKey, &DoReplyWithBuffer<WrapKeyState>, state.Pass()); |
216 if (status.IsError()) | |
217 CompleteWithError(status, &result); | |
218 else | |
219 result.completeWithBuffer(buffer); | |
220 } | 648 } |
221 | 649 |
222 void WebCryptoImpl::unwrapKey( | 650 void WebCryptoImpl::unwrapKey( |
223 blink::WebCryptoKeyFormat format, | 651 blink::WebCryptoKeyFormat format, |
224 const unsigned char* wrapped_key, | 652 const unsigned char* wrapped_key, |
225 unsigned wrapped_key_size, | 653 unsigned wrapped_key_size, |
226 const blink::WebCryptoKey& wrapping_key, | 654 const blink::WebCryptoKey& wrapping_key, |
227 const blink::WebCryptoAlgorithm& unwrap_algorithm, | 655 const blink::WebCryptoAlgorithm& unwrap_algorithm, |
228 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, | 656 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, |
229 bool extractable, | 657 bool extractable, |
230 blink::WebCryptoKeyUsageMask usages, | 658 blink::WebCryptoKeyUsageMask usages, |
231 blink::WebCryptoResult result) { | 659 blink::WebCryptoResult result) { |
232 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 660 scoped_ptr<UnwrapKeyState> state(new UnwrapKeyState(format, |
233 Status status = | 661 wrapped_key, |
234 webcrypto::UnwrapKey(format, | 662 wrapped_key_size, |
235 webcrypto::CryptoData(wrapped_key, wrapped_key_size), | 663 wrapping_key, |
236 wrapping_key, | 664 unwrap_algorithm, |
237 unwrap_algorithm, | 665 unwrapped_key_algorithm, |
238 unwrapped_key_algorithm, | 666 extractable, |
239 extractable, | 667 usages, |
240 usages, | 668 result)); |
241 &key); | 669 PostToCryptoThreadAndReply( |
242 if (status.IsError()) | 670 FROM_HERE, &DoUnwrapKey, &DoUnwrapKeyReply, state.Pass()); |
243 CompleteWithError(status, &result); | |
244 else | |
245 result.completeWithKey(key); | |
246 } | |
247 | |
248 bool WebCryptoImpl::digestSynchronous( | |
249 const blink::WebCryptoAlgorithmId algorithm_id, | |
250 const unsigned char* data, | |
251 unsigned int data_size, | |
252 blink::WebArrayBuffer& result) { | |
253 blink::WebCryptoAlgorithm algorithm = | |
254 blink::WebCryptoAlgorithm::adoptParamsAndCreate(algorithm_id, NULL); | |
255 return (webcrypto::Digest( | |
256 algorithm, webcrypto::CryptoData(data, data_size), &result)) | |
257 .IsSuccess(); | |
258 } | 671 } |
259 | 672 |
260 blink::WebCryptoDigestor* WebCryptoImpl::createDigestor( | 673 blink::WebCryptoDigestor* WebCryptoImpl::createDigestor( |
261 blink::WebCryptoAlgorithmId algorithm_id) { | 674 blink::WebCryptoAlgorithmId algorithm_id) { |
262 return webcrypto::CreateDigestor(algorithm_id).release(); | 675 return webcrypto::CreateDigestor(algorithm_id).release(); |
263 } | 676 } |
264 | 677 |
265 bool WebCryptoImpl::deserializeKeyForClone( | 678 bool WebCryptoImpl::deserializeKeyForClone( |
266 const blink::WebCryptoKeyAlgorithm& algorithm, | 679 const blink::WebCryptoKeyAlgorithm& algorithm, |
267 blink::WebCryptoKeyType type, | 680 blink::WebCryptoKeyType type, |
268 bool extractable, | 681 bool extractable, |
269 blink::WebCryptoKeyUsageMask usages, | 682 blink::WebCryptoKeyUsageMask usages, |
270 const unsigned char* key_data, | 683 const unsigned char* key_data, |
271 unsigned key_data_size, | 684 unsigned key_data_size, |
272 blink::WebCryptoKey& key) { | 685 blink::WebCryptoKey& key) { |
273 Status status = webcrypto::DeserializeKeyForClone( | 686 // TODO(eroman): Rather than do the import immediately on the current thread, |
687 // it could defer to the crypto thread. | |
688 return webcrypto::DeserializeKeyForClone( | |
274 algorithm, | 689 algorithm, |
275 type, | 690 type, |
276 extractable, | 691 extractable, |
277 usages, | 692 usages, |
278 webcrypto::CryptoData(key_data, key_data_size), | 693 webcrypto::CryptoData(key_data, key_data_size), |
279 &key); | 694 &key); |
280 return status.IsSuccess(); | |
281 } | 695 } |
282 | 696 |
283 bool WebCryptoImpl::serializeKeyForClone( | 697 bool WebCryptoImpl::serializeKeyForClone( |
284 const blink::WebCryptoKey& key, | 698 const blink::WebCryptoKey& key, |
285 blink::WebVector<unsigned char>& key_data) { | 699 blink::WebVector<unsigned char>& key_data) { |
286 Status status = webcrypto::SerializeKeyForClone(key, &key_data); | 700 return webcrypto::SerializeKeyForClone(key, &key_data); |
287 return status.IsSuccess(); | |
288 } | 701 } |
289 | 702 |
290 } // namespace content | 703 } // namespace content |
OLD | NEW |