1 // Copyright 2009 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/ssl/ssl_client_auth_cache.h"
6
7 #include <utility>
8
9 #include "base/functional/callback.h"
10 #include "base/time/time.h"
11 #include "net/cert/x509_certificate.h"
12 #include "net/ssl/openssl_private_key.h"
13 #include "net/ssl/ssl_private_key.h"
14 #include "net/test/cert_test_util.h"
15 #include "net/test/test_data_directory.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/boringssl/src/include/openssl/evp.h"
18
19 namespace net {
20
21 namespace {
MakeMockKey()22 scoped_refptr<SSLPrivateKey> MakeMockKey() {
23 bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
24 return WrapOpenSSLPrivateKey(std::move(pkey));
25 }
26 } // namespace
27
TEST(SSLClientAuthCacheTest,LookupAddRemove)28 TEST(SSLClientAuthCacheTest, LookupAddRemove) {
29 SSLClientAuthCache cache;
30
31 HostPortPair server1("foo1", 443);
32 scoped_refptr<X509Certificate> cert1(
33 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
34 ASSERT_TRUE(cert1);
35
36 HostPortPair server2("foo2", 443);
37 scoped_refptr<X509Certificate> cert2(
38 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"));
39 ASSERT_TRUE(cert2);
40
41 HostPortPair server3("foo3", 443);
42 scoped_refptr<X509Certificate> cert3(
43 ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"));
44 ASSERT_TRUE(cert3);
45
46 scoped_refptr<X509Certificate> cached_cert;
47 scoped_refptr<SSLPrivateKey> cached_pkey;
48 // Lookup non-existent client certificate.
49 cached_cert = nullptr;
50 EXPECT_FALSE(cache.Lookup(server1, &cached_cert, &cached_pkey));
51
52 // Add client certificate for server1.
53 cache.Add(server1, cert1.get(), MakeMockKey());
54 cached_cert = nullptr;
55 EXPECT_TRUE(cache.Lookup(server1, &cached_cert, &cached_pkey));
56 EXPECT_EQ(cert1, cached_cert);
57
58 // Add client certificate for server2.
59 cache.Add(server2, cert2.get(), MakeMockKey());
60 cached_cert = nullptr;
61 EXPECT_TRUE(cache.Lookup(server1, &cached_cert, &cached_pkey));
62 EXPECT_EQ(cert1.get(), cached_cert.get());
63 cached_cert = nullptr;
64 EXPECT_TRUE(cache.Lookup(server2, &cached_cert, &cached_pkey));
65 EXPECT_EQ(cert2, cached_cert);
66
67 // Overwrite the client certificate for server1.
68 cache.Add(server1, cert3.get(), MakeMockKey());
69 cached_cert = nullptr;
70 EXPECT_TRUE(cache.Lookup(server1, &cached_cert, &cached_pkey));
71 EXPECT_EQ(cert3, cached_cert);
72 cached_cert = nullptr;
73 EXPECT_TRUE(cache.Lookup(server2, &cached_cert, &cached_pkey));
74 EXPECT_EQ(cert2, cached_cert);
75
76 // Remove client certificate of server1.
77 cache.Remove(server1);
78 cached_cert = nullptr;
79 EXPECT_FALSE(cache.Lookup(server1, &cached_cert, &cached_pkey));
80 cached_cert = nullptr;
81 EXPECT_TRUE(cache.Lookup(server2, &cached_cert, &cached_pkey));
82 EXPECT_EQ(cert2, cached_cert);
83
84 // Remove non-existent client certificate.
85 cache.Remove(server1);
86 cached_cert = nullptr;
87 EXPECT_FALSE(cache.Lookup(server1, &cached_cert, &cached_pkey));
88 cached_cert = nullptr;
89 EXPECT_TRUE(cache.Lookup(server2, &cached_cert, &cached_pkey));
90 EXPECT_EQ(cert2, cached_cert);
91 }
92
93 // Check that if the server differs only by port number, it is considered
94 // a separate server.
TEST(SSLClientAuthCacheTest,LookupWithPort)95 TEST(SSLClientAuthCacheTest, LookupWithPort) {
96 SSLClientAuthCache cache;
97
98 HostPortPair server1("foo", 443);
99 scoped_refptr<X509Certificate> cert1(
100 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
101 ASSERT_TRUE(cert1);
102
103 HostPortPair server2("foo", 8443);
104 scoped_refptr<X509Certificate> cert2(
105 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"));
106 ASSERT_TRUE(cert2);
107
108 cache.Add(server1, cert1.get(), MakeMockKey());
109 cache.Add(server2, cert2.get(), MakeMockKey());
110
111 scoped_refptr<X509Certificate> cached_cert;
112 scoped_refptr<SSLPrivateKey> cached_pkey;
113 EXPECT_TRUE(cache.Lookup(server1, &cached_cert, &cached_pkey));
114 EXPECT_EQ(cert1.get(), cached_cert.get());
115 EXPECT_TRUE(cache.Lookup(server2, &cached_cert, &cached_pkey));
116 EXPECT_EQ(cert2.get(), cached_cert.get());
117 }
118
119 // Check that the a nullptr certificate, indicating the user has declined to
120 // send a certificate, is properly cached.
TEST(SSLClientAuthCacheTest,LookupNullPreference)121 TEST(SSLClientAuthCacheTest, LookupNullPreference) {
122 SSLClientAuthCache cache;
123
124 HostPortPair server1("foo", 443);
125 scoped_refptr<X509Certificate> cert1(
126 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
127 ASSERT_TRUE(cert1);
128
129 cache.Add(server1, nullptr, MakeMockKey());
130
131 scoped_refptr<X509Certificate> cached_cert(cert1);
132 scoped_refptr<SSLPrivateKey> cached_pkey;
133 // Make sure that |cached_cert| is updated to nullptr, indicating the user
134 // declined to send a certificate to |server1|.
135 EXPECT_TRUE(cache.Lookup(server1, &cached_cert, &cached_pkey));
136 EXPECT_EQ(nullptr, cached_cert.get());
137
138 // Remove the existing cached certificate.
139 cache.Remove(server1);
140 cached_cert = nullptr;
141 EXPECT_FALSE(cache.Lookup(server1, &cached_cert, &cached_pkey));
142
143 // Add a new preference for a specific certificate.
144 cache.Add(server1, cert1.get(), MakeMockKey());
145 cached_cert = nullptr;
146 EXPECT_TRUE(cache.Lookup(server1, &cached_cert, &cached_pkey));
147 EXPECT_EQ(cert1, cached_cert);
148
149 // Replace the specific preference with a nullptr certificate.
150 cache.Add(server1, nullptr, MakeMockKey());
151 cached_cert = nullptr;
152 EXPECT_TRUE(cache.Lookup(server1, &cached_cert, &cached_pkey));
153 EXPECT_EQ(nullptr, cached_cert.get());
154 }
155
156 // Check that the Clear() method removes all cache entries.
TEST(SSLClientAuthCacheTest,Clear)157 TEST(SSLClientAuthCacheTest, Clear) {
158 SSLClientAuthCache cache;
159
160 HostPortPair server1("foo", 443);
161 scoped_refptr<X509Certificate> cert1(
162 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
163 ASSERT_TRUE(cert1);
164
165 cache.Add(server1, cert1.get(), MakeMockKey());
166
167 HostPortPair server2("foo2", 443);
168 cache.Add(server2, nullptr, MakeMockKey());
169
170 scoped_refptr<X509Certificate> cached_cert;
171 scoped_refptr<SSLPrivateKey> cached_pkey;
172
173 // Demonstrate the set up is correct.
174 EXPECT_TRUE(cache.Lookup(server1, &cached_cert, &cached_pkey));
175 EXPECT_EQ(cert1, cached_cert);
176
177 EXPECT_TRUE(cache.Lookup(server2, &cached_cert, &cached_pkey));
178 EXPECT_EQ(nullptr, cached_cert.get());
179
180 cache.Clear();
181
182 // Check that we no longer have entries for either server.
183 EXPECT_FALSE(cache.Lookup(server1, &cached_cert, &cached_pkey));
184 EXPECT_FALSE(cache.Lookup(server2, &cached_cert, &cached_pkey));
185 }
186
187 } // namespace net
188