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 |