| 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 |