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