diff options
36 files changed, 577 insertions, 259 deletions
diff --git a/chrome/browser/net/transport_security_persister.cc b/chrome/browser/net/transport_security_persister.cc index 76bc514..c6a27d2 100644 --- a/chrome/browser/net/transport_security_persister.cc +++ b/chrome/browser/net/transport_security_persister.cc @@ -20,32 +20,46 @@ #include "net/base/x509_certificate.h" using content::BrowserThread; -using net::Fingerprint; -using net::FingerprintVector; +using net::HashValue; +using net::HashValueTag; +using net::HashValueVector; using net::TransportSecurityState; namespace { -ListValue* SPKIHashesToListValue(const FingerprintVector& hashes) { +ListValue* SPKIHashesToListValue(const HashValueVector& hashes) { ListValue* pins = new ListValue; - for (FingerprintVector::const_iterator i = hashes.begin(); + for (HashValueVector::const_iterator i = hashes.begin(); i != hashes.end(); ++i) { - std::string hash_str(reinterpret_cast<const char*>(i->data), - sizeof(i->data)); + std::string label; + switch (i->tag) { + case net::HASH_VALUE_SHA1: + label = "sha1/"; + break; + case net::HASH_VALUE_SHA256: + label = "sha256/"; + break; + default: + LOG(WARNING) << "Skipping invalid fingerprint with unknown type " + << i->tag; + continue; + } + + std::string hash_str(reinterpret_cast<const char*>(i->data()), i->size()); std::string b64; base::Base64Encode(hash_str, &b64); - pins->Append(new StringValue("sha1/" + b64)); + pins->Append(new StringValue(label + b64)); } return pins; } -void SPKIHashesFromListValue(const ListValue& pins, FingerprintVector* hashes) { +void SPKIHashesFromListValue(const ListValue& pins, HashValueVector* hashes) { size_t num_pins = pins.GetSize(); for (size_t i = 0; i < num_pins; ++i) { std::string type_and_base64; - Fingerprint fingerprint; + HashValue fingerprint; if (pins.GetString(i, &type_and_base64) && TransportSecurityState::ParsePin(type_and_base64, &fingerprint)) { hashes->push_back(fingerprint); diff --git a/chrome/browser/net/transport_security_persister_unittest.cc b/chrome/browser/net/transport_security_persister_unittest.cc index 2607a09..fcde3f8 100644 --- a/chrome/browser/net/transport_security_persister_unittest.cc +++ b/chrome/browser/net/transport_security_persister_unittest.cc @@ -6,6 +6,7 @@ #include <map> #include <string> +#include <vector> #include "base/file_path.h" #include "base/file_util.h" @@ -96,10 +97,12 @@ TEST_F(TransportSecurityPersisterTest, SerializeData2) { TEST_F(TransportSecurityPersisterTest, SerializeData3) { // Add an entry. - net::SHA1Fingerprint fp1; - memset(fp1.data, 0, sizeof(fp1.data)); - net::SHA1Fingerprint fp2; - memset(fp2.data, 1, sizeof(fp2.data)); + net::HashValue fp1; + fp1.tag = net::HASH_VALUE_SHA1; + memset(fp1.data(), 0, fp1.size()); + net::HashValue fp2; + fp2.tag = net::HASH_VALUE_SHA1; + memset(fp2.data(), 1, fp2.size()); TransportSecurityState::DomainState example_state; example_state.upgrade_expiry = base::Time::Now() + base::TimeDelta::FromSeconds(1000); @@ -111,8 +114,8 @@ TEST_F(TransportSecurityPersisterTest, SerializeData3) { state_.EnableHost("www.example.com", example_state); // Add another entry. - memset(fp1.data, 2, sizeof(fp1.data)); - memset(fp2.data, 3, sizeof(fp2.data)); + memset(fp1.data(), 2, fp1.size()); + memset(fp2.data(), 3, fp2.size()); example_state.upgrade_expiry = base::Time::Now() + base::TimeDelta::FromSeconds(3000); example_state.upgrade_mode = @@ -181,17 +184,26 @@ TEST_F(TransportSecurityPersisterTest, PublicKeyHashes) { TransportSecurityState::DomainState domain_state; static const char kTestDomain[] = "example.com"; EXPECT_FALSE(state_.GetDomainState(kTestDomain, false, &domain_state)); - net::FingerprintVector hashes; - EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(hashes)); + std::vector<net::HashValueVector> hashes; + for (size_t i = 0; i < net::HASH_VALUE_TAGS_COUNT; ++i) { + net::HashValueVector v; + hashes.push_back(v); + } + EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes)); - net::SHA1Fingerprint hash; - memset(hash.data, '1', sizeof(hash.data)); - domain_state.static_spki_hashes.push_back(hash); + net::HashValue sha1; + sha1.tag = net::HASH_VALUE_SHA1; + memset(sha1.data(), '1', sha1.size()); + domain_state.static_spki_hashes.push_back(sha1); EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes)); - hashes.push_back(hash); + +DLOG(WARNING) << hashes[net::HASH_VALUE_SHA1].size(); + hashes[net::HASH_VALUE_SHA1].push_back(sha1); +DLOG(WARNING) << hashes[net::HASH_VALUE_SHA1].size(); EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(hashes)); - hashes[0].data[0] = '2'; + + hashes[net::HASH_VALUE_SHA1][0].data()[0] = '2'; EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes)); const base::Time current_time(base::Time::Now()); @@ -204,8 +216,9 @@ TEST_F(TransportSecurityPersisterTest, PublicKeyHashes) { EXPECT_TRUE(persister_->LoadEntries(ser, &dirty)); EXPECT_TRUE(state_.GetDomainState(kTestDomain, false, &domain_state)); EXPECT_EQ(1u, domain_state.static_spki_hashes.size()); - EXPECT_EQ(0, memcmp(domain_state.static_spki_hashes[0].data, hash.data, - sizeof(hash.data))); + EXPECT_EQ(sha1.tag, domain_state.static_spki_hashes[0].tag); + EXPECT_EQ(0, memcmp(domain_state.static_spki_hashes[0].data(), sha1.data(), + sha1.size())); } TEST_F(TransportSecurityPersisterTest, ForcePreloads) { diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc index 397d9e9..a413e5f 100644 --- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc +++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc @@ -1084,18 +1084,32 @@ void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests( connection_tester_->RunAllTests(url); } -void SPKIHashesToString(const net::FingerprintVector& hashes, +void SPKIHashesToString(const net::HashValueVector& hashes, std::string* string) { - for (net::FingerprintVector::const_iterator + for (net::HashValueVector::const_iterator i = hashes.begin(); i != hashes.end(); ++i) { - base::StringPiece hash_str(reinterpret_cast<const char*>(i->data), - arraysize(i->data)); + std::string label; + switch (i->tag) { + case net::HASH_VALUE_SHA1: + label = "sha1/"; + break; + case net::HASH_VALUE_SHA256: + label = "sha256/"; + break; + default: + NOTREACHED(); + LOG(WARNING) << "Invalid fingerprint of unknown type " << i->tag; + label = "unknown/"; + } + + base::StringPiece hash_str(reinterpret_cast<const char*>(i->data()), + i->size()); std::string encoded; base::Base64Encode(hash_str, &encoded); if (i != hashes.begin()) *string += ","; - *string += "sha1/" + encoded; + *string += label + encoded; } } @@ -1171,7 +1185,7 @@ void NetInternalsMessageHandler::IOThreadImpl::OnHSTSAdd( i = type_and_b64s.begin(); i != type_and_b64s.end(); ++i) { std::string type_and_b64; RemoveChars(*i, " \t\r\n", &type_and_b64); - net::SHA1Fingerprint hash; + net::HashValue hash; if (!net::TransportSecurityState::ParsePin(type_and_b64, &hash)) continue; diff --git a/net/base/cert_test_util.cc b/net/base/cert_test_util.cc index cdfd6b0..7815872 100644 --- a/net/base/cert_test_util.cc +++ b/net/base/cert_test_util.cc @@ -53,7 +53,7 @@ scoped_refptr<X509Certificate> ImportCertFromFile( } ScopedTestEVPolicy::ScopedTestEVPolicy(EVRootCAMetadata* ev_root_ca_metadata, - const SHA1Fingerprint& fingerprint, + const SHA1HashValue& fingerprint, const char* policy) : fingerprint_(fingerprint), ev_root_ca_metadata_(ev_root_ca_metadata) { diff --git a/net/base/cert_test_util.h b/net/base/cert_test_util.h index ee370e7..eb9e7eb 100644 --- a/net/base/cert_test_util.h +++ b/net/base/cert_test_util.h @@ -40,12 +40,12 @@ scoped_refptr<X509Certificate> ImportCertFromFile(const FilePath& certs_dir, class ScopedTestEVPolicy { public: ScopedTestEVPolicy(EVRootCAMetadata* ev_root_ca_metadata, - const SHA1Fingerprint& fingerprint, + const SHA1HashValue& fingerprint, const char* policy); ~ScopedTestEVPolicy(); private: - SHA1Fingerprint fingerprint_; + SHA1HashValue fingerprint_; EVRootCAMetadata* const ev_root_ca_metadata_; }; diff --git a/net/base/cert_verify_proc.cc b/net/base/cert_verify_proc.cc index 420a8a5..31b13bf 100644 --- a/net/base/cert_verify_proc.cc +++ b/net/base/cert_verify_proc.cc @@ -217,8 +217,9 @@ bool CertVerifyProc::IsBlacklisted(X509Certificate* cert) { } // static +// NOTE: This implementation assumes and enforces that the hashes are SHA1. bool CertVerifyProc::IsPublicKeyBlacklisted( - const std::vector<SHA1Fingerprint>& public_key_hashes) { + const std::vector<HashValueVector>& public_key_hashes) { static const unsigned kNumHashes = 9; static const uint8 kHashes[kNumHashes][base::kSHA1Length] = { // Subject: CN=DigiNotar Root CA @@ -263,11 +264,14 @@ bool CertVerifyProc::IsPublicKeyBlacklisted( 0xd1, 0x72, 0xbd, 0x53, 0xe0, 0xd3, 0x07, 0x83, 0x4b, 0xd1}, }; + const HashValueVector& sha1_hashes = public_key_hashes[HASH_VALUE_SHA1]; for (unsigned i = 0; i < kNumHashes; i++) { - for (std::vector<SHA1Fingerprint>::const_iterator - j = public_key_hashes.begin(); j != public_key_hashes.end(); ++j) { - if (memcmp(j->data, kHashes[i], base::kSHA1Length) == 0) + for (HashValueVector::const_iterator j = sha1_hashes.begin(); + j != sha1_hashes.end(); ++j) { + if (j->tag == HASH_VALUE_SHA1 && + memcmp(j->data(), kHashes[i], base::kSHA1Length) == 0) { return true; + } } } diff --git a/net/base/cert_verify_proc.h b/net/base/cert_verify_proc.h index a4801cfd..790847f 100644 --- a/net/base/cert_verify_proc.h +++ b/net/base/cert_verify_proc.h @@ -75,9 +75,9 @@ class NET_EXPORT CertVerifyProc static bool IsBlacklisted(X509Certificate* cert); // IsPublicKeyBlacklisted returns true iff one of |public_key_hashes| (which - // are SHA1 hashes of SubjectPublicKeyInfo structures) is explicitly blocked. + // are hashes of SubjectPublicKeyInfo structures) is explicitly blocked. static bool IsPublicKeyBlacklisted( - const std::vector<SHA1Fingerprint>& public_key_hashes); + const std::vector<HashValueVector>& public_key_hashes); }; } // namespace net diff --git a/net/base/cert_verify_proc_mac.cc b/net/base/cert_verify_proc_mac.cc index 49798b5..f38c5b1 100644 --- a/net/base/cert_verify_proc_mac.cc +++ b/net/base/cert_verify_proc_mac.cc @@ -8,6 +8,9 @@ #include <CoreServices/CoreServices.h> #include <Security/Security.h> +#include <string> +#include <vector> + #include "base/logging.h" #include "base/mac/mac_logging.h" #include "base/mac/scoped_cftyperef.h" @@ -231,7 +234,7 @@ void GetCertChainInfo(CFArrayRef cert_chain, } void AppendPublicKeyHashes(CFArrayRef chain, - std::vector<SHA1Fingerprint>* hashes) { + std::vector<HashValueVector>* hashes) { const CFIndex n = CFArrayGetCount(chain); for (CFIndex i = 0; i < n; i++) { SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( @@ -246,9 +249,15 @@ void AppendPublicKeyHashes(CFArrayRef chain, if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) continue; - SHA1Fingerprint hash; - CC_SHA1(spki_bytes.data(), spki_bytes.size(), hash.data); - hashes->push_back(hash); + HashValue sha1; + sha1.tag = HASH_VALUE_SHA1; + CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data()); + (*hashes)[HASH_VALUE_SHA1].push_back(sha1); + + HashValue sha256; + sha256.tag = HASH_VALUE_SHA256; + CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data()); + (*hashes)[HASH_VALUE_SHA256].push_back(sha256); } } @@ -325,7 +334,7 @@ bool IsIssuedByKnownRoot(CFArrayRef chain) { return false; SecCertificateRef root_ref = reinterpret_cast<SecCertificateRef>( const_cast<void*>(CFArrayGetValueAtIndex(chain, n - 1))); - SHA1Fingerprint hash = X509Certificate::CalculateFingerprint(root_ref); + SHA1HashValue hash = X509Certificate::CalculateFingerprint(root_ref); return IsSHA1HashInSortedArray( hash, &kKnownRootCertSHA1Hashes[0][0], sizeof(kKnownRootCertSHA1Hashes)); } diff --git a/net/base/cert_verify_proc_nss.cc b/net/base/cert_verify_proc_nss.cc index 3108555..db9b34a 100644 --- a/net/base/cert_verify_proc_nss.cc +++ b/net/base/cert_verify_proc_nss.cc @@ -4,6 +4,9 @@ #include "net/base/cert_verify_proc_nss.h" +#include <string> +#include <vector> + #include <cert.h> #include <nss.h> #include <prerror.h> @@ -597,9 +600,19 @@ bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle, return false; } -SHA1Fingerprint CertPublicKeyHash(CERTCertificate* cert) { - SHA1Fingerprint hash; - SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data, +HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) { + HashValue hash; + hash.tag = HASH_VALUE_SHA1; + SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(), + cert->derPublicKey.data, cert->derPublicKey.len); + DCHECK_EQ(rv, SECSuccess); + return hash; +} + +HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) { + HashValue hash; + hash.tag = HASH_VALUE_SHA256; + SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(), cert->derPublicKey.data, cert->derPublicKey.len); DCHECK_EQ(rv, SECSuccess); return hash; @@ -607,14 +620,18 @@ SHA1Fingerprint CertPublicKeyHash(CERTCertificate* cert) { void AppendPublicKeyHashes(CERTCertList* cert_list, CERTCertificate* root_cert, - std::vector<SHA1Fingerprint>* hashes) { + std::vector<HashValueVector>* hashes) { + // TODO(palmer): Generalize this to handle any and all HashValueTags. for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list); node = CERT_LIST_NEXT(node)) { - hashes->push_back(CertPublicKeyHash(node->cert)); + (*hashes)[HASH_VALUE_SHA1].push_back(CertPublicKeyHashSHA1(node->cert)); + (*hashes)[HASH_VALUE_SHA256].push_back(CertPublicKeyHashSHA256(node->cert)); + } + if (root_cert) { + (*hashes)[HASH_VALUE_SHA1].push_back(CertPublicKeyHashSHA1(root_cert)); + (*hashes)[HASH_VALUE_SHA256].push_back(CertPublicKeyHashSHA256(root_cert)); } - if (root_cert) - hashes->push_back(CertPublicKeyHash(root_cert)); } // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp @@ -667,7 +684,7 @@ bool VerifyEV(CERTCertificate* cert_handle, int flags, CRLSet* crl_set) { return false; } - SHA1Fingerprint fingerprint = + SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(root_ca); std::vector<SECOidTag> ev_policy_tags; if (!metadata->GetPolicyOIDsForCA(fingerprint, &ev_policy_tags)) diff --git a/net/base/cert_verify_proc_openssl.cc b/net/base/cert_verify_proc_openssl.cc index 9b467c5..0c02249 100644 --- a/net/base/cert_verify_proc_openssl.cc +++ b/net/base/cert_verify_proc_openssl.cc @@ -6,9 +6,13 @@ #include <openssl/x509v3.h> +#include <string> +#include <vector> + #include "base/logging.h" #include "base/sha1.h" #include "crypto/openssl_util.h" +#include "crypto/sha2.h" #include "net/base/asn1_util.h" #include "net/base/cert_status_flags.h" #include "net/base/cert_verify_result.h" @@ -131,7 +135,7 @@ void GetCertChainInfo(X509_STORE_CTX* store_ctx, } void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx, - std::vector<SHA1Fingerprint>* hashes) { + std::vector<HashValueVector>* hashes) { STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); for (int i = 0; i < sk_X509_num(chain); ++i) { X509* cert = sk_X509_value(chain, i); @@ -145,10 +149,16 @@ void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx, if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) continue; - SHA1Fingerprint hash; + HashValue sha1; + sha1.tag = HASH_VALUE_SHA1; base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), - spki_bytes.size(), hash.data); - hashes->push_back(hash); + spki_bytes.size(), sha1.data()); + (*hashes)[HASH_VALUE_SHA1].push_back(sha1); + + HashValue sha256; + sha256.tag = HASH_VALUE_SHA256; + crypto::SHA256HashString(spki_bytes, sha1.data(), crypto::kSHA256Length); + (*hashes)[HASH_VALUE_SHA256].push_back(sha256); } } diff --git a/net/base/cert_verify_proc_unittest.cc b/net/base/cert_verify_proc_unittest.cc index 6898a5b..317aacc5 100644 --- a/net/base/cert_verify_proc_unittest.cc +++ b/net/base/cert_verify_proc_unittest.cc @@ -120,7 +120,7 @@ TEST_F(CertVerifyProcTest, PaypalNullCertParsing) { ASSERT_NE(static_cast<X509Certificate*>(NULL), paypal_null_cert); - const SHA1Fingerprint& fingerprint = + const SHA1HashValue& fingerprint = paypal_null_cert->fingerprint(); for (size_t i = 0; i < 20; ++i) EXPECT_EQ(paypal_null_fingerprint[i], fingerprint.data[i]); @@ -397,11 +397,13 @@ TEST_F(CertVerifyProcTest, DigiNotarCerts) { std::string spki_sha1 = base::SHA1HashString(spki.as_string()); - std::vector<SHA1Fingerprint> public_keys; - SHA1Fingerprint fingerprint; - ASSERT_EQ(sizeof(fingerprint.data), spki_sha1.size()); - memcpy(fingerprint.data, spki_sha1.data(), spki_sha1.size()); - public_keys.push_back(fingerprint); + std::vector<HashValueVector> public_keys(HASH_VALUE_TAGS_COUNT); + public_keys[HASH_VALUE_SHA1] = HashValueVector(); + HashValue fingerprint; + fingerprint.tag = HASH_VALUE_SHA1; + ASSERT_EQ(fingerprint.size(), spki_sha1.size()); + memcpy(fingerprint.data(), spki_sha1.data(), spki_sha1.size()); + public_keys[HASH_VALUE_SHA1].push_back(fingerprint); EXPECT_TRUE(CertVerifyProc::IsPublicKeyBlacklisted(public_keys)) << "Public key not blocked for " << kDigiNotarFilenames[i]; @@ -453,10 +455,14 @@ TEST_F(CertVerifyProcTest, PublicKeyHashes) { int error = Verify(cert_chain, "cert.se", flags, NULL, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); - ASSERT_LE(3u, verify_result.public_key_hashes.size()); - for (unsigned i = 0; i < 3; i++) { + ASSERT_LE(static_cast<size_t>(HASH_VALUE_TAGS_COUNT), + verify_result.public_key_hashes.size()); + const HashValueVector& sha1_hashes = + verify_result.public_key_hashes[HASH_VALUE_SHA1]; + ASSERT_LE(3u, sha1_hashes.size()); + for (unsigned i = 0; i < 3; ++i) { EXPECT_EQ(HexEncode(kCertSESPKIs[i], base::kSHA1Length), - HexEncode(verify_result.public_key_hashes[i].data, base::kSHA1Length)); + HexEncode(sha1_hashes[i].data(), base::kSHA1Length)); } } diff --git a/net/base/cert_verify_proc_win.cc b/net/base/cert_verify_proc_win.cc index 045ea16..cedba2c 100644 --- a/net/base/cert_verify_proc_win.cc +++ b/net/base/cert_verify_proc_win.cc @@ -4,6 +4,9 @@ #include "net/base/cert_verify_proc_win.h" +#include <string> +#include <vector> + #include "base/memory/scoped_ptr.h" #include "base/sha1.h" #include "base/string_util.h" @@ -282,7 +285,7 @@ bool IsIssuedByKnownRoot(PCCERT_CHAIN_CONTEXT chain_context) { PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement; PCCERT_CONTEXT cert = element[num_elements - 1]->pCertContext; - SHA1Fingerprint hash = X509Certificate::CalculateFingerprint(cert); + SHA1HashValue hash = X509Certificate::CalculateFingerprint(cert); return IsSHA1HashInSortedArray( hash, &kKnownRootCertSHA1Hashes[0][0], sizeof(kKnownRootCertSHA1Hashes)); } @@ -441,7 +444,7 @@ bool CheckRevocationWithCRLSet(PCCERT_CHAIN_CONTEXT chain, } void AppendPublicKeyHashes(PCCERT_CHAIN_CONTEXT chain, - std::vector<SHA1Fingerprint>* hashes) { + std::vector<HashValueVector>* hashes) { if (chain->cChain == 0) return; @@ -459,10 +462,16 @@ void AppendPublicKeyHashes(PCCERT_CHAIN_CONTEXT chain, if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) continue; - SHA1Fingerprint hash; + HashValue sha1; + sha1.tag = HASH_VALUE_SHA1; base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), - spki_bytes.size(), hash.data); - hashes->push_back(hash); + spki_bytes.size(), sha1.data()); + (*hashes)[HASH_VALUE_SHA1].push_back(sha1); + + HashValue sha256; + sha256.tag = HASH_VALUE_SHA256; + crypto::SHA256HashString(spki_bytes, sha1.data(), crypto::kSHA256Length); + (*hashes)[HASH_VALUE_SHA256].push_back(sha256); } } @@ -503,7 +512,7 @@ bool CheckEV(PCCERT_CHAIN_CONTEXT chain_context, // Look up the EV policy OID of the root CA. PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext; - SHA1Fingerprint fingerprint = + SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(root_cert); EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); return metadata->HasEVPolicyOID(fingerprint, policy_oid); diff --git a/net/base/cert_verify_result.cc b/net/base/cert_verify_result.cc index d51566b..86735d4 100644 --- a/net/base/cert_verify_result.cc +++ b/net/base/cert_verify_result.cc @@ -24,7 +24,13 @@ void CertVerifyResult::Reset() { has_md5_ca = false; has_md2_ca = false; is_issued_by_known_root = false; + public_key_hashes.clear(); + public_key_hashes.reserve(HASH_VALUE_TAGS_COUNT); + HashValueVector sha1s; + public_key_hashes.push_back(sha1s); + HashValueVector sha256s; + public_key_hashes.push_back(sha256s); } -} // namespace net +} // namespace net diff --git a/net/base/cert_verify_result.h b/net/base/cert_verify_result.h index 06baad2..0d33ed9 100644 --- a/net/base/cert_verify_result.h +++ b/net/base/cert_verify_result.h @@ -45,10 +45,15 @@ class NET_EXPORT CertVerifyResult { bool has_md5_ca; bool has_md2_ca; - // If the certificate was successfully verified then this contains the SHA1 - // fingerprints of the SubjectPublicKeyInfos of the chain. The fingerprint - // from the leaf certificate will be the first element of the vector. - std::vector<SHA1Fingerprint> public_key_hashes; + // If the certificate was successfully verified then this contains the + // fingerprints, in several hash algorithms, of the SubjectPublicKeyInfos + // of the chain. The fingerprint from the leaf certificate will be the + // first element of each sub-vector. + // + // This is a vector of vectors: Index the outer vector with + // FingerprintTag, and then the inner HashValueVectors will be + // fingerprints made with the algorithm named by the FingerprintTag. + std::vector<HashValueVector> public_key_hashes; // is_issued_by_known_root is true if we recognise the root CA as a standard // root. If it isn't then it's probably the case that this certificate was diff --git a/net/base/ev_root_ca_metadata.cc b/net/base/ev_root_ca_metadata.cc index 301732f..2ccce80 100644 --- a/net/base/ev_root_ca_metadata.cc +++ b/net/base/ev_root_ca_metadata.cc @@ -33,7 +33,7 @@ struct EVMetadata { // The SHA-1 fingerprint of the root CA certificate, used as a unique // identifier for a root CA certificate. - SHA1Fingerprint fingerprint; + SHA1HashValue fingerprint; // The EV policy OIDs of the root CA. const char policy_oids[kMaxOIDsPerCA][kMaxOIDLength]; @@ -73,7 +73,7 @@ static const EVMetadata ev_root_ca_metadata[] = { // https://premiumecc.affirmtrust.com:4433/ { { { 0xb8, 0x23, 0x6b, 0x00, 0x2f, 0x1d, 0x16, 0x86, 0x53, 0x01, 0x55, 0x6c, 0x11, 0xa4, 0x37, 0xca, 0xeb, 0xff, 0xc3, 0xbb } }, - {"1.3.6.1.4.1.34697.2.4", ""}, + {"1.3.6.1.4.1.34697.2.4", ""}, }, // CertPlus Class 2 Primary CA (KEYNECTIS) // https://www.keynectis.com/ @@ -322,7 +322,7 @@ EVRootCAMetadata* EVRootCAMetadata::GetInstance() { #if defined(USE_NSS) bool EVRootCAMetadata::GetPolicyOIDsForCA( - const SHA1Fingerprint& fingerprint, + const SHA1HashValue& fingerprint, std::vector<PolicyOID>* policy_oids) const { PolicyOIDMap::const_iterator iter = ev_policy_.find(fingerprint); if (iter == ev_policy_.end()) @@ -342,7 +342,7 @@ int EVRootCAMetadata::NumPolicyOIDs() const { return policy_oids_.size(); } -bool EVRootCAMetadata::AddEVCA(const SHA1Fingerprint& fingerprint, +bool EVRootCAMetadata::AddEVCA(const SHA1HashValue& fingerprint, const char* policy) { if (ev_policy_.find(fingerprint) != ev_policy_.end()) return false; @@ -357,7 +357,7 @@ bool EVRootCAMetadata::AddEVCA(const SHA1Fingerprint& fingerprint, return true; } -bool EVRootCAMetadata::RemoveEVCA(const SHA1Fingerprint& fingerprint) { +bool EVRootCAMetadata::RemoveEVCA(const SHA1HashValue& fingerprint) { PolicyOIDMap::iterator it = ev_policy_.find(fingerprint); if (it == ev_policy_.end()) return false; @@ -416,7 +416,7 @@ bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const { return false; } -bool EVRootCAMetadata::HasEVPolicyOID(const SHA1Fingerprint& fingerprint, +bool EVRootCAMetadata::HasEVPolicyOID(const SHA1HashValue& fingerprint, PolicyOID policy_oid) const { for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) { if (!fingerprint.Equals(ev_root_ca_metadata[i].fingerprint)) @@ -434,7 +434,7 @@ bool EVRootCAMetadata::HasEVPolicyOID(const SHA1Fingerprint& fingerprint, return it != extra_cas_.end() && it->second == policy_oid; } -bool EVRootCAMetadata::AddEVCA(const SHA1Fingerprint& fingerprint, +bool EVRootCAMetadata::AddEVCA(const SHA1HashValue& fingerprint, const char* policy) { for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) { if (fingerprint.Equals(ev_root_ca_metadata[i].fingerprint)) @@ -448,7 +448,7 @@ bool EVRootCAMetadata::AddEVCA(const SHA1Fingerprint& fingerprint, return true; } -bool EVRootCAMetadata::RemoveEVCA(const SHA1Fingerprint& fingerprint) { +bool EVRootCAMetadata::RemoveEVCA(const SHA1HashValue& fingerprint) { ExtraEVCAMap::iterator it = extra_cas_.find(fingerprint); if (it == extra_cas_.end()) return false; @@ -461,12 +461,12 @@ bool EVRootCAMetadata::RemoveEVCA(const SHA1Fingerprint& fingerprint) { // These are just stub functions for platforms where we don't use this EV // metadata. -bool EVRootCAMetadata::AddEVCA(const SHA1Fingerprint& fingerprint, +bool EVRootCAMetadata::AddEVCA(const SHA1HashValue& fingerprint, const char* policy) { return true; } -bool EVRootCAMetadata::RemoveEVCA(const SHA1Fingerprint& fingerprint) { +bool EVRootCAMetadata::RemoveEVCA(const SHA1HashValue& fingerprint) { return true; } diff --git a/net/base/ev_root_ca_metadata.h b/net/base/ev_root_ca_metadata.h index ab76c49..864e120 100644 --- a/net/base/ev_root_ca_metadata.h +++ b/net/base/ev_root_ca_metadata.h @@ -12,6 +12,7 @@ #endif #include <map> +#include <string> #include <vector> #include "net/base/net_export.h" @@ -39,7 +40,7 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata { #if defined(USE_NSS) // If the root CA cert has an EV policy OID, returns true and appends the // policy OIDs to |*policy_oids|. Otherwise, returns false. - bool GetPolicyOIDsForCA(const SHA1Fingerprint& fingerprint, + bool GetPolicyOIDsForCA(const SHA1HashValue& fingerprint, std::vector<PolicyOID>* policy_oids) const; const PolicyOID* GetPolicyOIDs() const; int NumPolicyOIDs() const; @@ -49,18 +50,18 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata { // Returns true if the root CA with the given certificate fingerprint has // the EV policy OID policy_oid. - bool HasEVPolicyOID(const SHA1Fingerprint& fingerprint, + bool HasEVPolicyOID(const SHA1HashValue& fingerprint, PolicyOID policy_oid) const; #endif // AddEVCA adds an EV CA to the list of known EV CAs with the given policy. // |policy| is expressed as a string of dotted numbers. It returns true on // success. - bool AddEVCA(const SHA1Fingerprint& fingerprint, const char* policy); + bool AddEVCA(const SHA1HashValue& fingerprint, const char* policy); // RemoveEVCA removes an EV CA that was previously added by AddEVCA. It // returns true on success. - bool RemoveEVCA(const SHA1Fingerprint& fingerprint); + bool RemoveEVCA(const SHA1HashValue& fingerprint); private: friend struct base::DefaultLazyInstanceTraits<EVRootCAMetadata>; @@ -69,8 +70,8 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata { ~EVRootCAMetadata(); #if defined(USE_NSS) - typedef std::map<SHA1Fingerprint, std::vector<PolicyOID>, - SHA1FingerprintLessThan> PolicyOIDMap; + typedef std::map<SHA1HashValue, std::vector<PolicyOID>, + SHA1HashValueLessThan> PolicyOIDMap; // RegisterOID registers |policy|, a policy OID in dotted string form, and // writes the memoized form to |*out|. It returns true on success. @@ -79,8 +80,8 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata { PolicyOIDMap ev_policy_; std::vector<PolicyOID> policy_oids_; #elif defined(OS_WIN) - typedef std::map<SHA1Fingerprint, std::string, - SHA1FingerprintLessThan> ExtraEVCAMap; + typedef std::map<SHA1HashValue, std::string, + SHA1HashValueLessThan> ExtraEVCAMap; // extra_cas_ contains any EV CA metadata that was added at runtime. ExtraEVCAMap extra_cas_; diff --git a/net/base/ev_root_ca_metadata_unittest.cc b/net/base/ev_root_ca_metadata_unittest.cc index 1a1ef35..6b022ea 100644 --- a/net/base/ev_root_ca_metadata_unittest.cc +++ b/net/base/ev_root_ca_metadata_unittest.cc @@ -13,10 +13,10 @@ namespace net { static const char kVerisignPolicy[] = "2.16.840.1.113733.1.7.23.6"; static const char kThawtePolicy[] = "2.16.840.1.113733.1.7.48.1"; static const char kFakePolicy[] = "2.16.840.1.42"; -static const SHA1Fingerprint kVerisignFingerprint = +static const SHA1HashValue kVerisignFingerprint = { { 0x74, 0x2c, 0x31, 0x92, 0xe6, 0x07, 0xe4, 0x24, 0xeb, 0x45, 0x49, 0x54, 0x2b, 0xe1, 0xbb, 0xc5, 0x3e, 0x61, 0x74, 0xe2 } }; -static const SHA1Fingerprint kFakeFingerprint = +static const SHA1HashValue kFakeFingerprint = { { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 } }; @@ -89,6 +89,6 @@ TEST(EVRootCAMetadataTest, AddRemove) { kFakePolicy)); } -#endif // defined(OS_WIN) +#endif // defined(OS_WIN) } // namespace net diff --git a/net/base/multi_threaded_cert_verifier.h b/net/base/multi_threaded_cert_verifier.h index 1ef04ab..5b1278c 100644 --- a/net/base/multi_threaded_cert_verifier.h +++ b/net/base/multi_threaded_cert_verifier.h @@ -66,8 +66,8 @@ class NET_EXPORT_PRIVATE MultiThreadedCertVerifier // Input parameters of a certificate verification request. struct RequestParams { - RequestParams(const SHA1Fingerprint& cert_fingerprint_arg, - const SHA1Fingerprint& ca_fingerprint_arg, + RequestParams(const SHA1HashValue& cert_fingerprint_arg, + const SHA1HashValue& ca_fingerprint_arg, const std::string& hostname_arg, int flags_arg) : cert_fingerprint(cert_fingerprint_arg), @@ -92,8 +92,8 @@ class NET_EXPORT_PRIVATE MultiThreadedCertVerifier return hostname < other.hostname; } - SHA1Fingerprint cert_fingerprint; - SHA1Fingerprint ca_fingerprint; + SHA1HashValue cert_fingerprint; + SHA1HashValue ca_fingerprint; std::string hostname; int flags; }; diff --git a/net/base/multi_threaded_cert_verifier_unittest.cc b/net/base/multi_threaded_cert_verifier_unittest.cc index 945cd7a..b25ea88 100644 --- a/net/base/multi_threaded_cert_verifier_unittest.cc +++ b/net/base/multi_threaded_cert_verifier_unittest.cc @@ -243,10 +243,10 @@ TEST_F(MultiThreadedCertVerifierTest, CancelRequestThenQuit) { } TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) { - SHA1Fingerprint a_key; + SHA1HashValue a_key; memset(a_key.data, 'a', sizeof(a_key.data)); - SHA1Fingerprint z_key; + SHA1HashValue z_key; memset(z_key.data, 'z', sizeof(z_key.data)); struct { diff --git a/net/base/ssl_info.cc b/net/base/ssl_info.cc index db4ac67..55ef1de 100644 --- a/net/base/ssl_info.cc +++ b/net/base/ssl_info.cc @@ -30,6 +30,7 @@ SSLInfo& SSLInfo::operator=(const SSLInfo& info) { channel_id_sent = info.channel_id_sent; handshake_type = info.handshake_type; public_key_hashes = info.public_key_hashes; + return *this; } @@ -42,7 +43,13 @@ void SSLInfo::Reset() { client_cert_sent = false; channel_id_sent = false; handshake_type = HANDSHAKE_UNKNOWN; + public_key_hashes.clear(); + public_key_hashes.reserve(HASH_VALUE_TAGS_COUNT); + HashValueVector sha1s; + public_key_hashes.push_back(sha1s); + HashValueVector sha256s; + public_key_hashes.push_back(sha256s); } void SSLInfo::SetCertError(int error) { diff --git a/net/base/ssl_info.h b/net/base/ssl_info.h index b3c37d2..e9c6ea5 100644 --- a/net/base/ssl_info.h +++ b/net/base/ssl_info.h @@ -71,8 +71,11 @@ class NET_EXPORT SSLInfo { HandshakeType handshake_type; - // The hashes of the SubjectPublicKeyInfos from each certificate in the chain. - std::vector<SHA1Fingerprint> public_key_hashes; + // The hashes of the SubjectPublicKeyInfos from each certificate in the + // chain. This is a vector of vectors: Index the outer vector with + // FingerprintTag, and then the inner HashValueVectors will be + // fingerprints made with the algorithm named by the FingerprintTag. + std::vector<HashValueVector> public_key_hashes; }; } // namespace net diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc index 747dc7e..61cdb40 100644 --- a/net/base/transport_security_state.cc +++ b/net/base/transport_security_state.cc @@ -33,6 +33,7 @@ #include "googleurl/src/gurl.h" #include "net/base/dns_util.h" #include "net/base/ssl_info.h" +#include "net/base/x509_cert_types.h" #include "net/base/x509_certificate.h" #include "net/http/http_util.h" @@ -218,69 +219,78 @@ static StringPair Split(const std::string& source, char delimiter) { return pair; } -// TODO(palmer): Support both sha256 and sha1. This will require additional -// infrastructure code changes and can come in a later patch. -// // static bool TransportSecurityState::ParsePin(const std::string& value, - SHA1Fingerprint* out) { + HashValue* out) { StringPair slash = Split(Strip(value), '/'); - if (slash.first != "sha1") + + if (slash.first == "sha1") + out->tag = HASH_VALUE_SHA1; + else if (slash.first == "sha256") + out->tag = HASH_VALUE_SHA256; + else return false; std::string decoded; if (!base::Base64Decode(slash.second, &decoded) || - decoded.size() != arraysize(out->data)) { + decoded.size() != out->size()) { return false; } - memcpy(out->data, decoded.data(), arraysize(out->data)); + memcpy(out->data(), decoded.data(), out->size()); return true; } static bool ParseAndAppendPin(const std::string& value, - FingerprintVector* fingerprints) { + HashValueVector* fingerprints) { // The base64'd fingerprint MUST be a quoted-string. 20 bytes base64'd is 28 - // characters; 32 bytes base64'd is 44 characters. TODO(palmer): Support - // SHA256. + // characters; 32 bytes base64'd is 44 characters. size_t size = value.size(); - if (size != 30 || value[0] != '"' || value[size - 1] != '"') + if ((size != 30 && size != 46) || value[0] != '"' || value[size - 1] != '"') return false; std::string unquoted = HttpUtil::Unquote(value); std::string decoded; - SHA1Fingerprint fp; + HashValue fp; - if (!base::Base64Decode(unquoted, &decoded) || - decoded.size() != arraysize(fp.data)) { + // This code has to assume that 32 bytes is SHA-256 and 20 bytes is SHA-1. + // Currently, those are the only two possibilities, so the assumption is + // valid. + if (!base::Base64Decode(unquoted, &decoded)) return false; - } - memcpy(fp.data, decoded.data(), arraysize(fp.data)); + if (decoded.size() == 20) + fp.tag = HASH_VALUE_SHA1; + else if (decoded.size() == 32) + fp.tag = HASH_VALUE_SHA256; + else + return false; + + memcpy(fp.data(), decoded.data(), fp.size()); fingerprints->push_back(fp); return true; } -struct FingerprintsEqualPredicate { - explicit FingerprintsEqualPredicate(const SHA1Fingerprint& fingerprint) : +struct HashValuesEqualPredicate { + explicit HashValuesEqualPredicate(const HashValue& fingerprint) : fingerprint_(fingerprint) {} - bool operator()(const SHA1Fingerprint& other) const { + bool operator()(const HashValue& other) const { return fingerprint_.Equals(other); } - const SHA1Fingerprint& fingerprint_; + const HashValue& fingerprint_; }; // Returns true iff there is an item in |pins| which is not present in // |from_cert_chain|. Such an SPKI hash is called a "backup pin". -static bool IsBackupPinPresent(const FingerprintVector& pins, - const FingerprintVector& from_cert_chain) { - for (FingerprintVector::const_iterator +static bool IsBackupPinPresent(const HashValueVector& pins, + const HashValueVector& from_cert_chain) { + for (HashValueVector::const_iterator i = pins.begin(); i != pins.end(); ++i) { - FingerprintVector::const_iterator j = + HashValueVector::const_iterator j = std::find_if(from_cert_chain.begin(), from_cert_chain.end(), - FingerprintsEqualPredicate(*i)); + HashValuesEqualPredicate(*i)); if (j == from_cert_chain.end()) return true; } @@ -288,12 +298,12 @@ static bool IsBackupPinPresent(const FingerprintVector& pins, return false; } -static bool HashesIntersect(const FingerprintVector& a, - const FingerprintVector& b) { - for (FingerprintVector::const_iterator +static bool HashesIntersect(const HashValueVector& a, + const HashValueVector& b) { + for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) { - FingerprintVector::const_iterator j = - std::find_if(b.begin(), b.end(), FingerprintsEqualPredicate(*i)); + HashValueVector::const_iterator j = + std::find_if(b.begin(), b.end(), HashValuesEqualPredicate(*i)); if (j != b.end()) return true; } @@ -306,17 +316,30 @@ static bool HashesIntersect(const FingerprintVector& a, // backup pin is a pin intended for disaster recovery, not day-to-day use, and // thus must be absent from the certificate chain. The Public-Key-Pins header // specification requires both. -static bool IsPinListValid(const FingerprintVector& pins, +static bool IsPinListValid(const HashValueVector& pins, const SSLInfo& ssl_info) { + // Fast fail: 1 live + 1 backup = at least 2 pins. (Check for actual + // liveness and backupness below.) if (pins.size() < 2) return false; - const FingerprintVector& from_cert_chain = ssl_info.public_key_hashes; - if (from_cert_chain.empty()) + // Site operators might pin a key using either the SHA-1 or SHA-256 hash + // of the SPKI. So check for success using either hash function. + // + // TODO(palmer): Make this generic so that it works regardless of what + // HashValueTags are defined in the future. + const HashValueVector& from_cert_chain_sha1 = + ssl_info.public_key_hashes[HASH_VALUE_SHA1]; + const HashValueVector& from_cert_chain_sha256 = + ssl_info.public_key_hashes[HASH_VALUE_SHA256]; + + if (from_cert_chain_sha1.empty() && from_cert_chain_sha256.empty()) return false; - return IsBackupPinPresent(pins, from_cert_chain) && - HashesIntersect(pins, from_cert_chain); + return (IsBackupPinPresent(pins, from_cert_chain_sha1) || + IsBackupPinPresent(pins, from_cert_chain_sha256)) && + (HashesIntersect(pins, from_cert_chain_sha1) || + HashesIntersect(pins, from_cert_chain_sha256)); } // "Public-Key-Pins" ":" @@ -328,7 +351,7 @@ bool TransportSecurityState::DomainState::ParsePinsHeader( const SSLInfo& ssl_info) { bool parsed_max_age = false; int max_age_candidate = 0; - FingerprintVector pins; + HashValueVector pins; std::string source = value; @@ -349,11 +372,10 @@ bool TransportSecurityState::DomainState::ParsePinsHeader( if (max_age_candidate > kMaxHSTSAgeSecs) max_age_candidate = kMaxHSTSAgeSecs; parsed_max_age = true; - } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) { + } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1") || + LowerCaseEqualsASCII(equals.first, "pin-sha256")) { if (!ParseAndAppendPin(equals.second, &pins)) return false; - } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) { - // TODO(palmer) } else { // Silently ignore unknown directives for forward compatibility. } @@ -369,7 +391,7 @@ bool TransportSecurityState::DomainState::ParsePinsHeader( dynamic_spki_hashes.clear(); if (max_age_candidate > 0) { - for (FingerprintVector::const_iterator i = pins.begin(); + for (HashValueVector::const_iterator i = pins.begin(); i != pins.end(); ++i) { dynamic_spki_hashes.push_back(*i); } @@ -476,8 +498,8 @@ bool TransportSecurityState::DomainState::ParseSTSHeader( } static bool AddHash(const std::string& type_and_base64, - FingerprintVector* out) { - SHA1Fingerprint hash; + HashValueVector* out) { + HashValue hash; if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) return false; @@ -743,13 +765,13 @@ void TransportSecurityState::AddOrUpdateForcedHosts( } static std::string HashesToBase64String( - const FingerprintVector& hashes) { + const HashValueVector& hashes) { std::vector<std::string> hashes_strs; - for (FingerprintVector::const_iterator + for (HashValueVector::const_iterator i = hashes.begin(); i != hashes.end(); i++) { std::string s; - const std::string hash_str(reinterpret_cast<const char*>(i->data), - sizeof(i->data)); + const std::string hash_str(reinterpret_cast<const char*>(i->data()), + i->size()); base::Base64Encode(hash_str, &s); hashes_strs.push_back(s); } @@ -767,24 +789,43 @@ TransportSecurityState::DomainState::~DomainState() { } bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted( - const FingerprintVector& hashes) const { - if (HashesIntersect(bad_static_spki_hashes, hashes)) { - LOG(ERROR) << "Rejecting public key chain for domain " << domain - << ". Validated chain: " << HashesToBase64String(hashes) - << ", matches one or more bad hashes: " - << HashesToBase64String(bad_static_spki_hashes); + const std::vector<HashValueVector>& hashes) const { + // Validate that hashes is not empty. By the time this code is called (in + // production), that should never happen, but it's good to be defensive. + // And, hashes *can* be empty in some test scenarios. + bool empty = true; + for (size_t i = 0; i < hashes.size(); ++i) { + if (hashes[i].size()) { + empty = false; + break; + } + } + if (empty) { + LOG(ERROR) << "Rejecting empty certificate chain for public key pinned " + "domain " << domain; return false; } - if (!(dynamic_spki_hashes.empty() && static_spki_hashes.empty()) && - !HashesIntersect(dynamic_spki_hashes, hashes) && - !HashesIntersect(static_spki_hashes, hashes)) { - LOG(ERROR) << "Rejecting public key chain for domain " << domain - << ". Validated chain: " << HashesToBase64String(hashes) - << ", expected: " << HashesToBase64String(dynamic_spki_hashes) - << " or: " << HashesToBase64String(static_spki_hashes); + for (size_t i = 0; i < hashes.size(); ++i) { + if (HashesIntersect(bad_static_spki_hashes, hashes[i])) { + LOG(ERROR) << "Rejecting public key chain for domain " << domain + << ". Validated chain: " << HashesToBase64String(hashes[i]) + << ", matches one or more bad hashes: " + << HashesToBase64String(bad_static_spki_hashes); + return false; + } - return false; + if (!(dynamic_spki_hashes.empty() && static_spki_hashes.empty()) && + hashes[i].size() > 0 && + !HashesIntersect(dynamic_spki_hashes, hashes[i]) && + !HashesIntersect(static_spki_hashes, hashes[i])) { + LOG(ERROR) << "Rejecting public key chain for domain " << domain + << ". Validated chain: " << HashesToBase64String(hashes[i]) + << ", expected: " << HashesToBase64String(dynamic_spki_hashes) + << " or: " << HashesToBase64String(static_spki_hashes); + + return false; + } } return true; diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h index 2e4b42e..4500583 100644 --- a/net/base/transport_security_state.h +++ b/net/base/transport_security_state.h @@ -91,9 +91,10 @@ class NET_EXPORT TransportSecurityState // // |bad_static_spki_hashes| contains public keys that we don't want to // trust. - bool IsChainOfPublicKeysPermitted(const FingerprintVector& hashes) const; + bool IsChainOfPublicKeysPermitted( + const std::vector<HashValueVector>& hashes) const; - // Returns true if any of the FingerprintVectors |static_spki_hashes|, + // Returns true if any of the HashValueVectors |static_spki_hashes|, // |bad_static_spki_hashes|, or |dynamic_spki_hashes| contains any // items. bool HasPins() const; @@ -131,10 +132,10 @@ class NET_EXPORT TransportSecurityState // |dynamic_spki_hashes| take precedence over |static_spki_hashes|. // That is, |IsChainOfPublicKeysPermitted| first checks dynamic pins and // then checks static pins. - FingerprintVector static_spki_hashes; + HashValueVector static_spki_hashes; // Optional; hashes of dynamically pinned SubjectPublicKeyInfos. - FingerprintVector dynamic_spki_hashes; + HashValueVector dynamic_spki_hashes; // The absolute time (UTC) when the |dynamic_spki_hashes| expire. base::Time dynamic_spki_hashes_expiry; @@ -142,7 +143,7 @@ class NET_EXPORT TransportSecurityState // Optional; hashes of static known-bad SubjectPublicKeyInfos which // MUST NOT intersect with the set of SPKIs in the TLS server's // certificate chain. - FingerprintVector bad_static_spki_hashes; + HashValueVector bad_static_spki_hashes; // The following members are not valid when stored in |enabled_hosts_|: @@ -255,7 +256,7 @@ class NET_EXPORT TransportSecurityState // Decodes a pin string |value| (e.g. "sha1/hvfkN/qlp/zhXR3cuerq6jd2Z7g="). // If parsing succeeded, updates |*out| and returns true; otherwise returns // false without updating |*out|. - static bool ParsePin(const std::string& value, Fingerprint* out); + static bool ParsePin(const std::string& value, HashValue* out); // The maximum number of seconds for which we'll cache an HSTS request. static const long int kMaxHSTSAgeSecs; diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc index ec20313..2840413 100644 --- a/net/base/transport_security_state_unittest.cc +++ b/net/base/transport_security_state_unittest.cc @@ -6,11 +6,13 @@ #include <algorithm> #include <string> +#include <vector> #include "base/base64.h" #include "base/file_path.h" #include "base/sha1.h" #include "base/string_piece.h" +#include "crypto/sha2.h" #include "net/base/asn1_util.h" #include "net/base/cert_test_util.h" #include "net/base/cert_verifier.h" @@ -20,6 +22,7 @@ #include "net/base/ssl_info.h" #include "net/base/test_completion_callback.h" #include "net/base/test_root_certs.h" +#include "net/base/x509_cert_types.h" #include "net/base/x509_certificate.h" #include "net/http/http_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -91,7 +94,8 @@ TEST_F(TransportSecurityStateTest, BogusHeaders) { } static bool GetPublicKeyHash(const net::X509Certificate::OSCertHandle& cert, - SHA1Fingerprint* fingerprint) { + HashValue* fingerprint, + HashValueTag tag) { std::string der_bytes; if (!net::X509Certificate::GetDEREncoded(cert, &der_bytes)) return false; @@ -100,28 +104,52 @@ static bool GetPublicKeyHash(const net::X509Certificate::OSCertHandle& cert, if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) return false; - base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()), - spki.size(), fingerprint->data); + fingerprint->tag = tag; + switch (tag) { + case HASH_VALUE_SHA1: + base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()), + spki.size(), fingerprint->data()); + break; + case HASH_VALUE_SHA256: + crypto::SHA256HashString(spki, fingerprint->data(), + crypto::kSHA256Length); + break; + default: + NOTREACHED() << "Unknown HashValueTag " << tag; + } + return true; } -static std::string GetPinFromCert(X509Certificate* cert) { - SHA1Fingerprint spki_hash; - EXPECT_TRUE(GetPublicKeyHash(cert->os_cert_handle(), &spki_hash)); +static std::string GetPinFromCert(X509Certificate* cert, HashValueTag tag) { + HashValue spki_hash; + EXPECT_TRUE(GetPublicKeyHash(cert->os_cert_handle(), &spki_hash, tag)); std::string base64; - base::Base64Encode(base::StringPiece(reinterpret_cast<char*>(spki_hash.data), - sizeof(spki_hash.data)), - &base64); - return "pin-sha1=" + HttpUtil::Quote(base64); + base::Base64Encode(base::StringPiece( + reinterpret_cast<char*>(spki_hash.data()), spki_hash.size()), &base64); + + std::string label; + switch (tag) { + case HASH_VALUE_SHA1: + label = "pin-sha1="; + break; + case HASH_VALUE_SHA256: + label = "pin-sha256="; + break; + default: + NOTREACHED() << "Unknown HashValueTag " << tag; + } + + return label + HttpUtil::Quote(base64); } -TEST_F(TransportSecurityStateTest, BogusPinsHeaders) { +static void TestBogusPinsHeaders(HashValueTag tag) { TransportSecurityState::DomainState state; SSLInfo ssl_info; ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); - std::string good_pin = GetPinFromCert(ssl_info.cert); + std::string good_pin = GetPinFromCert(ssl_info.cert, tag); base::Time now = base::Time::Now(); // The backup pin is fake --- it just has to not be in the chain. @@ -180,6 +208,14 @@ TEST_F(TransportSecurityStateTest, BogusPinsHeaders) { EXPECT_FALSE(state.include_subdomains); } +TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA1) { + TestBogusPinsHeaders(HASH_VALUE_SHA1); +} + +TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA256) { + TestBogusPinsHeaders(HASH_VALUE_SHA256); +} + TEST_F(TransportSecurityStateTest, ValidSTSHeaders) { TransportSecurityState::DomainState state; base::Time expiry; @@ -240,7 +276,7 @@ TEST_F(TransportSecurityStateTest, ValidSTSHeaders) { EXPECT_TRUE(state.include_subdomains); } -TEST_F(TransportSecurityStateTest, ValidPinsHeaders) { +static void TestValidPinsHeaders(HashValueTag tag) { TransportSecurityState::DomainState state; base::Time expiry; base::Time now = base::Time::Now(); @@ -280,7 +316,8 @@ TEST_F(TransportSecurityStateTest, ValidPinsHeaders) { // Normally, ssl_client_socket_nss would do this, but for a unit test we // fake it. ssl_info.public_key_hashes = result.public_key_hashes; - std::string good_pin = GetPinFromCert(ssl_info.cert); + std::string good_pin = GetPinFromCert(ssl_info.cert, /*tag*/HASH_VALUE_SHA1); + DLOG(WARNING) << "good pin: " << good_pin; // The backup pin is fake --- we just need an SPKI hash that does not match // the hash of any SPKI in the certificate chain. @@ -356,6 +393,14 @@ TEST_F(TransportSecurityStateTest, ValidPinsHeaders) { EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); } +TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA1) { + TestValidPinsHeaders(HASH_VALUE_SHA1); +} + +TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA256) { + TestValidPinsHeaders(HASH_VALUE_SHA256); +} + TEST_F(TransportSecurityStateTest, SimpleMatches) { TransportSecurityState state; TransportSecurityState::DomainState domain_state; @@ -783,7 +828,7 @@ TEST_F(TransportSecurityStateTest, BuiltinCertPins) { EXPECT_TRUE(state.GetDomainState("chrome.google.com", true, &domain_state)); EXPECT_TRUE(HasPins("chrome.google.com")); - FingerprintVector hashes; + std::vector<HashValueVector> hashes; // Checks that a built-in list does exist. EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes)); EXPECT_FALSE(HasPins("www.paypal.com")); @@ -829,20 +874,17 @@ TEST_F(TransportSecurityStateTest, BuiltinCertPins) { } static bool AddHash(const std::string& type_and_base64, - FingerprintVector* out) { - std::string hash_str; - if (type_and_base64.find("sha1/") == 0 && - base::Base64Decode(type_and_base64.substr(5, type_and_base64.size() - 5), - &hash_str) && - hash_str.size() == base::kSHA1Length) { - SHA1Fingerprint hash; - memcpy(hash.data, hash_str.data(), sizeof(hash.data)); - out->push_back(hash); - return true; - } - return false; + HashValueVector* out) { + HashValue hash; + + if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) + return false; + + out->push_back(hash); + return true; } + TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCerts) { // kGoodPath is plus.google.com via Google Internet Authority. static const char* kGoodPath[] = { @@ -862,7 +904,7 @@ TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCerts) { NULL, }; - std::vector<net::SHA1Fingerprint> good_hashes, bad_hashes; + HashValueVector good_hashes, bad_hashes; for (size_t i = 0; kGoodPath[i]; i++) { EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes)); @@ -876,8 +918,13 @@ TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCerts) { EXPECT_TRUE(state.GetDomainState("plus.google.com", true, &domain_state)); EXPECT_TRUE(domain_state.HasPins()); - EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(good_hashes)); - EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad_hashes)); + std::vector<HashValueVector> good; + good.push_back(good_hashes); + EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(good)); + + std::vector<HashValueVector> bad; + bad.push_back(bad_hashes); + EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad)); } TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) { @@ -898,7 +945,7 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) { NULL, }; - std::vector<net::SHA1Fingerprint> good_hashes, bad_hashes; + HashValueVector good_hashes, bad_hashes; for (size_t i = 0; kGoodPath[i]; i++) { EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes)); @@ -912,8 +959,13 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) { EXPECT_TRUE(state.GetDomainState("blog.torproject.org", true, &domain_state)); EXPECT_TRUE(domain_state.HasPins()); - EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(good_hashes)); - EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad_hashes)); + std::vector<HashValueVector> good; + good.push_back(good_hashes); + EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(good)); + + std::vector<HashValueVector> bad; + bad.push_back(bad_hashes); + EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad)); } TEST_F(TransportSecurityStateTest, OptionalHSTSCertPins) { diff --git a/net/base/x509_cert_types.cc b/net/base/x509_cert_types.cc index 174000a..d7d4e08 100644 --- a/net/base/x509_cert_types.cc +++ b/net/base/x509_cert_types.cc @@ -38,7 +38,7 @@ int CompareSHA1Hashes(const void* a, const void* b) { } // namespace // static -bool IsSHA1HashInSortedArray(const SHA1Fingerprint& hash, +bool IsSHA1HashInSortedArray(const SHA1HashValue& hash, const uint8* array, size_t array_byte_len) { DCHECK_EQ(0u, array_byte_len % base::kSHA1Length); diff --git a/net/base/x509_cert_types.h b/net/base/x509_cert_types.h index cfde622..b73ec048 100644 --- a/net/base/x509_cert_types.h +++ b/net/base/x509_cert_types.h @@ -7,10 +7,12 @@ #include <string.h> +#include <algorithm> #include <set> #include <string> #include <vector> +#include "base/logging.h" #include "base/string_piece.h" #include "build/build_config.h" #include "net/base/net_export.h" @@ -28,32 +30,132 @@ namespace net { class X509Certificate; // SHA-1 fingerprint (160 bits) of a certificate. -struct NET_EXPORT SHA1Fingerprint { - bool Equals(const SHA1Fingerprint& other) const { +struct NET_EXPORT SHA1HashValue { + bool Equals(const SHA1HashValue& other) const { return memcmp(data, other.data, sizeof(data)) == 0; } unsigned char data[20]; }; -// In the future there will be a generic Fingerprint type, with at least two -// implementations: SHA1 and SHA256. See http://crbug.com/117914. Until that -// work is done (in a separate patch) this typedef bridges the gap. -typedef SHA1Fingerprint Fingerprint; +class NET_EXPORT SHA1HashValueLessThan { + public: + bool operator() (const SHA1HashValue& lhs, + const SHA1HashValue& rhs) const { + return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) < 0; + } +}; + +struct NET_EXPORT SHA256HashValue { + bool Equals(const SHA256HashValue& other) const { + return memcmp(data, other.data, sizeof(data)) == 0; + } -typedef std::vector<Fingerprint> FingerprintVector; + unsigned char data[32]; +}; -class NET_EXPORT SHA1FingerprintLessThan { +class NET_EXPORT SHA256HashValueLessThan { public: - bool operator() (const SHA1Fingerprint& lhs, - const SHA1Fingerprint& rhs) const { + bool operator() (const SHA256HashValue& lhs, + const SHA256HashValue& rhs) const { return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) < 0; } }; +enum HashValueTag { + HASH_VALUE_SHA1, + HASH_VALUE_SHA256, + + // This must always be last. + HASH_VALUE_TAGS_COUNT +}; + +struct NET_EXPORT HashValue { + bool Equals(const HashValue& other) const { + if (tag != other.tag) + return false; + switch (tag) { + case HASH_VALUE_SHA1: + return fingerprint.sha1.Equals(other.fingerprint.sha1); + break; + case HASH_VALUE_SHA256: + return fingerprint.sha256.Equals(other.fingerprint.sha256); + break; + default: + NOTREACHED() << "Unknown HashValueTag " << tag; + return false; + } + } + + size_t size() const { + switch (tag) { + case HASH_VALUE_SHA1: + return sizeof(fingerprint.sha1.data); + break; + case HASH_VALUE_SHA256: + return sizeof(fingerprint.sha256.data); + break; + default: + NOTREACHED() << "Unknown HashValueTag " << tag; + return 0; + } + } + + unsigned char* data() { + switch (tag) { + case HASH_VALUE_SHA1: + return fingerprint.sha1.data; + break; + case HASH_VALUE_SHA256: + return fingerprint.sha256.data; + break; + default: + NOTREACHED() << "Unknown HashValueTag " << tag; + return NULL; + } + } + + const unsigned char* data() const { + switch (tag) { + case HASH_VALUE_SHA1: + return fingerprint.sha1.data; + break; + case HASH_VALUE_SHA256: + return fingerprint.sha256.data; + break; + default: + NOTREACHED() << "Unknown HashValueTag " << tag; + return NULL; + } + } + + HashValueTag tag; + + union { + SHA1HashValue sha1; + SHA256HashValue sha256; + } fingerprint; +}; + +class NET_EXPORT HashValueLessThan { + public: + bool operator() (const HashValue& lhs, + const HashValue& rhs) const { + size_t lhs_size = lhs.size(); + size_t rhs_size = rhs.size(); + int r = memcmp(lhs.data(), rhs.data(), std::min(lhs_size, rhs_size)); + + if (r == 0 && lhs_size != rhs_size) + return lhs_size < rhs_size; + return r < 0; + } +}; + +typedef std::vector<HashValue> HashValueVector; + // IsSHA1HashInSortedArray returns true iff |hash| is in |array|, a sorted // array of SHA1 hashes. -bool NET_EXPORT IsSHA1HashInSortedArray(const SHA1Fingerprint& hash, +bool NET_EXPORT IsSHA1HashInSortedArray(const SHA1HashValue& hash, const uint8* array, size_t array_byte_len); @@ -130,10 +232,10 @@ class NET_EXPORT CertPolicy { private: // The set of fingerprints of allowed certificates. - std::set<SHA1Fingerprint, SHA1FingerprintLessThan> allowed_; + std::set<SHA1HashValue, SHA1HashValueLessThan> allowed_; // The set of fingerprints of denied certificates. - std::set<SHA1Fingerprint, SHA1FingerprintLessThan> denied_; + std::set<SHA1HashValue, SHA1HashValueLessThan> denied_; }; #if defined(OS_MACOSX) && !defined(OS_IOS) diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc index 7f1c41e..29b11a8 100644 --- a/net/base/x509_certificate.cc +++ b/net/base/x509_certificate.cc @@ -91,7 +91,7 @@ class X509CertificateCache { // the cached OS certificate handle will be freed. int ref_count; }; - typedef std::map<SHA1Fingerprint, Entry, SHA1FingerprintLessThan> CertMap; + typedef std::map<SHA1HashValue, Entry, SHA1HashValueLessThan> CertMap; // Obtain an instance of X509CertificateCache via a LazyInstance. X509CertificateCache() {} @@ -114,7 +114,7 @@ base::LazyInstance<X509CertificateCache>::Leaky void X509CertificateCache::InsertOrUpdate( X509Certificate::OSCertHandle* cert_handle) { DCHECK(cert_handle); - SHA1Fingerprint fingerprint = + SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(*cert_handle); X509Certificate::OSCertHandle old_handle = NULL; @@ -160,7 +160,7 @@ void X509CertificateCache::InsertOrUpdate( } void X509CertificateCache::Remove(X509Certificate::OSCertHandle cert_handle) { - SHA1Fingerprint fingerprint = + SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(cert_handle); base::AutoLock lock(lock_); diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 4055f0a..debdb44 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -247,10 +247,10 @@ class NET_EXPORT X509Certificate const base::Time& valid_expiry() const { return valid_expiry_; } // The fingerprint of this certificate. - const SHA1Fingerprint& fingerprint() const { return fingerprint_; } + const SHA1HashValue& fingerprint() const { return fingerprint_; } // The fingerprint of the intermediate CA certificates. - const SHA1Fingerprint& ca_fingerprint() const { + const SHA1HashValue& ca_fingerprint() const { return ca_fingerprint_; } @@ -425,11 +425,11 @@ class NET_EXPORT X509Certificate // Calculates the SHA-1 fingerprint of the certificate. Returns an empty // (all zero) fingerprint on failure. - static SHA1Fingerprint CalculateFingerprint(OSCertHandle cert_handle); + static SHA1HashValue CalculateFingerprint(OSCertHandle cert_handle); // Calculates the SHA-1 fingerprint of the intermediate CA certificates. // Returns an empty (all zero) fingerprint on failure. - static SHA1Fingerprint CalculateCAFingerprint( + static SHA1HashValue CalculateCAFingerprint( const OSCertHandles& intermediates); private: @@ -495,10 +495,10 @@ class NET_EXPORT X509Certificate base::Time valid_expiry_; // The fingerprint of this certificate. - SHA1Fingerprint fingerprint_; + SHA1HashValue fingerprint_; // The fingerprint of the intermediate CA certificates. - SHA1Fingerprint ca_fingerprint_; + SHA1HashValue ca_fingerprint_; // The serial number of this certificate, DER encoded. std::string serial_number_; diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc index c694579..645d737 100644 --- a/net/base/x509_certificate_mac.cc +++ b/net/base/x509_certificate_mac.cc @@ -577,9 +577,9 @@ void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { } // static -SHA1Fingerprint X509Certificate::CalculateFingerprint( +SHA1HashValue X509Certificate::CalculateFingerprint( OSCertHandle cert) { - SHA1Fingerprint sha1; + SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); CSSM_DATA cert_data; @@ -596,9 +596,9 @@ SHA1Fingerprint X509Certificate::CalculateFingerprint( } // static -SHA1Fingerprint X509Certificate::CalculateCAFingerprint( +SHA1HashValue X509Certificate::CalculateCAFingerprint( const OSCertHandles& intermediates) { - SHA1Fingerprint sha1; + SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so @@ -720,7 +720,7 @@ bool X509Certificate::GetSSLClientCertificates( continue; // Skip duplicates (a cert may be in multiple keychains). - const SHA1Fingerprint& fingerprint = cert->fingerprint(); + const SHA1HashValue& fingerprint = cert->fingerprint(); unsigned i; for (i = 0; i < certs->size(); ++i) { if ((*certs)[i]->fingerprint().Equals(fingerprint)) diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc index eddab65..060f4f7 100644 --- a/net/base/x509_certificate_nss.cc +++ b/net/base/x509_certificate_nss.cc @@ -384,9 +384,9 @@ void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { } // static -SHA1Fingerprint X509Certificate::CalculateFingerprint( +SHA1HashValue X509Certificate::CalculateFingerprint( OSCertHandle cert) { - SHA1Fingerprint sha1; + SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); DCHECK(NULL != cert->derCert.data); @@ -400,9 +400,9 @@ SHA1Fingerprint X509Certificate::CalculateFingerprint( } // static -SHA1Fingerprint X509Certificate::CalculateCAFingerprint( +SHA1HashValue X509Certificate::CalculateCAFingerprint( const OSCertHandles& intermediates) { - SHA1Fingerprint sha1; + SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); HASHContext* sha1_ctx = HASH_Create(HASH_AlgSHA1); diff --git a/net/base/x509_certificate_openssl.cc b/net/base/x509_certificate_openssl.cc index 43198dc..aef938d 100644 --- a/net/base/x509_certificate_openssl.cc +++ b/net/base/x509_certificate_openssl.cc @@ -288,8 +288,8 @@ void X509Certificate::ResetCertStore() { } // static -SHA1Fingerprint X509Certificate::CalculateFingerprint(OSCertHandle cert) { - SHA1Fingerprint sha1; +SHA1HashValue X509Certificate::CalculateFingerprint(OSCertHandle cert) { + SHA1HashValue sha1; unsigned int sha1_size = static_cast<unsigned int>(sizeof(sha1.data)); int ret = X509_digest(cert, EVP_sha1(), sha1.data, &sha1_size); CHECK(ret); @@ -298,9 +298,9 @@ SHA1Fingerprint X509Certificate::CalculateFingerprint(OSCertHandle cert) { } // static -SHA1Fingerprint X509Certificate::CalculateCAFingerprint( +SHA1HashValue X509Certificate::CalculateCAFingerprint( const OSCertHandles& intermediates) { - SHA1Fingerprint sha1; + SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); SHA_CTX sha1_ctx; diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc index 76a50c1b..f8f43fc 100644 --- a/net/base/x509_certificate_unittest.cc +++ b/net/base/x509_certificate_unittest.cc @@ -186,7 +186,7 @@ void CheckGoogleCert(const scoped_refptr<X509Certificate>& google_cert, const Time& valid_expiry = google_cert->valid_expiry(); EXPECT_EQ(valid_to, valid_expiry.ToDoubleT()); - const SHA1Fingerprint& fingerprint = google_cert->fingerprint(); + const SHA1HashValue& fingerprint = google_cert->fingerprint(); for (size_t i = 0; i < 20; ++i) EXPECT_EQ(expected_fingerprint[i], fingerprint.data[i]); @@ -243,7 +243,7 @@ TEST(X509CertificateTest, WebkitCertParsing) { const Time& valid_expiry = webkit_cert->valid_expiry(); EXPECT_EQ(1300491319, valid_expiry.ToDoubleT()); // Mar 18 23:35:19 2011 GMT - const SHA1Fingerprint& fingerprint = webkit_cert->fingerprint(); + const SHA1HashValue& fingerprint = webkit_cert->fingerprint(); for (size_t i = 0; i < 20; ++i) EXPECT_EQ(webkit_fingerprint[i], fingerprint.data[i]); @@ -298,7 +298,7 @@ TEST(X509CertificateTest, ThawteCertParsing) { const Time& valid_expiry = thawte_cert->valid_expiry(); EXPECT_EQ(1263772799, valid_expiry.ToDoubleT()); // Jan 17 23:59:59 2010 GMT - const SHA1Fingerprint& fingerprint = thawte_cert->fingerprint(); + const SHA1HashValue& fingerprint = thawte_cert->fingerprint(); for (size_t i = 0; i < 20; ++i) EXPECT_EQ(thawte_fingerprint[i], fingerprint.data[i]); @@ -888,7 +888,7 @@ TEST_P(X509CertificateParseTest, CanParseFormat) { // Compare the parsed certificate with the expected certificate, by // comparing fingerprints. const X509Certificate* cert = certs[i]; - const SHA1Fingerprint& actual_fingerprint = cert->fingerprint(); + const SHA1HashValue& actual_fingerprint = cert->fingerprint(); uint8* expected_fingerprint = test_data_.chain_fingerprints[i]; for (size_t j = 0; j < 20; ++j) diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc index 5079622..26c1587 100644 --- a/net/base/x509_certificate_win.cc +++ b/net/base/x509_certificate_win.cc @@ -338,13 +338,13 @@ void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { } // static -SHA1Fingerprint X509Certificate::CalculateFingerprint( +SHA1HashValue X509Certificate::CalculateFingerprint( OSCertHandle cert) { DCHECK(NULL != cert->pbCertEncoded); DCHECK_NE(static_cast<DWORD>(0), cert->cbCertEncoded); BOOL rv; - SHA1Fingerprint sha1; + SHA1HashValue sha1; DWORD sha1_size = sizeof(sha1.data); rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, cert->cbCertEncoded, sha1.data, &sha1_size); @@ -358,9 +358,9 @@ SHA1Fingerprint X509Certificate::CalculateFingerprint( // functions to ensure it is fast. Reimplement this function with // CryptoAPI. May need to cache the HCRYPTPROV to reduce the overhead. // static -SHA1Fingerprint X509Certificate::CalculateCAFingerprint( +SHA1HashValue X509Certificate::CalculateCAFingerprint( const OSCertHandles& intermediates) { - SHA1Fingerprint sha1; + SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); SHA1Context* sha1_ctx = SHA1_NewContext(); diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 21089d5..f0fa173 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -131,8 +131,8 @@ static bool IsOCSPStaplingSupported() { #elif defined(USE_NSS) typedef SECStatus (*CacheOCSPResponseFromSideChannelFunction)( - CERTCertDBHandle *handle, CERTCertificate *cert, PRTime time, - SECItem *encodedResponse, void *pwArg); + CERTCertDBHandle* handle, CERTCertificate* cert, PRTime time, + SECItem* encodedResponse, void* pwArg); // On Linux, we dynamically link against the system version of libnss3.so. In // order to continue working on systems without up-to-date versions of NSS we @@ -2763,10 +2763,14 @@ bool SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { ssl_info->connection_status = core_->state().ssl_connection_status; ssl_info->public_key_hashes = server_cert_verify_result_.public_key_hashes; - for (std::vector<SHA1Fingerprint>::const_iterator - i = side_pinned_public_keys_.begin(); - i != side_pinned_public_keys_.end(); i++) { - ssl_info->public_key_hashes.push_back(*i); + // TODO(palmer) TODO(agl): Do side pins need to be in both SHA1 and SHA256 + // forms? If consumers of side pins only care about SHA1, it is OK to put + // them only in the HASH_VALUE_SHA1 vector. + HashValueVector& sha1_hashes = + ssl_info->public_key_hashes[HASH_VALUE_SHA1]; + for (HashValueVector::const_iterator i = side_pinned_public_keys_.begin(); + i != side_pinned_public_keys_.end(); ++i) { + sha1_hashes.push_back(*i); } ssl_info->is_issued_by_known_root = server_cert_verify_result_.is_issued_by_known_root; diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index ba34a2c..f8f602f 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -157,7 +157,7 @@ class SSLClientSocketNSS : public SSLClientSocket { CompletionCallback user_connect_callback_; CertVerifyResult server_cert_verify_result_; - std::vector<SHA1Fingerprint> side_pinned_public_keys_; + HashValueVector side_pinned_public_keys_; CertVerifier* const cert_verifier_; scoped_ptr<SingleRequestCertVerifier> verifier_; diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 0178d37..3d785e9 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -147,7 +147,7 @@ void CheckSSLInfo(const SSLInfo& ssl_info) { EXPECT_NE(0, cipher_suite); } -bool FingerprintsEqual(const FingerprintVector& a, const FingerprintVector& b) { +bool FingerprintsEqual(const HashValueVector& a, const HashValueVector& b) { size_t size = a.size(); if (size != b.size()) @@ -550,7 +550,7 @@ class URLRequestTestHTTP : public URLRequestTest { strlen(expected_data))); } - bool DoManyCookiesRequest(int num_cookies){ + bool DoManyCookiesRequest(int num_cookies) { TestDelegate d; URLRequest r(test_server_.GetURL("set-many-cookies?" + base::IntToString(num_cookies)), @@ -564,7 +564,7 @@ class URLRequestTestHTTP : public URLRequestTest { bool is_success = r.status().is_success(); - if (!is_success){ + if (!is_success) { // Requests handled by ChromeFrame send a less precise error message, // ERR_CONNECTION_ABORTED. EXPECT_TRUE(r.status().error() == ERR_RESPONSE_HEADERS_TOO_BIG || @@ -1473,7 +1473,7 @@ class TestSSLConfigService : public SSLConfigService { // This the fingerprint of the "Testing CA" certificate used by the testserver. // See net/data/ssl/certificates/ocsp-test-root.pem. -static const SHA1Fingerprint kOCSPTestCertFingerprint = +static const SHA1HashValue kOCSPTestCertFingerprint = { { 0xf1, 0xad, 0xf6, 0xce, 0x42, 0xac, 0xe7, 0xb4, 0xf4, 0x24, 0xdb, 0x1a, 0xf7, 0xa0, 0x9f, 0x09, 0xa1, 0xea, 0xf1, 0x5c } }; |