1 // Copyright 2013 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/client_cert_store_nss.h"
6
7 #include <cert.h>
8 #include <certt.h>
9 #include <pk11pub.h>
10
11 #include <memory>
12 #include <string>
13
14 #include "base/files/file_util.h"
15 #include "base/functional/bind.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/run_loop.h"
18 #include "base/test/task_environment.h"
19 #include "crypto/nss_util.h"
20 #include "crypto/scoped_test_nss_db.h"
21 #include "net/cert/pem.h"
22 #include "net/cert/x509_certificate.h"
23 #include "net/cert/x509_util_nss.h"
24 #include "net/ssl/client_cert_identity_test_util.h"
25 #include "net/ssl/client_cert_store_unittest-inl.h"
26 #include "net/ssl/ssl_cert_request_info.h"
27 #include "net/ssl/ssl_private_key.h"
28 #include "net/ssl/ssl_private_key_test_util.h"
29 #include "net/test/cert_test_util.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "third_party/boringssl/src/include/openssl/ssl.h"
32
33 namespace net {
34
35 namespace {
36
SaveIdentitiesAndQuitCallback(ClientCertIdentityList * out_identities,base::OnceClosure quit_closure,ClientCertIdentityList in_identities)37 void SaveIdentitiesAndQuitCallback(ClientCertIdentityList* out_identities,
38 base::OnceClosure quit_closure,
39 ClientCertIdentityList in_identities) {
40 *out_identities = std::move(in_identities);
41 std::move(quit_closure).Run();
42 }
43
SavePrivateKeyAndQuitCallback(scoped_refptr<net::SSLPrivateKey> * out_key,base::OnceClosure quit_closure,scoped_refptr<net::SSLPrivateKey> in_key)44 void SavePrivateKeyAndQuitCallback(scoped_refptr<net::SSLPrivateKey>* out_key,
45 base::OnceClosure quit_closure,
46 scoped_refptr<net::SSLPrivateKey> in_key) {
47 *out_key = std::move(in_key);
48 std::move(quit_closure).Run();
49 }
50
51 } // namespace
52
53 class ClientCertStoreNSSTestDelegate {
54 public:
55 ClientCertStoreNSSTestDelegate() = default;
56
SelectClientCerts(const CertificateList & input_certs,const SSLCertRequestInfo & cert_request_info,ClientCertIdentityList * selected_identities)57 bool SelectClientCerts(const CertificateList& input_certs,
58 const SSLCertRequestInfo& cert_request_info,
59 ClientCertIdentityList* selected_identities) {
60 *selected_identities =
61 FakeClientCertIdentityListFromCertificateList(input_certs);
62
63 // Filters |selected_identities| using the logic being used to filter the
64 // system store when GetClientCerts() is called.
65 crypto::EnsureNSSInit();
66 ClientCertStoreNSS::FilterCertsOnWorkerThread(selected_identities,
67 cert_request_info);
68 return true;
69 }
70 };
71
72 INSTANTIATE_TYPED_TEST_SUITE_P(NSS,
73 ClientCertStoreTest,
74 ClientCertStoreNSSTestDelegate);
75
76 // Tests that ClientCertStoreNSS attempts to build a certificate chain by
77 // querying NSS before return a certificate.
TEST(ClientCertStoreNSSTest,BuildsCertificateChain)78 TEST(ClientCertStoreNSSTest, BuildsCertificateChain) {
79 base::test::TaskEnvironment task_environment;
80
81 // Set up a test DB and import client_1.pem and client_1_ca.pem.
82 crypto::ScopedTestNSSDB test_db;
83 scoped_refptr<X509Certificate> client_1(ImportClientCertAndKeyFromFile(
84 GetTestCertsDirectory(), "client_1.pem", "client_1.pk8", test_db.slot()));
85 ASSERT_TRUE(client_1.get());
86 scoped_refptr<X509Certificate> client_1_ca(
87 ImportCertFromFile(GetTestCertsDirectory(), "client_1_ca.pem"));
88 ASSERT_TRUE(client_1_ca.get());
89 ASSERT_TRUE(ImportClientCertToSlot(client_1_ca, test_db.slot()));
90 std::string pkcs8_key;
91 ASSERT_TRUE(base::ReadFileToString(
92 GetTestCertsDirectory().AppendASCII("client_1.pk8"), &pkcs8_key));
93
94 auto store = std::make_unique<ClientCertStoreNSS>(
95 ClientCertStoreNSS::PasswordDelegateFactory());
96
97 // These test keys are RSA keys.
98 std::vector<uint16_t> expected = SSLPrivateKey::DefaultAlgorithmPreferences(
99 EVP_PKEY_RSA, true /* supports PSS */);
100
101 {
102 // Request certificates matching B CA, |client_1|'s issuer.
103 auto request = base::MakeRefCounted<SSLCertRequestInfo>();
104 request->cert_authorities.emplace_back(
105 reinterpret_cast<const char*>(kAuthority1DN), sizeof(kAuthority1DN));
106
107 ClientCertIdentityList selected_identities;
108 base::RunLoop loop;
109 store->GetClientCerts(
110 *request.get(),
111 base::BindOnce(SaveIdentitiesAndQuitCallback, &selected_identities,
112 loop.QuitClosure()));
113 loop.Run();
114
115 // The result be |client_1| with no intermediates.
116 ASSERT_EQ(1u, selected_identities.size());
117 scoped_refptr<X509Certificate> selected_cert =
118 selected_identities[0]->certificate();
119 EXPECT_TRUE(x509_util::CryptoBufferEqual(client_1->cert_buffer(),
120 selected_cert->cert_buffer()));
121 ASSERT_EQ(0u, selected_cert->intermediate_buffers().size());
122
123 scoped_refptr<SSLPrivateKey> ssl_private_key;
124 base::RunLoop key_loop;
125 selected_identities[0]->AcquirePrivateKey(
126 base::BindOnce(SavePrivateKeyAndQuitCallback, &ssl_private_key,
127 key_loop.QuitClosure()));
128 key_loop.Run();
129
130 ASSERT_TRUE(ssl_private_key);
131 EXPECT_EQ(expected, ssl_private_key->GetAlgorithmPreferences());
132 TestSSLPrivateKeyMatches(ssl_private_key.get(), pkcs8_key);
133 }
134
135 {
136 // Request certificates matching C Root CA, |client_1_ca|'s issuer.
137 auto request = base::MakeRefCounted<SSLCertRequestInfo>();
138 request->cert_authorities.emplace_back(
139 reinterpret_cast<const char*>(kAuthorityRootDN),
140 sizeof(kAuthorityRootDN));
141
142 ClientCertIdentityList selected_identities;
143 base::RunLoop loop;
144 store->GetClientCerts(
145 *request.get(),
146 base::BindOnce(SaveIdentitiesAndQuitCallback, &selected_identities,
147 loop.QuitClosure()));
148 loop.Run();
149
150 // The result be |client_1| with |client_1_ca| as an intermediate.
151 ASSERT_EQ(1u, selected_identities.size());
152 scoped_refptr<X509Certificate> selected_cert =
153 selected_identities[0]->certificate();
154 EXPECT_TRUE(x509_util::CryptoBufferEqual(client_1->cert_buffer(),
155 selected_cert->cert_buffer()));
156 ASSERT_EQ(1u, selected_cert->intermediate_buffers().size());
157 EXPECT_TRUE(x509_util::CryptoBufferEqual(
158 client_1_ca->cert_buffer(),
159 selected_cert->intermediate_buffers()[0].get()));
160
161 scoped_refptr<SSLPrivateKey> ssl_private_key;
162 base::RunLoop key_loop;
163 selected_identities[0]->AcquirePrivateKey(
164 base::BindOnce(SavePrivateKeyAndQuitCallback, &ssl_private_key,
165 key_loop.QuitClosure()));
166 key_loop.Run();
167 ASSERT_TRUE(ssl_private_key);
168 EXPECT_EQ(expected, ssl_private_key->GetAlgorithmPreferences());
169 TestSSLPrivateKeyMatches(ssl_private_key.get(), pkcs8_key);
170 }
171 }
172
TEST(ClientCertStoreNSSTest,SubjectPrintableStringContainingUTF8)173 TEST(ClientCertStoreNSSTest, SubjectPrintableStringContainingUTF8) {
174 base::test::TaskEnvironment task_environment;
175
176 crypto::ScopedTestNSSDB test_db;
177 base::FilePath certs_dir =
178 GetTestNetDataDirectory().AppendASCII("parse_certificate_unittest");
179
180 ASSERT_TRUE(ImportSensitiveKeyFromFile(
181 certs_dir, "v3_certificate_template.pk8", test_db.slot()));
182 std::string pkcs8_key;
183 ASSERT_TRUE(base::ReadFileToString(
184 certs_dir.AppendASCII("v3_certificate_template.pk8"), &pkcs8_key));
185
186 std::string file_data;
187 ASSERT_TRUE(base::ReadFileToString(
188 certs_dir.AppendASCII(
189 "subject_printable_string_containing_utf8_client_cert.pem"),
190 &file_data));
191
192 net::PEMTokenizer pem_tokenizer(file_data, {"CERTIFICATE"});
193 ASSERT_TRUE(pem_tokenizer.GetNext());
194 std::string cert_der(pem_tokenizer.data());
195 ASSERT_FALSE(pem_tokenizer.GetNext());
196
197 ScopedCERTCertificate cert(x509_util::CreateCERTCertificateFromBytes(
198 reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size()));
199 ASSERT_TRUE(cert);
200
201 ASSERT_TRUE(ImportClientCertToSlot(cert.get(), test_db.slot()));
202
203 auto store = std::make_unique<ClientCertStoreNSS>(
204 ClientCertStoreNSS::PasswordDelegateFactory());
205
206 // These test keys are RSA keys.
207 std::vector<uint16_t> expected = SSLPrivateKey::DefaultAlgorithmPreferences(
208 EVP_PKEY_RSA, true /* supports PSS */);
209
210 constexpr uint8_t kAuthorityDN[] = {
211 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
212 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
213 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
214 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49,
215 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
216 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64};
217 auto request = base::MakeRefCounted<SSLCertRequestInfo>();
218 request->cert_authorities.emplace_back(
219 reinterpret_cast<const char*>(kAuthorityDN), sizeof(kAuthorityDN));
220
221 ClientCertIdentityList selected_identities;
222 base::RunLoop loop;
223 store->GetClientCerts(
224 *request.get(), base::BindOnce(SaveIdentitiesAndQuitCallback,
225 &selected_identities, loop.QuitClosure()));
226 loop.Run();
227
228 // The result be |cert| with no intermediates.
229 ASSERT_EQ(1u, selected_identities.size());
230 scoped_refptr<X509Certificate> selected_cert =
231 selected_identities[0]->certificate();
232 EXPECT_TRUE(x509_util::IsSameCertificate(cert.get(), selected_cert.get()));
233 EXPECT_EQ(0u, selected_cert->intermediate_buffers().size());
234
235 scoped_refptr<SSLPrivateKey> ssl_private_key;
236 base::RunLoop key_loop;
237 selected_identities[0]->AcquirePrivateKey(base::BindOnce(
238 SavePrivateKeyAndQuitCallback, &ssl_private_key, key_loop.QuitClosure()));
239 key_loop.Run();
240
241 ASSERT_TRUE(ssl_private_key);
242 EXPECT_EQ(expected, ssl_private_key->GetAlgorithmPreferences());
243 TestSSLPrivateKeyMatches(ssl_private_key.get(), pkcs8_key);
244 }
245
246 // TODO(mattm): is it possible to unittest slot unlocking?
247
248 } // namespace net
249