Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: content/child/webcrypto/platform_crypto_openssl.cc

Issue 353043005: [webcrypto] Wire up {spki, pkcs8} import/export for OpenSSL. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | content/child/webcrypto/shared_crypto_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | content/child/webcrypto/shared_crypto_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698