diff options
author | davidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-06 23:11:09 +0000 |
---|---|---|
committer | davidben@chromium.org <davidben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-06 23:11:09 +0000 |
commit | dc06f75b3eeef693d0c4bc95ba6d8f91948e62c8 (patch) | |
tree | 7af647b45ee265b0da804b1d8de36b248dc3520b | |
parent | 519317c7d6c060ab0c21c7f3897a7ca687e02015 (diff) | |
download | chromium_src-dc06f75b3eeef693d0c4bc95ba6d8f91948e62c8.zip chromium_src-dc06f75b3eeef693d0c4bc95ba6d8f91948e62c8.tar.gz chromium_src-dc06f75b3eeef693d0c4bc95ba6d8f91948e62c8.tar.bz2 |
Align OpenSSL and NSS ChannelID formats.
NSS would use "" as the password while OpenSSL would use "\0\0" (UCS-2 encoding
of a NUL-terminated string) because of how PKCS#12 recommended encoding
passwords. Make the OpenSSL code use the same format so that we can freely switch
back and forth between NSS and OpenSSL.
(This is in case we need to roll back an OpenSSL cutover and the release has
hit some early release channel already.)
BUG=399121
Review URL: https://codereview.chromium.org/435593003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287890 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | crypto/ec_private_key_openssl.cc | 55 | ||||
-rw-r--r-- | crypto/ec_private_key_unittest.cc | 60 |
2 files changed, 78 insertions, 37 deletions
diff --git a/crypto/ec_private_key_openssl.cc b/crypto/ec_private_key_openssl.cc index beda29f..2d44759 100644 --- a/crypto/ec_private_key_openssl.cc +++ b/crypto/ec_private_key_openssl.cc @@ -117,28 +117,31 @@ ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( 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()); - ScopedBIO 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. - ScopedX509_SIG 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; - ScopedPKCS8_PRIV_KEY_INFO 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.get()) + if (!p8_decrypted) { + p8_decrypted.reset(PKCS8_decrypt_pbe( + p8_encrypted.get(), + reinterpret_cast<const uint8_t*>(password.data()), + password.size())); + } + + if (!p8_decrypted) return NULL; // Create a new EVP_PKEY for it. @@ -164,14 +167,14 @@ bool ECPrivateKey::ExportEncryptedPrivateKey( // 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. - ScopedX509_SIG 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; diff --git a/crypto/ec_private_key_unittest.cc b/crypto/ec_private_key_unittest.cc index 0f4479b..6993a20 100644 --- a/crypto/ec_private_key_unittest.cc +++ b/crypto/ec_private_key_unittest.cc @@ -6,6 +6,7 @@ #include <vector> +#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" @@ -152,7 +153,6 @@ TEST(ECPrivateKeyUnitTest, LoadNSSKeyTest) { 0x58, 0x82, 0x14, 0xfb, 0x47, 0x85, 0x3c, 0xc3, 0xdf, 0xdd, 0xcc, 0x79, 0x9f, 0x41, 0x83, 0x72, 0xf2, 0x0a, 0xe9, 0xe1, 0x2c, 0x12, 0xb0, 0xb0, 0x0a, 0xb2, 0x1d, 0xca, 0x15, 0xb2, 0xca}; - unsigned int nss_key_len = 187; static const unsigned char nss_pub_key[] = { 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, @@ -162,22 +162,62 @@ TEST(ECPrivateKeyUnitTest, LoadNSSKeyTest) { 0xd7, 0x5c, 0x5d, 0xc5, 0x53, 0x6e, 0xe5, 0xa9, 0x33, 0xd5, 0xcc, 0xab, 0x53, 0x78, 0xdd, 0xd6, 0x12, 0x3a, 0x5e, 0xeb, 0xbf, 0xdf, 0x16, 0xd3, 0x2c, 0x3b, 0xe8, 0xdb, 0x19, 0xfc, 0x5e}; - unsigned int nss_pub_key_len = 91; scoped_ptr<crypto::ECPrivateKey> keypair_nss( crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( "", - std::vector<uint8>(nss_key, nss_key + nss_key_len), - std::vector<uint8>(nss_pub_key, nss_pub_key + nss_pub_key_len))); + std::vector<uint8>(nss_key, nss_key + arraysize(nss_key)), + std::vector<uint8>(nss_pub_key, + nss_pub_key + arraysize(nss_pub_key)))); EXPECT_TRUE(keypair_nss.get()); } -// The plan is to migrate to OpenSSL everywhere, so making NSS implementation be -// able to load the OpenSSL generated keys isn't that important. -#if defined(USE_OPENSSL) +// Although the plan is to transition from OpenSSL to NSS, ensure NSS can import +// OpenSSL's format so that it is possible to rollback. TEST(ECPrivateKeyUnitTest, LoadOpenSSLKeyTest) { static const unsigned char openssl_key[] = { + 0x30, 0x81, 0xb0, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0d, 0x04, 0x08, 0xb2, 0xfe, 0x68, + 0xc2, 0xea, 0x0f, 0x10, 0x9c, 0x02, 0x01, 0x01, 0x04, 0x81, 0x90, 0xe2, + 0xf6, 0x1c, 0xca, 0xad, 0x64, 0x30, 0xbf, 0x88, 0x04, 0x35, 0xe5, 0x0f, + 0x11, 0x49, 0x06, 0x01, 0x14, 0x33, 0x80, 0xa2, 0x78, 0x44, 0x5b, 0xaa, + 0x0d, 0xd7, 0x00, 0x36, 0x9d, 0x91, 0x97, 0x37, 0x20, 0x7b, 0x27, 0xc1, + 0xa0, 0xa2, 0x73, 0x06, 0x15, 0xdf, 0xc8, 0x13, 0x9b, 0xc9, 0x8c, 0x9c, + 0xce, 0x00, 0xd0, 0xc8, 0x42, 0xc1, 0xda, 0x2b, 0x07, 0x2b, 0x12, 0xa3, + 0xce, 0x10, 0x39, 0x7a, 0xf1, 0x55, 0x69, 0x8d, 0xa5, 0xc4, 0x2a, 0x00, + 0x0d, 0x94, 0xc6, 0xde, 0x6a, 0x3d, 0xb7, 0xe5, 0x6d, 0x59, 0x3e, 0x09, + 0xb5, 0xe3, 0x3e, 0xfc, 0x50, 0x56, 0xe9, 0x50, 0x42, 0x7c, 0xe7, 0xf0, + 0x19, 0xbd, 0x31, 0xa7, 0x85, 0x47, 0xb3, 0xe9, 0xb3, 0x50, 0x3c, 0xc9, + 0x32, 0x37, 0x1a, 0x93, 0x78, 0x48, 0x78, 0x82, 0xde, 0xad, 0x5c, 0xf2, + 0xcf, 0xf2, 0xbb, 0x2c, 0x44, 0x05, 0x7f, 0x4a, 0xf9, 0xb1, 0x2b, 0xdd, + 0x49, 0xf6, 0x7e, 0xd0, 0x42, 0xaa, 0x14, 0x3c, 0x24, 0x77, 0xb4}; + static const unsigned char openssl_pub_key[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, + 0x67, 0xe7, 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34, + 0xf6, 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6, 0x50, + 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56, 0xfb, 0x33, + 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27, 0xc5, 0xaa, 0x44, + 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d}; + + scoped_ptr<crypto::ECPrivateKey> keypair_openssl( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + "", + std::vector<uint8>(openssl_key, openssl_key + arraysize(openssl_key)), + std::vector<uint8>(openssl_pub_key, + openssl_pub_key + arraysize(openssl_pub_key)))); + + EXPECT_TRUE(keypair_openssl.get()); +} + +// The Android code writes out Channel IDs differently from the NSS +// implementation; the empty password is converted to "\0\0". The OpenSSL port +// should support either. +#if defined(USE_OPENSSL) +TEST(ECPrivateKeyUnitTest, LoadOldOpenSSLKeyTest) { + static const unsigned char openssl_key[] = { 0x30, 0x82, 0x01, 0xa1, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0d, 0x04, 0x08, 0x86, 0xaa, 0xd7, 0xdf, 0x3b, 0x91, 0x97, 0x60, 0x02, 0x01, 0x01, 0x04, 0x82, 0x01, @@ -214,7 +254,6 @@ TEST(ECPrivateKeyUnitTest, LoadOpenSSLKeyTest) { 0xc2, 0xc1, 0x55, 0x22, 0x42, 0x2f, 0x13, 0x7d, 0x93, 0x27, 0xc8, 0x11, 0x35, 0xc5, 0xe3, 0xc5, 0xaa, 0x15, 0x3c, 0xac, 0x30, 0xbc, 0x45, 0x16, 0xed}; - unsigned int openssl_key_len = 421; static const unsigned char openssl_pub_key[] = { 0x30, 0x82, 0x01, 0x4b, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x30, 0x81, 0xf7, 0x02, 0x01, 0x01, 0x30, @@ -244,14 +283,13 @@ TEST(ECPrivateKeyUnitTest, LoadOpenSSLKeyTest) { 0x88, 0x38, 0xc0, 0xdb, 0xba, 0xf6, 0x99, 0xd8, 0xa5, 0x3b, 0x83, 0xe9, 0xe3, 0xd5, 0x61, 0x99, 0x73, 0x42, 0xc6, 0x6c, 0xe8, 0x0a, 0x95, 0x40, 0x41, 0x3b, 0x0d, 0x10, 0xa7, 0x4a, 0x93, 0xdb, 0x5a, 0xe7, 0xec}; - unsigned int openssl_pub_key_len = 335; scoped_ptr<crypto::ECPrivateKey> keypair_openssl( crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( "", - std::vector<uint8>(openssl_key, openssl_key + openssl_key_len), + std::vector<uint8>(openssl_key, openssl_key + arraysize(openssl_key)), std::vector<uint8>(openssl_pub_key, - openssl_pub_key + openssl_pub_key_len))); + openssl_pub_key + arraysize(openssl_pub_key)))); EXPECT_TRUE(keypair_openssl.get()); } |