Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: net/base/crl_filter.cc

Issue 6965015: net: add CRL filter infrastructure. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ... Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/json/json_reader.h"
7 #include "base/logging.h"
8 #include "base/values.h"
9 #include "crypto/sha2.h"
10 #include "net/base/crl_filter.h"
11
12 #if defined(USE_SYSTEM_ZLIB)
13 #include <zlib.h>
14 #else
15 #include "third_party/zlib/zlib.h"
16 #endif
17
18 namespace net {
19
20 // Decompress zlib decompressed |in| into |out|. |out_len| is the number of
21 // bytes at |out| and must be exactly equal to the size of the decompressed
22 // data. |dict| optionally contains a pre-shared dictionary.
23 static bool DecompressZlib(char* out, int out_len, base::StringPiece in,
24 base::StringPiece dict) {
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 int r = inflate(&z, Z_FINISH);
36 if (r == Z_NEED_DICT) {
37 r = inflateSetDictionary(&z, reinterpret_cast<const Bytef*>(dict.data()),
38 dict.size());
39 if (r != Z_OK)
40 return false;
41 r = inflate(&z, Z_FINISH);
42 }
43 if (r != Z_STREAM_END)
44 return false;
45 if (z.avail_in || z.avail_out)
46 return false;
47 return true;
48 }
49
50 /* A RangeDecoder is a type of entropy coder. It is superior to a Huffman
51 * encoder because symbols can use fractions of bits.
52 *
53 * Conceptually a number range is split into regions with one region for each
54 * symbol. The size of the region is proportional to the probability of the
55 * symbol:
56 *
57 * +-----+ <- 2**32 - 1
58 * | |
59 * | B |
60 * | |
61 * +-----+ <- 2**30
62 * | A |
63 * +-----+ <- 0
64 *
65 * Here, symbol B is 3 times more probable than A.
66 *
67 * This pattern is recursive: it repeats inside each region:
68 *
69 * +-----+ /+-----+
70 * | | / | |
71 * | B | / | B |
72 * | | / | |
73 * +-----+/ +-----+
74 * | A | | A |
75 * +-----+-----+-----+
76 *
77 * In this implementation, the probabilities are fixed and so are the same at
78 * every level.
79 *
80 * A range coder encodes a series of symbols by specifing a fraction along the
81 * number space such that it hits the correct symbols in order. You have to
82 * know how many symbols to expect from a range coder because it obviously
83 * produces an infinite series of symbols from any input value.
84 *
85 * In order to make the implementation fast on a computer, a high and low point
86 * are maintained that cover the current valid span of the number space.
87 * Whenever the span is small enough to that the most significant 8 bits of the
88 * high and low values are equal, a byte is produced and the current span is
89 * expanded by a factor of 256.
90 *
91 * A decoder reads these bytes and decodes symbols as required. For example,
92 * say that it reads the first byte as 0x80. It knows that the maximum value of
93 * the final span is 0x80fffffff... and the minimum value is 0x8000000...
94 * That's sufficient to figure out that the first symbol is a B.
95 *
96 * In the following, we keep track of these values:
97 * high_, low_: the high and low values of the current span. This is needed
98 * to mirror the state of the encoder so that span expansions occur at
99 * the same point.
100 *
101 * vhigh_, vlow_: the high and low values of the possible final span.
102 * vbits_: the number of bits of |vhigh_| and |vlow_| that are from data.
103 * (The rest of those values is filled with 0xff or 0x00, respectively.)
104 */
105 class RangeDecoder {
106 public:
107 // in: the input bytes
108 // spans: the probabilities of the symbols. The sum of these values must
109 // equal 2**32 - 1.
110 RangeDecoder(base::StringPiece in, const std::vector<uint32> spans)
111 : in_(in),
112 spans_(spans),
113 high_(-1),
114 vhigh_(-1),
115 low_(0),
116 vlow_(0),
117 vbits_(0) {
118 }
119
120 bool Decode(unsigned* out_symbol) {
121 // high_ and low_ mirror the state of the encoder so, when they agree on
122 // the first byte, we have to perform span expansion.
123 while (high_ >> 24 == low_ >> 24) {
124 vhigh_ <<= 8;
125 vhigh_ |= 0xff;
126 vlow_ <<= 8;
127 vbits_ -= 8;
128
129 high_ <<= 8;
130 high_ |= 0xff;
131 low_ <<= 8;
132 }
133
134 // r is the range of the current span, used as a scaling factor.
135 uint64 r = high_ - low_;
136
137 // We consider each symbol in turn and decide if the final span is such
138 // that it must be the next symbol.
139 for (unsigned i = 0; i < spans_.size(); i++) {
140 const uint32 span = spans_[i];
141 const uint32 scaled = (r * span) >> 32;
142
143 // Since our knowledge of the final span is incremental, |vhigh_| and
144 // |vlow_| might be sufficiently far apart that we can't determine the
145 // next symbol. In this case we have to read more data.
146 while (vhigh_ > low_ + scaled && vlow_ <= low_ + scaled) {
147 // We need more information to disambiguate this. Note that 32-bits of
148 // information is always sufficient to disambiguate.
149 uint32 b = 0;
150 if (!in_.empty())
151 b = static_cast<uint8>(in_[0]);
152 in_.remove_prefix(1);
153 vhigh_ &= ~(static_cast<uint32>(0xff) << (24 - vbits_));
154 vhigh_ |= b << (24 - vbits_);
155 vlow_ |= b << (24 - vbits_);
156 vbits_ += 8;
157 }
158
159 // This symbol covers all the possible values for the final span, so this
160 // must be the next symbol.
161 if (vhigh_ <= low_ + scaled) {
162 high_ = low_ + scaled;
163 *out_symbol = i;
164 return true;
165 }
166
167 low_ += scaled + 1;
168 }
169
170 // Since the sum of |spans_| equals 2**32-1, one of the symbols must cover
171 // the current span.
172 NOTREACHED();
173 return false;
174 }
175
176 private:
177 base::StringPiece in_;
178 const std::vector<uint32> spans_;
179
180 uint32 high_, vhigh_, low_, vlow_;
181 unsigned vbits_;
182
183 DISALLOW_COPY_AND_ASSIGN(RangeDecoder);
184 };
185
186 // A GolombCompressedSet is built from a set of random hash values where each
187 // value is less than a pre-agreed limit. Since the hash values are uniform,
188 // their differences are geometrically distributed and golomb encoding is the
189 // optimal encoding for geometrically distributed values.
190 //
191 // Thus the set [1, 10, 15] is turned into delta values ([1, 9, 5]) and each
192 // delta value is Golomb encoded to make a GCS.
193 //
194 // Golomb encoding of a value, v, requires knowledge of the geometric
195 // parameter, M, and consists of (q, r) where v = qM + r. q is unary encoded
196 // and r is binary encoded. In this code M is fixed at 1024.
197 //
198 // A couple of implementation tricks are used to speed things up:
199 //
200 // First, the bits are consumed in blocks of 32 and are little endian encoded,
201 // thus saving a endianness conversion on most systems. Also, the bits inside
202 // each word are ordered such that the first bit is the least-significant bit
203 // and the unary encoding is terminated with a 1 rather than the usual 0.
204 // This allows us to use a DeBruijn sequence to do unary decoding.
205 class GolombCompressedSet {
206 public:
207 class iterator {
208 public:
209 iterator(base::StringPiece data, unsigned num_values)
210 : full_data_(data),
211 num_values_(num_values) {
212 Reset();
213 }
214
215 void Reset() {
216 data_ = full_data_;
217 pending_ = 0;
218 bits_pending_ = 0;
219 current_ = 0;
220 }
221
222 bool Next(uint64* out) {
223 unsigned q, r;
224 if (!ReadUnary(&q))
225 return false;
226 if (!ReadBinary10(&r))
227 return false;
228
229 uint64 step = static_cast<uint64>(q) << 10;
230 step |= r;
231 current_ += step;
232 *out = current_;
233 return true;
234 }
235
236 bool NextDelta(unsigned* out_delta) {
237 unsigned q, r;
238 if (!ReadUnary(&q))
239 return false;
240 if (!ReadBinary10(&r))
241 return false;
242
243 *out_delta = static_cast<unsigned>(q) << 10;
244 *out_delta |= r;
245 return true;
246 }
247
248 bool Contains(uint64 v) {
249 Reset();
250
251 uint64 value;
252 for (unsigned i = 0; i < num_values_; i++) {
253 if (!Next(&value))
254 return false;
255 if (value == v)
256 return true;
257 if (value > v)
258 return false;
259 }
260
261 return false;
262 }
263
264 private:
265 bool ReadUnary(unsigned* out) {
266 *out = 0;
267
268 uint32 w;
269 if (!CurrentWord(&w))
270 return false;
271
272 while (w == 0) {
273 *out += 32;
274 if (!CurrentWord(&w))
275 return false;
276 }
277
278 // A DeBruijn sequence contains all possible subsequences. kDeBruijn is an
279 // example of a 32-bit word that contains all possible 5-bit subsequences.
280 // When decoding Golomb values, we quickly need to find the number of
281 // consequtive zero bits. (w&-w) results in a word with only the
282 // least-significant true bit set. Since this work has only a single bit
283 // set, its value is a power of two and multiplying by it is the same as a
284 // left shift by the position of that bit.
285 //
286 // Thus we multiply (i.e. left-shift) by the DeBruijn value and check the
287 // top 5 bits. Since each 5-bit subsequence in kDeBruijn is unique, we can
288 // determine by how many bits it has been shifted with a lookup table.
289 static const uint32 kDeBruijn = 0x077CB531;
290 static const uint8 kDeBruijnLookup[32] = {
291 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
292 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
293 };
294
295 MSVC_SUPPRESS_WARNING(4146);
296 uint8 r = kDeBruijnLookup[((w & -w) * kDeBruijn) >> 27];
297 *out += r;
298 pending_ >>= r + 1;
299 bits_pending_ -= r + 1;
300 return true;
301 }
302
303 bool ReadBinary10(unsigned* out) {
304 uint32 w;
305 if (!CurrentWord(&w))
306 return false;
307 *out = w & 0x3ff;
308 pending_ >>= 10;
309 bits_pending_ -= 10;
310 return true;
311 }
312
313 bool CurrentWord(uint32* out) {
314 if (bits_pending_ < 32) {
315 if (!ReadWord() && bits_pending_ == 0)
316 return false;
317 }
318 *out = static_cast<uint32>(pending_);
319 return true;
320 }
321
322 bool ReadWord() {
323 DCHECK_LE(bits_pending_, 32u);
324
325 uint32 w;
326 if (data_.size() < 4)
327 return false;
328 memcpy(&w, data_.data(), 4);
329 data_.remove_prefix(4);
330
331 uint64 w64 = w;
332 w64 <<= bits_pending_;
333 pending_ |= w64;
334 bits_pending_ += 32;
335 return true;
336 }
337
338 base::StringPiece full_data_;
339 base::StringPiece data_;
340 const unsigned num_values_;
341 uint64 pending_;
342 unsigned bits_pending_;
343 uint32 current_;
344 };
345
346 GolombCompressedSet(base::StringPiece data,
347 unsigned num_values)
348 : full_data_(data),
349 num_values_(num_values) {
350 }
351
352 iterator begin() const {
353 return iterator(full_data_, num_values_);
354 }
355
356 private:
357
358 base::StringPiece full_data_;
359 const unsigned num_values_;
360
361 DISALLOW_COPY_AND_ASSIGN(GolombCompressedSet);
362 };
363
364 // BitWriter buffers a number of bits in a format that matches
365 // GolombCompressedSet's expectations: the bits are packed least-significant
366 // first in little-endian, 32-bit words.
367 class BitWriter {
368 public:
369 BitWriter()
370 : buf_(NULL),
371 buf_len_(0),
372 buf_used_(0),
373 current_(0),
374 num_bits_(0) {
375 }
376
377 void WriteBit(bool b) {
378 current_ >>= 1;
379 if (b)
380 current_ |= 0x80000000u;
381 num_bits_++;
382
383 if (num_bits_ == sizeof(current_) * 8)
384 Flush();
385 }
386
387 // WriteGolomb10 outputs v using Golomb encoding with a geometric parameter
388 // of 1024.
389 void WriteGolomb10(unsigned v) {
390 const unsigned q = v >> 10;
391 unsigned r = v & 0x3ff;
392
393 for (unsigned i = 0; i < q; i++)
394 WriteBit(false);
395 WriteBit(true);
396 for (unsigned i = 0; i < 10; i++) {
397 WriteBit((r&1) == 1);
398 r >>= 1;
399 }
400 }
401
402 void Flush() {
403 if (num_bits_ > 0) {
404 current_ >>= 32 - num_bits_;
405 }
406
407 if (buf_len_ < buf_used_ + sizeof(current_)) {
408 if (buf_) {
409 buf_len_ += sizeof(current_);
410 buf_len_ *= 2;
411 buf_ = reinterpret_cast<uint8*>(realloc(buf_, buf_len_));
412 } else {
413 buf_len_ = 1024;
414 buf_ = reinterpret_cast<uint8*>(malloc(buf_len_));
415 }
416 }
417 // assumes little endian
418 memcpy(buf_ + buf_used_, &current_, sizeof(current_));
419 buf_used_ += sizeof(current_);
420
421 current_ = 0;
422 num_bits_ = 0;
423 }
424
425 std::string as_string() {
426 Flush();
427 return std::string(reinterpret_cast<char*>(buf_), buf_used_);
428 }
429
430 private:
431 uint8* buf_;
432 unsigned buf_len_;
433 unsigned buf_used_;
434 uint32 current_;
435 unsigned num_bits_;
436 };
437
438 CRLFilter::~CRLFilter() {
439 }
440
441 // CRL filter format:
442 //
443 // uint16le description_len
444 // byte[description_len] description_bytes
445 // byte[] compressed_header
446 // byte[] gcs_bytes
447 //
448 // description_bytes consists of a JSON dictionary with the following keys:
449 // Version (int): currently 0
450 // Contents (string): "CRLFilter" or "CRLFilterDelta" (magic value)
451 // DeltaFrom (int); if this is a delta filter (see below), then this contains
452 // the sequence number of the reference filter.
453 // HeaderZLength (int): the number of bytes of compressed header.
454 // HeaderLength (int): the number of bytes of header after decompression.
455 // RangeLength (int): if this is a delta filter then this is the number of
456 // bytes of range coded data.
457 //
458 // The uncompressed header is also a JSON dictionary with the following keys:
459 // Sequence (int): the sequence number of this filter.
460 // Version (int): currently 0.
461 // NotBefore (int, epoch seconds): the filter is not valid before this time.
462 // NotAfter (int, epoch seconds): the filter is not valid after this time.
463 // MaxRange (int): the limit of the GCS encoded values
464 // NumEntries (int): the number of GCS entries
465 //
466 // CRLsIncluded (array): the covered CRLs. Each element in the array is a
467 // dictionary with the following keys:
468 //
469 // URL (string): the URL of the CRL
470 // ParentSPKISHA256 (string): base64 encoded, SHA256 hash of the CRL
471 // signer's SPKI.
472 //
473 // A delta CRL filter is similar to a CRL filter:
474 //
475 // uint16le description_len
476 // byte[description_len] description_bytes
477 // byte[] delta_compressed_header
478 // uint32le[3] range_probabilities
479 // byte[] range_bytes
480 // byte[] gcs_bytes
481 //
482 // A delta CRL filter applies to a specific CRL filter as given in the
483 // description's "DeltaFrom" value. The compressed header is compressed with
484 // the header bytes of the base CRL filter given as a zlib preshared
485 // dictionary.
486 //
487 // range_probabilities contains the probabilies of the three encoded symbols.
488 // The sum of these values must be 0xffffffff. Next are the range encoded
489 // bytes, the length of which is given in "RangeLength". There's one symbol for
490 // each GCS value in the final filter. (This number is given in the
491 // "NumEntries" value of the header.). Each symbol is either SAME (0), INSERT
492 // (1) or DELETE (2). SAME values are copied into the new filter, INSERTed
493 // values are given as a delta from the last value, GCS encoded in |gcs_bytes|.
494 // DELETEed values are omitted from the final filter.
495
496 // ReadDescription reads the description (including length prefix) from |data|
497 // and updates |data| to remove the description on return. Caller takes
498 // ownership of the returned pointer.
499 static DictionaryValue* ReadDescription(base::StringPiece* data) {
500 if (data->size() < 2)
501 return NULL;
502 uint16 description_len;
503 memcpy(&description_len, data->data(), 2); // assumes little-endian.
504 data->remove_prefix(2);
505
506 if (data->size() < description_len)
507 return NULL;
508
509 const base::StringPiece description_bytes(data->data(), description_len);
510 data->remove_prefix(description_len);
511
512 scoped_ptr<Value> description(base::JSONReader::Read(
513 description_bytes.as_string(), true /* allow trailing comma */));
514 if (description.get() == NULL)
515 return NULL;
516
517 if (!description->IsType(Value::TYPE_DICTIONARY))
518 return NULL;
519 return reinterpret_cast<DictionaryValue*>(description.release());
520 }
521
522 // CRLFilterFromHeader constructs a CRLFilter from the bytes of a header
523 // structures. The header is JSON. See above for details of the keys.
524 //
525 // static
526 CRLFilter* CRLFilter::CRLFilterFromHeader(base::StringPiece header_bytes) {
527 scoped_ptr<Value> header(base::JSONReader::Read(
528 header_bytes.as_string(),
529 true /* allow trailing comma */));
530 if (header.get() == NULL)
531 return NULL;
532
533 if (!header->IsType(Value::TYPE_DICTIONARY))
534 return NULL;
535 DictionaryValue* header_dict =
536 reinterpret_cast<DictionaryValue*>(header.get());
537 int version;
538 if (!header_dict->GetInteger("Version", &version) ||
539 version != 0) {
540 return NULL;
541 }
542
543 double not_before, not_after, max_range, num_entries;
544 if (!header_dict->GetDouble("NotBefore", &not_before) ||
545 !header_dict->GetDouble("NotAfter", &not_after) ||
546 !header_dict->GetDouble("NumEntries", &num_entries) ||
547 !header_dict->GetDouble("MaxRange", &max_range)) {
548 return NULL;
549 }
550
551 if (not_before <= 0 || not_after <= 0 || max_range <= 0 || num_entries <= 0)
552 return NULL;
553
554 int sequence;
555 if (!header_dict->GetInteger("Sequence", &sequence) ||
556 sequence <= 0) {
557 // Sequence is assumed to be zero if omitted.
558 sequence = 0;
559 }
560
561 scoped_ptr<CRLFilter> crl_filter(new CRLFilter);
562 crl_filter->sequence_ = sequence;
563 crl_filter->not_before_ = not_before;
564 crl_filter->not_after_ = not_after;
565 crl_filter->max_range_ = max_range;
566 crl_filter->num_entries_ = num_entries;
567 crl_filter->header_bytes_ = header_bytes.as_string();
568
569 ListValue* crls_included;
570 if (!header_dict->GetList("CRLsIncluded", &crls_included))
571 return NULL;
572
573 for (size_t i = 0; i < crls_included->GetSize(); i++) {
574 DictionaryValue* included_crl_dict;
575 if (!crls_included->GetDictionary(i, &included_crl_dict))
576 return NULL;
577 std::string url, parent_spki_sha256_b64;
578 if (!included_crl_dict->GetString("URL", &url) ||
579 !included_crl_dict->GetString("ParentSPKISHA256",
580 &parent_spki_sha256_b64)) {
581 return NULL;
582 }
583
584 std::string parent_spki_sha256;
585 if (!base::Base64Decode(parent_spki_sha256_b64,
586 &parent_spki_sha256)) {
587 return NULL;
588 }
589 crl_filter->crls_included_.insert(
590 std::make_pair<std::string, std::string>(
591 url,
592 parent_spki_sha256));
593 }
594
595 return crl_filter.release();
596 }
597
598 // kMaxHeaderLengthBytes contains the sanity limit of the size of a CRL
599 // filter's decompressed header.
600 static const int kMaxHeaderLengthBytes = 1024 * 1024;
601
602 // static
603 CRLFilter* CRLFilter::Parse(base::StringPiece data) {
604 // Other parts of Chrome assume that we're little endian, so we don't lose
605 // anything by doing this.
606 #if defined(__BYTE_ORDER)
607 // Linux check
608 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN,
609 datapack_assumes_little_endian);
610 #elif defined(__BIG_ENDIAN__)
611 // Mac check
612 #error DataPack assumes little endian
613 #endif
614
615 scoped_ptr<DictionaryValue> description_dict(
616 ReadDescription(&data));
617 if (!description_dict.get())
618 return NULL;
619
620 std::string contents;
621 if (!description_dict->GetString("Contents", &contents))
622 return NULL;
623 if (contents != "CRLFilter")
624 return NULL;
625
626 int version;
627 if (!description_dict->GetInteger("Version", &version) ||
628 version != 0) {
629 return NULL;
630 }
631
632 int compressed_header_len;
633 if (!description_dict->GetInteger("HeaderZLength", &compressed_header_len))
634 return NULL;
635
636 if (compressed_header_len <= 0 ||
637 data.size() < static_cast<unsigned>(compressed_header_len)) {
638 return NULL;
639 }
640 const base::StringPiece compressed_header(data.data(), compressed_header_len);
641 data.remove_prefix(compressed_header_len);
642
643 int header_len;
644 if (!description_dict->GetInteger("HeaderLength", &header_len))
645 return NULL;
646 if (header_len < 0 || header_len > kMaxHeaderLengthBytes) {
647 NOTREACHED();
648 return NULL;
649 }
650
651 scoped_array<char> header_bytes(new char[header_len]);
652 base::StringPiece no_dict;
653 if (!DecompressZlib(header_bytes.get(), header_len, compressed_header,
654 no_dict)) {
655 return NULL;
656 }
657
658 scoped_refptr<CRLFilter> crl_filter(CRLFilterFromHeader(
659 base::StringPiece(header_bytes.get(), header_len)));
660
661 if (!crl_filter.get())
662 return NULL;
663
664 // The remainder is the Golomb Compressed Set.
665 crl_filter->gcs_bytes_ = data.as_string();
666 crl_filter->gcs_.reset(new GolombCompressedSet(crl_filter->gcs_bytes_,
667 crl_filter->num_entries_));
668 return crl_filter.release();
669 }
670
671 CRLFilter* CRLFilter::ApplyDelta(base::StringPiece data) {
672 scoped_ptr<DictionaryValue> description_dict(
673 ReadDescription(&data));
674 if (!description_dict.get())
675 return NULL;
676
677 int compressed_header_len, header_len, delta_from, version, range_length;
678 std::string contents;
679 if (!description_dict->GetInteger("HeaderZLength", &compressed_header_len) ||
680 !description_dict->GetInteger("HeaderLength", &header_len) ||
681 !description_dict->GetInteger("RangeLength", &range_length) ||
682 !description_dict->GetInteger("DeltaFrom", &delta_from) ||
683 !description_dict->GetInteger("Version", &version) ||
684 !description_dict->GetString("Contents", &contents)) {
685 return NULL;
686 }
687
688 if (version != 0 || contents != "CRLFilterDelta")
689 return NULL;
690
691 if (delta_from < 0 || static_cast<unsigned>(delta_from) != sequence_)
692 return NULL;
693
694 if (compressed_header_len <= 0 ||
695 data.size() < static_cast<unsigned>(compressed_header_len) ||
696 header_len < 0 ||
697 header_len > kMaxHeaderLengthBytes) {
698 return NULL;
699 }
700
701 const base::StringPiece compressed_header(data.data(), compressed_header_len);
702 data.remove_prefix(compressed_header_len);
703
704 scoped_array<char> header_bytes(new char[header_len]);
705 if (!DecompressZlib(header_bytes.get(), header_len, compressed_header,
706 header_bytes_)) {
707 return NULL;
708 }
709
710 scoped_refptr<CRLFilter> crl_filter(CRLFilterFromHeader(
711 base::StringPiece(header_bytes.get(), header_len)));
712
713 if (!crl_filter.get())
714 return NULL;
715
716 // Next are the three span values.
717 static const unsigned num_span_values = 3;
718 if (data.size() < num_span_values * sizeof(uint32))
719 return NULL;
720
721 std::vector<uint32> spans(num_span_values);
722 memcpy(&spans[0], data.data(), num_span_values * sizeof(uint32));
723 data.remove_prefix(num_span_values * sizeof(uint32));
724
725 if (data.size() < static_cast<unsigned>(range_length))
726 return NULL;
727 RangeDecoder decoder(data.substr(0, range_length), spans);
728 data.remove_prefix(range_length);
729
730 GolombCompressedSet gcs(data, 0 /* no values; we don't know that yet. */);
731 GolombCompressedSet::iterator gcs_deltas(gcs.begin());
732 GolombCompressedSet::iterator gcs_prev(gcs_->begin());
733 BitWriter bitwriter;
734
735 uint64 last = 0, v;
736 for (unsigned i = 0; i < crl_filter->num_entries_;) {
737 unsigned symbol, delta;
738 if (!decoder.Decode(&symbol))
739 return NULL;
740 if (symbol == SYMBOL_SAME) {
741 if (!gcs_prev.Next(&v))
742 return NULL;
743 bitwriter.WriteGolomb10(v - last);
744 last = v;
745 i++;
746 } else if (symbol == SYMBOL_INSERT) {
747 if (!gcs_deltas.NextDelta(&delta))
748 return NULL;
749 bitwriter.WriteGolomb10(delta);
750 last += delta;
751 i++;
752 } else if (symbol == SYMBOL_DELETE) {
753 if (!gcs_prev.Next(&v))
754 return NULL;
755 } else {
756 NOTREACHED();
757 return NULL;
758 }
759 }
760
761 crl_filter->gcs_bytes_ = bitwriter.as_string();
762 crl_filter->gcs_.reset(new GolombCompressedSet(crl_filter->gcs_bytes_,
763 crl_filter->num_entries_));
764 return crl_filter.release();
765 }
766
767 bool CRLFilter::CRLIsCovered(
768 std::vector<base::StringPiece> crl_urls,
769 const std::string& parent_spki_sha256) {
770 for (std::vector<base::StringPiece>::const_iterator
771 i = crl_urls.begin(); i != crl_urls.end(); i++) {
772 if (crls_included_.count(std::make_pair<std::string, std::string>(
773 i->as_string(), parent_spki_sha256))) {
774 return true;
775 }
776 }
777 return false;
778 }
779
780 // FNV1a64 computes the FNV1a 64-bit hash of the concatenation of |a| and
781 // |b|.
782 static uint64 FNV1a64(const std::string& a, const std::string& b) {
783 uint64 x = 14695981039346656037ull;
784 static const uint64 p = 1099511628211ull;
785 for (size_t i = 0; i < a.size(); i++) {
786 x ^= static_cast<uint8>(a[i]);
787 x *= p;
788 }
789 for (size_t i = 0; i < b.size(); i++) {
790 x ^= static_cast<uint8>(b[i]);
791 x *= p;
792 }
793 return x;
794 }
795
796 CRLFilter::Result CRLFilter::CheckCertificate(
797 base::StringPiece cert_spki,
798 const std::string& serial_number,
799 std::vector<base::StringPiece> crl_urls,
800 base::StringPiece parent_spki) {
801 const std::string parent_spki_sha256 =
802 crypto::SHA256HashString(parent_spki.as_string());
803
804 if (!CRLIsCovered(crl_urls, parent_spki_sha256))
805 return UNKNOWN;
806
807 uint64 h = FNV1a64(serial_number, parent_spki_sha256);
808 h %= max_range_;
809
810 GolombCompressedSet::iterator it(gcs_->begin());
811 if (it.Contains(h))
812 return PROBABLY_REVOKED;
813 return NOT_REVOKED;
814 }
815
816 int64 CRLFilter::not_before() const {
817 return not_before_;
818 }
819
820 int64 CRLFilter::not_after() const {
821 return not_after_;
822 }
823
824 uint64 CRLFilter::max_range() const {
825 return max_range_;
826 }
827
828 unsigned CRLFilter::num_entries() const {
829 return num_entries_;
830 }
831
832 std::vector<uint64> CRLFilter::DebugValues() {
833 std::vector<uint64> ret;
834 uint64 v;
835
836 GolombCompressedSet::iterator it(gcs_->begin());
837
838 for (unsigned i = 0; i < num_entries_; i++) {
839 if (!it.Next(&v)) {
840 ret.clear();
841 break;
842 }
843 ret.push_back(v);
844 }
845 return ret;
846 }
847
848 std::string CRLFilter::SHA256() const {
849 std::string s = header_bytes_;
850 s += gcs_bytes_;
851 return crypto::SHA256HashString(s);
852 }
853
854 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698