Home | History | Annotate | Download | only in cert
      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.
     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 
     48 CRLSet::CRLSet()
     49     : sequence_(0),
     50       not_after_(0) {
     51 }
     52 
     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.
    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 
    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 
    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
    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 
    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 
    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 
    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
    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 
    483 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 
    546 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 
    558 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 
    588 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 
    596 uint32 CRLSet::sequence() const {
    597   return sequence_;
    598 }
    599 
    600 const CRLSet::CRLList& CRLSet::crls() const {
    601   return crls_;
    602 }
    603 
    604 // static
    605 CRLSet* CRLSet::EmptyCRLSetForTesting() {
    606   return ForTesting(false, NULL, "");
    607 }
    608 
    609 CRLSet* CRLSet::ExpiredCRLSetForTesting() {
    610   return ForTesting(true, NULL, "");
    611 }
    612 
    613 // static
    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