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/platform_crypto.h" | 5 #include "content/child/webcrypto/platform_crypto.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 #include <openssl/aes.h> | 8 #include <openssl/aes.h> |
9 #include <openssl/evp.h> | 9 #include <openssl/evp.h> |
10 #include <openssl/hmac.h> | 10 #include <openssl/hmac.h> |
11 #include <openssl/pkcs12.h> | |
11 #include <openssl/rand.h> | 12 #include <openssl/rand.h> |
12 #include <openssl/sha.h> | 13 #include <openssl/sha.h> |
13 | 14 |
14 #include "base/logging.h" | 15 #include "base/logging.h" |
15 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
16 #include "content/child/webcrypto/crypto_data.h" | 17 #include "content/child/webcrypto/crypto_data.h" |
17 #include "content/child/webcrypto/status.h" | 18 #include "content/child/webcrypto/status.h" |
18 #include "content/child/webcrypto/webcrypto_util.h" | 19 #include "content/child/webcrypto/webcrypto_util.h" |
19 #include "crypto/openssl_util.h" | 20 #include "crypto/openssl_util.h" |
20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
(...skipping 21 matching lines...) Expand all Loading... | |
42 } | 43 } |
43 | 44 |
44 const std::vector<unsigned char>& key() const { return key_; } | 45 const std::vector<unsigned char>& key() const { return key_; } |
45 | 46 |
46 private: | 47 private: |
47 const std::vector<unsigned char> key_; | 48 const std::vector<unsigned char> key_; |
48 | 49 |
49 DISALLOW_COPY_AND_ASSIGN(SymKey); | 50 DISALLOW_COPY_AND_ASSIGN(SymKey); |
50 }; | 51 }; |
51 | 52 |
53 class PublicKey : public Key { | |
54 public: | |
55 // Takes ownership of |key|. | |
56 // TODO(eroman): use Pass() semantics. | |
57 static Status Create(EVP_PKEY* key, | |
58 const blink::WebCryptoKeyAlgorithm& algorithm, | |
59 scoped_ptr<PublicKey>* out) { | |
60 out->reset(new PublicKey(key)); | |
61 return ExportKeySpki(out->get(), &(*out)->serialized_key_); | |
62 } | |
63 | |
64 EVP_PKEY* key() { return key_.get(); } | |
65 | |
66 virtual SymKey* AsSymKey() OVERRIDE { return NULL; } | |
67 virtual PublicKey* AsPublicKey() OVERRIDE { return this; } | |
68 virtual PrivateKey* AsPrivateKey() OVERRIDE { return NULL; } | |
69 | |
70 virtual bool ThreadSafeSerializeForClone( | |
71 blink::WebVector<uint8>* key_data) OVERRIDE { | |
72 key_data->assign(Uint8VectorStart(serialized_key_), serialized_key_.size()); | |
73 return true; | |
74 } | |
75 | |
76 private: | |
77 explicit PublicKey(EVP_PKEY* key) : key_(key) {} | |
78 | |
79 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> key_; | |
80 std::vector<uint8> serialized_key_; | |
81 | |
82 DISALLOW_COPY_AND_ASSIGN(PublicKey); | |
83 }; | |
84 | |
85 class PrivateKey : public Key { | |
86 public: | |
87 // Takes ownership of |key|. | |
88 // TODO(eroman): use Pass() semantics. | |
89 static Status Create(EVP_PKEY* key, | |
90 const blink::WebCryptoKeyAlgorithm& algorithm, | |
91 scoped_ptr<PrivateKey>* out) { | |
92 out->reset(new PrivateKey(key)); | |
93 return ExportKeyPkcs8(out->get(), algorithm, &(*out)->serialized_key_); | |
94 } | |
95 | |
96 EVP_PKEY* key() { return key_.get(); } | |
97 | |
98 virtual SymKey* AsSymKey() OVERRIDE { return NULL; } | |
99 virtual PublicKey* AsPublicKey() OVERRIDE { return NULL; } | |
100 virtual PrivateKey* AsPrivateKey() OVERRIDE { return this; } | |
101 | |
102 virtual bool ThreadSafeSerializeForClone( | |
103 blink::WebVector<uint8>* key_data) OVERRIDE { | |
104 key_data->assign(Uint8VectorStart(serialized_key_), serialized_key_.size()); | |
105 return true; | |
106 } | |
107 | |
108 private: | |
109 explicit PrivateKey(EVP_PKEY* key) : key_(key) {} | |
110 | |
111 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> key_; | |
112 std::vector<uint8> serialized_key_; | |
113 | |
114 DISALLOW_COPY_AND_ASSIGN(PrivateKey); | |
115 }; | |
116 | |
52 namespace { | 117 namespace { |
53 | 118 |
54 const EVP_CIPHER* GetAESCipherByKeyLength(unsigned int key_length_bytes) { | 119 const EVP_CIPHER* GetAESCipherByKeyLength(unsigned int key_length_bytes) { |
55 // OpenSSL supports AES CBC ciphers for only 3 key lengths: 128, 192, 256 bits | 120 // OpenSSL supports AES CBC ciphers for only 3 key lengths: 128, 192, 256 bits |
56 switch (key_length_bytes) { | 121 switch (key_length_bytes) { |
57 case 16: | 122 case 16: |
58 return EVP_aes_128_cbc(); | 123 return EVP_aes_128_cbc(); |
59 case 24: | 124 case 24: |
60 return EVP_aes_192_cbc(); | 125 return EVP_aes_192_cbc(); |
61 case 32: | 126 case 32: |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 const unsigned int final_output_len = | 211 const unsigned int final_output_len = |
147 static_cast<unsigned int>(output_len) + | 212 static_cast<unsigned int>(output_len) + |
148 static_cast<unsigned int>(final_output_chunk_len); | 213 static_cast<unsigned int>(final_output_chunk_len); |
149 DCHECK_LE(final_output_len, output_max_len); | 214 DCHECK_LE(final_output_len, output_max_len); |
150 | 215 |
151 buffer->resize(final_output_len); | 216 buffer->resize(final_output_len); |
152 | 217 |
153 return Status::Success(); | 218 return Status::Success(); |
154 } | 219 } |
155 | 220 |
221 // Creates a blink::WebCryptoAlgorithm having the modulus length and public | |
222 // exponent of |key|. | |
223 Status CreateRsaHashedKeyAlgorithm( | |
224 blink::WebCryptoAlgorithmId rsa_algorithm, | |
225 blink::WebCryptoAlgorithmId hash_algorithm, | |
226 EVP_PKEY* key, | |
227 blink::WebCryptoKeyAlgorithm* key_algorithm) { | |
228 DCHECK(IsAlgorithmRsa(rsa_algorithm)); | |
229 DCHECK(EVP_PKEY_id(key) == EVP_PKEY_RSA); | |
Ryan Sleevi
2014/06/27 01:43:25
DCHECK_EQ
eroman
2014/06/27 02:12:47
Done.
| |
230 | |
231 crypto::ScopedOpenSSL<RSA, RSA_free> rsa(EVP_PKEY_get1_RSA(key)); | |
232 if (!rsa.get()) | |
233 return Status::ErrorUnexpected(); | |
234 | |
235 unsigned int modulus_length_bits = RSA_size(rsa.get()) * 8; | |
236 | |
237 // Convert the public exponent to big-endian representation. | |
238 std::vector<uint8> e(BN_num_bytes(rsa.get()->e)); | |
239 if (e.size() == 0) | |
240 return Status::ErrorUnexpected(); | |
241 if (static_cast<int>(e.size()) != BN_bn2bin(rsa.get()->e, &e[0])) | |
Ryan Sleevi
2014/06/27 01:43:25
I think these may differ dependent on leading bits
eroman
2014/06/27 02:12:47
Looks like at least in the current implementation,
| |
242 return Status::ErrorUnexpected(); | |
243 | |
244 *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed( | |
245 rsa_algorithm, modulus_length_bits, &e[0], e.size(), hash_algorithm); | |
246 | |
247 return Status::Success(); | |
248 } | |
249 | |
250 // Verifies that |key| is consistent with the input algorithm id, and creates a | |
251 // blink::WebCryptoKeyAlgorithm describing the key. | |
252 // Returns Status::Success() on success and sets |*key_algorithm|. | |
253 Status ValidateKeyTypeAndCreateKeyAlgorithm( | |
254 const blink::WebCryptoAlgorithm& algorithm, | |
255 EVP_PKEY* key, | |
256 blink::WebCryptoKeyAlgorithm* key_algorithm) { | |
257 if (IsAlgorithmRsa(algorithm.id())) { | |
258 if (EVP_PKEY_id(key) != EVP_PKEY_RSA) | |
259 return Status::DataError(); // Data did not define an RSA key. | |
260 return CreateRsaHashedKeyAlgorithm(algorithm.id(), | |
261 GetInnerHashAlgorithm(algorithm).id(), | |
262 key, | |
263 key_algorithm); | |
264 return Status::Success(); | |
265 } | |
266 | |
267 return Status::ErrorUnsupported(); | |
268 } | |
269 | |
156 } // namespace | 270 } // namespace |
157 | 271 |
158 class DigestorOpenSSL : public blink::WebCryptoDigestor { | 272 class DigestorOpenSSL : public blink::WebCryptoDigestor { |
159 public: | 273 public: |
160 explicit DigestorOpenSSL(blink::WebCryptoAlgorithmId algorithm_id) | 274 explicit DigestorOpenSSL(blink::WebCryptoAlgorithmId algorithm_id) |
161 : initialized_(false), | 275 : initialized_(false), |
162 digest_context_(EVP_MD_CTX_create()), | 276 digest_context_(EVP_MD_CTX_create()), |
163 algorithm_id_(algorithm_id) {} | 277 algorithm_id_(algorithm_id) {} |
164 | 278 |
165 virtual bool consume(const unsigned char* data, unsigned int size) { | 279 virtual bool consume(const unsigned char* data, unsigned int size) { |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
442 bool* signature_match) { | 556 bool* signature_match) { |
443 // TODO(eroman): http://crbug.com/267888 | 557 // TODO(eroman): http://crbug.com/267888 |
444 return Status::ErrorUnsupported(); | 558 return Status::ErrorUnsupported(); |
445 } | 559 } |
446 | 560 |
447 Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, | 561 Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, |
448 const CryptoData& key_data, | 562 const CryptoData& key_data, |
449 bool extractable, | 563 bool extractable, |
450 blink::WebCryptoKeyUsageMask usage_mask, | 564 blink::WebCryptoKeyUsageMask usage_mask, |
451 blink::WebCryptoKey* key) { | 565 blink::WebCryptoKey* key) { |
452 // TODO(eroman): http://crbug.com/267888 | 566 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
453 return Status::ErrorUnsupported(); | 567 |
568 crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf( | |
569 const_cast<uint8*>(key_data.bytes()), key_data.byte_length())); | |
570 if (!bio.get()) | |
571 return Status::ErrorUnexpected(); | |
572 | |
573 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> public_key( | |
574 d2i_PUBKEY_bio(bio.get(), NULL)); | |
575 if (!public_key.get()) | |
576 return Status::DataError(); | |
577 | |
578 blink::WebCryptoKeyAlgorithm key_algorithm; | |
579 Status status = ValidateKeyTypeAndCreateKeyAlgorithm( | |
580 algorithm, public_key.get(), &key_algorithm); | |
581 if (status.IsError()) | |
582 return status; | |
583 | |
584 scoped_ptr<PublicKey> key_handle; | |
585 status = PublicKey::Create(public_key.release(), key_algorithm, &key_handle); | |
586 if (status.IsError()) | |
587 return status; | |
588 | |
589 *key = blink::WebCryptoKey::create(key_handle.release(), | |
590 blink::WebCryptoKeyTypePublic, | |
591 extractable, | |
592 key_algorithm, | |
593 usage_mask); | |
594 | |
595 return Status::Success(); | |
454 } | 596 } |
455 | 597 |
456 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, | 598 Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm, |
457 const CryptoData& key_data, | 599 const CryptoData& key_data, |
458 bool extractable, | 600 bool extractable, |
459 blink::WebCryptoKeyUsageMask usage_mask, | 601 blink::WebCryptoKeyUsageMask usage_mask, |
460 blink::WebCryptoKey* key) { | 602 blink::WebCryptoKey* key) { |
461 // TODO(eroman): http://crbug.com/267888 | 603 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
462 return Status::ErrorUnsupported(); | 604 |
605 crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf( | |
606 const_cast<uint8*>(key_data.bytes()), key_data.byte_length())); | |
607 if (!bio.get()) | |
608 return Status::ErrorUnexpected(); | |
609 | |
610 crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8inf( | |
Ryan Sleevi
2014/06/27 01:43:24
// TODO reminder - need to validate the EVP data a
eroman
2014/06/27 02:12:47
Done. I have added comments linking to the corresp
| |
611 d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL)); | |
612 if (!p8inf.get()) | |
613 return Status::DataError(); | |
614 | |
615 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> private_key( | |
616 EVP_PKCS82PKEY(p8inf.get())); | |
617 if (!private_key.get()) | |
618 return Status::DataError(); | |
619 | |
620 blink::WebCryptoKeyAlgorithm key_algorithm; | |
621 Status status = ValidateKeyTypeAndCreateKeyAlgorithm( | |
622 algorithm, private_key.get(), &key_algorithm); | |
623 if (status.IsError()) | |
624 return status; | |
625 | |
626 scoped_ptr<PrivateKey> key_handle; | |
627 status = | |
628 PrivateKey::Create(private_key.release(), key_algorithm, &key_handle); | |
629 if (status.IsError()) | |
630 return status; | |
631 | |
632 *key = blink::WebCryptoKey::create(key_handle.release(), | |
633 blink::WebCryptoKeyTypePrivate, | |
634 extractable, | |
635 key_algorithm, | |
636 usage_mask); | |
637 | |
638 return Status::Success(); | |
463 } | 639 } |
464 | 640 |
465 Status ExportKeySpki(PublicKey* key, std::vector<uint8>* buffer) { | 641 Status ExportKeySpki(PublicKey* key, std::vector<uint8>* buffer) { |
466 // TODO(eroman): http://crbug.com/267888 | 642 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
467 return Status::ErrorUnsupported(); | 643 crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem())); |
644 if (!i2d_PUBKEY_bio(bio.get(), key->key())) | |
645 return Status::ErrorUnexpected(); | |
646 | |
647 uint8* data = NULL; | |
648 long len = BIO_get_mem_data(bio.get(), &data); | |
649 if (!data || len < 0) | |
650 return Status::ErrorUnexpected(); | |
651 | |
652 buffer->assign(data, data + len); | |
653 return Status::Success(); | |
468 } | 654 } |
469 | 655 |
470 Status ExportKeyPkcs8(PrivateKey* key, | 656 Status ExportKeyPkcs8(PrivateKey* key, |
471 const blink::WebCryptoKeyAlgorithm& key_algorithm, | 657 const blink::WebCryptoKeyAlgorithm& key_algorithm, |
472 std::vector<uint8>* buffer) { | 658 std::vector<uint8>* buffer) { |
473 // TODO(eroman): http://crbug.com/267888 | 659 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
474 return Status::ErrorUnsupported(); | 660 crypto::ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem())); |
661 | |
662 if (!i2d_PKCS8PrivateKeyInfo_bio(bio.get(), key->key())) | |
663 return Status::ErrorUnexpected(); | |
664 | |
665 uint8* data = NULL; | |
666 long len = BIO_get_mem_data(bio.get(), &data); | |
667 if (!data || len < 0) | |
668 return Status::ErrorUnexpected(); | |
669 | |
670 buffer->assign(data, data + len); | |
671 return Status::Success(); | |
475 } | 672 } |
476 | 673 |
477 Status ExportRsaPublicKey(PublicKey* key, | 674 Status ExportRsaPublicKey(PublicKey* key, |
478 std::vector<uint8>* modulus, | 675 std::vector<uint8>* modulus, |
479 std::vector<uint8>* public_exponent) { | 676 std::vector<uint8>* public_exponent) { |
480 // TODO(eroman): http://crbug.com/267888 | 677 // TODO(eroman): http://crbug.com/267888 |
481 return Status::ErrorUnsupported(); | 678 return Status::ErrorUnsupported(); |
482 } | 679 } |
483 | 680 |
484 Status ExportRsaPrivateKey(PrivateKey* key, | 681 Status ExportRsaPrivateKey(PrivateKey* key, |
(...skipping 26 matching lines...) Expand all Loading... | |
511 blink::WebCryptoKey* key) { | 708 blink::WebCryptoKey* key) { |
512 // TODO(eroman): http://crbug.com/267888 | 709 // TODO(eroman): http://crbug.com/267888 |
513 return false; | 710 return false; |
514 } | 711 } |
515 | 712 |
516 } // namespace platform | 713 } // namespace platform |
517 | 714 |
518 } // namespace webcrypto | 715 } // namespace webcrypto |
519 | 716 |
520 } // namespace content | 717 } // namespace content |
OLD | NEW |