• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "base/base64.h"
6 #include "base/debug/trace_event.h"
7 #include "base/format_macros.h"
8 #include "base/json/json_reader.h"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h"
14 #include "base/values.h"
15 #include "crypto/sha2.h"
16 #include "net/cert/crl_set.h"
17 #include "third_party/zlib/zlib.h"
18 
19 namespace net {
20 
21 // Decompress zlib decompressed |in| into |out|. |out_len| is the number of
22 // bytes at |out| and must be exactly equal to the size of the decompressed
23 // data.
DecompressZlib(uint8 * out,int out_len,base::StringPiece in)24 static bool DecompressZlib(uint8* out, int out_len, base::StringPiece in) {
25   z_stream z;
26   memset(&z, 0, sizeof(z));
27 
28   z.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(in.data()));
29   z.avail_in = in.size();
30   z.next_out = reinterpret_cast<Bytef*>(out);
31   z.avail_out = out_len;
32 
33   if (inflateInit(&z) != Z_OK)
34     return false;
35   bool ret = false;
36   int r = inflate(&z, Z_FINISH);
37   if (r != Z_STREAM_END)
38     goto err;
39   if (z.avail_in || z.avail_out)
40     goto err;
41   ret = true;
42 
43  err:
44   inflateEnd(&z);
45   return ret;
46 }
47 
CRLSet()48 CRLSet::CRLSet()
49     : sequence_(0),
50       not_after_(0) {
51 }
52 
~CRLSet()53 CRLSet::~CRLSet() {
54 }
55 
56 // CRLSet format:
57 //
58 // uint16le header_len
59 // byte[header_len] header_bytes
60 // repeated {
61 //   byte[32] parent_spki_sha256
62 //   uint32le num_serials
63 //   [num_serials] {
64 //     uint8 serial_length;
65 //     byte[serial_length] serial;
66 //   }
67 //
68 // header_bytes consists of a JSON dictionary with the following keys:
69 //   Version (int): currently 0
70 //   ContentType (string): "CRLSet" or "CRLSetDelta" (magic value)
71 //   DeltaFrom (int32): if this is a delta update (see below), then this
72 //       contains the sequence number of the base CRLSet.
73 //   Sequence (int32): the monotonic sequence number of this CRL set.
74 //
75 // A delta CRLSet is similar to a CRLSet:
76 //
77 // struct CompressedChanges {
78 //    uint32le uncompressed_size
79 //    uint32le compressed_size
80 //    byte[compressed_size] zlib_data
81 // }
82 //
83 // uint16le header_len
84 // byte[header_len] header_bytes
85 // CompressedChanges crl_changes
86 // [crl_changes.uncompressed_size] {
87 //   switch (crl_changes[i]) {
88 //   case 0:
89 //     // CRL is the same
90 //   case 1:
91 //     // New CRL inserted
92 //     // See CRL structure from the non-delta format
93 //   case 2:
94 //     // CRL deleted
95 //   case 3:
96 //     // CRL changed
97 //     CompressedChanges serials_changes
98 //     [serials_changes.uncompressed_size] {
99 //       switch (serials_changes[i]) {
100 //       case 0:
101 //         // the serial is the same
102 //       case 1:
103 //         // serial inserted
104 //         uint8 serial_length
105 //         byte[serial_length] serial
106 //       case 2:
107 //         // serial deleted
108 //       }
109 //     }
110 //   }
111 // }
112 //
113 // A delta CRLSet applies to a specific CRL set as given in the
114 // header's "DeltaFrom" value. The delta describes the changes to each CRL
115 // in turn with a zlib compressed array of options: either the CRL is the same,
116 // a new CRL is inserted, the CRL is deleted or the CRL is updated. In the case
117 // of an update, the serials in the CRL are considered in the same fashion
118 // except there is no delta update of a serial number: they are either
119 // inserted, deleted or left the same.
120 
121 // ReadHeader reads the header (including length prefix) from |data| and
122 // updates |data| to remove the header on return. Caller takes ownership of the
123 // returned pointer.
ReadHeader(base::StringPiece * data)124 static base::DictionaryValue* ReadHeader(base::StringPiece* data) {
125   if (data->size() < 2)
126     return NULL;
127   uint16 header_len;
128   memcpy(&header_len, data->data(), 2);  // assumes little-endian.
129   data->remove_prefix(2);
130 
131   if (data->size() < header_len)
132     return NULL;
133 
134   const base::StringPiece header_bytes(data->data(), header_len);
135   data->remove_prefix(header_len);
136 
137   scoped_ptr<base::Value> header(base::JSONReader::Read(
138       header_bytes, base::JSON_ALLOW_TRAILING_COMMAS));
139   if (header.get() == NULL)
140     return NULL;
141 
142   if (!header->IsType(base::Value::TYPE_DICTIONARY))
143     return NULL;
144   return reinterpret_cast<base::DictionaryValue*>(header.release());
145 }
146 
147 // kCurrentFileVersion is the version of the CRLSet file format that we
148 // currently implement.
149 static const int kCurrentFileVersion = 0;
150 
ReadCRL(base::StringPiece * data,std::string * out_parent_spki_hash,std::vector<std::string> * out_serials)151 static bool ReadCRL(base::StringPiece* data, std::string* out_parent_spki_hash,
152                     std::vector<std::string>* out_serials) {
153   if (data->size() < crypto::kSHA256Length)
154     return false;
155   out_parent_spki_hash->assign(data->data(), crypto::kSHA256Length);
156   data->remove_prefix(crypto::kSHA256Length);
157 
158   if (data->size() < sizeof(uint32))
159     return false;
160   uint32 num_serials;
161   memcpy(&num_serials, data->data(), sizeof(uint32));  // assumes little endian
162   if (num_serials > 32 * 1024 * 1024)  // Sanity check.
163     return false;
164 
165   out_serials->reserve(num_serials);
166   data->remove_prefix(sizeof(uint32));
167 
168   for (uint32 i = 0; i < num_serials; ++i) {
169     if (data->size() < sizeof(uint8))
170       return false;
171 
172     uint8 serial_length = data->data()[0];
173     data->remove_prefix(sizeof(uint8));
174 
175     if (data->size() < serial_length)
176       return false;
177 
178     out_serials->push_back(std::string());
179     out_serials->back().assign(data->data(), serial_length);
180     data->remove_prefix(serial_length);
181   }
182 
183   return true;
184 }
185 
CopyBlockedSPKIsFromHeader(base::DictionaryValue * header_dict)186 bool CRLSet::CopyBlockedSPKIsFromHeader(base::DictionaryValue* header_dict) {
187   base::ListValue* blocked_spkis_list = NULL;
188   if (!header_dict->GetList("BlockedSPKIs", &blocked_spkis_list)) {
189     // BlockedSPKIs is optional, so it's fine if we don't find it.
190     return true;
191   }
192 
193   blocked_spkis_.clear();
194   blocked_spkis_.reserve(blocked_spkis_list->GetSize());
195 
196   std::string spki_sha256_base64;
197 
198   for (size_t i = 0; i < blocked_spkis_list->GetSize(); ++i) {
199     spki_sha256_base64.clear();
200 
201     if (!blocked_spkis_list->GetString(i, &spki_sha256_base64))
202       return false;
203 
204     blocked_spkis_.push_back(std::string());
205     if (!base::Base64Decode(spki_sha256_base64, &blocked_spkis_.back())) {
206       blocked_spkis_.pop_back();
207       return false;
208     }
209   }
210 
211   return true;
212 }
213 
214 // static
Parse(base::StringPiece data,scoped_refptr<CRLSet> * out_crl_set)215 bool CRLSet::Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set) {
216   TRACE_EVENT0("CRLSet", "Parse");
217   // Other parts of Chrome assume that we're little endian, so we don't lose
218   // anything by doing this.
219 #if defined(__BYTE_ORDER)
220   // Linux check
221   COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);
222 #elif defined(__BIG_ENDIAN__)
223   // Mac check
224   #error assumes little endian
225 #endif
226 
227   scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
228   if (!header_dict.get())
229     return false;
230 
231   std::string contents;
232   if (!header_dict->GetString("ContentType", &contents))
233     return false;
234   if (contents != "CRLSet")
235     return false;
236 
237   int version;
238   if (!header_dict->GetInteger("Version", &version) ||
239       version != kCurrentFileVersion) {
240     return false;
241   }
242 
243   int sequence;
244   if (!header_dict->GetInteger("Sequence", &sequence))
245     return false;
246 
247   double not_after;
248   if (!header_dict->GetDouble("NotAfter", &not_after)) {
249     // NotAfter is optional for now.
250     not_after = 0;
251   }
252   if (not_after < 0)
253     return false;
254 
255   scoped_refptr<CRLSet> crl_set(new CRLSet());
256   crl_set->sequence_ = static_cast<uint32>(sequence);
257   crl_set->not_after_ = static_cast<uint64>(not_after);
258   crl_set->crls_.reserve(64);  // Value observed experimentally.
259 
260   for (size_t crl_index = 0; !data.empty(); crl_index++) {
261     // Speculatively push back a pair and pass it to ReadCRL() to avoid
262     // unnecessary copies.
263     crl_set->crls_.push_back(
264         std::make_pair(std::string(), std::vector<std::string>()));
265     std::pair<std::string, std::vector<std::string> >* const back_pair =
266         &crl_set->crls_.back();
267 
268     if (!ReadCRL(&data, &back_pair->first, &back_pair->second)) {
269       // Undo the speculative push_back() performed above.
270       crl_set->crls_.pop_back();
271       return false;
272     }
273 
274     crl_set->crls_index_by_issuer_[back_pair->first] = crl_index;
275   }
276 
277   if (!crl_set->CopyBlockedSPKIsFromHeader(header_dict.get()))
278     return false;
279 
280   *out_crl_set = crl_set;
281   return true;
282 }
283 
284 // kMaxUncompressedChangesLength is the largest changes array that we'll
285 // accept. This bounds the number of CRLs in the CRLSet as well as the number
286 // of serial numbers in a given CRL.
287 static const unsigned kMaxUncompressedChangesLength = 1024 * 1024;
288 
ReadChanges(base::StringPiece * data,std::vector<uint8> * out_changes)289 static bool ReadChanges(base::StringPiece* data,
290                         std::vector<uint8>* out_changes) {
291   uint32 uncompressed_size, compressed_size;
292   if (data->size() < 2 * sizeof(uint32))
293     return false;
294   // assumes little endian.
295   memcpy(&uncompressed_size, data->data(), sizeof(uint32));
296   data->remove_prefix(4);
297   memcpy(&compressed_size, data->data(), sizeof(uint32));
298   data->remove_prefix(4);
299 
300   if (uncompressed_size > kMaxUncompressedChangesLength)
301     return false;
302   if (data->size() < compressed_size)
303     return false;
304 
305   out_changes->clear();
306   if (uncompressed_size == 0)
307     return true;
308 
309   out_changes->resize(uncompressed_size);
310   base::StringPiece compressed(data->data(), compressed_size);
311   data->remove_prefix(compressed_size);
312   return DecompressZlib(&(*out_changes)[0], uncompressed_size, compressed);
313 }
314 
315 // These are the range coder symbols used in delta updates.
316 enum {
317   SYMBOL_SAME = 0,
318   SYMBOL_INSERT = 1,
319   SYMBOL_DELETE = 2,
320   SYMBOL_CHANGED = 3,
321 };
322 
ReadDeltaCRL(base::StringPiece * data,const std::vector<std::string> & old_serials,std::vector<std::string> * out_serials)323 bool ReadDeltaCRL(base::StringPiece* data,
324                   const std::vector<std::string>& old_serials,
325                   std::vector<std::string>* out_serials) {
326   std::vector<uint8> changes;
327   if (!ReadChanges(data, &changes))
328     return false;
329 
330   size_t i = 0;
331   for (std::vector<uint8>::const_iterator k = changes.begin();
332        k != changes.end(); ++k) {
333     if (*k == SYMBOL_SAME) {
334       if (i >= old_serials.size())
335         return false;
336       out_serials->push_back(old_serials[i]);
337       i++;
338     } else if (*k == SYMBOL_INSERT) {
339       uint8 serial_length;
340       if (data->size() < sizeof(uint8))
341         return false;
342       memcpy(&serial_length, data->data(), sizeof(uint8));
343       data->remove_prefix(sizeof(uint8));
344 
345       if (data->size() < serial_length)
346         return false;
347       const std::string serial(data->data(), serial_length);
348       data->remove_prefix(serial_length);
349 
350       out_serials->push_back(serial);
351     } else if (*k == SYMBOL_DELETE) {
352       if (i >= old_serials.size())
353         return false;
354       i++;
355     } else {
356       NOTREACHED();
357       return false;
358     }
359   }
360 
361   if (i != old_serials.size())
362     return false;
363   return true;
364 }
365 
ApplyDelta(const base::StringPiece & in_data,scoped_refptr<CRLSet> * out_crl_set)366 bool CRLSet::ApplyDelta(const base::StringPiece& in_data,
367                         scoped_refptr<CRLSet>* out_crl_set) {
368   base::StringPiece data(in_data);
369   scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
370   if (!header_dict.get())
371     return false;
372 
373   std::string contents;
374   if (!header_dict->GetString("ContentType", &contents))
375     return false;
376   if (contents != "CRLSetDelta")
377     return false;
378 
379   int version;
380   if (!header_dict->GetInteger("Version", &version) ||
381       version != kCurrentFileVersion) {
382     return false;
383   }
384 
385   int sequence, delta_from;
386   if (!header_dict->GetInteger("Sequence", &sequence) ||
387       !header_dict->GetInteger("DeltaFrom", &delta_from) ||
388       delta_from < 0 ||
389       static_cast<uint32>(delta_from) != sequence_) {
390     return false;
391   }
392 
393   double not_after;
394   if (!header_dict->GetDouble("NotAfter", &not_after)) {
395     // NotAfter is optional for now.
396     not_after = 0;
397   }
398   if (not_after < 0)
399     return false;
400 
401   scoped_refptr<CRLSet> crl_set(new CRLSet);
402   crl_set->sequence_ = static_cast<uint32>(sequence);
403   crl_set->not_after_ = static_cast<uint64>(not_after);
404 
405   if (!crl_set->CopyBlockedSPKIsFromHeader(header_dict.get()))
406     return false;
407 
408   std::vector<uint8> crl_changes;
409 
410   if (!ReadChanges(&data, &crl_changes))
411     return false;
412 
413   size_t i = 0, j = 0;
414   for (std::vector<uint8>::const_iterator k = crl_changes.begin();
415        k != crl_changes.end(); ++k) {
416     if (*k == SYMBOL_SAME) {
417       if (i >= crls_.size())
418         return false;
419       crl_set->crls_.push_back(crls_[i]);
420       crl_set->crls_index_by_issuer_[crls_[i].first] = j;
421       i++;
422       j++;
423     } else if (*k == SYMBOL_INSERT) {
424       std::string parent_spki_hash;
425       std::vector<std::string> serials;
426       if (!ReadCRL(&data, &parent_spki_hash, &serials))
427         return false;
428       crl_set->crls_.push_back(std::make_pair(parent_spki_hash, serials));
429       crl_set->crls_index_by_issuer_[parent_spki_hash] = j;
430       j++;
431     } else if (*k == SYMBOL_DELETE) {
432       if (i >= crls_.size())
433         return false;
434       i++;
435     } else if (*k == SYMBOL_CHANGED) {
436       if (i >= crls_.size())
437         return false;
438       std::vector<std::string> serials;
439       if (!ReadDeltaCRL(&data, crls_[i].second, &serials))
440         return false;
441       crl_set->crls_.push_back(std::make_pair(crls_[i].first, serials));
442       crl_set->crls_index_by_issuer_[crls_[i].first] = j;
443       i++;
444       j++;
445     } else {
446       NOTREACHED();
447       return false;
448     }
449   }
450 
451   if (!data.empty())
452     return false;
453   if (i != crls_.size())
454     return false;
455 
456   *out_crl_set = crl_set;
457   return true;
458 }
459 
460 // static
GetIsDeltaUpdate(const base::StringPiece & in_data,bool * is_delta)461 bool CRLSet::GetIsDeltaUpdate(const base::StringPiece& in_data,
462                               bool* is_delta) {
463   base::StringPiece data(in_data);
464   scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
465   if (!header_dict.get())
466     return false;
467 
468   std::string contents;
469   if (!header_dict->GetString("ContentType", &contents))
470     return false;
471 
472   if (contents == "CRLSet") {
473     *is_delta = false;
474   } else if (contents == "CRLSetDelta") {
475     *is_delta = true;
476   } else {
477     return false;
478   }
479 
480   return true;
481 }
482 
Serialize() const483 std::string CRLSet::Serialize() const {
484   std::string header = base::StringPrintf(
485       "{"
486       "\"Version\":0,"
487       "\"ContentType\":\"CRLSet\","
488       "\"Sequence\":%u,"
489       "\"DeltaFrom\":0,"
490       "\"NumParents\":%u,"
491       "\"BlockedSPKIs\":[",
492       static_cast<unsigned>(sequence_),
493       static_cast<unsigned>(crls_.size()));
494 
495   for (std::vector<std::string>::const_iterator i = blocked_spkis_.begin();
496        i != blocked_spkis_.end(); ++i) {
497     std::string spki_hash_base64;
498     base::Base64Encode(*i, &spki_hash_base64);
499 
500     if (i != blocked_spkis_.begin())
501       header += ",";
502     header += "\"" + spki_hash_base64 + "\"";
503   }
504   header += "]";
505   if (not_after_ != 0)
506     header += base::StringPrintf(",\"NotAfter\":%" PRIu64, not_after_);
507   header += "}";
508 
509   size_t len = 2 /* header len */ + header.size();
510 
511   for (CRLList::const_iterator i = crls_.begin(); i != crls_.end(); ++i) {
512     len += i->first.size() + 4 /* num serials */;
513     for (std::vector<std::string>::const_iterator j = i->second.begin();
514          j != i->second.end(); ++j) {
515       len += 1 /* serial length */ + j->size();
516     }
517   }
518 
519   std::string ret;
520   char* out = WriteInto(&ret, len + 1 /* to include final NUL */);
521   size_t off = 0;
522   out[off++] = header.size();
523   out[off++] = header.size() >> 8;
524   memcpy(out + off, header.data(), header.size());
525   off += header.size();
526 
527   for (CRLList::const_iterator i = crls_.begin(); i != crls_.end(); ++i) {
528     memcpy(out + off, i->first.data(), i->first.size());
529     off += i->first.size();
530     const uint32 num_serials = i->second.size();
531     memcpy(out + off, &num_serials, sizeof(num_serials));
532     off += sizeof(num_serials);
533 
534     for (std::vector<std::string>::const_iterator j = i->second.begin();
535          j != i->second.end(); ++j) {
536       out[off++] = j->size();
537       memcpy(out + off, j->data(), j->size());
538       off += j->size();
539     }
540   }
541 
542   CHECK_EQ(off, len);
543   return ret;
544 }
545 
CheckSPKI(const base::StringPiece & spki_hash) const546 CRLSet::Result CRLSet::CheckSPKI(const base::StringPiece& spki_hash) const {
547   for (std::vector<std::string>::const_iterator i = blocked_spkis_.begin();
548        i != blocked_spkis_.end(); ++i) {
549     if (spki_hash.size() == i->size() &&
550         memcmp(spki_hash.data(), i->data(), i->size()) == 0) {
551       return REVOKED;
552     }
553   }
554 
555   return GOOD;
556 }
557 
CheckSerial(const base::StringPiece & serial_number,const base::StringPiece & issuer_spki_hash) const558 CRLSet::Result CRLSet::CheckSerial(
559     const base::StringPiece& serial_number,
560     const base::StringPiece& issuer_spki_hash) const {
561   base::StringPiece serial(serial_number);
562 
563   if (!serial.empty() && (serial[0] & 0x80) != 0) {
564     // This serial number is negative but the process which generates CRL sets
565     // will reject any certificates with negative serial numbers as invalid.
566     return UNKNOWN;
567   }
568 
569   // Remove any leading zero bytes.
570   while (serial.size() > 1 && serial[0] == 0x00)
571     serial.remove_prefix(1);
572 
573   base::hash_map<std::string, size_t>::const_iterator i =
574       crls_index_by_issuer_.find(issuer_spki_hash.as_string());
575   if (i == crls_index_by_issuer_.end())
576     return UNKNOWN;
577   const std::vector<std::string>& serials = crls_[i->second].second;
578 
579   for (std::vector<std::string>::const_iterator i = serials.begin();
580        i != serials.end(); ++i) {
581     if (base::StringPiece(*i) == serial)
582       return REVOKED;
583   }
584 
585   return GOOD;
586 }
587 
IsExpired() const588 bool CRLSet::IsExpired() const {
589   if (not_after_ == 0)
590     return false;
591 
592   uint64 now = base::Time::Now().ToTimeT();
593   return now > not_after_;
594 }
595 
sequence() const596 uint32 CRLSet::sequence() const {
597   return sequence_;
598 }
599 
crls() const600 const CRLSet::CRLList& CRLSet::crls() const {
601   return crls_;
602 }
603 
604 // static
EmptyCRLSetForTesting()605 CRLSet* CRLSet::EmptyCRLSetForTesting() {
606   return ForTesting(false, NULL, "");
607 }
608 
ExpiredCRLSetForTesting()609 CRLSet* CRLSet::ExpiredCRLSetForTesting() {
610   return ForTesting(true, NULL, "");
611 }
612 
613 // static
ForTesting(bool is_expired,const SHA256HashValue * issuer_spki,const std::string & serial_number)614 CRLSet* CRLSet::ForTesting(bool is_expired,
615                            const SHA256HashValue* issuer_spki,
616                            const std::string& serial_number) {
617   CRLSet* crl_set = new CRLSet;
618   if (is_expired)
619     crl_set->not_after_ = 1;
620   if (issuer_spki != NULL) {
621     const std::string spki(reinterpret_cast<const char*>(issuer_spki->data),
622                            sizeof(issuer_spki->data));
623     crl_set->crls_.push_back(make_pair(spki, std::vector<std::string>()));
624     crl_set->crls_index_by_issuer_[spki] = 0;
625   }
626 
627   if (!serial_number.empty())
628     crl_set->crls_[0].second.push_back(serial_number);
629 
630   return crl_set;
631 }
632 
633 }  // namespace net
634