1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/cert/crl_set.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <string_view>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/base64.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/json/json_reader.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
14*6777b538SAndroid Build Coastguard Worker #include "crypto/sha2.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/base/trace_constants.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/base/tracing.h"
17*6777b538SAndroid Build Coastguard Worker #include "third_party/boringssl/src/include/openssl/bytestring.h"
18*6777b538SAndroid Build Coastguard Worker #include "third_party/boringssl/src/include/openssl/mem.h"
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker namespace net {
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker namespace {
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker // CRLSet format:
25*6777b538SAndroid Build Coastguard Worker //
26*6777b538SAndroid Build Coastguard Worker // uint16le header_len
27*6777b538SAndroid Build Coastguard Worker // byte[header_len] header_bytes
28*6777b538SAndroid Build Coastguard Worker // repeated {
29*6777b538SAndroid Build Coastguard Worker // byte[32] parent_spki_sha256
30*6777b538SAndroid Build Coastguard Worker // uint32le num_serials
31*6777b538SAndroid Build Coastguard Worker // [num_serials] {
32*6777b538SAndroid Build Coastguard Worker // uint8_t serial_length;
33*6777b538SAndroid Build Coastguard Worker // byte[serial_length] serial;
34*6777b538SAndroid Build Coastguard Worker // }
35*6777b538SAndroid Build Coastguard Worker //
36*6777b538SAndroid Build Coastguard Worker // header_bytes consists of a JSON dictionary with the following keys:
37*6777b538SAndroid Build Coastguard Worker // Version (int): currently 0
38*6777b538SAndroid Build Coastguard Worker // ContentType (string): "CRLSet" (magic value)
39*6777b538SAndroid Build Coastguard Worker // Sequence (int32_t): the monotonic sequence number of this CRL set.
40*6777b538SAndroid Build Coastguard Worker // NotAfter (optional) (double/int64_t): The number of seconds since the
41*6777b538SAndroid Build Coastguard Worker // Unix epoch, after which, this CRLSet is expired.
42*6777b538SAndroid Build Coastguard Worker // BlockedSPKIs (array of string): An array of Base64 encoded, SHA-256 hashed
43*6777b538SAndroid Build Coastguard Worker // SubjectPublicKeyInfos that should be blocked.
44*6777b538SAndroid Build Coastguard Worker // LimitedSubjects (object/map of string -> array of string): A map between
45*6777b538SAndroid Build Coastguard Worker // the Base64-encoded SHA-256 hash of the DER-encoded Subject and the
46*6777b538SAndroid Build Coastguard Worker // Base64-encoded SHA-256 hashes of the SubjectPublicKeyInfos that are
47*6777b538SAndroid Build Coastguard Worker // allowed for that subject.
48*6777b538SAndroid Build Coastguard Worker // KnownInterceptionSPKIs (array of string): An array of Base64-encoded
49*6777b538SAndroid Build Coastguard Worker // SHA-256 hashed SubjectPublicKeyInfos known to be used for interception.
50*6777b538SAndroid Build Coastguard Worker // BlockedInterceptionSPKIs (array of string): An array of Base64-encoded
51*6777b538SAndroid Build Coastguard Worker // SHA-256 hashed SubjectPublicKeyInfos known to be used for interception
52*6777b538SAndroid Build Coastguard Worker // and that should be actively blocked.
53*6777b538SAndroid Build Coastguard Worker //
54*6777b538SAndroid Build Coastguard Worker // ReadHeader reads the header (including length prefix) from |data| and
55*6777b538SAndroid Build Coastguard Worker // updates |data| to remove the header on return. Caller takes ownership of the
56*6777b538SAndroid Build Coastguard Worker // returned pointer.
ReadHeader(std::string_view * data)57*6777b538SAndroid Build Coastguard Worker std::optional<base::Value> ReadHeader(std::string_view* data) {
58*6777b538SAndroid Build Coastguard Worker uint16_t header_len;
59*6777b538SAndroid Build Coastguard Worker if (data->size() < sizeof(header_len)) {
60*6777b538SAndroid Build Coastguard Worker return std::nullopt;
61*6777b538SAndroid Build Coastguard Worker }
62*6777b538SAndroid Build Coastguard Worker // Assumes little-endian.
63*6777b538SAndroid Build Coastguard Worker memcpy(&header_len, data->data(), sizeof(header_len));
64*6777b538SAndroid Build Coastguard Worker data->remove_prefix(sizeof(header_len));
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker if (data->size() < header_len) {
67*6777b538SAndroid Build Coastguard Worker return std::nullopt;
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker const std::string_view header_bytes = data->substr(0, header_len);
71*6777b538SAndroid Build Coastguard Worker data->remove_prefix(header_len);
72*6777b538SAndroid Build Coastguard Worker
73*6777b538SAndroid Build Coastguard Worker std::optional<base::Value> header =
74*6777b538SAndroid Build Coastguard Worker base::JSONReader::Read(header_bytes, base::JSON_ALLOW_TRAILING_COMMAS);
75*6777b538SAndroid Build Coastguard Worker if (!header || !header->is_dict()) {
76*6777b538SAndroid Build Coastguard Worker return std::nullopt;
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker return header;
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker // kCurrentFileVersion is the version of the CRLSet file format that we
83*6777b538SAndroid Build Coastguard Worker // currently implement.
84*6777b538SAndroid Build Coastguard Worker static const int kCurrentFileVersion = 0;
85*6777b538SAndroid Build Coastguard Worker
ReadCRL(std::string_view * data,std::string * out_parent_spki_hash,std::vector<std::string> * out_serials)86*6777b538SAndroid Build Coastguard Worker bool ReadCRL(std::string_view* data,
87*6777b538SAndroid Build Coastguard Worker std::string* out_parent_spki_hash,
88*6777b538SAndroid Build Coastguard Worker std::vector<std::string>* out_serials) {
89*6777b538SAndroid Build Coastguard Worker if (data->size() < crypto::kSHA256Length)
90*6777b538SAndroid Build Coastguard Worker return false;
91*6777b538SAndroid Build Coastguard Worker *out_parent_spki_hash = std::string(data->substr(0, crypto::kSHA256Length));
92*6777b538SAndroid Build Coastguard Worker data->remove_prefix(crypto::kSHA256Length);
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker uint32_t num_serials;
95*6777b538SAndroid Build Coastguard Worker if (data->size() < sizeof(num_serials))
96*6777b538SAndroid Build Coastguard Worker return false;
97*6777b538SAndroid Build Coastguard Worker // Assumes little endian.
98*6777b538SAndroid Build Coastguard Worker memcpy(&num_serials, data->data(), sizeof(num_serials));
99*6777b538SAndroid Build Coastguard Worker data->remove_prefix(sizeof(num_serials));
100*6777b538SAndroid Build Coastguard Worker
101*6777b538SAndroid Build Coastguard Worker if (num_serials > 32 * 1024 * 1024) // Sanity check.
102*6777b538SAndroid Build Coastguard Worker return false;
103*6777b538SAndroid Build Coastguard Worker
104*6777b538SAndroid Build Coastguard Worker out_serials->reserve(num_serials);
105*6777b538SAndroid Build Coastguard Worker
106*6777b538SAndroid Build Coastguard Worker for (uint32_t i = 0; i < num_serials; ++i) {
107*6777b538SAndroid Build Coastguard Worker if (data->size() < sizeof(uint8_t))
108*6777b538SAndroid Build Coastguard Worker return false;
109*6777b538SAndroid Build Coastguard Worker
110*6777b538SAndroid Build Coastguard Worker uint8_t serial_length = (*data)[0];
111*6777b538SAndroid Build Coastguard Worker data->remove_prefix(sizeof(uint8_t));
112*6777b538SAndroid Build Coastguard Worker
113*6777b538SAndroid Build Coastguard Worker if (data->size() < serial_length)
114*6777b538SAndroid Build Coastguard Worker return false;
115*6777b538SAndroid Build Coastguard Worker
116*6777b538SAndroid Build Coastguard Worker out_serials->push_back(std::string());
117*6777b538SAndroid Build Coastguard Worker out_serials->back() = std::string(data->substr(0, serial_length));
118*6777b538SAndroid Build Coastguard Worker data->remove_prefix(serial_length);
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker return true;
122*6777b538SAndroid Build Coastguard Worker }
123*6777b538SAndroid Build Coastguard Worker
124*6777b538SAndroid Build Coastguard Worker // CopyHashListFromHeader parses a list of base64-encoded, SHA-256 hashes from
125*6777b538SAndroid Build Coastguard Worker // the given |key| (without path expansion) in |header_dict| and sets |*out|
126*6777b538SAndroid Build Coastguard Worker // to the decoded values. It's not an error if |key| is not found in
127*6777b538SAndroid Build Coastguard Worker // |header_dict|.
CopyHashListFromHeader(const base::Value::Dict & header_dict,const char * key,std::vector<std::string> * out)128*6777b538SAndroid Build Coastguard Worker bool CopyHashListFromHeader(const base::Value::Dict& header_dict,
129*6777b538SAndroid Build Coastguard Worker const char* key,
130*6777b538SAndroid Build Coastguard Worker std::vector<std::string>* out) {
131*6777b538SAndroid Build Coastguard Worker const base::Value::List* list = header_dict.FindList(key);
132*6777b538SAndroid Build Coastguard Worker if (!list) {
133*6777b538SAndroid Build Coastguard Worker // Hash lists are optional so it's not an error if not present.
134*6777b538SAndroid Build Coastguard Worker return true;
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker
137*6777b538SAndroid Build Coastguard Worker out->clear();
138*6777b538SAndroid Build Coastguard Worker out->reserve(list->size());
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Worker std::string sha256_base64;
141*6777b538SAndroid Build Coastguard Worker
142*6777b538SAndroid Build Coastguard Worker for (const base::Value& i : *list) {
143*6777b538SAndroid Build Coastguard Worker sha256_base64.clear();
144*6777b538SAndroid Build Coastguard Worker
145*6777b538SAndroid Build Coastguard Worker if (!i.is_string())
146*6777b538SAndroid Build Coastguard Worker return false;
147*6777b538SAndroid Build Coastguard Worker sha256_base64 = i.GetString();
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Worker out->push_back(std::string());
150*6777b538SAndroid Build Coastguard Worker if (!base::Base64Decode(sha256_base64, &out->back())) {
151*6777b538SAndroid Build Coastguard Worker out->pop_back();
152*6777b538SAndroid Build Coastguard Worker return false;
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker }
155*6777b538SAndroid Build Coastguard Worker
156*6777b538SAndroid Build Coastguard Worker return true;
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker // CopyHashToHashesMapFromHeader parse a map from base64-encoded, SHA-256
160*6777b538SAndroid Build Coastguard Worker // hashes to lists of the same, from the given |key| in |header_dict|. It
161*6777b538SAndroid Build Coastguard Worker // copies the map data into |out| (after base64-decoding).
CopyHashToHashesMapFromHeader(const base::Value::Dict & header_dict,const char * key,std::unordered_map<std::string,std::vector<std::string>> * out)162*6777b538SAndroid Build Coastguard Worker bool CopyHashToHashesMapFromHeader(
163*6777b538SAndroid Build Coastguard Worker const base::Value::Dict& header_dict,
164*6777b538SAndroid Build Coastguard Worker const char* key,
165*6777b538SAndroid Build Coastguard Worker std::unordered_map<std::string, std::vector<std::string>>* out) {
166*6777b538SAndroid Build Coastguard Worker out->clear();
167*6777b538SAndroid Build Coastguard Worker
168*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* dict = header_dict.FindDict(key);
169*6777b538SAndroid Build Coastguard Worker if (dict == nullptr) {
170*6777b538SAndroid Build Coastguard Worker // Maps are optional so it's not an error if not present.
171*6777b538SAndroid Build Coastguard Worker return true;
172*6777b538SAndroid Build Coastguard Worker }
173*6777b538SAndroid Build Coastguard Worker
174*6777b538SAndroid Build Coastguard Worker for (auto i : *dict) {
175*6777b538SAndroid Build Coastguard Worker if (!i.second.is_list()) {
176*6777b538SAndroid Build Coastguard Worker return false;
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker
179*6777b538SAndroid Build Coastguard Worker std::vector<std::string> allowed_spkis;
180*6777b538SAndroid Build Coastguard Worker for (const auto& j : i.second.GetList()) {
181*6777b538SAndroid Build Coastguard Worker allowed_spkis.emplace_back();
182*6777b538SAndroid Build Coastguard Worker if (!j.is_string() ||
183*6777b538SAndroid Build Coastguard Worker !base::Base64Decode(j.GetString(), &allowed_spkis.back())) {
184*6777b538SAndroid Build Coastguard Worker return false;
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker }
187*6777b538SAndroid Build Coastguard Worker
188*6777b538SAndroid Build Coastguard Worker std::string subject_hash;
189*6777b538SAndroid Build Coastguard Worker if (!base::Base64Decode(i.first, &subject_hash)) {
190*6777b538SAndroid Build Coastguard Worker return false;
191*6777b538SAndroid Build Coastguard Worker }
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Worker (*out)[subject_hash] = allowed_spkis;
194*6777b538SAndroid Build Coastguard Worker }
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Worker return true;
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker } // namespace
200*6777b538SAndroid Build Coastguard Worker
201*6777b538SAndroid Build Coastguard Worker CRLSet::CRLSet() = default;
202*6777b538SAndroid Build Coastguard Worker
203*6777b538SAndroid Build Coastguard Worker CRLSet::~CRLSet() = default;
204*6777b538SAndroid Build Coastguard Worker
205*6777b538SAndroid Build Coastguard Worker // static
Parse(std::string_view data,scoped_refptr<CRLSet> * out_crl_set)206*6777b538SAndroid Build Coastguard Worker bool CRLSet::Parse(std::string_view data, scoped_refptr<CRLSet>* out_crl_set) {
207*6777b538SAndroid Build Coastguard Worker TRACE_EVENT0(NetTracingCategory(), "CRLSet::Parse");
208*6777b538SAndroid Build Coastguard Worker // Other parts of Chrome assume that we're little endian, so we don't lose
209*6777b538SAndroid Build Coastguard Worker // anything by doing this.
210*6777b538SAndroid Build Coastguard Worker #if defined(__BYTE_ORDER)
211*6777b538SAndroid Build Coastguard Worker // Linux check
212*6777b538SAndroid Build Coastguard Worker static_assert(__BYTE_ORDER == __LITTLE_ENDIAN, "assumes little endian");
213*6777b538SAndroid Build Coastguard Worker #elif defined(__BIG_ENDIAN__)
214*6777b538SAndroid Build Coastguard Worker // Mac check
215*6777b538SAndroid Build Coastguard Worker #error assumes little endian
216*6777b538SAndroid Build Coastguard Worker #endif
217*6777b538SAndroid Build Coastguard Worker
218*6777b538SAndroid Build Coastguard Worker std::optional<base::Value> header_value = ReadHeader(&data);
219*6777b538SAndroid Build Coastguard Worker if (!header_value) {
220*6777b538SAndroid Build Coastguard Worker return false;
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker
223*6777b538SAndroid Build Coastguard Worker const base::Value::Dict& header_dict = header_value->GetDict();
224*6777b538SAndroid Build Coastguard Worker
225*6777b538SAndroid Build Coastguard Worker const std::string* contents = header_dict.FindString("ContentType");
226*6777b538SAndroid Build Coastguard Worker if (!contents || (*contents != "CRLSet"))
227*6777b538SAndroid Build Coastguard Worker return false;
228*6777b538SAndroid Build Coastguard Worker
229*6777b538SAndroid Build Coastguard Worker if (header_dict.FindInt("Version") != kCurrentFileVersion)
230*6777b538SAndroid Build Coastguard Worker return false;
231*6777b538SAndroid Build Coastguard Worker
232*6777b538SAndroid Build Coastguard Worker std::optional<int> sequence = header_dict.FindInt("Sequence");
233*6777b538SAndroid Build Coastguard Worker if (!sequence)
234*6777b538SAndroid Build Coastguard Worker return false;
235*6777b538SAndroid Build Coastguard Worker
236*6777b538SAndroid Build Coastguard Worker // NotAfter is optional for now.
237*6777b538SAndroid Build Coastguard Worker double not_after = header_dict.FindDouble("NotAfter").value_or(0);
238*6777b538SAndroid Build Coastguard Worker if (not_after < 0)
239*6777b538SAndroid Build Coastguard Worker return false;
240*6777b538SAndroid Build Coastguard Worker
241*6777b538SAndroid Build Coastguard Worker auto crl_set = base::WrapRefCounted(new CRLSet());
242*6777b538SAndroid Build Coastguard Worker crl_set->sequence_ = static_cast<uint32_t>(*sequence);
243*6777b538SAndroid Build Coastguard Worker crl_set->not_after_ = static_cast<uint64_t>(not_after);
244*6777b538SAndroid Build Coastguard Worker crl_set->crls_.reserve(64); // Value observed experimentally.
245*6777b538SAndroid Build Coastguard Worker
246*6777b538SAndroid Build Coastguard Worker while (!data.empty()) {
247*6777b538SAndroid Build Coastguard Worker std::string spki_hash;
248*6777b538SAndroid Build Coastguard Worker std::vector<std::string> blocked_serials;
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker if (!ReadCRL(&data, &spki_hash, &blocked_serials)) {
251*6777b538SAndroid Build Coastguard Worker return false;
252*6777b538SAndroid Build Coastguard Worker }
253*6777b538SAndroid Build Coastguard Worker crl_set->crls_[std::move(spki_hash)] = std::move(blocked_serials);
254*6777b538SAndroid Build Coastguard Worker }
255*6777b538SAndroid Build Coastguard Worker
256*6777b538SAndroid Build Coastguard Worker std::vector<std::string> blocked_interception_spkis;
257*6777b538SAndroid Build Coastguard Worker if (!CopyHashListFromHeader(header_dict, "BlockedSPKIs",
258*6777b538SAndroid Build Coastguard Worker &crl_set->blocked_spkis_) ||
259*6777b538SAndroid Build Coastguard Worker !CopyHashToHashesMapFromHeader(header_dict, "LimitedSubjects",
260*6777b538SAndroid Build Coastguard Worker &crl_set->limited_subjects_) ||
261*6777b538SAndroid Build Coastguard Worker !CopyHashListFromHeader(header_dict, "KnownInterceptionSPKIs",
262*6777b538SAndroid Build Coastguard Worker &crl_set->known_interception_spkis_) ||
263*6777b538SAndroid Build Coastguard Worker !CopyHashListFromHeader(header_dict, "BlockedInterceptionSPKIs",
264*6777b538SAndroid Build Coastguard Worker &blocked_interception_spkis)) {
265*6777b538SAndroid Build Coastguard Worker return false;
266*6777b538SAndroid Build Coastguard Worker }
267*6777b538SAndroid Build Coastguard Worker
268*6777b538SAndroid Build Coastguard Worker // Add the BlockedInterceptionSPKIs to both lists; these are provided as
269*6777b538SAndroid Build Coastguard Worker // a separate list to allow less data to be sent over the wire, even though
270*6777b538SAndroid Build Coastguard Worker // they are duplicated in-memory.
271*6777b538SAndroid Build Coastguard Worker crl_set->blocked_spkis_.insert(crl_set->blocked_spkis_.end(),
272*6777b538SAndroid Build Coastguard Worker blocked_interception_spkis.begin(),
273*6777b538SAndroid Build Coastguard Worker blocked_interception_spkis.end());
274*6777b538SAndroid Build Coastguard Worker crl_set->known_interception_spkis_.insert(
275*6777b538SAndroid Build Coastguard Worker crl_set->known_interception_spkis_.end(),
276*6777b538SAndroid Build Coastguard Worker blocked_interception_spkis.begin(), blocked_interception_spkis.end());
277*6777b538SAndroid Build Coastguard Worker
278*6777b538SAndroid Build Coastguard Worker // Defines kSPKIBlockList and kKnownInterceptionList
279*6777b538SAndroid Build Coastguard Worker #include "net/cert/cert_verify_proc_blocklist.inc"
280*6777b538SAndroid Build Coastguard Worker for (const auto& hash : kSPKIBlockList) {
281*6777b538SAndroid Build Coastguard Worker crl_set->blocked_spkis_.emplace_back(reinterpret_cast<const char*>(hash),
282*6777b538SAndroid Build Coastguard Worker crypto::kSHA256Length);
283*6777b538SAndroid Build Coastguard Worker }
284*6777b538SAndroid Build Coastguard Worker
285*6777b538SAndroid Build Coastguard Worker for (const auto& hash : kKnownInterceptionList) {
286*6777b538SAndroid Build Coastguard Worker crl_set->known_interception_spkis_.emplace_back(
287*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const char*>(hash), crypto::kSHA256Length);
288*6777b538SAndroid Build Coastguard Worker }
289*6777b538SAndroid Build Coastguard Worker
290*6777b538SAndroid Build Coastguard Worker // Sort, as these will be std::binary_search()'d.
291*6777b538SAndroid Build Coastguard Worker std::sort(crl_set->blocked_spkis_.begin(), crl_set->blocked_spkis_.end());
292*6777b538SAndroid Build Coastguard Worker std::sort(crl_set->known_interception_spkis_.begin(),
293*6777b538SAndroid Build Coastguard Worker crl_set->known_interception_spkis_.end());
294*6777b538SAndroid Build Coastguard Worker
295*6777b538SAndroid Build Coastguard Worker *out_crl_set = std::move(crl_set);
296*6777b538SAndroid Build Coastguard Worker return true;
297*6777b538SAndroid Build Coastguard Worker }
298*6777b538SAndroid Build Coastguard Worker
CheckSPKI(std::string_view spki_hash) const299*6777b538SAndroid Build Coastguard Worker CRLSet::Result CRLSet::CheckSPKI(std::string_view spki_hash) const {
300*6777b538SAndroid Build Coastguard Worker if (std::binary_search(blocked_spkis_.begin(), blocked_spkis_.end(),
301*6777b538SAndroid Build Coastguard Worker spki_hash))
302*6777b538SAndroid Build Coastguard Worker return REVOKED;
303*6777b538SAndroid Build Coastguard Worker return GOOD;
304*6777b538SAndroid Build Coastguard Worker }
305*6777b538SAndroid Build Coastguard Worker
CheckSubject(std::string_view encoded_subject,std::string_view spki_hash) const306*6777b538SAndroid Build Coastguard Worker CRLSet::Result CRLSet::CheckSubject(std::string_view encoded_subject,
307*6777b538SAndroid Build Coastguard Worker std::string_view spki_hash) const {
308*6777b538SAndroid Build Coastguard Worker const std::string digest(crypto::SHA256HashString(encoded_subject));
309*6777b538SAndroid Build Coastguard Worker const auto i = limited_subjects_.find(digest);
310*6777b538SAndroid Build Coastguard Worker if (i == limited_subjects_.end()) {
311*6777b538SAndroid Build Coastguard Worker return GOOD;
312*6777b538SAndroid Build Coastguard Worker }
313*6777b538SAndroid Build Coastguard Worker
314*6777b538SAndroid Build Coastguard Worker for (const auto& j : i->second) {
315*6777b538SAndroid Build Coastguard Worker if (spki_hash == j) {
316*6777b538SAndroid Build Coastguard Worker return GOOD;
317*6777b538SAndroid Build Coastguard Worker }
318*6777b538SAndroid Build Coastguard Worker }
319*6777b538SAndroid Build Coastguard Worker
320*6777b538SAndroid Build Coastguard Worker return REVOKED;
321*6777b538SAndroid Build Coastguard Worker }
322*6777b538SAndroid Build Coastguard Worker
CheckSerial(std::string_view serial_number,std::string_view issuer_spki_hash) const323*6777b538SAndroid Build Coastguard Worker CRLSet::Result CRLSet::CheckSerial(std::string_view serial_number,
324*6777b538SAndroid Build Coastguard Worker std::string_view issuer_spki_hash) const {
325*6777b538SAndroid Build Coastguard Worker std::string_view serial(serial_number);
326*6777b538SAndroid Build Coastguard Worker
327*6777b538SAndroid Build Coastguard Worker if (!serial.empty() && (serial[0] & 0x80) != 0) {
328*6777b538SAndroid Build Coastguard Worker // This serial number is negative but the process which generates CRL sets
329*6777b538SAndroid Build Coastguard Worker // will reject any certificates with negative serial numbers as invalid.
330*6777b538SAndroid Build Coastguard Worker return UNKNOWN;
331*6777b538SAndroid Build Coastguard Worker }
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker // Remove any leading zero bytes.
334*6777b538SAndroid Build Coastguard Worker while (serial.size() > 1 && serial[0] == 0x00)
335*6777b538SAndroid Build Coastguard Worker serial.remove_prefix(1);
336*6777b538SAndroid Build Coastguard Worker
337*6777b538SAndroid Build Coastguard Worker auto it = crls_.find(std::string(issuer_spki_hash));
338*6777b538SAndroid Build Coastguard Worker if (it == crls_.end())
339*6777b538SAndroid Build Coastguard Worker return UNKNOWN;
340*6777b538SAndroid Build Coastguard Worker
341*6777b538SAndroid Build Coastguard Worker for (const auto& issuer_serial : it->second) {
342*6777b538SAndroid Build Coastguard Worker if (issuer_serial == serial)
343*6777b538SAndroid Build Coastguard Worker return REVOKED;
344*6777b538SAndroid Build Coastguard Worker }
345*6777b538SAndroid Build Coastguard Worker
346*6777b538SAndroid Build Coastguard Worker return GOOD;
347*6777b538SAndroid Build Coastguard Worker }
348*6777b538SAndroid Build Coastguard Worker
IsKnownInterceptionKey(std::string_view spki_hash) const349*6777b538SAndroid Build Coastguard Worker bool CRLSet::IsKnownInterceptionKey(std::string_view spki_hash) const {
350*6777b538SAndroid Build Coastguard Worker return std::binary_search(known_interception_spkis_.begin(),
351*6777b538SAndroid Build Coastguard Worker known_interception_spkis_.end(), spki_hash);
352*6777b538SAndroid Build Coastguard Worker }
353*6777b538SAndroid Build Coastguard Worker
IsExpired() const354*6777b538SAndroid Build Coastguard Worker bool CRLSet::IsExpired() const {
355*6777b538SAndroid Build Coastguard Worker if (not_after_ == 0)
356*6777b538SAndroid Build Coastguard Worker return false;
357*6777b538SAndroid Build Coastguard Worker
358*6777b538SAndroid Build Coastguard Worker uint64_t now = base::Time::Now().ToTimeT();
359*6777b538SAndroid Build Coastguard Worker return now > not_after_;
360*6777b538SAndroid Build Coastguard Worker }
361*6777b538SAndroid Build Coastguard Worker
sequence() const362*6777b538SAndroid Build Coastguard Worker uint32_t CRLSet::sequence() const {
363*6777b538SAndroid Build Coastguard Worker return sequence_;
364*6777b538SAndroid Build Coastguard Worker }
365*6777b538SAndroid Build Coastguard Worker
CrlsForTesting() const366*6777b538SAndroid Build Coastguard Worker const CRLSet::CRLList& CRLSet::CrlsForTesting() const {
367*6777b538SAndroid Build Coastguard Worker return crls_;
368*6777b538SAndroid Build Coastguard Worker }
369*6777b538SAndroid Build Coastguard Worker
370*6777b538SAndroid Build Coastguard Worker // static
BuiltinCRLSet()371*6777b538SAndroid Build Coastguard Worker scoped_refptr<CRLSet> CRLSet::BuiltinCRLSet() {
372*6777b538SAndroid Build Coastguard Worker constexpr char kCRLSet[] =
373*6777b538SAndroid Build Coastguard Worker "\x31\x00{\"ContentType\":\"CRLSet\",\"Sequence\":0,\"Version\":0}";
374*6777b538SAndroid Build Coastguard Worker scoped_refptr<CRLSet> ret;
375*6777b538SAndroid Build Coastguard Worker bool parsed = CRLSet::Parse({kCRLSet, sizeof(kCRLSet) - 1}, &ret);
376*6777b538SAndroid Build Coastguard Worker DCHECK(parsed);
377*6777b538SAndroid Build Coastguard Worker return ret;
378*6777b538SAndroid Build Coastguard Worker }
379*6777b538SAndroid Build Coastguard Worker
380*6777b538SAndroid Build Coastguard Worker // static
EmptyCRLSetForTesting()381*6777b538SAndroid Build Coastguard Worker scoped_refptr<CRLSet> CRLSet::EmptyCRLSetForTesting() {
382*6777b538SAndroid Build Coastguard Worker return ForTesting(false, nullptr, "", "", {});
383*6777b538SAndroid Build Coastguard Worker }
384*6777b538SAndroid Build Coastguard Worker
385*6777b538SAndroid Build Coastguard Worker // static
ExpiredCRLSetForTesting()386*6777b538SAndroid Build Coastguard Worker scoped_refptr<CRLSet> CRLSet::ExpiredCRLSetForTesting() {
387*6777b538SAndroid Build Coastguard Worker return ForTesting(true, nullptr, "", "", {});
388*6777b538SAndroid Build Coastguard Worker }
389*6777b538SAndroid Build Coastguard Worker
390*6777b538SAndroid Build Coastguard Worker // static
ForTesting(bool is_expired,const SHA256HashValue * issuer_spki,std::string_view serial_number,std::string_view utf8_common_name,const std::vector<std::string> & acceptable_spki_hashes_for_cn)391*6777b538SAndroid Build Coastguard Worker scoped_refptr<CRLSet> CRLSet::ForTesting(
392*6777b538SAndroid Build Coastguard Worker bool is_expired,
393*6777b538SAndroid Build Coastguard Worker const SHA256HashValue* issuer_spki,
394*6777b538SAndroid Build Coastguard Worker std::string_view serial_number,
395*6777b538SAndroid Build Coastguard Worker std::string_view utf8_common_name,
396*6777b538SAndroid Build Coastguard Worker const std::vector<std::string>& acceptable_spki_hashes_for_cn) {
397*6777b538SAndroid Build Coastguard Worker std::string subject_hash;
398*6777b538SAndroid Build Coastguard Worker if (!utf8_common_name.empty()) {
399*6777b538SAndroid Build Coastguard Worker CBB cbb, top_level, set, inner_seq, oid, cn;
400*6777b538SAndroid Build Coastguard Worker uint8_t* x501_data;
401*6777b538SAndroid Build Coastguard Worker size_t x501_len;
402*6777b538SAndroid Build Coastguard Worker static const uint8_t kCommonNameOID[] = {0x55, 0x04, 0x03}; // 2.5.4.3
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker CBB_zero(&cbb);
405*6777b538SAndroid Build Coastguard Worker
406*6777b538SAndroid Build Coastguard Worker if (!CBB_init(&cbb, 32) ||
407*6777b538SAndroid Build Coastguard Worker !CBB_add_asn1(&cbb, &top_level, CBS_ASN1_SEQUENCE) ||
408*6777b538SAndroid Build Coastguard Worker !CBB_add_asn1(&top_level, &set, CBS_ASN1_SET) ||
409*6777b538SAndroid Build Coastguard Worker !CBB_add_asn1(&set, &inner_seq, CBS_ASN1_SEQUENCE) ||
410*6777b538SAndroid Build Coastguard Worker !CBB_add_asn1(&inner_seq, &oid, CBS_ASN1_OBJECT) ||
411*6777b538SAndroid Build Coastguard Worker !CBB_add_bytes(&oid, kCommonNameOID, sizeof(kCommonNameOID)) ||
412*6777b538SAndroid Build Coastguard Worker !CBB_add_asn1(&inner_seq, &cn, CBS_ASN1_UTF8STRING) ||
413*6777b538SAndroid Build Coastguard Worker !CBB_add_bytes(
414*6777b538SAndroid Build Coastguard Worker &cn, reinterpret_cast<const uint8_t*>(utf8_common_name.data()),
415*6777b538SAndroid Build Coastguard Worker utf8_common_name.size()) ||
416*6777b538SAndroid Build Coastguard Worker !CBB_finish(&cbb, &x501_data, &x501_len)) {
417*6777b538SAndroid Build Coastguard Worker CBB_cleanup(&cbb);
418*6777b538SAndroid Build Coastguard Worker return nullptr;
419*6777b538SAndroid Build Coastguard Worker }
420*6777b538SAndroid Build Coastguard Worker
421*6777b538SAndroid Build Coastguard Worker subject_hash.assign(crypto::SHA256HashString(
422*6777b538SAndroid Build Coastguard Worker std::string_view(reinterpret_cast<char*>(x501_data), x501_len)));
423*6777b538SAndroid Build Coastguard Worker OPENSSL_free(x501_data);
424*6777b538SAndroid Build Coastguard Worker }
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker auto crl_set = base::WrapRefCounted(new CRLSet());
427*6777b538SAndroid Build Coastguard Worker crl_set->sequence_ = 0;
428*6777b538SAndroid Build Coastguard Worker if (is_expired)
429*6777b538SAndroid Build Coastguard Worker crl_set->not_after_ = 1;
430*6777b538SAndroid Build Coastguard Worker
431*6777b538SAndroid Build Coastguard Worker if (issuer_spki) {
432*6777b538SAndroid Build Coastguard Worker const std::string spki(reinterpret_cast<const char*>(issuer_spki->data),
433*6777b538SAndroid Build Coastguard Worker sizeof(issuer_spki->data));
434*6777b538SAndroid Build Coastguard Worker std::vector<std::string> serials;
435*6777b538SAndroid Build Coastguard Worker if (!serial_number.empty()) {
436*6777b538SAndroid Build Coastguard Worker serials.push_back(std::string(serial_number));
437*6777b538SAndroid Build Coastguard Worker // |serial_number| is in DER-encoded form, which means it may have a
438*6777b538SAndroid Build Coastguard Worker // leading 0x00 to indicate it is a positive INTEGER. CRLSets are stored
439*6777b538SAndroid Build Coastguard Worker // without these leading 0x00, as handled in CheckSerial(), so remove
440*6777b538SAndroid Build Coastguard Worker // that here. As DER-encoding means that any sequences of leading zeroes
441*6777b538SAndroid Build Coastguard Worker // should be omitted, except to indicate sign, there should only ever
442*6777b538SAndroid Build Coastguard Worker // be one, and the next byte should have the high bit set.
443*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(serials[0][0] & 0x80, 0); // Negative serials are not allowed.
444*6777b538SAndroid Build Coastguard Worker if (serials[0][0] == 0x00) {
445*6777b538SAndroid Build Coastguard Worker serials[0].erase(0, 1);
446*6777b538SAndroid Build Coastguard Worker // If there was a leading 0x00, then the high-bit of the next byte
447*6777b538SAndroid Build Coastguard Worker // should have been set.
448*6777b538SAndroid Build Coastguard Worker DCHECK(!serials[0].empty() && serials[0][0] & 0x80);
449*6777b538SAndroid Build Coastguard Worker }
450*6777b538SAndroid Build Coastguard Worker }
451*6777b538SAndroid Build Coastguard Worker
452*6777b538SAndroid Build Coastguard Worker crl_set->crls_.emplace(std::move(spki), std::move(serials));
453*6777b538SAndroid Build Coastguard Worker }
454*6777b538SAndroid Build Coastguard Worker
455*6777b538SAndroid Build Coastguard Worker if (!subject_hash.empty())
456*6777b538SAndroid Build Coastguard Worker crl_set->limited_subjects_[subject_hash] = acceptable_spki_hashes_for_cn;
457*6777b538SAndroid Build Coastguard Worker
458*6777b538SAndroid Build Coastguard Worker return crl_set;
459*6777b538SAndroid Build Coastguard Worker }
460*6777b538SAndroid Build Coastguard Worker
461*6777b538SAndroid Build Coastguard Worker } // namespace net
462