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