1// Copyright (c) 2013 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/quic/crypto/common_cert_set.h"
6
7#include "base/basictypes.h"
8#include "base/logging.h"
9#include "base/memory/singleton.h"
10#include "net/quic/quic_utils.h"
11
12using base::StringPiece;
13
14namespace net {
15
16namespace common_cert_set_0 {
17#include "net/quic/crypto/common_cert_set_0.c"
18}
19
20namespace {
21
22struct CertSet {
23  // num_certs contains the number of certificates in this set.
24  size_t num_certs;
25  // certs is an array of |num_certs| pointers to the DER encoded certificates.
26  const unsigned char* const* certs;
27  // lens is an array of |num_certs| integers describing the length, in bytes,
28  // of each certificate.
29  const size_t* lens;
30  // hash contains the 64-bit, FNV-1a hash of this set.
31  uint64 hash;
32};
33
34const CertSet kSets[] = {
35  {
36    common_cert_set_0::kNumCerts,
37    common_cert_set_0::kCerts,
38    common_cert_set_0::kLens,
39    common_cert_set_0::kHash,
40  },
41};
42
43const uint64 kSetHashes[] = {
44  common_cert_set_0::kHash,
45};
46
47// Compare returns a value less than, equal to or greater than zero if |a| is
48// lexicographically less than, equal to or greater than |b|, respectively.
49int Compare(StringPiece a, const unsigned char* b, size_t b_len) {
50  size_t len = a.size();
51  if (len > b_len) {
52    len = b_len;
53  }
54  int n = memcmp(a.data(), b, len);
55  if (n != 0) {
56    return n;
57  }
58
59  if (a.size() < b_len) {
60    return -1;
61  } else if (a.size() > b_len) {
62    return 1;
63  }
64  return 0;
65}
66
67// CommonCertSetsQUIC implements the CommonCertSets interface using the default
68// certificate sets.
69class CommonCertSetsQUIC : public CommonCertSets {
70 public:
71  // CommonCertSets interface.
72  virtual StringPiece GetCommonHashes() const OVERRIDE {
73    return StringPiece(reinterpret_cast<const char*>(kSetHashes),
74                       sizeof(uint64) * arraysize(kSetHashes));
75  }
76
77  virtual StringPiece GetCert(uint64 hash, uint32 index) const OVERRIDE {
78    for (size_t i = 0; i < arraysize(kSets); i++) {
79      if (kSets[i].hash == hash) {
80        if (index < kSets[i].num_certs) {
81          return StringPiece(
82              reinterpret_cast<const char*>(kSets[i].certs[index]),
83              kSets[i].lens[index]);
84        }
85        break;
86      }
87    }
88
89    return StringPiece();
90  }
91
92  virtual bool MatchCert(StringPiece cert, StringPiece common_set_hashes,
93                         uint64* out_hash, uint32* out_index) const OVERRIDE {
94    if (common_set_hashes.size() % sizeof(uint64) != 0) {
95      return false;
96    }
97
98    for (size_t i = 0; i < common_set_hashes.size() / sizeof(uint64); i++) {
99      uint64 hash;
100      memcpy(&hash, common_set_hashes.data() + i * sizeof(uint64),
101             sizeof(uint64));
102
103      for (size_t j = 0; j < arraysize(kSets); j++) {
104        if (kSets[j].hash != hash) {
105          continue;
106        }
107
108        if (kSets[j].num_certs == 0) {
109          continue;
110        }
111
112        // Binary search for a matching certificate.
113        size_t min = 0;
114        size_t max = kSets[j].num_certs - 1;
115        while (max >= min) {
116          size_t mid = min + ((max - min) / 2);
117          int n = Compare(cert, kSets[j].certs[mid], kSets[j].lens[mid]);
118          if (n < 0) {
119            if (mid == 0) {
120              break;
121            }
122            max = mid - 1;
123          } else if (n > 0) {
124            min = mid + 1;
125          } else {
126            *out_hash = hash;
127            *out_index = mid;
128            return true;
129          }
130        }
131      }
132    }
133
134    return false;
135  }
136
137  static CommonCertSetsQUIC* GetInstance() {
138    return Singleton<CommonCertSetsQUIC>::get();
139  }
140
141 private:
142  CommonCertSetsQUIC() {}
143  virtual ~CommonCertSetsQUIC() {}
144
145  friend struct DefaultSingletonTraits<CommonCertSetsQUIC>;
146  DISALLOW_COPY_AND_ASSIGN(CommonCertSetsQUIC);
147};
148
149}  // anonymous namespace
150
151CommonCertSets::~CommonCertSets() {}
152
153// static
154const CommonCertSets* CommonCertSets::GetInstanceQUIC() {
155  return CommonCertSetsQUIC::GetInstance();
156}
157
158}  // namespace net
159