1 // Copyright 2012 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/cert/crl_set.h"
11
12 #include <string_view>
13
14 #include "base/files/file_util.h"
15 #include "crypto/sha2.h"
16 #include "net/cert/asn1_util.h"
17 #include "net/cert/x509_certificate.h"
18 #include "net/cert/x509_util.h"
19 #include "net/test/cert_test_util.h"
20 #include "net/test/test_data_directory.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace net {
24
25 // These data blocks were generated using a lot of code that is still in
26 // development. For now, if you need to update them, you have to contact agl.
27 static const uint8_t kGIACRLSet[] = {
28 0x60, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
29 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
30 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
31 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
32 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
33 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
34 0x31, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
35 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0xb6, 0xb9, 0x54, 0x32, 0xab, 0xae,
36 0x57, 0xfe, 0x02, 0x0c, 0xb2, 0xb7, 0x4f, 0x4f, 0x9f, 0x91, 0x73, 0xc8, 0xc7,
37 0x08, 0xaf, 0xc9, 0xe7, 0x32, 0xac, 0xe2, 0x32, 0x79, 0x04, 0x7c, 0x6d, 0x05,
38 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00,
39 0x23, 0xb0, 0x0a, 0x10, 0x0e, 0x37, 0x06, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb1,
40 0x0a, 0x16, 0x25, 0x42, 0x54, 0x00, 0x03, 0x00, 0x00, 0x14, 0x51, 0x0a, 0x16,
41 0x69, 0xd1, 0xd7, 0x00, 0x03, 0x00, 0x00, 0x14, 0x52, 0x0a, 0x16, 0x70, 0x8c,
42 0x22, 0x00, 0x03, 0x00, 0x00, 0x14, 0x53, 0x0a, 0x16, 0x71, 0x31, 0x2c, 0x00,
43 0x03, 0x00, 0x00, 0x14, 0x54, 0x0a, 0x16, 0x7d, 0x75, 0x9d, 0x00, 0x03, 0x00,
44 0x00, 0x14, 0x55, 0x0a, 0x1f, 0xee, 0xf9, 0x49, 0x00, 0x03, 0x00, 0x00, 0x23,
45 0xae, 0x0a, 0x1f, 0xfc, 0xd1, 0x89, 0x00, 0x03, 0x00, 0x00, 0x23, 0xaf, 0x0a,
46 0x61, 0xdd, 0xc7, 0x48, 0x00, 0x03, 0x00, 0x00, 0x18, 0x0e, 0x0a, 0x61, 0xe6,
47 0x12, 0x64, 0x00, 0x03, 0x00, 0x00, 0x18, 0x0f, 0x0a, 0x61, 0xe9, 0x46, 0x56,
48 0x00, 0x03, 0x00, 0x00, 0x18, 0x10, 0x0a, 0x64, 0x63, 0x49, 0xd2, 0x00, 0x03,
49 0x00, 0x00, 0x1d, 0x77,
50 };
51
52 static const uint8_t kBlockedSPKICRLSet[] = {
53 0x8e, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
54 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
55 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
56 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
57 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
58 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
59 0x30, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
60 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x34, 0x37, 0x44, 0x45, 0x51, 0x70, 0x6a,
61 0x38, 0x48, 0x42, 0x53, 0x61, 0x2b, 0x2f, 0x54, 0x49, 0x6d, 0x57, 0x2b, 0x35,
62 0x4a, 0x43, 0x65, 0x75, 0x51, 0x65, 0x52, 0x6b, 0x6d, 0x35, 0x4e, 0x4d, 0x70,
63 0x4a, 0x57, 0x5a, 0x47, 0x33, 0x68, 0x53, 0x75, 0x46, 0x55, 0x3d, 0x22, 0x5d,
64 0x7d,
65 };
66
67 static const uint8_t kExpiredCRLSet[] = {
68 0x6d, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
69 0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
70 0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
71 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x31, 0x2c, 0x22,
72 0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
73 0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
74 0x30, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
75 0x49, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x4e, 0x6f, 0x74, 0x41, 0x66,
76 0x74, 0x65, 0x72, 0x22, 0x3a, 0x31, 0x7d,
77 };
78
79 // kGIASPKISHA256 is the SHA256 digest the Google Internet Authority's
80 // SubjectPublicKeyInfo.
81 static const uint8_t kGIASPKISHA256[32] = {
82 0xb6, 0xb9, 0x54, 0x32, 0xab, 0xae, 0x57, 0xfe, 0x02, 0x0c, 0xb2, 0xb7, 0x4f,
83 0x4f, 0x9f, 0x91, 0x73, 0xc8, 0xc7, 0x08, 0xaf, 0xc9, 0xe7, 0x32, 0xac, 0xe2,
84 0x32, 0x79, 0x04, 0x7c, 0x6d, 0x05,
85 };
86
TEST(CRLSetTest,Parse)87 TEST(CRLSetTest, Parse) {
88 std::string_view s(reinterpret_cast<const char*>(kGIACRLSet),
89 sizeof(kGIACRLSet));
90 scoped_refptr<CRLSet> set;
91 EXPECT_TRUE(CRLSet::Parse(s, &set));
92 ASSERT_TRUE(set.get() != nullptr);
93
94 const CRLSet::CRLList& crls = set->CrlsForTesting();
95 ASSERT_EQ(1u, crls.size());
96 const std::vector<std::string>& serials = crls.begin()->second;
97 static const unsigned kExpectedNumSerials = 13;
98 ASSERT_EQ(kExpectedNumSerials, serials.size());
99 EXPECT_EQ(std::string("\x10\x0D\x7F\x30\x00\x03\x00\x00\x23\xB0", 10),
100 serials[0]);
101 EXPECT_EQ(std::string("\x64\x63\x49\xD2\x00\x03\x00\x00\x1D\x77", 10),
102 serials[kExpectedNumSerials - 1]);
103
104 const std::string gia_spki_hash(reinterpret_cast<const char*>(kGIASPKISHA256),
105 sizeof(kGIASPKISHA256));
106 EXPECT_EQ(CRLSet::REVOKED,
107 set->CheckSerial(
108 std::string("\x16\x7D\x75\x9D\x00\x03\x00\x00\x14\x55", 10),
109 gia_spki_hash));
110 EXPECT_EQ(CRLSet::GOOD,
111 set->CheckSerial(
112 std::string("\x47\x54\x3E\x79\x00\x03\x00\x00\x14\xF5", 10),
113 gia_spki_hash));
114
115 EXPECT_FALSE(set->IsExpired());
116 }
117
TEST(CRLSetTest,BlockedSPKIs)118 TEST(CRLSetTest, BlockedSPKIs) {
119 std::string_view s(reinterpret_cast<const char*>(kBlockedSPKICRLSet),
120 sizeof(kBlockedSPKICRLSet));
121 scoped_refptr<CRLSet> set;
122 EXPECT_TRUE(CRLSet::Parse(s, &set));
123 ASSERT_TRUE(set.get() != nullptr);
124
125 const uint8_t spki_hash[] = {
126 227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36,
127 39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85,
128 0,
129 };
130
131 EXPECT_EQ(CRLSet::GOOD, set->CheckSPKI(""));
132 EXPECT_EQ(CRLSet::REVOKED,
133 set->CheckSPKI(reinterpret_cast<const char*>(spki_hash)));
134 }
135
TEST(CertVerifyProcTest,CRLSetIncorporatesStaticBlocklist)136 TEST(CertVerifyProcTest, CRLSetIncorporatesStaticBlocklist) {
137 // Test both the builtin CRLSet and a parsed CRLSet to be sure that both
138 // include the block list.
139 scoped_refptr<CRLSet> set1 = CRLSet::BuiltinCRLSet();
140 ASSERT_TRUE(set1);
141 std::string_view s(reinterpret_cast<const char*>(kGIACRLSet),
142 sizeof(kGIACRLSet));
143 scoped_refptr<CRLSet> set2;
144 EXPECT_TRUE(CRLSet::Parse(s, &set2));
145 ASSERT_TRUE(set2);
146
147 static const char* const kDigiNotarFilenames[] = {
148 "diginotar_root_ca.pem", "diginotar_cyber_ca.pem",
149 "diginotar_services_1024_ca.pem", "diginotar_pkioverheid.pem",
150 "diginotar_pkioverheid_g2.pem", nullptr,
151 };
152
153 base::FilePath certs_dir = GetTestCertsDirectory();
154
155 for (size_t i = 0; kDigiNotarFilenames[i]; i++) {
156 scoped_refptr<X509Certificate> diginotar_cert =
157 ImportCertFromFile(certs_dir, kDigiNotarFilenames[i]);
158 ASSERT_TRUE(diginotar_cert);
159 std::string_view spki;
160 ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(
161 x509_util::CryptoBufferAsStringPiece(diginotar_cert->cert_buffer()),
162 &spki));
163
164 std::string spki_sha256 = crypto::SHA256HashString(spki);
165
166 EXPECT_EQ(CRLSet::REVOKED, set1->CheckSPKI(spki_sha256))
167 << "Public key not blocked for " << kDigiNotarFilenames[i];
168 EXPECT_EQ(CRLSet::REVOKED, set2->CheckSPKI(spki_sha256))
169 << "Public key not blocked for " << kDigiNotarFilenames[i];
170 }
171 }
172
TEST(CRLSetTest,BlockedSubjects)173 TEST(CRLSetTest, BlockedSubjects) {
174 std::string crl_set_bytes;
175 EXPECT_TRUE(base::ReadFileToString(
176 GetTestCertsDirectory().AppendASCII("crlset_by_root_subject.raw"),
177 &crl_set_bytes));
178 scoped_refptr<CRLSet> set;
179 EXPECT_TRUE(CRLSet::Parse(crl_set_bytes, &set));
180 ASSERT_TRUE(set.get() != nullptr);
181
182 scoped_refptr<X509Certificate> root = CreateCertificateChainFromFile(
183 GetTestCertsDirectory(), "root_ca_cert.pem",
184 X509Certificate::FORMAT_AUTO);
185 std::string_view root_der =
186 net::x509_util::CryptoBufferAsStringPiece(root->cert_buffer());
187
188 std::string_view spki;
189 ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(root_der, &spki));
190 SHA256HashValue spki_sha256;
191 crypto::SHA256HashString(spki, spki_sha256.data, sizeof(spki_sha256.data));
192
193 std::string_view subject;
194 ASSERT_TRUE(asn1::ExtractSubjectFromDERCert(root_der, &subject));
195
196 // Unrelated subjects are unaffected.
197 EXPECT_EQ(CRLSet::GOOD, set->CheckSubject("abcdef", ""));
198
199 // The subject in question is considered revoked if used with an unknown SPKI
200 // hash.
201 EXPECT_EQ(CRLSet::REVOKED,
202 set->CheckSubject(
203 subject,
204 std::string_view(reinterpret_cast<const char*>(kGIASPKISHA256),
205 sizeof(kGIASPKISHA256))));
206
207 // When used with the correct hash, that subject should be accepted.
208 EXPECT_EQ(CRLSet::GOOD,
209 set->CheckSubject(
210 subject, std::string_view(
211 reinterpret_cast<const char*>(spki_sha256.data),
212 sizeof(spki_sha256.data))));
213 }
214
TEST(CRLSetTest,Expired)215 TEST(CRLSetTest, Expired) {
216 // This CRLSet has an expiry value set to one second past midnight, 1st Jan,
217 // 1970.
218 std::string_view s(reinterpret_cast<const char*>(kExpiredCRLSet),
219 sizeof(kExpiredCRLSet));
220 scoped_refptr<CRLSet> set;
221 EXPECT_TRUE(CRLSet::Parse(s, &set));
222 ASSERT_TRUE(set.get() != nullptr);
223
224 EXPECT_TRUE(set->IsExpired());
225 }
226
227 } // namespace net
228