OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "crypto/ec_private_key.h" | |
6 | |
7 #include <openssl/bytestring.h> | |
8 #include <openssl/ec.h> | |
9 #include <openssl/evp.h> | |
10 #include <openssl/mem.h> | |
11 #include <openssl/pkcs12.h> | |
12 #include <openssl/x509.h> | |
13 #include <stddef.h> | |
14 #include <stdint.h> | |
15 | |
16 #include <memory> | |
17 | |
18 #include "base/logging.h" | |
19 #include "crypto/auto_cbb.h" | |
20 #include "crypto/openssl_util.h" | |
21 #include "crypto/scoped_openssl_types.h" | |
22 | |
23 namespace crypto { | |
24 | |
25 namespace { | |
26 | |
27 // Function pointer definition, for injecting the required key export function | |
28 // into ExportKeyWithBio, below. |bio| is a temporary memory BIO object, and | |
29 // |key| is a handle to the input key object. Return 1 on success, 0 otherwise. | |
30 // NOTE: Used with OpenSSL functions, which do not comply with the Chromium | |
31 // style guide, hence the unusual parameter placement / types. | |
32 typedef int (*ExportBioFunction)(BIO* bio, const void* key); | |
33 | |
34 using ScopedPKCS8_PRIV_KEY_INFO = | |
35 ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>; | |
36 using ScopedX509_SIG = ScopedOpenSSL<X509_SIG, X509_SIG_free>; | |
37 | |
38 // Helper to export |key| into |output| via the specified ExportBioFunction. | |
39 bool ExportKeyWithBio(const void* key, | |
40 ExportBioFunction export_fn, | |
41 std::vector<uint8_t>* output) { | |
42 if (!key) | |
43 return false; | |
44 | |
45 ScopedBIO bio(BIO_new(BIO_s_mem())); | |
46 if (!bio.get()) | |
47 return false; | |
48 | |
49 if (!export_fn(bio.get(), key)) | |
50 return false; | |
51 | |
52 char* data = NULL; | |
53 long len = BIO_get_mem_data(bio.get(), &data); | |
54 if (!data || len < 0) | |
55 return false; | |
56 | |
57 output->assign(data, data + len); | |
58 return true; | |
59 } | |
60 | |
61 } // namespace | |
62 | |
63 ECPrivateKey::~ECPrivateKey() { | |
64 if (key_) | |
65 EVP_PKEY_free(key_); | |
66 } | |
67 | |
68 ECPrivateKey* ECPrivateKey::Copy() const { | |
69 std::unique_ptr<ECPrivateKey> copy(new ECPrivateKey); | |
70 if (key_) | |
71 copy->key_ = EVP_PKEY_up_ref(key_); | |
72 return copy.release(); | |
73 } | |
74 | |
75 // static | |
76 ECPrivateKey* ECPrivateKey::Create() { | |
77 OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
78 | |
79 ScopedEC_KEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); | |
80 if (!ec_key.get() || !EC_KEY_generate_key(ec_key.get())) | |
81 return NULL; | |
82 | |
83 std::unique_ptr<ECPrivateKey> result(new ECPrivateKey()); | |
84 result->key_ = EVP_PKEY_new(); | |
85 if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_, ec_key.get())) | |
86 return NULL; | |
87 | |
88 CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_type(result->key_->type)); | |
89 return result.release(); | |
90 } | |
91 | |
92 // static | |
93 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( | |
94 const std::string& password, | |
95 const std::vector<uint8_t>& encrypted_private_key_info, | |
96 const std::vector<uint8_t>& subject_public_key_info) { | |
97 // NOTE: The |subject_public_key_info| can be ignored here, it is only | |
98 // useful for the NSS implementation (which uses the public key's SHA1 | |
99 // as a lookup key when storing the private one in its store). | |
100 if (encrypted_private_key_info.empty()) | |
101 return NULL; | |
102 | |
103 OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
104 | |
105 const uint8_t* data = &encrypted_private_key_info[0]; | |
106 const uint8_t* ptr = data; | |
107 ScopedX509_SIG p8_encrypted( | |
108 d2i_X509_SIG(NULL, &ptr, encrypted_private_key_info.size())); | |
109 if (!p8_encrypted || ptr != data + encrypted_private_key_info.size()) | |
110 return NULL; | |
111 | |
112 ScopedPKCS8_PRIV_KEY_INFO p8_decrypted; | |
113 if (password.empty()) { | |
114 // Hack for reading keys generated by an older version of the OpenSSL | |
115 // code. OpenSSL used to use "\0\0" rather than the empty string because it | |
116 // would treat the password as an ASCII string to be converted to UCS-2 | |
117 // while NSS used a byte string. | |
118 p8_decrypted.reset(PKCS8_decrypt_pbe( | |
119 p8_encrypted.get(), reinterpret_cast<const uint8_t*>("\0\0"), 2)); | |
120 } | |
121 if (!p8_decrypted) { | |
122 p8_decrypted.reset(PKCS8_decrypt_pbe( | |
123 p8_encrypted.get(), | |
124 reinterpret_cast<const uint8_t*>(password.data()), | |
125 password.size())); | |
126 } | |
127 | |
128 if (!p8_decrypted) | |
129 return NULL; | |
130 | |
131 // Create a new EVP_PKEY for it. | |
132 std::unique_ptr<ECPrivateKey> result(new ECPrivateKey); | |
133 result->key_ = EVP_PKCS82PKEY(p8_decrypted.get()); | |
134 if (!result->key_ || EVP_PKEY_type(result->key_->type) != EVP_PKEY_EC) | |
135 return NULL; | |
136 | |
137 return result.release(); | |
138 } | |
139 | |
140 bool ECPrivateKey::ExportEncryptedPrivateKey(const std::string& password, | |
141 int iterations, | |
142 std::vector<uint8_t>* output) { | |
143 OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
144 // Convert into a PKCS#8 object. | |
145 ScopedPKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(key_)); | |
146 if (!pkcs8.get()) | |
147 return false; | |
148 | |
149 // Encrypt the object. | |
150 // NOTE: NSS uses SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC | |
151 // so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL | |
152 // equivalent. | |
153 ScopedX509_SIG encrypted(PKCS8_encrypt_pbe( | |
154 NID_pbe_WithSHA1And3_Key_TripleDES_CBC, | |
155 nullptr, | |
156 reinterpret_cast<const uint8_t*>(password.data()), | |
157 password.size(), | |
158 nullptr, | |
159 0, | |
160 iterations, | |
161 pkcs8.get())); | |
162 if (!encrypted.get()) | |
163 return false; | |
164 | |
165 // Write it into |*output| | |
166 return ExportKeyWithBio(encrypted.get(), | |
167 reinterpret_cast<ExportBioFunction>(i2d_PKCS8_bio), | |
168 output); | |
169 } | |
170 | |
171 bool ECPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) { | |
172 OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
173 uint8_t *der; | |
174 size_t der_len; | |
175 AutoCBB cbb; | |
176 if (!CBB_init(cbb.get(), 0) || | |
177 !EVP_marshal_public_key(cbb.get(), key_) || | |
178 !CBB_finish(cbb.get(), &der, &der_len)) { | |
179 return false; | |
180 } | |
181 output->assign(der, der + der_len); | |
182 OPENSSL_free(der); | |
183 return true; | |
184 } | |
185 | |
186 bool ECPrivateKey::ExportRawPublicKey(std::string* output) { | |
187 OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
188 | |
189 // Export the x and y field elements as 32-byte, big-endian numbers. (This is | |
190 // the same as X9.62 uncompressed form without the leading 0x04 byte.) | |
191 EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key_); | |
192 ScopedBIGNUM x(BN_new()); | |
193 ScopedBIGNUM y(BN_new()); | |
194 uint8_t buf[64]; | |
195 if (!x || !y || | |
196 !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key), | |
197 EC_KEY_get0_public_key(ec_key), | |
198 x.get(), y.get(), nullptr) || | |
199 !BN_bn2bin_padded(buf, 32, x.get()) || | |
200 !BN_bn2bin_padded(buf + 32, 32, y.get())) { | |
201 return false; | |
202 } | |
203 | |
204 output->assign(reinterpret_cast<const char*>(buf), sizeof(buf)); | |
205 return true; | |
206 } | |
207 | |
208 bool ECPrivateKey::ExportValueForTesting(std::vector<uint8_t>* output) { | |
209 OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
210 EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key_); | |
211 uint8_t *der; | |
212 size_t der_len; | |
213 AutoCBB cbb; | |
214 if (!CBB_init(cbb.get(), 0) || | |
215 !EC_KEY_marshal_private_key(cbb.get(), ec_key, 0 /* enc_flags */) || | |
216 !CBB_finish(cbb.get(), &der, &der_len)) { | |
217 return false; | |
218 } | |
219 output->assign(der, der + der_len); | |
220 OPENSSL_free(der); | |
221 return true; | |
222 } | |
223 | |
224 ECPrivateKey::ECPrivateKey() : key_(NULL) {} | |
225 | |
226 } // namespace crypto | |
OLD | NEW |