Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(813)

Unified Diff: net/base/origin_bound_cert_service_unittest.cc

Issue 8662036: Support EC certs in OriginBoundCertService and OriginBoundCertStore. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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)

Powered by Google App Engine
This is Rietveld 408576698