diff options
author | bulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-29 15:08:48 +0000 |
---|---|---|
committer | bulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-29 15:08:48 +0000 |
commit | 06256e5dee1d1aa8e5feebe3399634408914a66e (patch) | |
tree | 4f3398c7dd1a2020515579fcec6672e5a42d0b5e /net | |
parent | 5123b36099d7dfff857b2d170e8593f60b77df12 (diff) | |
download | chromium_src-06256e5dee1d1aa8e5feebe3399634408914a66e.zip chromium_src-06256e5dee1d1aa8e5feebe3399634408914a66e.tar.gz chromium_src-06256e5dee1d1aa8e5feebe3399634408914a66e.tar.bz2 |
Decouples TransportSecurityState from NSS.
Adds support for TransportSecurityState to run on top of OpenSSL.
BUG=
TEST=TransportSecurityStateTest.*
Review URL: http://codereview.chromium.org/8050021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@103276 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/transport_security_state.cc | 123 | ||||
-rw-r--r-- | net/base/transport_security_state_unittest.cc | 18 |
2 files changed, 109 insertions, 32 deletions
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc index 31454fd..a0e187b 100644 --- a/net/base/transport_security_state.cc +++ b/net/base/transport_security_state.cc @@ -4,12 +4,17 @@ #include "net/base/transport_security_state.h" +#if defined(USE_OPENSSL) +#include <openssl/ssl.h> +#include <openssl/ecdsa.h> +#else // !defined(USE_OPENSSL) #include <nspr.h> #include <cryptohi.h> #include <hasht.h> #include <keyhi.h> #include <pk11pub.h> +#endif #include "base/base64.h" #include "base/json/json_reader.h" @@ -26,6 +31,10 @@ #include "googleurl/src/gurl.h" #include "net/base/dns_util.h" +#if defined(USE_OPENSSL) +#include "crypto/openssl_util.h" +#endif + namespace net { const long int TransportSecurityState::kMaxHSTSAgeSecs = 86400 * 365; // 1 year @@ -394,6 +403,55 @@ static const uint8 kP256SubjectPublicKeyInfoPrefix[] = { 0x42, 0x00, }; +// VerifySignature returns true iff |sig| is a valid signature of +// |hash| by |pubkey|. The actual implementation is crypto library +// specific. +static bool VerifySignature(const base::StringPiece& pubkey, + const base::StringPiece& sig, + const base::StringPiece& hash); + +#if defined(USE_OPENSSL) + +static EVP_PKEY* DecodeX962P256PublicKey( + const base::StringPiece& pubkey_bytes) { + // The public key is an X9.62 encoded P256 point. + if (pubkey_bytes.size() != 1 + 2*32) + return NULL; + + std::string pubkey_spki( + reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix), + sizeof(kP256SubjectPublicKeyInfoPrefix)); + pubkey_spki += pubkey_bytes.as_string(); + + EVP_PKEY* ret = NULL; + const unsigned char* der_pubkey = + reinterpret_cast<const unsigned char*>(pubkey_spki.data()); + d2i_PUBKEY(&ret, &der_pubkey, pubkey_spki.size()); + return ret; +} + +static bool VerifySignature(const base::StringPiece& pubkey, + const base::StringPiece& sig, + const base::StringPiece& hash) { + crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> secpubkey( + DecodeX962P256PublicKey(pubkey)); + if (!secpubkey.get()) + return false; + + + crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key( + EVP_PKEY_get1_EC_KEY(secpubkey.get())); + if (!ec_key.get()) + return false; + + return ECDSA_verify(0, reinterpret_cast<const unsigned char*>(hash.data()), + hash.size(), + reinterpret_cast<const unsigned char*>(sig.data()), + sig.size(), ec_key.get()) == 1; +} + +#else + // DecodeX962P256PublicKey parses an uncompressed, X9.62 format, P256 elliptic // curve point from |pubkey_bytes| and returns it as a SECKEYPublicKey. static SECKEYPublicKey* DecodeX962P256PublicKey( @@ -421,6 +479,41 @@ static SECKEYPublicKey* DecodeX962P256PublicKey( return public_key; } +static bool VerifySignature(const base::StringPiece& pubkey, + const base::StringPiece& sig, + const base::StringPiece& hash) { + SECKEYPublicKey* secpubkey = DecodeX962P256PublicKey(pubkey); + if (!secpubkey) + return false; + + SECItem sigitem; + memset(&sigitem, 0, sizeof(sigitem)); + sigitem.data = reinterpret_cast<uint8*>(const_cast<char*>(sig.data())); + sigitem.len = sig.size(); + + // |decoded_sigitem| is newly allocated, as is the data that it points to. + SECItem* decoded_sigitem = DSAU_DecodeDerSigToLen( + &sigitem, SECKEY_SignatureLen(secpubkey)); + + if (!decoded_sigitem) { + SECKEY_DestroyPublicKey(secpubkey); + return false; + } + + SECItem hashitem; + memset(&hashitem, 0, sizeof(hashitem)); + hashitem.data = reinterpret_cast<unsigned char*>( + const_cast<char*>(hash.data())); + hashitem.len = hash.size(); + + SECStatus rv = PK11_Verify(secpubkey, decoded_sigitem, &hashitem, NULL); + SECKEY_DestroyPublicKey(secpubkey); + SECITEM_FreeItem(decoded_sigitem, PR_TRUE); + return rv == SECSuccess; +} + +#endif // !defined(USE_OPENSSL) + // These are the tag values that we use. Tags are little-endian on the wire and // these values correspond to the ASCII of the name. static const uint32 kTagALGO = 0x4f474c41; @@ -474,34 +567,10 @@ bool TransportSecurityState::ParseSidePin( leaf_spki.as_string(), leaf_spki_hash, sizeof(leaf_spki_hash)); have_leaf_spki_hash = true; } - SECItem hashitem; - memset(&hashitem, 0, sizeof(hashitem)); - hashitem.data = leaf_spki_hash; - hashitem.len = sizeof(leaf_spki_hash); - - SECKEYPublicKey* secpubkey = DecodeX962P256PublicKey(pubkey); - if (!secpubkey) - continue; - - SECItem sigitem; - memset(&sigitem, 0, sizeof(sigitem)); - sigitem.data = reinterpret_cast<uint8*>(const_cast<char*>(sig.data())); - sigitem.len = sig.size(); - - // |decoded_sigitem| is newly allocated, as is the data that it points to. - SECItem* decoded_sigitem = DSAU_DecodeDerSigToLen( - &sigitem, SECKEY_SignatureLen(secpubkey)); - - if (!decoded_sigitem) { - SECKEY_DestroyPublicKey(secpubkey); - continue; - } - - SECStatus rv = PK11_Verify(secpubkey, decoded_sigitem, &hashitem, NULL); - SECKEY_DestroyPublicKey(secpubkey); - SECITEM_FreeItem(decoded_sigitem, PR_TRUE); - if (rv == SECSuccess) { + if (VerifySignature(pubkey, sig, base::StringPiece( + reinterpret_cast<const char*>(leaf_spki_hash), + sizeof(leaf_spki_hash)))) { SHA1Fingerprint fpr; base::SHA1HashBytes( reinterpret_cast<const uint8*>(pubkey.data()), diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc index 11c6edf..3169025 100644 --- a/net/base/transport_security_state_unittest.cc +++ b/net/base/transport_security_state_unittest.cc @@ -3,13 +3,25 @@ // found in the LICENSE file. #include "base/string_piece.h" -#include "crypto/nss_util.h" #include "net/base/transport_security_state.h" #include "testing/gtest/include/gtest/gtest.h" +#if defined(USE_OPENSSL) +#include "crypto/openssl_util.h" +#else +#include "crypto/nss_util.h" +#endif + namespace net { class TransportSecurityStateTest : public testing::Test { + virtual void SetUp() { +#if defined(USE_NSS) + crypto::EnsureNSSInit(); +#elif defined(USE_OPENSSL) + crypto::EnsureOpenSSLInit(); +#endif + } }; TEST_F(TransportSecurityStateTest, BogusHeaders) { @@ -909,7 +921,6 @@ static const uint8 kSidePinExpectedHash[20] = { }; TEST_F(TransportSecurityStateTest, ParseSidePins) { - crypto::EnsureNSSInit(); base::StringPiece leaf_spki(reinterpret_cast<const char*>(kSidePinLeafSPKI), sizeof(kSidePinLeafSPKI)); @@ -925,7 +936,6 @@ TEST_F(TransportSecurityStateTest, ParseSidePins) { } TEST_F(TransportSecurityStateTest, ParseSidePinsFailsWithBadData) { - crypto::EnsureNSSInit(); uint8 leaf_spki_copy[sizeof(kSidePinLeafSPKI)]; memcpy(leaf_spki_copy, kSidePinLeafSPKI, sizeof(leaf_spki_copy)); @@ -957,8 +967,6 @@ TEST_F(TransportSecurityStateTest, DISABLED_ParseSidePinsFuzz) { // Disabled because it's too slow for normal tests. Run manually when // changing the underlying code. - crypto::EnsureNSSInit(); - base::StringPiece leaf_spki(reinterpret_cast<const char*>(kSidePinLeafSPKI), sizeof(kSidePinLeafSPKI)); uint8 side_info_copy[sizeof(kSidePinInfo)]; |