Index: net/base/origin_bound_cert_service_unittest.cc |
diff --git a/net/base/origin_bound_cert_service_unittest.cc b/net/base/origin_bound_cert_service_unittest.cc |
index 3fdb443cf3cb0e77beebf9c454f2eec822ec1360..c4353c47c22455ce71de69720d1a0e14d3ec8f3b 100644 |
--- a/net/base/origin_bound_cert_service_unittest.cc |
+++ b/net/base/origin_bound_cert_service_unittest.cc |
@@ -7,8 +7,13 @@ |
#include <string> |
#include <vector> |
+#if !defined(USE_OPENSSL) |
Ryan Sleevi
2011/11/25 00:07:02
nit: Move this to the bottom of the includes ( htt
|
+#include <cert.h> |
+#endif |
+ |
#include "base/bind.h" |
#include "base/memory/scoped_ptr.h" |
+#include "crypto/ec_private_key.h" |
#include "crypto/rsa_private_key.h" |
#include "net/base/default_origin_bound_cert_store.h" |
#include "net/base/net_errors.h" |
@@ -33,37 +38,79 @@ TEST(OriginBoundCertServiceTest, CacheHit) { |
std::string origin("https://encrypted.google.com:443"); |
int error; |
+ std::vector<OriginBoundCertType> types; |
+ types.push_back(ORIGIN_BOUND_RSA_CERT); |
TestCompletionCallback callback; |
OriginBoundCertService::RequestHandle request_handle; |
// Asynchronous completion. |
+ OriginBoundCertType type1; |
std::string private_key_info1, der_cert1; |
EXPECT_EQ(0, service->cert_count()); |
error = service->GetOriginBoundCert( |
- origin, &private_key_info1, &der_cert1, callback.callback(), |
- &request_handle); |
+ origin, types, &type1, &private_key_info1, &der_cert1, |
+ callback.callback(), &request_handle); |
EXPECT_EQ(ERR_IO_PENDING, error); |
EXPECT_TRUE(request_handle != NULL); |
error = callback.WaitForResult(); |
EXPECT_EQ(OK, error); |
EXPECT_EQ(1, service->cert_count()); |
+ EXPECT_EQ(ORIGIN_BOUND_RSA_CERT, type1); |
EXPECT_FALSE(private_key_info1.empty()); |
EXPECT_FALSE(der_cert1.empty()); |
// Synchronous completion. |
+ OriginBoundCertType type2; |
+ // If we request EC and RSA, should still retrieve the RSA cert. |
+ types.insert(types.begin(), ORIGIN_BOUND_EC_CERT); |
std::string private_key_info2, der_cert2; |
error = service->GetOriginBoundCert( |
- origin, &private_key_info2, &der_cert2, callback.callback(), |
- &request_handle); |
+ origin, types, &type2, &private_key_info2, &der_cert2, |
+ callback.callback(), &request_handle); |
EXPECT_TRUE(request_handle == NULL); |
EXPECT_EQ(OK, error); |
EXPECT_EQ(1, service->cert_count()); |
- |
+ EXPECT_EQ(ORIGIN_BOUND_RSA_CERT, type2); |
EXPECT_EQ(private_key_info1, private_key_info2); |
EXPECT_EQ(der_cert1, der_cert2); |
- EXPECT_EQ(2u, service->requests()); |
- EXPECT_EQ(1u, service->cert_store_hits()); |
+ // Request only EC. Should generate a new EC cert and discard the old RSA |
+ // cert. |
+ OriginBoundCertType type3; |
+ types.pop_back(); // Remove ORIGIN_BOUND_RSA_CERT from requested types. |
+ std::string private_key_info3, der_cert3; |
+ EXPECT_EQ(1, service->cert_count()); |
+ error = service->GetOriginBoundCert( |
+ origin, types, &type3, &private_key_info3, &der_cert3, |
+ callback.callback(), &request_handle); |
+ EXPECT_EQ(ERR_IO_PENDING, error); |
+ EXPECT_TRUE(request_handle != NULL); |
+ error = callback.WaitForResult(); |
+ EXPECT_EQ(OK, error); |
+ EXPECT_EQ(1, service->cert_count()); |
+ EXPECT_EQ(ORIGIN_BOUND_EC_CERT, type3); |
+ EXPECT_FALSE(private_key_info1.empty()); |
+ EXPECT_FALSE(der_cert1.empty()); |
+ EXPECT_NE(private_key_info1, private_key_info3); |
+ EXPECT_NE(der_cert1, der_cert3); |
+ |
+ // Synchronous completion. |
+ // If we request RSA and EC, should now retrieve the EC cert. |
+ OriginBoundCertType type4; |
+ types.insert(types.begin(), ORIGIN_BOUND_RSA_CERT); |
+ std::string private_key_info4, der_cert4; |
+ error = service->GetOriginBoundCert( |
+ origin, types, &type4, &private_key_info4, &der_cert4, |
+ callback.callback(), &request_handle); |
+ EXPECT_TRUE(request_handle == NULL); |
+ EXPECT_EQ(OK, error); |
+ EXPECT_EQ(1, service->cert_count()); |
+ EXPECT_EQ(ORIGIN_BOUND_EC_CERT, type4); |
+ EXPECT_EQ(private_key_info3, private_key_info4); |
+ EXPECT_EQ(der_cert3, der_cert4); |
+ |
+ EXPECT_EQ(4u, service->requests()); |
+ EXPECT_EQ(2u, service->cert_store_hits()); |
EXPECT_EQ(0u, service->inflight_joins()); |
} |
@@ -71,15 +118,18 @@ TEST(OriginBoundCertServiceTest, StoreCerts) { |
scoped_ptr<OriginBoundCertService> service( |
new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
int error; |
+ std::vector<OriginBoundCertType> types; |
+ types.push_back(ORIGIN_BOUND_RSA_CERT); |
TestCompletionCallback callback; |
OriginBoundCertService::RequestHandle request_handle; |
std::string origin1("https://encrypted.google.com:443"); |
+ OriginBoundCertType type1; |
std::string private_key_info1, der_cert1; |
EXPECT_EQ(0, service->cert_count()); |
error = service->GetOriginBoundCert( |
- origin1, &private_key_info1, &der_cert1, callback.callback(), |
- &request_handle); |
+ origin1, types, &type1, &private_key_info1, &der_cert1, |
+ callback.callback(), &request_handle); |
EXPECT_EQ(ERR_IO_PENDING, error); |
EXPECT_TRUE(request_handle != NULL); |
error = callback.WaitForResult(); |
@@ -87,10 +137,11 @@ TEST(OriginBoundCertServiceTest, StoreCerts) { |
EXPECT_EQ(1, service->cert_count()); |
std::string origin2("https://www.verisign.com:443"); |
+ OriginBoundCertType type2; |
std::string private_key_info2, der_cert2; |
error = service->GetOriginBoundCert( |
- origin2, &private_key_info2, &der_cert2, callback.callback(), |
- &request_handle); |
+ origin2, types, &type2, &private_key_info2, &der_cert2, |
+ callback.callback(), &request_handle); |
EXPECT_EQ(ERR_IO_PENDING, error); |
EXPECT_TRUE(request_handle != NULL); |
error = callback.WaitForResult(); |
@@ -98,10 +149,12 @@ TEST(OriginBoundCertServiceTest, StoreCerts) { |
EXPECT_EQ(2, service->cert_count()); |
std::string origin3("https://www.twitter.com:443"); |
+ OriginBoundCertType type3; |
std::string private_key_info3, der_cert3; |
+ types[0] = ORIGIN_BOUND_EC_CERT; |
error = service->GetOriginBoundCert( |
- origin3, &private_key_info3, &der_cert3, callback.callback(), |
- &request_handle); |
+ origin3, types, &type3, &private_key_info3, &der_cert3, |
+ callback.callback(), &request_handle); |
EXPECT_EQ(ERR_IO_PENDING, error); |
EXPECT_TRUE(request_handle != NULL); |
error = callback.WaitForResult(); |
@@ -114,6 +167,9 @@ TEST(OriginBoundCertServiceTest, StoreCerts) { |
EXPECT_NE(der_cert1, der_cert3); |
EXPECT_NE(private_key_info2, private_key_info3); |
EXPECT_NE(der_cert2, der_cert3); |
+ EXPECT_EQ(ORIGIN_BOUND_RSA_CERT, type1); |
+ EXPECT_EQ(ORIGIN_BOUND_RSA_CERT, type2); |
+ EXPECT_EQ(ORIGIN_BOUND_EC_CERT, type3); |
} |
// Tests an inflight join. |
@@ -122,23 +178,30 @@ TEST(OriginBoundCertServiceTest, InflightJoin) { |
new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
std::string origin("https://encrypted.google.com:443"); |
int error; |
+ std::vector<OriginBoundCertType> types; |
+ types.push_back(ORIGIN_BOUND_RSA_CERT); |
+ OriginBoundCertType type1; |
std::string private_key_info1, der_cert1; |
TestCompletionCallback callback1; |
OriginBoundCertService::RequestHandle request_handle1; |
+ OriginBoundCertType type2; |
std::string private_key_info2, der_cert2; |
TestCompletionCallback callback2; |
OriginBoundCertService::RequestHandle request_handle2; |
error = service->GetOriginBoundCert( |
- origin, &private_key_info1, &der_cert1, callback1.callback(), |
- &request_handle1); |
+ origin, types, &type1, &private_key_info1, &der_cert1, |
+ callback1.callback(), &request_handle1); |
EXPECT_EQ(ERR_IO_PENDING, error); |
EXPECT_TRUE(request_handle1 != NULL); |
+ // If we request EC and RSA in the 2nd request, should still join with the |
+ // original request. |
+ types.insert(types.begin(), ORIGIN_BOUND_EC_CERT); |
error = service->GetOriginBoundCert( |
- origin, &private_key_info2, &der_cert2, callback2.callback(), |
- &request_handle2); |
+ origin, types, &type2, &private_key_info2, &der_cert2, |
+ callback2.callback(), &request_handle2); |
EXPECT_EQ(ERR_IO_PENDING, error); |
EXPECT_TRUE(request_handle2 != NULL); |
@@ -147,22 +210,77 @@ TEST(OriginBoundCertServiceTest, InflightJoin) { |
error = callback2.WaitForResult(); |
EXPECT_EQ(OK, error); |
+ EXPECT_EQ(ORIGIN_BOUND_RSA_CERT, type1); |
+ EXPECT_EQ(ORIGIN_BOUND_RSA_CERT, type2); |
EXPECT_EQ(2u, service->requests()); |
EXPECT_EQ(0u, service->cert_store_hits()); |
EXPECT_EQ(1u, service->inflight_joins()); |
} |
-TEST(OriginBoundCertServiceTest, ExtractValuesFromBytes) { |
+// Tests an inflight join with mismatching request types. |
+TEST(OriginBoundCertServiceTest, InflightJoinCancel) { |
scoped_ptr<OriginBoundCertService> service( |
new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
std::string origin("https://encrypted.google.com:443"); |
+ int error; |
+ std::vector<OriginBoundCertType> types1; |
+ types1.push_back(ORIGIN_BOUND_RSA_CERT); |
+ std::vector<OriginBoundCertType> types2; |
+ types2.push_back(ORIGIN_BOUND_EC_CERT); |
+ |
+ OriginBoundCertType type1; |
+ std::string private_key_info1, der_cert1; |
+ TestCompletionCallback callback1; |
+ OriginBoundCertService::RequestHandle request_handle1; |
+ |
+ OriginBoundCertType type2; |
+ std::string private_key_info2, der_cert2; |
+ TestCompletionCallback callback2; |
+ OriginBoundCertService::RequestHandle request_handle2; |
+ |
+ error = service->GetOriginBoundCert( |
+ origin, types1, &type1, &private_key_info1, &der_cert1, |
+ callback1.callback(), &request_handle1); |
+ EXPECT_EQ(ERR_IO_PENDING, error); |
+ EXPECT_TRUE(request_handle1 != NULL); |
+ // If we request only EC in the 2nd request, it should cancel the original |
+ // request. |
+ error = service->GetOriginBoundCert( |
+ origin, types2, &type2, &private_key_info2, &der_cert2, |
+ callback2.callback(), &request_handle2); |
+ EXPECT_EQ(ERR_IO_PENDING, error); |
+ EXPECT_TRUE(request_handle2 != NULL); |
+ |
+ error = callback1.WaitForResult(); |
+ EXPECT_EQ(ERR_ABORTED, error); |
+ error = callback2.WaitForResult(); |
+ EXPECT_EQ(OK, error); |
+ |
+ EXPECT_TRUE(private_key_info1.empty()); |
+ EXPECT_TRUE(der_cert1.empty()); |
+ EXPECT_FALSE(private_key_info2.empty()); |
+ EXPECT_FALSE(der_cert2.empty()); |
+ EXPECT_EQ(ORIGIN_BOUND_INVALID_CERT_TYPE, type1); |
+ EXPECT_EQ(ORIGIN_BOUND_EC_CERT, type2); |
+ EXPECT_EQ(2u, service->requests()); |
+ EXPECT_EQ(0u, service->cert_store_hits()); |
+ EXPECT_EQ(1u, service->inflight_joins()); |
+} |
+ |
+TEST(OriginBoundCertServiceTest, ExtractValuesFromBytesRSA) { |
+ scoped_ptr<OriginBoundCertService> service( |
+ new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
+ std::string origin("https://encrypted.google.com:443"); |
+ OriginBoundCertType type; |
std::string private_key_info, der_cert; |
int error; |
+ std::vector<OriginBoundCertType> types; |
+ types.push_back(ORIGIN_BOUND_RSA_CERT); |
TestCompletionCallback callback; |
OriginBoundCertService::RequestHandle request_handle; |
error = service->GetOriginBoundCert( |
- origin, &private_key_info, &der_cert, callback.callback(), |
+ origin, types, &type, &private_key_info, &der_cert, callback.callback(), |
&request_handle); |
EXPECT_EQ(ERR_IO_PENDING, error); |
EXPECT_TRUE(request_handle != NULL); |
@@ -181,16 +299,77 @@ TEST(OriginBoundCertServiceTest, ExtractValuesFromBytes) { |
EXPECT_TRUE(x509cert != NULL); |
} |
+TEST(OriginBoundCertServiceTest, ExtractValuesFromBytesEC) { |
+ scoped_ptr<OriginBoundCertService> service( |
+ new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
+ std::string origin("https://encrypted.google.com:443"); |
+ OriginBoundCertType type; |
+ std::string private_key_info, der_cert; |
+ int error; |
+ std::vector<OriginBoundCertType> types; |
+ types.push_back(ORIGIN_BOUND_EC_CERT); |
+ TestCompletionCallback callback; |
+ OriginBoundCertService::RequestHandle request_handle; |
+ |
+ error = service->GetOriginBoundCert( |
+ origin, types, &type, &private_key_info, &der_cert, callback.callback(), |
+ &request_handle); |
+ EXPECT_EQ(ERR_IO_PENDING, error); |
+ EXPECT_TRUE(request_handle != NULL); |
+ error = callback.WaitForResult(); |
+ EXPECT_EQ(OK, error); |
+ |
+#if !defined(USE_OPENSSL) |
+ // The SubjectPublicKeyInfo can be extracted from the certificate data, so the |
+ // OriginBoundCertService doesn't store it independently. It takes a little |
+ // work to extract so we use some NSS functions here to do it. |
wtc
2011/11/30 23:29:04
I seem to remember agl wrote some code to extract
Ryan Sleevi
2011/11/30 23:35:48
asn1::ExtractSPKIFromDERCert()
Lives in net/base/
mattm
2011/12/02 01:55:59
Done.
mattm
2011/12/02 01:55:59
Thanks!
|
+ SECItem cert_item; |
+ cert_item.data = (unsigned char*) der_cert.data(); |
+ cert_item.len = der_cert.size(); |
+ CERTCertificate* cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), |
+ &cert_item, |
+ NULL, |
+ PR_FALSE, |
+ PR_TRUE); |
+ ASSERT_TRUE(cert); |
+ |
+ std::vector<uint8> spki( |
+ cert->derPublicKey.data, |
+ cert->derPublicKey.data + cert->derPublicKey.len); |
+ |
+ CERT_DestroyCertificate(cert); |
+#else |
+#error "not implemented" |
Ryan Sleevi
2011/11/25 00:07:02
Is this necessary, given the #if !defined(USE_OPEN
mattm
2011/12/02 01:55:59
Nope, it was more of a documentation thing (like,
|
+#endif |
+ |
+ // Check that we can retrieve the key from the bytes. |
+ std::vector<uint8> key_vec(private_key_info.begin(), private_key_info.end()); |
+ scoped_ptr<crypto::ECPrivateKey> private_key( |
+ crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( |
+ OriginBoundCertService::kEPKIPassword, key_vec, spki)); |
+ EXPECT_TRUE(private_key != NULL); |
+ |
+ // Check that we can retrieve the cert from the bytes. |
+ scoped_refptr<X509Certificate> x509cert( |
+ X509Certificate::CreateFromBytes(der_cert.data(), der_cert.size())); |
+ EXPECT_TRUE(x509cert != NULL); |
+} |
+ |
// Tests that the callback of a canceled request is never made. |
TEST(OriginBoundCertServiceTest, CancelRequest) { |
scoped_ptr<OriginBoundCertService> service( |
new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
std::string origin("https://encrypted.google.com:443"); |
+ OriginBoundCertType type; |
std::string private_key_info, der_cert; |
int error; |
+ std::vector<OriginBoundCertType> types; |
+ types.push_back(ORIGIN_BOUND_RSA_CERT); |
OriginBoundCertService::RequestHandle request_handle; |
error = service->GetOriginBoundCert(origin, |
+ types, |
+ &type, |
&private_key_info, |
&der_cert, |
base::Bind(&FailTest), |
@@ -206,6 +385,8 @@ TEST(OriginBoundCertServiceTest, CancelRequest) { |
for (int i = 0; i < 5; ++i) { |
error = service->GetOriginBoundCert( |
"https://encrypted.google.com:" + std::string(1, (char) ('1' + i)), |
+ types, |
+ &type, |
&private_key_info, |
&der_cert, |
callback.callback(), |
@@ -214,6 +395,10 @@ TEST(OriginBoundCertServiceTest, CancelRequest) { |
EXPECT_TRUE(request_handle != NULL); |
error = callback.WaitForResult(); |
} |
+ |
+ // Even though the original request was cancelled, the service will still |
+ // store the result, it just doesn't call the callback. |
+ EXPECT_EQ(6, service->cert_count()); |
} |
#endif // !defined(USE_OPENSSL) |