blob: 4d7b0f61dca2fdca1eff8217f233987cccde85de [file] [log] [blame]
[email protected]ab782c92012-07-09 23:12:141// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]eaa60482011-11-09 05:08:512// 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
davidben74f67442016-10-01 01:45:227#include <openssl/bio.h>
8#include <openssl/bn.h>
davidben7dad2a32016-03-01 23:47:479#include <openssl/bytestring.h>
[email protected]d4db0b62013-10-17 16:09:2410#include <openssl/ec.h>
davidben74f67442016-10-01 01:45:2211#include <openssl/ec_key.h>
[email protected]d4db0b62013-10-17 16:09:2412#include <openssl/evp.h>
davidben7dad2a32016-03-01 23:47:4713#include <openssl/mem.h>
[email protected]d4db0b62013-10-17 16:09:2414#include <openssl/pkcs12.h>
15#include <openssl/x509.h>
avidd373b8b2015-12-21 21:34:4316#include <stddef.h>
17#include <stdint.h>
[email protected]d4db0b62013-10-17 16:09:2418
davidben74f67442016-10-01 01:45:2219#include <utility>
20
[email protected]eaa60482011-11-09 05:08:5121#include "base/logging.h"
[email protected]d4db0b62013-10-17 16:09:2422#include "crypto/openssl_util.h"
[email protected]eaa60482011-11-09 05:08:5123
24namespace crypto {
25
[email protected]d4db0b62013-10-17 16:09:2426namespace {
[email protected]eaa60482011-11-09 05:08:5127
[email protected]d4db0b62013-10-17 16:09:2428// Function pointer definition, for injecting the required key export function
29// into ExportKeyWithBio, below. |bio| is a temporary memory BIO object, and
30// |key| is a handle to the input key object. Return 1 on success, 0 otherwise.
31// NOTE: Used with OpenSSL functions, which do not comply with the Chromium
32// style guide, hence the unusual parameter placement / types.
33typedef int (*ExportBioFunction)(BIO* bio, const void* key);
34
35// Helper to export |key| into |output| via the specified ExportBioFunction.
36bool ExportKeyWithBio(const void* key,
37 ExportBioFunction export_fn,
avidd373b8b2015-12-21 21:34:4338 std::vector<uint8_t>* output) {
[email protected]d4db0b62013-10-17 16:09:2439 if (!key)
40 return false;
41
davidben74f67442016-10-01 01:45:2242 bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
rsleeviffe5a132016-06-28 01:51:5243 if (!bio)
[email protected]d4db0b62013-10-17 16:09:2444 return false;
45
46 if (!export_fn(bio.get(), key))
47 return false;
48
rsleeviffe5a132016-06-28 01:51:5249 char* data = nullptr;
[email protected]d4db0b62013-10-17 16:09:2450 long len = BIO_get_mem_data(bio.get(), &data);
51 if (!data || len < 0)
52 return false;
53
54 output->assign(data, data + len);
55 return true;
56}
57
[email protected]d4db0b62013-10-17 16:09:2458} // namespace
59
davidben74f67442016-10-01 01:45:2260ECPrivateKey::~ECPrivateKey() {}
[email protected]ab782c92012-07-09 23:12:1461
62// static
rsleeviffe5a132016-06-28 01:51:5263std::unique_ptr<ECPrivateKey> ECPrivateKey::Create() {
[email protected]d4db0b62013-10-17 16:09:2464 OpenSSLErrStackTracer err_tracer(FROM_HERE);
65
davidben74f67442016-10-01 01:45:2266 bssl::UniquePtr<EC_KEY> ec_key(
67 EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
rsleeviffe5a132016-06-28 01:51:5268 if (!ec_key || !EC_KEY_generate_key(ec_key.get()))
69 return nullptr;
[email protected]d4db0b62013-10-17 16:09:2470
thakisd1a18472016-04-08 22:30:4171 std::unique_ptr<ECPrivateKey> result(new ECPrivateKey());
davidben74f67442016-10-01 01:45:2272 result->key_.reset(EVP_PKEY_new());
73 if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_.get(), ec_key.get()))
rsleeviffe5a132016-06-28 01:51:5274 return nullptr;
[email protected]d4db0b62013-10-17 16:09:2475
davidben74f67442016-10-01 01:45:2276 CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_id(result->key_.get()));
rsleeviffe5a132016-06-28 01:51:5277 return result;
[email protected]eaa60482011-11-09 05:08:5178}
79
80// static
davidben212cdf62016-06-07 17:11:0981std::unique_ptr<ECPrivateKey> ECPrivateKey::CreateFromPrivateKeyInfo(
82 const std::vector<uint8_t>& input) {
83 OpenSSLErrStackTracer err_tracer(FROM_HERE);
84
85 CBS cbs;
86 CBS_init(&cbs, input.data(), input.size());
davidben74f67442016-10-01 01:45:2287 bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs));
davidben212cdf62016-06-07 17:11:0988 if (!pkey || CBS_len(&cbs) != 0 || EVP_PKEY_id(pkey.get()) != EVP_PKEY_EC)
89 return nullptr;
90
rsleeviffe5a132016-06-28 01:51:5291 std::unique_ptr<ECPrivateKey> result(new ECPrivateKey());
davidben74f67442016-10-01 01:45:2292 result->key_ = std::move(pkey);
davidben212cdf62016-06-07 17:11:0993 return result;
94}
95
96// static
rsleeviffe5a132016-06-28 01:51:5297std::unique_ptr<ECPrivateKey> ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
[email protected]eaa60482011-11-09 05:08:5198 const std::string& password,
avidd373b8b2015-12-21 21:34:4399 const std::vector<uint8_t>& encrypted_private_key_info,
100 const std::vector<uint8_t>& subject_public_key_info) {
[email protected]d4db0b62013-10-17 16:09:24101 // NOTE: The |subject_public_key_info| can be ignored here, it is only
102 // useful for the NSS implementation (which uses the public key's SHA1
103 // as a lookup key when storing the private one in its store).
104 if (encrypted_private_key_info.empty())
rsleeviffe5a132016-06-28 01:51:52105 return nullptr;
[email protected]d4db0b62013-10-17 16:09:24106
107 OpenSSLErrStackTracer err_tracer(FROM_HERE);
[email protected]dc06f752014-08-06 23:11:09108
109 const uint8_t* data = &encrypted_private_key_info[0];
110 const uint8_t* ptr = data;
davidben74f67442016-10-01 01:45:22111 bssl::UniquePtr<X509_SIG> p8_encrypted(
rsleeviffe5a132016-06-28 01:51:52112 d2i_X509_SIG(nullptr, &ptr, encrypted_private_key_info.size()));
[email protected]dc06f752014-08-06 23:11:09113 if (!p8_encrypted || ptr != data + encrypted_private_key_info.size())
rsleeviffe5a132016-06-28 01:51:52114 return nullptr;
[email protected]d4db0b62013-10-17 16:09:24115
davidben74f67442016-10-01 01:45:22116 bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> p8_decrypted;
[email protected]dc06f752014-08-06 23:11:09117 if (password.empty()) {
118 // Hack for reading keys generated by an older version of the OpenSSL
119 // code. OpenSSL used to use "\0\0" rather than the empty string because it
120 // would treat the password as an ASCII string to be converted to UCS-2
121 // while NSS used a byte string.
122 p8_decrypted.reset(PKCS8_decrypt_pbe(
123 p8_encrypted.get(), reinterpret_cast<const uint8_t*>("\0\0"), 2));
[email protected]cdddc0f92014-03-22 02:42:47124 }
[email protected]dc06f752014-08-06 23:11:09125 if (!p8_decrypted) {
126 p8_decrypted.reset(PKCS8_decrypt_pbe(
127 p8_encrypted.get(),
128 reinterpret_cast<const uint8_t*>(password.data()),
129 password.size()));
130 }
131
132 if (!p8_decrypted)
rsleeviffe5a132016-06-28 01:51:52133 return nullptr;
[email protected]d4db0b62013-10-17 16:09:24134
135 // Create a new EVP_PKEY for it.
rsleeviffe5a132016-06-28 01:51:52136 std::unique_ptr<ECPrivateKey> result(new ECPrivateKey());
davidben74f67442016-10-01 01:45:22137 result->key_.reset(EVP_PKCS82PKEY(p8_decrypted.get()));
138 if (!result->key_ || EVP_PKEY_id(result->key_.get()) != EVP_PKEY_EC)
rsleeviffe5a132016-06-28 01:51:52139 return nullptr;
[email protected]d4db0b62013-10-17 16:09:24140
rsleeviffe5a132016-06-28 01:51:52141 return result;
142}
143
144std::unique_ptr<ECPrivateKey> ECPrivateKey::Copy() const {
145 std::unique_ptr<ECPrivateKey> copy(new ECPrivateKey());
agl5a7cadf2016-07-13 16:52:53146 if (key_) {
davidben74f67442016-10-01 01:45:22147 EVP_PKEY_up_ref(key_.get());
148 copy->key_.reset(key_.get());
agl5a7cadf2016-07-13 16:52:53149 }
rsleeviffe5a132016-06-28 01:51:52150 return copy;
[email protected]eaa60482011-11-09 05:08:51151}
152
davidben212cdf62016-06-07 17:11:09153bool ECPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const {
154 OpenSSLErrStackTracer err_tracer(FROM_HERE);
155 uint8_t* der;
156 size_t der_len;
davidben74f67442016-10-01 01:45:22157 bssl::ScopedCBB cbb;
158 if (!CBB_init(cbb.get(), 0) ||
159 !EVP_marshal_private_key(cbb.get(), key_.get()) ||
davidben212cdf62016-06-07 17:11:09160 !CBB_finish(cbb.get(), &der, &der_len)) {
161 return false;
162 }
163 output->assign(der, der + der_len);
164 OPENSSL_free(der);
165 return true;
166}
167
168bool ECPrivateKey::ExportEncryptedPrivateKey(
169 const std::string& password,
170 int iterations,
171 std::vector<uint8_t>* output) const {
[email protected]d4db0b62013-10-17 16:09:24172 OpenSSLErrStackTracer err_tracer(FROM_HERE);
173 // Convert into a PKCS#8 object.
davidben74f67442016-10-01 01:45:22174 bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> pkcs8(EVP_PKEY2PKCS8(key_.get()));
rsleeviffe5a132016-06-28 01:51:52175 if (!pkcs8)
[email protected]d4db0b62013-10-17 16:09:24176 return false;
177
178 // Encrypt the object.
179 // NOTE: NSS uses SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
180 // so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL
181 // equivalent.
davidben74f67442016-10-01 01:45:22182 bssl::UniquePtr<X509_SIG> encrypted(
183 PKCS8_encrypt_pbe(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr,
184 reinterpret_cast<const uint8_t*>(password.data()),
185 password.size(), nullptr, 0, iterations, pkcs8.get()));
rsleeviffe5a132016-06-28 01:51:52186 if (!encrypted)
[email protected]d4db0b62013-10-17 16:09:24187 return false;
188
189 // Write it into |*output|
190 return ExportKeyWithBio(encrypted.get(),
191 reinterpret_cast<ExportBioFunction>(i2d_PKCS8_bio),
192 output);
[email protected]eaa60482011-11-09 05:08:51193}
194
davidben212cdf62016-06-07 17:11:09195bool ECPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const {
[email protected]d4db0b62013-10-17 16:09:24196 OpenSSLErrStackTracer err_tracer(FROM_HERE);
davidben7dad2a32016-03-01 23:47:47197 uint8_t *der;
198 size_t der_len;
davidben74f67442016-10-01 01:45:22199 bssl::ScopedCBB cbb;
davidben7dad2a32016-03-01 23:47:47200 if (!CBB_init(cbb.get(), 0) ||
davidben74f67442016-10-01 01:45:22201 !EVP_marshal_public_key(cbb.get(), key_.get()) ||
davidben7dad2a32016-03-01 23:47:47202 !CBB_finish(cbb.get(), &der, &der_len)) {
[email protected]ac30ed0e2014-06-24 04:12:34203 return false;
davidben7dad2a32016-03-01 23:47:47204 }
205 output->assign(der, der + der_len);
206 OPENSSL_free(der);
[email protected]ac30ed0e2014-06-24 04:12:34207 return true;
208}
209
davidben212cdf62016-06-07 17:11:09210bool ECPrivateKey::ExportRawPublicKey(std::string* output) const {
[email protected]d4db0b62013-10-17 16:09:24211 OpenSSLErrStackTracer err_tracer(FROM_HERE);
davidben7dad2a32016-03-01 23:47:47212
213 // Export the x and y field elements as 32-byte, big-endian numbers. (This is
214 // the same as X9.62 uncompressed form without the leading 0x04 byte.)
davidben74f67442016-10-01 01:45:22215 EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key_.get());
216 bssl::UniquePtr<BIGNUM> x(BN_new());
217 bssl::UniquePtr<BIGNUM> y(BN_new());
davidben7dad2a32016-03-01 23:47:47218 uint8_t buf[64];
219 if (!x || !y ||
220 !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key),
221 EC_KEY_get0_public_key(ec_key),
222 x.get(), y.get(), nullptr) ||
223 !BN_bn2bin_padded(buf, 32, x.get()) ||
224 !BN_bn2bin_padded(buf + 32, 32, y.get())) {
225 return false;
226 }
227
228 output->assign(reinterpret_cast<const char*>(buf), sizeof(buf));
229 return true;
[email protected]eaa60482011-11-09 05:08:51230}
231
davidben74f67442016-10-01 01:45:22232ECPrivateKey::ECPrivateKey() {}
[email protected]d4db0b62013-10-17 16:09:24233
[email protected]eaa60482011-11-09 05:08:51234} // namespace crypto