1 // Copyright (c) 2021 The Chromium Authors. All rights reserved.
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 "quiche/quic/core/crypto/client_proof_source.h"
6
7 #include "quiche/quic/platform/api/quic_expect_bug.h"
8 #include "quiche/quic/platform/api/quic_test.h"
9 #include "quiche/quic/test_tools/test_certificates.h"
10
11 namespace quic {
12 namespace test {
13
14 quiche::QuicheReferenceCountedPointer<ClientProofSource::Chain>
TestCertChain()15 TestCertChain() {
16 return quiche::QuicheReferenceCountedPointer<ClientProofSource::Chain>(
17 new ClientProofSource::Chain({std::string(kTestCertificate)}));
18 }
19
TestPrivateKey()20 CertificatePrivateKey TestPrivateKey() {
21 CBS private_key_cbs;
22 CBS_init(&private_key_cbs,
23 reinterpret_cast<const uint8_t*>(kTestCertificatePrivateKey.data()),
24 kTestCertificatePrivateKey.size());
25
26 return CertificatePrivateKey(
27 bssl::UniquePtr<EVP_PKEY>(EVP_parse_private_key(&private_key_cbs)));
28 }
29
TestCertAndKey()30 const ClientProofSource::CertAndKey* TestCertAndKey() {
31 static const ClientProofSource::CertAndKey cert_and_key(TestCertChain(),
32 TestPrivateKey());
33 return &cert_and_key;
34 }
35
36 quiche::QuicheReferenceCountedPointer<ClientProofSource::Chain>
NullCertChain()37 NullCertChain() {
38 return quiche::QuicheReferenceCountedPointer<ClientProofSource::Chain>();
39 }
40
41 quiche::QuicheReferenceCountedPointer<ClientProofSource::Chain>
EmptyCertChain()42 EmptyCertChain() {
43 return quiche::QuicheReferenceCountedPointer<ClientProofSource::Chain>(
44 new ClientProofSource::Chain(std::vector<std::string>()));
45 }
46
BadCertChain()47 quiche::QuicheReferenceCountedPointer<ClientProofSource::Chain> BadCertChain() {
48 return quiche::QuicheReferenceCountedPointer<ClientProofSource::Chain>(
49 new ClientProofSource::Chain({"This is the content of a bad cert."}));
50 }
51
EmptyPrivateKey()52 CertificatePrivateKey EmptyPrivateKey() {
53 return CertificatePrivateKey(bssl::UniquePtr<EVP_PKEY>(EVP_PKEY_new()));
54 }
55
56 #define VERIFY_CERT_AND_KEY_MATCHES(lhs, rhs) \
57 do { \
58 SCOPED_TRACE(testing::Message()); \
59 VerifyCertAndKeyMatches(lhs.get(), rhs); \
60 } while (0)
61
VerifyCertAndKeyMatches(const ClientProofSource::CertAndKey * lhs,const ClientProofSource::CertAndKey * rhs)62 void VerifyCertAndKeyMatches(const ClientProofSource::CertAndKey* lhs,
63 const ClientProofSource::CertAndKey* rhs) {
64 if (lhs == rhs) {
65 return;
66 }
67
68 if (lhs == nullptr) {
69 ADD_FAILURE() << "lhs is nullptr, but rhs is not";
70 return;
71 }
72
73 if (rhs == nullptr) {
74 ADD_FAILURE() << "rhs is nullptr, but lhs is not";
75 return;
76 }
77
78 if (1 != EVP_PKEY_cmp(lhs->private_key.private_key(),
79 rhs->private_key.private_key())) {
80 ADD_FAILURE() << "Private keys mismatch";
81 return;
82 }
83
84 const ClientProofSource::Chain* lhs_chain = lhs->chain.get();
85 const ClientProofSource::Chain* rhs_chain = rhs->chain.get();
86
87 if (lhs_chain == rhs_chain) {
88 return;
89 }
90
91 if (lhs_chain == nullptr) {
92 ADD_FAILURE() << "lhs->chain is nullptr, but rhs->chain is not";
93 return;
94 }
95
96 if (rhs_chain == nullptr) {
97 ADD_FAILURE() << "rhs->chain is nullptr, but lhs->chain is not";
98 return;
99 }
100
101 if (lhs_chain->certs.size() != rhs_chain->certs.size()) {
102 ADD_FAILURE() << "Cert chain length differ. lhs:" << lhs_chain->certs.size()
103 << ", rhs:" << rhs_chain->certs.size();
104 return;
105 }
106
107 for (size_t i = 0; i < lhs_chain->certs.size(); ++i) {
108 if (lhs_chain->certs[i] != rhs_chain->certs[i]) {
109 ADD_FAILURE() << "The " << i << "-th certs differ.";
110 return;
111 }
112 }
113
114 // All good.
115 }
116
TEST(DefaultClientProofSource,FullDomain)117 TEST(DefaultClientProofSource, FullDomain) {
118 DefaultClientProofSource proof_source;
119 ASSERT_TRUE(proof_source.AddCertAndKey({"www.google.com"}, TestCertChain(),
120 TestPrivateKey()));
121 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
122 TestCertAndKey());
123 EXPECT_EQ(proof_source.GetCertAndKey("*.google.com"), nullptr);
124 EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
125 }
126
TEST(DefaultClientProofSource,WildcardDomain)127 TEST(DefaultClientProofSource, WildcardDomain) {
128 DefaultClientProofSource proof_source;
129 ASSERT_TRUE(proof_source.AddCertAndKey({"*.google.com"}, TestCertChain(),
130 TestPrivateKey()));
131 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
132 TestCertAndKey());
133 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*.google.com"),
134 TestCertAndKey());
135 EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
136 }
137
TEST(DefaultClientProofSource,DefaultDomain)138 TEST(DefaultClientProofSource, DefaultDomain) {
139 DefaultClientProofSource proof_source;
140 ASSERT_TRUE(
141 proof_source.AddCertAndKey({"*"}, TestCertChain(), TestPrivateKey()));
142 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
143 TestCertAndKey());
144 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*.google.com"),
145 TestCertAndKey());
146 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*"),
147 TestCertAndKey());
148 }
149
TEST(DefaultClientProofSource,FullAndWildcard)150 TEST(DefaultClientProofSource, FullAndWildcard) {
151 DefaultClientProofSource proof_source;
152 ASSERT_TRUE(proof_source.AddCertAndKey({"www.google.com", "*.google.com"},
153 TestCertChain(), TestPrivateKey()));
154 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
155 TestCertAndKey());
156 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("foo.google.com"),
157 TestCertAndKey());
158 EXPECT_EQ(proof_source.GetCertAndKey("www.example.com"), nullptr);
159 EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
160 }
161
TEST(DefaultClientProofSource,FullWildcardAndDefault)162 TEST(DefaultClientProofSource, FullWildcardAndDefault) {
163 DefaultClientProofSource proof_source;
164 ASSERT_TRUE(
165 proof_source.AddCertAndKey({"www.google.com", "*.google.com", "*"},
166 TestCertChain(), TestPrivateKey()));
167 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
168 TestCertAndKey());
169 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("foo.google.com"),
170 TestCertAndKey());
171 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.example.com"),
172 TestCertAndKey());
173 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*.google.com"),
174 TestCertAndKey());
175 VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*"),
176 TestCertAndKey());
177 }
178
TEST(DefaultClientProofSource,EmptyCerts)179 TEST(DefaultClientProofSource, EmptyCerts) {
180 DefaultClientProofSource proof_source;
181 EXPECT_QUIC_BUG(ASSERT_FALSE(proof_source.AddCertAndKey(
182 {"*"}, NullCertChain(), TestPrivateKey())),
183 "Certificate chain is empty");
184
185 EXPECT_QUIC_BUG(ASSERT_FALSE(proof_source.AddCertAndKey(
186 {"*"}, EmptyCertChain(), TestPrivateKey())),
187 "Certificate chain is empty");
188 EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
189 }
190
TEST(DefaultClientProofSource,BadCerts)191 TEST(DefaultClientProofSource, BadCerts) {
192 DefaultClientProofSource proof_source;
193 EXPECT_QUIC_BUG(ASSERT_FALSE(proof_source.AddCertAndKey({"*"}, BadCertChain(),
194 TestPrivateKey())),
195 "Unabled to parse leaf certificate");
196 EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
197 }
198
TEST(DefaultClientProofSource,KeyMismatch)199 TEST(DefaultClientProofSource, KeyMismatch) {
200 DefaultClientProofSource proof_source;
201 EXPECT_QUIC_BUG(ASSERT_FALSE(proof_source.AddCertAndKey(
202 {"www.google.com"}, TestCertChain(), EmptyPrivateKey())),
203 "Private key does not match the leaf certificate");
204 EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
205 }
206
207 } // namespace test
208 } // namespace quic
209