| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/ssl/openssl_client_key_store.h" | 5 #include "net/ssl/openssl_client_key_store.h" |
| 6 | 6 |
| 7 #include "base/logging.h" |
| 7 #include "base/memory/ref_counted.h" | 8 #include "base/memory/ref_counted.h" |
| 8 #include "crypto/scoped_openssl_types.h" | 9 #include "crypto/scoped_openssl_types.h" |
| 10 #include "net/ssl/ssl_private_key.h" |
| 9 #include "net/test/cert_test_util.h" | 11 #include "net/test/cert_test_util.h" |
| 10 #include "net/test/test_data_directory.h" | 12 #include "net/test/test_data_directory.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 12 | 14 |
| 13 namespace net { | 15 namespace net { |
| 14 | 16 |
| 15 namespace { | 17 namespace { |
| 16 | 18 |
| 17 // Return the internal reference count of a given EVP_PKEY. | |
| 18 int EVP_PKEY_get_refcount(EVP_PKEY* pkey) { | |
| 19 return pkey->references; | |
| 20 } | |
| 21 | |
| 22 // A common test class to ensure that the store is flushed after | 19 // A common test class to ensure that the store is flushed after |
| 23 // each test. | 20 // each test. |
| 24 class OpenSSLClientKeyStoreTest : public ::testing::Test { | 21 class OpenSSLClientKeyStoreTest : public ::testing::Test { |
| 25 public: | 22 public: |
| 26 OpenSSLClientKeyStoreTest() | 23 OpenSSLClientKeyStoreTest() |
| 27 : store_(OpenSSLClientKeyStore::GetInstance()) { | 24 : store_(OpenSSLClientKeyStore::GetInstance()) { |
| 28 } | 25 } |
| 29 | 26 |
| 30 ~OpenSSLClientKeyStoreTest() override { | 27 ~OpenSSLClientKeyStoreTest() override { |
| 31 if (store_) | 28 if (store_) |
| 32 store_->Flush(); | 29 store_->Flush(); |
| 33 } | 30 } |
| 34 | 31 |
| 35 protected: | 32 protected: |
| 36 OpenSSLClientKeyStore* store_; | 33 OpenSSLClientKeyStore* store_; |
| 37 }; | 34 }; |
| 38 | 35 |
| 36 class MockSSLPrivateKey : public SSLPrivateKey { |
| 37 public: |
| 38 MockSSLPrivateKey() : on_destroyed_(nullptr) {} |
| 39 |
| 40 void set_on_destroyed(bool* on_destroyed) { on_destroyed_ = on_destroyed; } |
| 41 |
| 42 Type GetType() override { |
| 43 NOTREACHED(); |
| 44 return Type::RSA; |
| 45 } |
| 46 |
| 47 std::vector<Hash> GetDigestPreferences() override { |
| 48 NOTREACHED(); |
| 49 return {}; |
| 50 } |
| 51 |
| 52 size_t GetMaxSignatureLengthInBytes() override { |
| 53 NOTREACHED(); |
| 54 return 0; |
| 55 } |
| 56 |
| 57 void SignDigest(Hash hash, |
| 58 const base::StringPiece& input, |
| 59 const SignCallback& callback) override { |
| 60 NOTREACHED(); |
| 61 } |
| 62 |
| 63 private: |
| 64 ~MockSSLPrivateKey() override { |
| 65 if (on_destroyed_) |
| 66 *on_destroyed_ = true; |
| 67 } |
| 68 |
| 69 bool* on_destroyed_; |
| 70 }; |
| 71 |
| 39 // Check that GetInstance() returns non-null | 72 // Check that GetInstance() returns non-null |
| 40 TEST_F(OpenSSLClientKeyStoreTest, GetInstance) { | 73 TEST_F(OpenSSLClientKeyStoreTest, GetInstance) { |
| 41 ASSERT_TRUE(store_); | 74 ASSERT_TRUE(store_); |
| 42 } | 75 } |
| 43 | 76 |
| 44 // Check that Flush() works correctly. | 77 // Check that Flush() works correctly. |
| 45 TEST_F(OpenSSLClientKeyStoreTest, Flush) { | 78 TEST_F(OpenSSLClientKeyStoreTest, Flush) { |
| 46 ASSERT_TRUE(store_); | 79 ASSERT_TRUE(store_); |
| 47 | 80 |
| 48 scoped_refptr<X509Certificate> cert_1( | 81 scoped_refptr<X509Certificate> cert_1( |
| 49 ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem")); | 82 ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem")); |
| 50 ASSERT_TRUE(cert_1.get()); | 83 ASSERT_TRUE(cert_1); |
| 51 | 84 |
| 52 crypto::ScopedEVP_PKEY priv_key(EVP_PKEY_new()); | 85 EXPECT_TRUE(store_->RecordClientCertPrivateKey( |
| 53 ASSERT_TRUE(priv_key.get()); | 86 cert_1.get(), make_scoped_refptr(new MockSSLPrivateKey))); |
| 54 | |
| 55 ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), | |
| 56 priv_key.get())); | |
| 57 | 87 |
| 58 store_->Flush(); | 88 store_->Flush(); |
| 59 | 89 |
| 60 // Retrieve the private key. This should fail because the store | 90 // Retrieve the private key. This should fail because the store |
| 61 // was flushed. | 91 // was flushed. |
| 62 crypto::ScopedEVP_PKEY pkey = store_->FetchClientCertPrivateKey(cert_1.get()); | 92 EXPECT_FALSE(store_->FetchClientCertPrivateKey(cert_1.get())); |
| 63 ASSERT_FALSE(pkey.get()); | |
| 64 } | 93 } |
| 65 | 94 |
| 66 // Check that trying to retrieve the private key of an unknown certificate | 95 // Check that trying to retrieve the private key of an unknown certificate |
| 67 // simply fails by returning null. | 96 // simply fails by returning null. |
| 68 TEST_F(OpenSSLClientKeyStoreTest, FetchEmptyPrivateKey) { | 97 TEST_F(OpenSSLClientKeyStoreTest, FetchEmptyPrivateKey) { |
| 69 ASSERT_TRUE(store_); | 98 ASSERT_TRUE(store_); |
| 70 | 99 |
| 71 scoped_refptr<X509Certificate> cert_1( | 100 scoped_refptr<X509Certificate> cert_1( |
| 72 ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem")); | 101 ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem")); |
| 73 ASSERT_TRUE(cert_1.get()); | 102 ASSERT_TRUE(cert_1); |
| 74 | 103 |
| 75 // Retrieve the private key now. This should fail because it was | 104 // Retrieve the private key now. This should fail because it was |
| 76 // never recorded in the store. | 105 // never recorded in the store. |
| 77 crypto::ScopedEVP_PKEY pkey = store_->FetchClientCertPrivateKey(cert_1.get()); | 106 EXPECT_FALSE(store_->FetchClientCertPrivateKey(cert_1.get())); |
| 78 ASSERT_FALSE(pkey.get()); | |
| 79 } | 107 } |
| 80 | 108 |
| 81 // Check that any private key recorded through RecordClientCertPrivateKey | 109 // Check that any private key recorded through RecordClientCertPrivateKey |
| 82 // can be retrieved with FetchClientCertPrivateKey. | 110 // can be retrieved with FetchClientCertPrivateKey. |
| 83 TEST_F(OpenSSLClientKeyStoreTest, RecordAndFetchPrivateKey) { | 111 TEST_F(OpenSSLClientKeyStoreTest, RecordAndFetchPrivateKey) { |
| 84 ASSERT_TRUE(store_); | 112 ASSERT_TRUE(store_); |
| 85 | 113 |
| 86 // Any certificate / key pair will do, the store is not supposed to | 114 // Any certificate / key pair will do, the store is not supposed to |
| 87 // check that the private and certificate public keys match. This is | 115 // check that the private and certificate public keys match. This is |
| 88 // by design since the private EVP_PKEY could be a wrapper around a | 116 // by design since the private EVP_PKEY could be a wrapper around a |
| 89 // JNI reference, with no way to access the real private key bits. | 117 // JNI reference, with no way to access the real private key bits. |
| 90 scoped_refptr<X509Certificate> cert_1( | 118 scoped_refptr<X509Certificate> cert_1( |
| 91 ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem")); | 119 ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem")); |
| 92 ASSERT_TRUE(cert_1.get()); | 120 ASSERT_TRUE(cert_1); |
| 93 | 121 |
| 94 crypto::ScopedEVP_PKEY priv_key(EVP_PKEY_new()); | 122 bool on_destroyed = false; |
| 95 ASSERT_TRUE(priv_key.get()); | 123 scoped_refptr<MockSSLPrivateKey> priv_key(new MockSSLPrivateKey); |
| 96 ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key.get())); | 124 priv_key->set_on_destroyed(&on_destroyed); |
| 97 | 125 |
| 98 // Add the key a first time, this should increment its reference count. | 126 // Add a key twice. |
| 99 ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), | 127 EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), priv_key)); |
| 100 priv_key.get())); | 128 EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), priv_key)); |
| 101 ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get())); | |
| 102 | 129 |
| 103 // Two successive calls with the same certificate / private key shall | 130 // Retrieve the private key. |
| 104 // also succeed, but the key's reference count should not be incremented. | 131 scoped_refptr<SSLPrivateKey> pkey2 = |
| 105 ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), | 132 store_->FetchClientCertPrivateKey(cert_1.get()); |
| 106 priv_key.get())); | 133 EXPECT_EQ(pkey2.get(), priv_key.get()); |
| 107 ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get())); | |
| 108 | 134 |
| 109 // Retrieve the private key. This should increment the private key's | 135 // Flush the key store and release all references. At this point, the private |
| 110 // reference count. | 136 // key should be cleanly destroyed. |
| 111 crypto::ScopedEVP_PKEY pkey2 = | |
| 112 store_->FetchClientCertPrivateKey(cert_1.get()); | |
| 113 ASSERT_EQ(pkey2.get(), priv_key.get()); | |
| 114 ASSERT_EQ(3, EVP_PKEY_get_refcount(priv_key.get())); | |
| 115 | |
| 116 // Flush the store explicitely, this should decrement the private | |
| 117 // key's reference count. | |
| 118 store_->Flush(); | 137 store_->Flush(); |
| 119 ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get())); | 138 priv_key = nullptr; |
| 139 pkey2 = nullptr; |
| 140 EXPECT_TRUE(on_destroyed); |
| 120 } | 141 } |
| 121 | 142 |
| 122 // Same test, but with two certificates / private keys. | 143 // Same test, but with two certificates / private keys. |
| 123 TEST_F(OpenSSLClientKeyStoreTest, RecordAndFetchTwoPrivateKeys) { | 144 TEST_F(OpenSSLClientKeyStoreTest, RecordAndFetchTwoPrivateKeys) { |
| 124 scoped_refptr<X509Certificate> cert_1( | 145 scoped_refptr<X509Certificate> cert_1( |
| 125 ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem")); | 146 ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem")); |
| 126 ASSERT_TRUE(cert_1.get()); | 147 ASSERT_TRUE(cert_1); |
| 127 | 148 |
| 128 scoped_refptr<X509Certificate> cert_2( | 149 scoped_refptr<X509Certificate> cert_2( |
| 129 ImportCertFromFile(GetTestCertsDirectory(), "client_2.pem")); | 150 ImportCertFromFile(GetTestCertsDirectory(), "client_2.pem")); |
| 130 ASSERT_TRUE(cert_2.get()); | 151 ASSERT_TRUE(cert_2); |
| 131 | 152 |
| 132 crypto::ScopedEVP_PKEY priv_key1(EVP_PKEY_new()); | 153 scoped_refptr<SSLPrivateKey> priv_key1(new MockSSLPrivateKey); |
| 133 ASSERT_TRUE(priv_key1.get()); | 154 scoped_refptr<SSLPrivateKey> priv_key2(new MockSSLPrivateKey); |
| 134 ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key1.get())); | |
| 135 | 155 |
| 136 crypto::ScopedEVP_PKEY priv_key2(EVP_PKEY_new()); | 156 EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), priv_key1)); |
| 137 ASSERT_TRUE(priv_key2.get()); | 157 EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_2.get(), priv_key2)); |
| 138 ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key2.get())); | |
| 139 | 158 |
| 140 ASSERT_NE(priv_key1.get(), priv_key2.get()); | 159 scoped_refptr<SSLPrivateKey> fetch_key1 = |
| 141 | |
| 142 // Add the key a first time, this shall succeed, and increment the | |
| 143 // reference count. | |
| 144 EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), | |
| 145 priv_key1.get())); | |
| 146 EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_2.get(), | |
| 147 priv_key2.get())); | |
| 148 EXPECT_EQ(2, EVP_PKEY_get_refcount(priv_key1.get())); | |
| 149 EXPECT_EQ(2, EVP_PKEY_get_refcount(priv_key2.get())); | |
| 150 | |
| 151 // Retrieve the private key now. This shall succeed and increment | |
| 152 // the private key's reference count. | |
| 153 crypto::ScopedEVP_PKEY fetch_key1 = | |
| 154 store_->FetchClientCertPrivateKey(cert_1.get()); | 160 store_->FetchClientCertPrivateKey(cert_1.get()); |
| 155 crypto::ScopedEVP_PKEY fetch_key2 = | 161 scoped_refptr<SSLPrivateKey> fetch_key2 = |
| 156 store_->FetchClientCertPrivateKey(cert_2.get()); | 162 store_->FetchClientCertPrivateKey(cert_2.get()); |
| 157 | 163 |
| 158 EXPECT_TRUE(fetch_key1.get()); | 164 EXPECT_TRUE(fetch_key1); |
| 159 EXPECT_TRUE(fetch_key2.get()); | 165 EXPECT_TRUE(fetch_key2); |
| 160 | 166 |
| 161 EXPECT_EQ(fetch_key1.get(), priv_key1.get()); | 167 EXPECT_EQ(fetch_key1.get(), priv_key1.get()); |
| 162 EXPECT_EQ(fetch_key2.get(), priv_key2.get()); | 168 EXPECT_EQ(fetch_key2.get(), priv_key2.get()); |
| 163 | |
| 164 EXPECT_EQ(3, EVP_PKEY_get_refcount(priv_key1.get())); | |
| 165 EXPECT_EQ(3, EVP_PKEY_get_refcount(priv_key2.get())); | |
| 166 } | 169 } |
| 167 | 170 |
| 168 } // namespace | 171 } // namespace |
| 169 } // namespace net | 172 } // namespace net |
| OLD | NEW |