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