OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "crypto/ec_private_key.h" | 5 #include "crypto/ec_private_key.h" |
6 | 6 |
7 #include <openssl/ec.h> | 7 #include <openssl/ec.h> |
8 #include <openssl/evp.h> | 8 #include <openssl/evp.h> |
9 #include <openssl/pkcs12.h> | 9 #include <openssl/pkcs12.h> |
10 #include <openssl/x509.h> | 10 #include <openssl/x509.h> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
14 #include "crypto/openssl_util.h" | 14 #include "crypto/openssl_util.h" |
| 15 #include "crypto/scoped_openssl_types.h" |
15 | 16 |
16 namespace crypto { | 17 namespace crypto { |
17 | 18 |
18 namespace { | 19 namespace { |
19 | 20 |
20 // Function pointer definition, for injecting the required key export function | 21 // Function pointer definition, for injecting the required key export function |
21 // into ExportKeyWithBio, below. |bio| is a temporary memory BIO object, and | 22 // into ExportKeyWithBio, below. |bio| is a temporary memory BIO object, and |
22 // |key| is a handle to the input key object. Return 1 on success, 0 otherwise. | 23 // |key| is a handle to the input key object. Return 1 on success, 0 otherwise. |
23 // NOTE: Used with OpenSSL functions, which do not comply with the Chromium | 24 // NOTE: Used with OpenSSL functions, which do not comply with the Chromium |
24 // style guide, hence the unusual parameter placement / types. | 25 // style guide, hence the unusual parameter placement / types. |
25 typedef int (*ExportBioFunction)(BIO* bio, const void* key); | 26 typedef int (*ExportBioFunction)(BIO* bio, const void* key); |
26 | 27 |
| 28 typedef scoped_ptr<PKCS8_PRIV_KEY_INFO, |
| 29 OpenSSLDestroyer<PKCS8_PRIV_KEY_INFO, |
| 30 PKCS8_PRIV_KEY_INFO_free> > |
| 31 ScopedPKCS8_PRIV_KEY_INFO; |
| 32 typedef scoped_ptr<X509_SIG, OpenSSLDestroyer<X509_SIG, X509_SIG_free> > |
| 33 ScopedX509_SIG; |
| 34 |
27 // Helper to export |key| into |output| via the specified ExportBioFunction. | 35 // Helper to export |key| into |output| via the specified ExportBioFunction. |
28 bool ExportKeyWithBio(const void* key, | 36 bool ExportKeyWithBio(const void* key, |
29 ExportBioFunction export_fn, | 37 ExportBioFunction export_fn, |
30 std::vector<uint8>* output) { | 38 std::vector<uint8>* output) { |
31 if (!key) | 39 if (!key) |
32 return false; | 40 return false; |
33 | 41 |
34 ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem())); | 42 ScopedBIO bio(BIO_new(BIO_s_mem())); |
35 if (!bio.get()) | 43 if (!bio.get()) |
36 return false; | 44 return false; |
37 | 45 |
38 if (!export_fn(bio.get(), key)) | 46 if (!export_fn(bio.get(), key)) |
39 return false; | 47 return false; |
40 | 48 |
41 char* data = NULL; | 49 char* data = NULL; |
42 long len = BIO_get_mem_data(bio.get(), &data); | 50 long len = BIO_get_mem_data(bio.get(), &data); |
43 if (!data || len < 0) | 51 if (!data || len < 0) |
44 return false; | 52 return false; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 EVP_PKEY_free(key_); | 88 EVP_PKEY_free(key_); |
81 } | 89 } |
82 | 90 |
83 // static | 91 // static |
84 bool ECPrivateKey::IsSupported() { return true; } | 92 bool ECPrivateKey::IsSupported() { return true; } |
85 | 93 |
86 // static | 94 // static |
87 ECPrivateKey* ECPrivateKey::Create() { | 95 ECPrivateKey* ECPrivateKey::Create() { |
88 OpenSSLErrStackTracer err_tracer(FROM_HERE); | 96 OpenSSLErrStackTracer err_tracer(FROM_HERE); |
89 | 97 |
90 ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key( | 98 ScopedEC_KEY ec_key( |
91 EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); | 99 EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); |
92 if (!ec_key.get() || !EC_KEY_generate_key(ec_key.get())) | 100 if (!ec_key.get() || !EC_KEY_generate_key(ec_key.get())) |
93 return NULL; | 101 return NULL; |
94 | 102 |
95 scoped_ptr<ECPrivateKey> result(new ECPrivateKey()); | 103 scoped_ptr<ECPrivateKey> result(new ECPrivateKey()); |
96 result->key_ = EVP_PKEY_new(); | 104 result->key_ = EVP_PKEY_new(); |
97 if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_, ec_key.get())) | 105 if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_, ec_key.get())) |
98 return NULL; | 106 return NULL; |
99 | 107 |
100 CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_type(result->key_->type)); | 108 CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_type(result->key_->type)); |
(...skipping 10 matching lines...) Expand all Loading... |
111 // as a lookup key when storing the private one in its store). | 119 // as a lookup key when storing the private one in its store). |
112 if (encrypted_private_key_info.empty()) | 120 if (encrypted_private_key_info.empty()) |
113 return NULL; | 121 return NULL; |
114 | 122 |
115 OpenSSLErrStackTracer err_tracer(FROM_HERE); | 123 OpenSSLErrStackTracer err_tracer(FROM_HERE); |
116 // Write the encrypted private key into a memory BIO. | 124 // Write the encrypted private key into a memory BIO. |
117 char* private_key_data = reinterpret_cast<char*>( | 125 char* private_key_data = reinterpret_cast<char*>( |
118 const_cast<uint8*>(&encrypted_private_key_info[0])); | 126 const_cast<uint8*>(&encrypted_private_key_info[0])); |
119 int private_key_data_len = | 127 int private_key_data_len = |
120 static_cast<int>(encrypted_private_key_info.size()); | 128 static_cast<int>(encrypted_private_key_info.size()); |
121 ScopedOpenSSL<BIO, BIO_free_all> bio( | 129 ScopedBIO bio( |
122 BIO_new_mem_buf(private_key_data, private_key_data_len)); | 130 BIO_new_mem_buf(private_key_data, private_key_data_len)); |
123 if (!bio.get()) | 131 if (!bio.get()) |
124 return NULL; | 132 return NULL; |
125 | 133 |
126 // Convert it, then decrypt it into a PKCS#8 object. | 134 // Convert it, then decrypt it into a PKCS#8 object. |
127 ScopedOpenSSL<X509_SIG, X509_SIG_free> p8_encrypted( | 135 ScopedX509_SIG p8_encrypted(d2i_PKCS8_bio(bio.get(), NULL)); |
128 d2i_PKCS8_bio(bio.get(), NULL)); | |
129 if (!p8_encrypted.get()) | 136 if (!p8_encrypted.get()) |
130 return NULL; | 137 return NULL; |
131 | 138 |
132 ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8_decrypted( | 139 ScopedPKCS8_PRIV_KEY_INFO p8_decrypted(PKCS8_decrypt( |
133 PKCS8_decrypt(p8_encrypted.get(), | 140 p8_encrypted.get(), password.c_str(), static_cast<int>(password.size()))); |
134 password.c_str(), | |
135 static_cast<int>(password.size()))); | |
136 if (!p8_decrypted.get() && password.empty()) { | 141 if (!p8_decrypted.get() && password.empty()) { |
137 // Hack for reading keys generated by ec_private_key_nss. Passing NULL | 142 // Hack for reading keys generated by ec_private_key_nss. Passing NULL |
138 // causes OpenSSL to use an empty password instead of "\0\0". | 143 // causes OpenSSL to use an empty password instead of "\0\0". |
139 p8_decrypted.reset(PKCS8_decrypt(p8_encrypted.get(), NULL, 0)); | 144 p8_decrypted.reset(PKCS8_decrypt(p8_encrypted.get(), NULL, 0)); |
140 } | 145 } |
141 if (!p8_decrypted.get()) | 146 if (!p8_decrypted.get()) |
142 return NULL; | 147 return NULL; |
143 | 148 |
144 // Create a new EVP_PKEY for it. | 149 // Create a new EVP_PKEY for it. |
145 scoped_ptr<ECPrivateKey> result(new ECPrivateKey); | 150 scoped_ptr<ECPrivateKey> result(new ECPrivateKey); |
146 result->key_ = EVP_PKCS82PKEY(p8_decrypted.get()); | 151 result->key_ = EVP_PKCS82PKEY(p8_decrypted.get()); |
147 if (!result->key_ || EVP_PKEY_type(result->key_->type) != EVP_PKEY_EC) | 152 if (!result->key_ || EVP_PKEY_type(result->key_->type) != EVP_PKEY_EC) |
148 return NULL; | 153 return NULL; |
149 | 154 |
150 return result.release(); | 155 return result.release(); |
151 } | 156 } |
152 | 157 |
153 bool ECPrivateKey::ExportEncryptedPrivateKey( | 158 bool ECPrivateKey::ExportEncryptedPrivateKey( |
154 const std::string& password, | 159 const std::string& password, |
155 int iterations, | 160 int iterations, |
156 std::vector<uint8>* output) { | 161 std::vector<uint8>* output) { |
157 OpenSSLErrStackTracer err_tracer(FROM_HERE); | 162 OpenSSLErrStackTracer err_tracer(FROM_HERE); |
158 // Convert into a PKCS#8 object. | 163 // Convert into a PKCS#8 object. |
159 ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8( | 164 ScopedPKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(key_)); |
160 EVP_PKEY2PKCS8(key_)); | |
161 if (!pkcs8.get()) | 165 if (!pkcs8.get()) |
162 return false; | 166 return false; |
163 | 167 |
164 // Encrypt the object. | 168 // Encrypt the object. |
165 // NOTE: NSS uses SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC | 169 // NOTE: NSS uses SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC |
166 // so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL | 170 // so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL |
167 // equivalent. | 171 // equivalent. |
168 ScopedOpenSSL<X509_SIG, X509_SIG_free> encrypted( | 172 ScopedX509_SIG encrypted(PKCS8_encrypt(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, |
169 PKCS8_encrypt(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, | 173 NULL, |
170 NULL, | 174 password.c_str(), |
171 password.c_str(), | 175 static_cast<int>(password.size()), |
172 static_cast<int>(password.size()), | 176 NULL, |
173 NULL, | 177 0, |
174 0, | 178 iterations, |
175 iterations, | 179 pkcs8.get())); |
176 pkcs8.get())); | |
177 if (!encrypted.get()) | 180 if (!encrypted.get()) |
178 return false; | 181 return false; |
179 | 182 |
180 // Write it into |*output| | 183 // Write it into |*output| |
181 return ExportKeyWithBio(encrypted.get(), | 184 return ExportKeyWithBio(encrypted.get(), |
182 reinterpret_cast<ExportBioFunction>(i2d_PKCS8_bio), | 185 reinterpret_cast<ExportBioFunction>(i2d_PKCS8_bio), |
183 output); | 186 output); |
184 } | 187 } |
185 | 188 |
186 bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) { | 189 bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) { |
(...skipping 17 matching lines...) Expand all Loading... |
204 len = i2d_PublicKey(key_, &derp); | 207 len = i2d_PublicKey(key_, &derp); |
205 if (len != kExpectedKeyLength) | 208 if (len != kExpectedKeyLength) |
206 return false; | 209 return false; |
207 | 210 |
208 output->assign(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1); | 211 output->assign(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1); |
209 return true; | 212 return true; |
210 } | 213 } |
211 | 214 |
212 bool ECPrivateKey::ExportValue(std::vector<uint8>* output) { | 215 bool ECPrivateKey::ExportValue(std::vector<uint8>* output) { |
213 OpenSSLErrStackTracer err_tracer(FROM_HERE); | 216 OpenSSLErrStackTracer err_tracer(FROM_HERE); |
214 ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(EVP_PKEY_get1_EC_KEY(key_)); | 217 ScopedEC_KEY ec_key(EVP_PKEY_get1_EC_KEY(key_)); |
215 return ExportKey(ec_key.get(), | 218 return ExportKey(ec_key.get(), |
216 reinterpret_cast<ExportDataFunction>(i2d_ECPrivateKey), | 219 reinterpret_cast<ExportDataFunction>(i2d_ECPrivateKey), |
217 output); | 220 output); |
218 } | 221 } |
219 | 222 |
220 bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { | 223 bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { |
221 OpenSSLErrStackTracer err_tracer(FROM_HERE); | 224 OpenSSLErrStackTracer err_tracer(FROM_HERE); |
222 ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(EVP_PKEY_get1_EC_KEY(key_)); | 225 ScopedEC_KEY ec_key(EVP_PKEY_get1_EC_KEY(key_)); |
223 return ExportKey(ec_key.get(), | 226 return ExportKey(ec_key.get(), |
224 reinterpret_cast<ExportDataFunction>(i2d_ECParameters), | 227 reinterpret_cast<ExportDataFunction>(i2d_ECParameters), |
225 output); | 228 output); |
226 } | 229 } |
227 | 230 |
228 ECPrivateKey::ECPrivateKey() : key_(NULL) {} | 231 ECPrivateKey::ECPrivateKey() : key_(NULL) {} |
229 | 232 |
230 } // namespace crypto | 233 } // namespace crypto |
OLD | NEW |