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