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