summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpalmer@chromium.org <palmer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-06 19:04:21 +0000
committerpalmer@chromium.org <palmer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-06 19:04:21 +0000
commita7c2609a96d01f2d5f9cecd15ddc55869e8c6a75 (patch)
tree6a2b69b0160fd4c77dbf1a91af54c48c023eb2af
parent9939d35f9827ed0929646607cbdb071af627ac38 (diff)
downloadchromium_src-a7c2609a96d01f2d5f9cecd15ddc55869e8c6a75.zip
chromium_src-a7c2609a96d01f2d5f9cecd15ddc55869e8c6a75.tar.gz
chromium_src-a7c2609a96d01f2d5f9cecd15ddc55869e8c6a75.tar.bz2
Implement SHA-256 fingerprint support.
The HTTP-based Public Key Pinning Internet Draft (tools.ietf.org/html/draft-ietf-websec-key-pinning) requires this. Per wtc, give the *Fingeprint* types more meaningful *HashValue* names. Cleaning up lint along the way. This CL reverts 149268, which reverted 149261 the previous version of this CL. It includes a fix to the compile problem that necessitated 149268. BUG=117914 TEST=net_unittests, unit_tests TransportSecurityPersisterTest Review URL: https://chromiumcodereview.appspot.com/10836062 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150124 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/net/transport_security_persister.cc32
-rw-r--r--chrome/browser/net/transport_security_persister_unittest.cc43
-rw-r--r--chrome/browser/ui/webui/net_internals/net_internals_ui.cc26
-rw-r--r--net/base/cert_test_util.cc2
-rw-r--r--net/base/cert_test_util.h4
-rw-r--r--net/base/cert_verify_proc.cc12
-rw-r--r--net/base/cert_verify_proc.h4
-rw-r--r--net/base/cert_verify_proc_mac.cc19
-rw-r--r--net/base/cert_verify_proc_nss.cc33
-rw-r--r--net/base/cert_verify_proc_openssl.cc18
-rw-r--r--net/base/cert_verify_proc_unittest.cc24
-rw-r--r--net/base/cert_verify_proc_win.cc21
-rw-r--r--net/base/cert_verify_result.cc8
-rw-r--r--net/base/cert_verify_result.h13
-rw-r--r--net/base/ev_root_ca_metadata.cc20
-rw-r--r--net/base/ev_root_ca_metadata.h17
-rw-r--r--net/base/ev_root_ca_metadata_unittest.cc6
-rw-r--r--net/base/multi_threaded_cert_verifier.h8
-rw-r--r--net/base/multi_threaded_cert_verifier_unittest.cc4
-rw-r--r--net/base/ssl_info.cc7
-rw-r--r--net/base/ssl_info.h7
-rw-r--r--net/base/transport_security_state.cc161
-rw-r--r--net/base/transport_security_state.h13
-rw-r--r--net/base/transport_security_state_unittest.cc118
-rw-r--r--net/base/x509_cert_types.cc2
-rw-r--r--net/base/x509_cert_types.h128
-rw-r--r--net/base/x509_certificate.cc6
-rw-r--r--net/base/x509_certificate.h12
-rw-r--r--net/base/x509_certificate_mac.cc10
-rw-r--r--net/base/x509_certificate_nss.cc8
-rw-r--r--net/base/x509_certificate_openssl.cc8
-rw-r--r--net/base/x509_certificate_unittest.cc8
-rw-r--r--net/base/x509_certificate_win.cc8
-rw-r--r--net/socket/ssl_client_socket_nss.cc16
-rw-r--r--net/socket/ssl_client_socket_nss.h2
-rw-r--r--net/url_request/url_request_unittest.cc8
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 } };