#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "crypto/openssl_util.h"
+#include "crypto/scoped_openssl_types.h"
namespace crypto {
// style guide, hence the unusual parameter placement / types.
typedef int (*ExportBioFunction)(BIO* bio, const void* key);
+typedef ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
+ ScopedPKCS8_PRIV_KEY_INFO;
+typedef ScopedOpenSSL<X509_SIG, X509_SIG_free>::Type ScopedX509_SIG;
+
// Helper to export |key| into |output| via the specified ExportBioFunction.
bool ExportKeyWithBio(const void* key,
ExportBioFunction export_fn,
if (!key)
return false;
- ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem()));
+ ScopedBIO bio(BIO_new(BIO_s_mem()));
if (!bio.get())
return false;
ECPrivateKey* ECPrivateKey::Create() {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
- ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(
- EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+ ScopedEC_KEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
if (!ec_key.get() || !EC_KEY_generate_key(ec_key.get()))
return NULL;
if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_, ec_key.get()))
return NULL;
+ CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_type(result->key_->type));
return result.release();
}
return NULL;
OpenSSLErrStackTracer err_tracer(FROM_HERE);
- // Write the encrypted private key into a memory BIO.
- char* private_key_data = reinterpret_cast<char*>(
- const_cast<uint8*>(&encrypted_private_key_info[0]));
- int private_key_data_len =
- static_cast<int>(encrypted_private_key_info.size());
- ScopedOpenSSL<BIO, BIO_free_all> bio(
- BIO_new_mem_buf(private_key_data, private_key_data_len));
- if (!bio.get())
- return NULL;
- // Convert it, then decrypt it into a PKCS#8 object.
- ScopedOpenSSL<X509_SIG, X509_SIG_free> p8_encrypted(
- d2i_PKCS8_bio(bio.get(), NULL));
- if (!p8_encrypted.get())
+ const uint8_t* data = &encrypted_private_key_info[0];
+ const uint8_t* ptr = data;
+ ScopedX509_SIG p8_encrypted(
+ d2i_X509_SIG(NULL, &ptr, encrypted_private_key_info.size()));
+ if (!p8_encrypted || ptr != data + encrypted_private_key_info.size())
return NULL;
- ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8_decrypted(
- PKCS8_decrypt(p8_encrypted.get(),
- password.c_str(),
- static_cast<int>(password.size())));
- if (!p8_decrypted.get() && password.empty()) {
- // Hack for reading keys generated by ec_private_key_nss. Passing NULL
- // causes OpenSSL to use an empty password instead of "\0\0".
- p8_decrypted.reset(PKCS8_decrypt(p8_encrypted.get(), NULL, 0));
+ ScopedPKCS8_PRIV_KEY_INFO p8_decrypted;
+ if (password.empty()) {
+ // Hack for reading keys generated by an older version of the OpenSSL
+ // code. OpenSSL used to use "\0\0" rather than the empty string because it
+ // would treat the password as an ASCII string to be converted to UCS-2
+ // while NSS used a byte string.
+ p8_decrypted.reset(PKCS8_decrypt_pbe(
+ p8_encrypted.get(), reinterpret_cast<const uint8_t*>("\0\0"), 2));
+ }
+ if (!p8_decrypted) {
+ p8_decrypted.reset(PKCS8_decrypt_pbe(
+ p8_encrypted.get(),
+ reinterpret_cast<const uint8_t*>(password.data()),
+ password.size()));
}
- if (!p8_decrypted.get())
+
+ if (!p8_decrypted)
return NULL;
// Create a new EVP_PKEY for it.
scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
result->key_ = EVP_PKCS82PKEY(p8_decrypted.get());
- if (!result->key_)
+ if (!result->key_ || EVP_PKEY_type(result->key_->type) != EVP_PKEY_EC)
return NULL;
return result.release();
std::vector<uint8>* output) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
// Convert into a PKCS#8 object.
- ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8(
- EVP_PKEY2PKCS8(key_));
+ ScopedPKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(key_));
if (!pkcs8.get())
return false;
// NOTE: NSS uses SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
// so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL
// equivalent.
- ScopedOpenSSL<X509_SIG, X509_SIG_free> encrypted(
- PKCS8_encrypt(NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
- NULL,
- password.c_str(),
- static_cast<int>(password.size()),
- NULL,
- 0,
- iterations,
- pkcs8.get()));
+ ScopedX509_SIG encrypted(PKCS8_encrypt_pbe(
+ NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+ reinterpret_cast<const uint8_t*>(password.data()),
+ password.size(),
+ NULL,
+ 0,
+ iterations,
+ pkcs8.get()));
if (!encrypted.get())
return false;
key_, reinterpret_cast<ExportBioFunction>(i2d_PUBKEY_bio), output);
}
+bool ECPrivateKey::ExportRawPublicKey(std::string* output) {
+ // i2d_PublicKey will produce an ANSI X9.62 public key which, for a P-256
+ // key, is 0x04 (meaning uncompressed) followed by the x and y field
+ // elements as 32-byte, big-endian numbers.
+ static const int kExpectedKeyLength = 65;
+
+ int len = i2d_PublicKey(key_, NULL);
+ if (len != kExpectedKeyLength)
+ return false;
+
+ uint8 buf[kExpectedKeyLength];
+ uint8* derp = buf;
+ len = i2d_PublicKey(key_, &derp);
+ if (len != kExpectedKeyLength)
+ return false;
+
+ output->assign(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1);
+ return true;
+}
+
bool ECPrivateKey::ExportValue(std::vector<uint8>* output) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
- ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(EVP_PKEY_get1_EC_KEY(key_));
+ ScopedEC_KEY ec_key(EVP_PKEY_get1_EC_KEY(key_));
return ExportKey(ec_key.get(),
reinterpret_cast<ExportDataFunction>(i2d_ECPrivateKey),
output);
bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
- ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(EVP_PKEY_get1_EC_KEY(key_));
+ ScopedEC_KEY ec_key(EVP_PKEY_get1_EC_KEY(key_));
return ExportKey(ec_key.get(),
reinterpret_cast<ExportDataFunction>(i2d_ECParameters),
output);