Chromium Code Reviews| 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..6d0bbfc472b9fe570cdc795680955fa1b906807e 100644 |
| --- a/net/base/origin_bound_cert_service_unittest.cc |
| +++ b/net/base/origin_bound_cert_service_unittest.cc |
| @@ -9,7 +9,9 @@ |
| #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/asn1_util.h" |
| #include "net/base/default_origin_bound_cert_store.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/test_completion_callback.h" |
| @@ -33,53 +35,178 @@ TEST(OriginBoundCertServiceTest, CacheHit) { |
| std::string origin("https://encrypted.google.com:443"); |
| int error; |
| + std::vector<uint8> types; |
| + types.push_back(CLIENT_CERT_RSA_SIGN); |
| TestCompletionCallback callback; |
| OriginBoundCertService::RequestHandle request_handle; |
| // Asynchronous completion. |
| + SSLClientCertType 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(CLIENT_CERT_RSA_SIGN, type1); |
| EXPECT_FALSE(private_key_info1.empty()); |
| EXPECT_FALSE(der_cert1.empty()); |
| // Synchronous completion. |
| + SSLClientCertType type2; |
| + // If we request EC and RSA, should still retrieve the RSA cert. |
| + types.insert(types.begin(), CLIENT_CERT_ECDSA_SIGN); |
| 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(CLIENT_CERT_RSA_SIGN, 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. |
| + SSLClientCertType type3; |
| + types.pop_back(); // Remove CLIENT_CERT_RSA_SIGN 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(CLIENT_CERT_ECDSA_SIGN, 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. |
| + SSLClientCertType type4; |
| + types.insert(types.begin(), CLIENT_CERT_RSA_SIGN); |
| + 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(CLIENT_CERT_ECDSA_SIGN, 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()); |
| } |
| +TEST(OriginBoundCertServiceTest, UnhandledTypes) { |
|
wtc
2011/12/02 22:06:59
Nit: UnhandledTypes => UnsupportedTypes ?
mattm
2011/12/05 22:19:20
Done.
|
| + scoped_ptr<OriginBoundCertService> service( |
| + new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
| + std::string origin("https://encrypted.google.com:443"); |
| + |
| + int error; |
| + std::vector<uint8> types; |
| + TestCompletionCallback callback; |
| + OriginBoundCertService::RequestHandle request_handle; |
| + |
| + // Empty requested_types. |
| + SSLClientCertType type1; |
| + std::string private_key_info1, der_cert1; |
| + error = service->GetOriginBoundCert( |
| + origin, types, &type1, &private_key_info1, &der_cert1, |
| + callback.callback(), &request_handle); |
| + EXPECT_EQ(ERR_INVALID_ARGUMENT, error); |
| + EXPECT_TRUE(request_handle == NULL); |
| + |
| + // No supported types in requested_types. |
| + types.push_back(2); |
| + types.push_back(3); |
| + error = service->GetOriginBoundCert( |
| + origin, types, &type1, &private_key_info1, &der_cert1, |
| + callback.callback(), &request_handle); |
| + EXPECT_EQ(ERR_INVALID_ARGUMENT, error); |
| + EXPECT_TRUE(request_handle == NULL); |
| + |
| + // Supported types after unsupported ones in requested_types. |
| + types.push_back(CLIENT_CERT_ECDSA_SIGN); |
| + types.push_back(CLIENT_CERT_RSA_SIGN); |
| + // Asynchronous completion. |
| + EXPECT_EQ(0, service->cert_count()); |
| + error = service->GetOriginBoundCert( |
| + 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(CLIENT_CERT_ECDSA_SIGN, type1); |
| + EXPECT_FALSE(private_key_info1.empty()); |
| + EXPECT_FALSE(der_cert1.empty()); |
| + |
| + // Now that the cert is created, doing requests for unsupported types |
| + // shouldn't affect the created cert. |
| + // Empty requested_types. |
| + types.clear(); |
| + SSLClientCertType type2; |
| + std::string private_key_info2, der_cert2; |
| + error = service->GetOriginBoundCert( |
| + origin, types, &type2, &private_key_info2, &der_cert2, |
| + callback.callback(), &request_handle); |
| + EXPECT_EQ(ERR_INVALID_ARGUMENT, error); |
| + EXPECT_TRUE(request_handle == NULL); |
| + |
| + // No supported types in requested_types. |
| + types.push_back(2); |
| + types.push_back(3); |
| + error = service->GetOriginBoundCert( |
| + origin, types, &type2, &private_key_info2, &der_cert2, |
| + callback.callback(), &request_handle); |
| + EXPECT_EQ(ERR_INVALID_ARGUMENT, error); |
| + EXPECT_TRUE(request_handle == NULL); |
| + |
| + // If we request EC, the cert we created before should still be there. |
| + types.push_back(CLIENT_CERT_RSA_SIGN); |
| + types.push_back(CLIENT_CERT_ECDSA_SIGN); |
| + error = service->GetOriginBoundCert( |
| + 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(CLIENT_CERT_ECDSA_SIGN, type2); |
| + EXPECT_EQ(private_key_info1, private_key_info2); |
| + EXPECT_EQ(der_cert1, der_cert2); |
| +} |
| + |
| TEST(OriginBoundCertServiceTest, StoreCerts) { |
| scoped_ptr<OriginBoundCertService> service( |
| new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
| int error; |
| + std::vector<uint8> types; |
| + types.push_back(CLIENT_CERT_RSA_SIGN); |
| TestCompletionCallback callback; |
| OriginBoundCertService::RequestHandle request_handle; |
| std::string origin1("https://encrypted.google.com:443"); |
| + SSLClientCertType 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 +214,11 @@ TEST(OriginBoundCertServiceTest, StoreCerts) { |
| EXPECT_EQ(1, service->cert_count()); |
| std::string origin2("https://www.verisign.com:443"); |
| + SSLClientCertType 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 +226,12 @@ TEST(OriginBoundCertServiceTest, StoreCerts) { |
| EXPECT_EQ(2, service->cert_count()); |
| std::string origin3("https://www.twitter.com:443"); |
| + SSLClientCertType type3; |
| std::string private_key_info3, der_cert3; |
| + types[0] = CLIENT_CERT_ECDSA_SIGN; |
| 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 +244,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(CLIENT_CERT_RSA_SIGN, type1); |
| + EXPECT_EQ(CLIENT_CERT_RSA_SIGN, type2); |
| + EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type3); |
| } |
| // Tests an inflight join. |
| @@ -122,23 +255,30 @@ TEST(OriginBoundCertServiceTest, InflightJoin) { |
| new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
| std::string origin("https://encrypted.google.com:443"); |
| int error; |
| + std::vector<uint8> types; |
| + types.push_back(CLIENT_CERT_RSA_SIGN); |
| + SSLClientCertType type1; |
| std::string private_key_info1, der_cert1; |
| TestCompletionCallback callback1; |
| OriginBoundCertService::RequestHandle request_handle1; |
| + SSLClientCertType 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(), CLIENT_CERT_ECDSA_SIGN); |
| 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 +287,77 @@ TEST(OriginBoundCertServiceTest, InflightJoin) { |
| error = callback2.WaitForResult(); |
| EXPECT_EQ(OK, error); |
| + EXPECT_EQ(CLIENT_CERT_RSA_SIGN, type1); |
| + EXPECT_EQ(CLIENT_CERT_RSA_SIGN, 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<uint8> types1; |
| + types1.push_back(CLIENT_CERT_RSA_SIGN); |
| + std::vector<uint8> types2; |
| + types2.push_back(CLIENT_CERT_ECDSA_SIGN); |
| + |
| + SSLClientCertType type1; |
| + std::string private_key_info1, der_cert1; |
| + TestCompletionCallback callback1; |
| + OriginBoundCertService::RequestHandle request_handle1; |
| + |
| + SSLClientCertType 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(CLIENT_CERT_INVALID_TYPE, type1); |
| + EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type2); |
| + EXPECT_EQ(2u, service->requests()); |
| + EXPECT_EQ(0u, service->cert_store_hits()); |
| + EXPECT_EQ(1u, service->inflight_joins()); |
|
wtc
2011/12/02 22:06:59
IMPORTANT: it seems that service->inflight_joins()
mattm
2011/12/05 22:19:20
Done.
|
| +} |
| + |
| +TEST(OriginBoundCertServiceTest, ExtractValuesFromBytesRSA) { |
| + scoped_ptr<OriginBoundCertService> service( |
| + new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL))); |
| + std::string origin("https://encrypted.google.com:443"); |
| + SSLClientCertType type; |
| std::string private_key_info, der_cert; |
| int error; |
| + std::vector<uint8> types; |
| + types.push_back(CLIENT_CERT_RSA_SIGN); |
| 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 +376,60 @@ 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"); |
| + SSLClientCertType type; |
| + std::string private_key_info, der_cert; |
| + int error; |
| + std::vector<uint8> types; |
| + types.push_back(CLIENT_CERT_ECDSA_SIGN); |
| + 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); |
| + |
| + base::StringPiece spki_piece; |
| + ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(der_cert, &spki_piece)); |
| + std::vector<uint8> spki( |
| + spki_piece.data(), |
| + spki_piece.data() + spki_piece.size()); |
| + |
| + // 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"); |
| + SSLClientCertType type; |
| std::string private_key_info, der_cert; |
| int error; |
| + std::vector<uint8> types; |
| + types.push_back(CLIENT_CERT_RSA_SIGN); |
| OriginBoundCertService::RequestHandle request_handle; |
| error = service->GetOriginBoundCert(origin, |
| + types, |
| + &type, |
| &private_key_info, |
| &der_cert, |
| base::Bind(&FailTest), |
| @@ -206,6 +445,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 +455,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) |