summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/net/transport_security_persister.cc21
-rw-r--r--chrome/browser/net/transport_security_persister_unittest.cc34
-rw-r--r--chrome/browser/ui/webui/net_internals/net_internals_ui.cc12
-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.cc11
-rw-r--r--net/base/cert_verify_proc.h5
-rw-r--r--net/base/cert_verify_proc_mac.cc17
-rw-r--r--net/base/cert_verify_proc_nss.cc30
-rw-r--r--net/base/cert_verify_proc_openssl.cc16
-rw-r--r--net/base/cert_verify_proc_unittest.cc25
-rw-r--r--net/base/cert_verify_proc_win.cc19
-rw-r--r--net/base/cert_verify_result.cc3
-rw-r--r--net/base/cert_verify_result.h8
-rw-r--r--net/base/ev_root_ca_metadata.cc20
-rw-r--r--net/base/ev_root_ca_metadata.h15
-rw-r--r--net/base/ev_root_ca_metadata_unittest.cc4
-rw-r--r--net/base/multi_threaded_cert_verifier.cc4
-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.cc2
-rw-r--r--net/base/ssl_info.h5
-rw-r--r--net/base/transport_security_state.cc164
-rw-r--r--net/base/transport_security_state.h14
-rw-r--r--net/base/transport_security_state_unittest.cc188
-rw-r--r--net/base/x509_cert_types.cc50
-rw-r--r--net/base/x509_cert_types.h79
-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.cc5
-rw-r--r--net/socket/ssl_client_socket_nss.h2
-rw-r--r--net/url_request/url_request_unittest.cc8
37 files changed, 583 insertions, 256 deletions
diff --git a/chrome/browser/net/transport_security_persister.cc b/chrome/browser/net/transport_security_persister.cc
index 76bc514..7e80742 100644
--- a/chrome/browser/net/transport_security_persister.cc
+++ b/chrome/browser/net/transport_security_persister.cc
@@ -20,32 +20,33 @@
#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 hash_str(reinterpret_cast<const char*>(i->data()), i->size());
std::string b64;
- base::Base64Encode(hash_str, &b64);
- pins->Append(new StringValue("sha1/" + b64));
+ if (base::Base64Encode(hash_str, &b64))
+ pins->Append(new StringValue(TransportSecurityState::HashValueLabel(*i) +
+ 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..32ddfa2 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,10 @@ 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(net::HASH_VALUE_SHA1);
+ memset(fp1.data(), 0, fp1.size());
+ net::HashValue fp2(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 +112,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 +182,19 @@ 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));
+ net::HashValueVector hashes;
+ 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(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);
+
+ hashes.push_back(sha1);
EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(hashes));
- hashes[0].data[0] = '2';
+
+ hashes[0].data()[0] = '2';
EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes));
const base::Time current_time(base::Time::Now());
@@ -204,8 +207,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 92c52d5..34f7b1b 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -1082,18 +1082,18 @@ 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));
+ 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 += net::TransportSecurityState::HashValueLabel(*i) + encoded;
}
}
@@ -1169,7 +1169,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 07c0df9..3ba21b9 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 HashValueVector& public_key_hashes) {
static const unsigned kNumHashes = 9;
static const uint8 kHashes[kNumHashes][base::kSHA1Length] = {
// Subject: CN=DigiNotar Root CA
@@ -264,10 +265,12 @@ bool CertVerifyProc::IsPublicKeyBlacklisted(
};
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 = public_key_hashes.begin();
+ j != public_key_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..475a533 100644
--- a/net/base/cert_verify_proc.h
+++ b/net/base/cert_verify_proc.h
@@ -75,9 +75,8 @@ 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.
- static bool IsPublicKeyBlacklisted(
- const std::vector<SHA1Fingerprint>& public_key_hashes);
+ // are hashes of SubjectPublicKeyInfo structures) is explicitly blocked.
+ static bool IsPublicKeyBlacklisted(const 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 76ac82f..e478929 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"
@@ -233,7 +236,7 @@ void GetCertChainInfo(CFArrayRef cert_chain,
}
void AppendPublicKeyHashes(CFArrayRef chain,
- std::vector<SHA1Fingerprint>* hashes) {
+ HashValueVector* hashes) {
const CFIndex n = CFArrayGetCount(chain);
for (CFIndex i = 0; i < n; i++) {
SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
@@ -248,9 +251,13 @@ 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(HASH_VALUE_SHA1);
+ CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data());
+ hashes->push_back(sha1);
+
+ HashValue sha256(HASH_VALUE_SHA256);
+ CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data());
+ hashes->push_back(sha256);
}
}
@@ -327,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 0df6e14..4fed288 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>
@@ -567,9 +570,17 @@ SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) {
return SECOID_AddEntry(&od);
}
-SHA1Fingerprint CertPublicKeyHash(CERTCertificate* cert) {
- SHA1Fingerprint hash;
- SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data,
+HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) {
+ HashValue hash(HASH_VALUE_SHA1);
+ SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(),
+ cert->derPublicKey.data, cert->derPublicKey.len);
+ DCHECK_EQ(SECSuccess, rv);
+ return hash;
+}
+
+HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) {
+ HashValue hash(HASH_VALUE_SHA256);
+ SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(),
cert->derPublicKey.data, cert->derPublicKey.len);
DCHECK_EQ(rv, SECSuccess);
return hash;
@@ -577,14 +588,17 @@ SHA1Fingerprint CertPublicKeyHash(CERTCertificate* cert) {
void AppendPublicKeyHashes(CERTCertList* cert_list,
CERTCertificate* root_cert,
- std::vector<SHA1Fingerprint>* hashes) {
+ HashValueVector* hashes) {
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->push_back(CertPublicKeyHashSHA1(node->cert));
+ hashes->push_back(CertPublicKeyHashSHA256(node->cert));
+ }
+ if (root_cert) {
+ hashes->push_back(CertPublicKeyHashSHA1(root_cert));
+ hashes->push_back(CertPublicKeyHashSHA256(root_cert));
}
- if (root_cert)
- hashes->push_back(CertPublicKeyHash(root_cert));
}
// Returns true if |cert_handle| contains a policy OID that is an EV policy
@@ -672,7 +686,7 @@ bool VerifyEV(CERTCertificate* cert_handle,
return false;
}
- SHA1Fingerprint fingerprint =
+ SHA1HashValue fingerprint =
X509Certificate::CalculateFingerprint(root_ca);
return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid);
}
diff --git a/net/base/cert_verify_proc_openssl.cc b/net/base/cert_verify_proc_openssl.cc
index 17d3d9b..a43fa5b 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_verifier.h"
@@ -132,7 +136,7 @@ void GetCertChainInfo(X509_STORE_CTX* store_ctx,
}
void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx,
- std::vector<SHA1Fingerprint>* hashes) {
+ 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);
@@ -146,10 +150,14 @@ void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx,
if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
continue;
- SHA1Fingerprint hash;
+ HashValue sha1(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->push_back(sha1);
+
+ HashValue sha256(HASH_VALUE_SHA256);
+ crypto::SHA256HashString(spki_bytes, sha1.data(), crypto::kSHA256Length);
+ hashes->push_back(sha256);
}
}
diff --git a/net/base/cert_verify_proc_unittest.cc b/net/base/cert_verify_proc_unittest.cc
index cfbf8a9..2638dec 100644
--- a/net/base/cert_verify_proc_unittest.cc
+++ b/net/base/cert_verify_proc_unittest.cc
@@ -121,7 +121,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]);
@@ -415,11 +415,11 @@ 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);
+ HashValueVector public_keys;
+ HashValue hash(HASH_VALUE_SHA1);
+ ASSERT_EQ(hash.size(), spki_sha1.size());
+ memcpy(hash.data(), spki_sha1.data(), spki_sha1.size());
+ public_keys.push_back(hash);
EXPECT_TRUE(CertVerifyProc::IsPublicKeyBlacklisted(public_keys)) <<
"Public key not blocked for " << kDigiNotarFilenames[i];
@@ -472,9 +472,18 @@ TEST_F(CertVerifyProcTest, PublicKeyHashes) {
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++) {
+
+ HashValueVector sha1_hashes;
+ for (unsigned i = 0; i < verify_result.public_key_hashes.size(); ++i) {
+ if (verify_result.public_key_hashes[i].tag != HASH_VALUE_SHA1)
+ continue;
+ sha1_hashes.push_back(verify_result.public_key_hashes[i]);
+ }
+ 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 154092b..9a3233f 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"
@@ -283,7 +286,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));
}
@@ -442,7 +445,7 @@ bool CheckRevocationWithCRLSet(PCCERT_CHAIN_CONTEXT chain,
}
void AppendPublicKeyHashes(PCCERT_CHAIN_CONTEXT chain,
- std::vector<SHA1Fingerprint>* hashes) {
+ HashValueVector* hashes) {
if (chain->cChain == 0)
return;
@@ -460,10 +463,14 @@ void AppendPublicKeyHashes(PCCERT_CHAIN_CONTEXT chain,
if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
continue;
- SHA1Fingerprint hash;
+ HashValue sha1(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->push_back(sha1);
+
+ HashValue sha256(HASH_VALUE_SHA256);
+ crypto::SHA256HashString(spki_bytes, sha1.data(), crypto::kSHA256Length);
+ hashes->push_back(sha256);
}
}
@@ -504,7 +511,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..f7d8c4c 100644
--- a/net/base/cert_verify_result.cc
+++ b/net/base/cert_verify_result.cc
@@ -24,7 +24,8 @@ void CertVerifyResult::Reset() {
has_md5_ca = false;
has_md2_ca = false;
is_issued_by_known_root = false;
+
public_key_hashes.clear();
}
-} // namespace net
+} // namespace net
diff --git a/net/base/cert_verify_result.h b/net/base/cert_verify_result.h
index 06baad2..e98dcfe 100644
--- a/net/base/cert_verify_result.h
+++ b/net/base/cert_verify_result.h
@@ -45,10 +45,10 @@ 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
+ // hashes, in several hash algorithms, of the SubjectPublicKeyInfos of the
+ // chain.
+ 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 d51c3b9b..9901ff3 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/
@@ -325,7 +325,7 @@ bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const {
}
bool EVRootCAMetadata::HasEVPolicyOID(
- const SHA1Fingerprint& fingerprint,
+ const SHA1HashValue& fingerprint,
PolicyOID policy_oid) const {
PolicyOIDMap::const_iterator iter = ev_policy_.find(fingerprint);
if (iter == ev_policy_.end())
@@ -338,7 +338,7 @@ bool EVRootCAMetadata::HasEVPolicyOID(
return false;
}
-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;
@@ -353,7 +353,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;
@@ -407,7 +407,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))
@@ -425,7 +425,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))
@@ -439,7 +439,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;
@@ -452,12 +452,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 4e7af40..57ebe80 100644
--- a/net/base/ev_root_ca_metadata.h
+++ b/net/base/ev_root_ca_metadata.h
@@ -13,6 +13,7 @@
#include <map>
#include <set>
+#include <string>
#include <vector>
#include "net/base/net_export.h"
@@ -43,18 +44,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>;
@@ -63,8 +64,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.
@@ -73,8 +74,8 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata {
PolicyOIDMap ev_policy_;
std::set<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 8859c70..0389b7d 100644
--- a/net/base/ev_root_ca_metadata_unittest.cc
+++ b/net/base/ev_root_ca_metadata_unittest.cc
@@ -19,10 +19,10 @@ namespace {
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 } };
diff --git a/net/base/multi_threaded_cert_verifier.cc b/net/base/multi_threaded_cert_verifier.cc
index b2c3a0a..54e0324 100644
--- a/net/base/multi_threaded_cert_verifier.cc
+++ b/net/base/multi_threaded_cert_verifier.cc
@@ -461,8 +461,8 @@ void MultiThreadedCertVerifier::CancelRequest(RequestHandle req) {
}
MultiThreadedCertVerifier::RequestParams::RequestParams(
- const SHA1Fingerprint& cert_fingerprint_arg,
- const SHA1Fingerprint& ca_fingerprint_arg,
+ const SHA1HashValue& cert_fingerprint_arg,
+ const SHA1HashValue& ca_fingerprint_arg,
const std::string& hostname_arg,
int flags_arg)
: cert_fingerprint(cert_fingerprint_arg),
diff --git a/net/base/multi_threaded_cert_verifier.h b/net/base/multi_threaded_cert_verifier.h
index 7407009..e4c0653 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 NET_EXPORT_PRIVATE 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);
@@ -88,8 +88,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 44532b3..7bf47a2 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..05882d3 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,6 +43,7 @@ void SSLInfo::Reset() {
client_cert_sent = false;
channel_id_sent = false;
handshake_type = HANDSHAKE_UNKNOWN;
+
public_key_hashes.clear();
}
diff --git a/net/base/ssl_info.h b/net/base/ssl_info.h
index b3c37d2..25019a26 100644
--- a/net/base/ssl_info.h
+++ b/net/base/ssl_info.h
@@ -71,8 +71,9 @@ 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, in several algorithms, of the SubjectPublicKeyInfos from
+ // each certificate in the chain.
+ HashValueVector public_key_hashes;
};
} // namespace net
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc
index db18853..4a93136 100644
--- a/net/base/transport_security_state.cc
+++ b/net/base/transport_security_state.cc
@@ -16,7 +16,6 @@
#endif
#include <algorithm>
-#include <utility>
#include "base/base64.h"
#include "base/logging.h"
@@ -33,6 +32,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"
@@ -225,69 +225,69 @@ 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) {
- // 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.
- size_t size = value.size();
- if (size != 30 || value[0] != '"' || value[size - 1] != '"')
- return false;
-
+ HashValueTag tag,
+ HashValueVector* hashes) {
std::string unquoted = HttpUtil::Unquote(value);
std::string decoded;
- SHA1Fingerprint 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;
+
+ HashValue hash(tag);
+ if (decoded.size() != hash.size())
return false;
- }
- memcpy(fp.data, decoded.data(), arraysize(fp.data));
- fingerprints->push_back(fp);
+ memcpy(hash.data(), decoded.data(), hash.size());
+ hashes->push_back(hash);
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;
}
@@ -295,14 +295,15 @@ static bool IsBackupPinPresent(const FingerprintVector& pins,
return false;
}
-static bool HashesIntersect(const FingerprintVector& a,
- const FingerprintVector& b) {
- for (FingerprintVector::const_iterator
- i = a.begin(); i != a.end(); ++i) {
- FingerprintVector::const_iterator j =
- std::find_if(b.begin(), b.end(), FingerprintsEqualPredicate(*i));
- if (j != b.end())
- return true;
+// Returns true if the intersection of |a| and |b| is not empty. If either
+// |a| or |b| is empty, returns false.
+static bool HashesIntersect(const HashValueVector& a,
+ const HashValueVector& b) {
+ for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) {
+ HashValueVector::const_iterator j =
+ std::find_if(b.begin(), b.end(), HashValuesEqualPredicate(*i));
+ if (j != b.end())
+ return true;
}
return false;
@@ -313,17 +314,19 @@ 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;
+ const HashValueVector& from_cert_chain = ssl_info.public_key_hashes;
if (from_cert_chain.empty())
return false;
return IsBackupPinPresent(pins, from_cert_chain) &&
- HashesIntersect(pins, from_cert_chain);
+ HashesIntersect(pins, from_cert_chain);
}
// "Public-Key-Pins" ":"
@@ -335,7 +338,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;
@@ -356,11 +359,18 @@ bool TransportSecurityState::DomainState::ParsePinsHeader(
if (max_age_candidate > kMaxHSTSAgeSecs)
max_age_candidate = kMaxHSTSAgeSecs;
parsed_max_age = true;
- } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) {
- if (!ParseAndAppendPin(equals.second, &pins))
+ } else if (StartsWithASCII(equals.first, "pin-", false)) {
+ HashValueTag tag;
+ if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) {
+ tag = HASH_VALUE_SHA1;
+ } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) {
+ tag = HASH_VALUE_SHA256;
+ } else {
+ LOG(WARNING) << "Ignoring pin of unknown type: " << equals.first;
+ return false;
+ }
+ if (!ParseAndAppendPin(equals.second, tag, &pins))
return false;
- } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) {
- // TODO(palmer)
} else {
// Silently ignore unknown directives for forward compatibility.
}
@@ -376,7 +386,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);
}
@@ -483,8 +493,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;
@@ -705,6 +715,21 @@ void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
entry->second_level_domain_name, DOMAIN_NUM_EVENTS);
}
+// static
+const char* TransportSecurityState::HashValueLabel(
+ const HashValue& hash_value) {
+ switch (hash_value.tag) {
+ case HASH_VALUE_SHA1:
+ return "sha1/";
+ case HASH_VALUE_SHA256:
+ return "sha256/";
+ default:
+ NOTREACHED();
+ LOG(WARNING) << "Invalid fingerprint of unknown type " << hash_value.tag;
+ return "unknown/";
+ }
+}
+
bool TransportSecurityState::GetStaticDomainState(
const std::string& canonicalized_host,
bool sni_enabled,
@@ -750,13 +775,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);
}
@@ -774,7 +799,16 @@ TransportSecurityState::DomainState::~DomainState() {
}
bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted(
- const FingerprintVector& hashes) const {
+ const 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.
+ if (hashes.empty()) {
+ LOG(ERROR) << "Rejecting empty public key chain for public-key-pinned "
+ "domain " << domain;
+ return false;
+ }
+
if (HashesIntersect(bad_static_spki_hashes, hashes)) {
LOG(ERROR) << "Rejecting public key chain for domain " << domain
<< ". Validated chain: " << HashesToBase64String(hashes)
@@ -783,18 +817,20 @@ bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted(
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);
+ // If there are no pins, then any valid chain is acceptable.
+ if (dynamic_spki_hashes.empty() && static_spki_hashes.empty())
+ return true;
- return false;
+ if (HashesIntersect(dynamic_spki_hashes, hashes) ||
+ HashesIntersect(static_spki_hashes, hashes)) {
+ return true;
}
- return true;
+ LOG(ERROR) << "Rejecting public key chain for domain " << domain
+ << ". Validated chain: " << HashesToBase64String(hashes)
+ << ", expected: " << HashesToBase64String(dynamic_spki_hashes)
+ << " or: " << HashesToBase64String(static_spki_hashes);
+ return false;
}
bool TransportSecurityState::DomainState::ShouldRedirectHTTPToHTTPS() const {
diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h
index 01c0a26..96402f6 100644
--- a/net/base/transport_security_state.h
+++ b/net/base/transport_security_state.h
@@ -91,9 +91,9 @@ 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 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 +131,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 +142,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_|:
@@ -252,7 +252,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;
@@ -272,6 +272,8 @@ class NET_EXPORT TransportSecurityState
// to the caller with |GetStaticDomainState|.
static void ReportUMAOnPinFailure(const std::string& host);
+ static const char* HashValueLabel(const HashValue& hash_value);
+
private:
// If a Delegate is present, notify it that the internal state has
// changed.
diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc
index ec20313..4b0aead 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,7 @@ TEST_F(TransportSecurityStateTest, BogusHeaders) {
}
static bool GetPublicKeyHash(const net::X509Certificate::OSCertHandle& cert,
- SHA1Fingerprint* fingerprint) {
+ HashValue* hash) {
std::string der_bytes;
if (!net::X509Certificate::GetDEREncoded(cert, &der_bytes))
return false;
@@ -100,28 +103,50 @@ 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);
+ switch (hash->tag) {
+ case HASH_VALUE_SHA1:
+ base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()),
+ spki.size(), hash->data());
+ break;
+ case HASH_VALUE_SHA256:
+ crypto::SHA256HashString(spki, hash->data(), crypto::kSHA256Length);
+ break;
+ default:
+ NOTREACHED() << "Unknown HashValueTag " << hash->tag;
+ }
+
return true;
}
-static std::string GetPinFromCert(X509Certificate* cert) {
- SHA1Fingerprint spki_hash;
+static std::string GetPinFromCert(X509Certificate* cert, HashValueTag tag) {
+ HashValue spki_hash(tag);
EXPECT_TRUE(GetPublicKeyHash(cert->os_cert_handle(), &spki_hash));
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 +205,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 +273,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 +313,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 +390,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 +825,7 @@ TEST_F(TransportSecurityStateTest, BuiltinCertPins) {
EXPECT_TRUE(state.GetDomainState("chrome.google.com", true, &domain_state));
EXPECT_TRUE(HasPins("chrome.google.com"));
- FingerprintVector hashes;
+ HashValueVector hashes;
// Checks that a built-in list does exist.
EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes));
EXPECT_FALSE(HasPins("www.paypal.com"));
@@ -829,18 +871,14 @@ 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) {
@@ -862,7 +900,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));
@@ -898,7 +936,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));
@@ -916,6 +954,100 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad_hashes));
}
+TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCertsMixedHashes) {
+ static const char* ee_sha1 = "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=";
+ static const char* ee_sha256 =
+ "sha256/sRJBQqWhpaKIGcc1NA7/jJ4vgWj+47oYfyU7waOS1+I=";
+ static const char* google_1024_sha1 = "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0=";
+ static const char* google_1024_sha256 =
+ "sha256/trlUMquuV/4CDLK3T0+fkXPIxwivyecyrOIyeQR8bQU=";
+ static const char* equifax_sha1 = "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=";
+ static const char* equifax_sha256 =
+ "sha256//1aAzXOlcD2gSBegdf1GJQanNQbEuBoVg+9UlHjSZHY=";
+ static const char* trustcenter_sha1 = "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=";
+ static const char* trustcenter_sha256 =
+ "sha256/Dq58KIA4NMLsboWMLU8/aTREzaAGEFW+EtUule8dd/M=";
+
+ // Good chains for plus.google.com chain up through google_1024_sha{1,256}
+ // to equifax_sha{1,256}. Bad chains chain up to Equifax through
+ // trustcenter_sha{1,256}, which is a blacklisted key. Even though Equifax
+ // and Google1024 are known-good, the blacklistedness of Trustcenter
+ // should override and cause pin validation failure.
+
+ TransportSecurityState state;
+ TransportSecurityState::DomainState domain_state;
+ EXPECT_TRUE(state.GetDomainState("plus.google.com", true, &domain_state));
+ EXPECT_TRUE(domain_state.HasPins());
+
+ // The statically-defined pins are all SHA-1, so we add some SHA-256 pins
+ // manually:
+ EXPECT_TRUE(AddHash(google_1024_sha256, &domain_state.static_spki_hashes));
+ EXPECT_TRUE(AddHash(trustcenter_sha256,
+ &domain_state.bad_static_spki_hashes));
+
+ // Try an all-good SHA1 chain.
+ HashValueVector validated_chain;
+ EXPECT_TRUE(AddHash(ee_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain));
+ EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain));
+
+ // Try an all-bad SHA1 chain.
+ validated_chain.clear();
+ EXPECT_TRUE(AddHash(ee_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(trustcenter_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain));
+ EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain));
+
+ // Try an all-good SHA-256 chain.
+ validated_chain.clear();
+ EXPECT_TRUE(AddHash(ee_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(google_1024_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain));
+ EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain));
+
+ // Try an all-bad SHA-256 chain.
+ validated_chain.clear();
+ EXPECT_TRUE(AddHash(ee_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain));
+ EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain));
+
+ // Try a mixed-hash good chain.
+ validated_chain.clear();
+ EXPECT_TRUE(AddHash(ee_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain));
+ EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain));
+
+ // Try a mixed-hash bad chain.
+ validated_chain.clear();
+ EXPECT_TRUE(AddHash(ee_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain));
+ EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain));
+
+ // Try a chain with all good hashes.
+ validated_chain.clear();
+ EXPECT_TRUE(AddHash(ee_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(ee_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(google_1024_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain));
+ EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain));
+
+ // Try a chain with all bad hashes.
+ validated_chain.clear();
+ EXPECT_TRUE(AddHash(ee_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(trustcenter_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain));
+ EXPECT_TRUE(AddHash(ee_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain));
+ EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain));
+ EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain));
+}
+
TEST_F(TransportSecurityStateTest, OptionalHSTSCertPins) {
TransportSecurityState state;
TransportSecurityState::DomainState domain_state;
diff --git a/net/base/x509_cert_types.cc b/net/base/x509_cert_types.cc
index 174000a..5e3c3d1 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);
@@ -143,4 +143,52 @@ bool ParseCertificateDate(const base::StringPiece& raw_date,
return true;
}
+bool HashValue::Equals(const HashValue& other) const {
+ if (tag != other.tag)
+ return false;
+ switch (tag) {
+ case HASH_VALUE_SHA1:
+ return fingerprint.sha1.Equals(other.fingerprint.sha1);
+ case HASH_VALUE_SHA256:
+ return fingerprint.sha256.Equals(other.fingerprint.sha256);
+ default:
+ NOTREACHED() << "Unknown HashValueTag " << tag;
+ return false;
+ }
+}
+
+size_t HashValue::size() const {
+ switch (tag) {
+ case HASH_VALUE_SHA1:
+ return sizeof(fingerprint.sha1.data);
+ case HASH_VALUE_SHA256:
+ return sizeof(fingerprint.sha256.data);
+ default:
+ NOTREACHED() << "Unknown HashValueTag " << tag;
+ // Although this is NOTREACHED, this function might be inlined and its
+ // return value can be passed to memset as the length argument. If we
+ // returned 0 here, it might result in what appears (in some stages of
+ // compilation) to be a call to to memset with a length argument of 0,
+ // which results in a warning. Therefore, we return a dummy value
+ // here.
+ return sizeof(fingerprint.sha1.data);
+ }
+}
+
+unsigned char* HashValue::data() {
+ return const_cast<unsigned char*>(const_cast<const HashValue*>(this)->data());
+}
+
+const unsigned char* HashValue::data() const {
+ switch (tag) {
+ case HASH_VALUE_SHA1:
+ return fingerprint.sha1.data;
+ case HASH_VALUE_SHA256:
+ return fingerprint.sha256.data;
+ default:
+ NOTREACHED() << "Unknown HashValueTag " << tag;
+ return NULL;
+ }
+}
+
} // namespace net
diff --git a/net/base/x509_cert_types.h b/net/base/x509_cert_types.h
index cfde622..cebcbce 100644
--- a/net/base/x509_cert_types.h
+++ b/net/base/x509_cert_types.h
@@ -11,6 +11,7 @@
#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 +29,84 @@ 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;
+ }
+};
-typedef std::vector<Fingerprint> FingerprintVector;
+struct NET_EXPORT SHA256HashValue {
+ bool Equals(const SHA256HashValue& other) const {
+ return memcmp(data, other.data, sizeof(data)) == 0;
+ }
-class NET_EXPORT SHA1FingerprintLessThan {
+ unsigned char data[32];
+};
+
+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
+};
+
+class NET_EXPORT HashValue {
+ public:
+ explicit HashValue(HashValueTag tag) : tag(tag) {}
+ HashValue() : tag(HASH_VALUE_SHA1) {}
+
+ bool Equals(const HashValue& other) const;
+ size_t size() const;
+ unsigned char* data();
+ const unsigned char* data() const;
+
+ HashValueTag tag;
+
+ private:
+ 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();
+
+ if (lhs_size != rhs_size)
+ return lhs_size < rhs_size;
+
+ return memcmp(lhs.data(), rhs.data(), lhs_size) < 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 +183,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 ab4c5c9..c8ba0bf 100644
--- a/net/base/x509_certificate.h
+++ b/net/base/x509_certificate.h
@@ -241,10 +241,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_;
}
@@ -419,11 +419,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:
@@ -489,10 +489,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 18afa58..55c11ac 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 860cb9c..26ebb57 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 05c7794..6a897aa 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -2773,9 +2773,8 @@ 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++) {
+ for (HashValueVector::const_iterator i = side_pinned_public_keys_.begin();
+ i != side_pinned_public_keys_.end(); ++i) {
ssl_info->public_key_hashes.push_back(*i);
}
ssl_info->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 406dabf..0897217 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())
@@ -553,7 +553,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)),
@@ -567,7 +567,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 ||
@@ -1478,7 +1478,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 } };