xref: /aosp_15_r20/external/cronet/net/cert/crl_set.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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