summaryrefslogtreecommitdiffstats
path: root/net/quic/crypto/common_cert_set.cc
blob: ee1ac67dcf7b8dfef7c60e3ba4b8578ebbeff213 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/quic/crypto/common_cert_set.h"

#include "base/basictypes.h"
#include "base/logging.h"
#include "net/quic/quic_utils.h"

using base::StringPiece;

namespace net {

namespace common_cert_set_0 {
#include "net/quic/crypto/common_cert_set_0.c"
}

struct CertSet {
  // num_certs contains the number of certificates in this set.
  size_t num_certs;
  // certs is an array of |num_certs| pointers to the DER encoded certificates.
  const unsigned char* const* certs;
  // lens is an array of |num_certs| integers describing the length, in bytes,
  // of each certificate.
  const size_t* lens;
  // hash contains the 64-bit, FNV-1a hash of this set.
  uint64 hash;
};

static const CertSet kSets[] = {
  {
    common_cert_set_0::kNumCerts,
    common_cert_set_0::kCerts,
    common_cert_set_0::kLens,
    common_cert_set_0::kHash,
  },
};

static const uint64 kSetHashes[] = {
  common_cert_set_0::kHash,
};

CommonCertSets::~CommonCertSets() {
}

CommonCertSetsQUIC::CommonCertSetsQUIC() {
}

StringPiece CommonCertSetsQUIC::GetCommonHashes() const {
  return StringPiece(reinterpret_cast<const char*>(kSetHashes),
                     sizeof(uint64) * arraysize(kSetHashes));
}

StringPiece CommonCertSetsQUIC::GetCert(uint64 hash, uint32 index) const {
  StringPiece cert;
  for (size_t i = 0; i < arraysize(kSets); i++) {
    if (kSets[i].hash == hash) {
      if (index < kSets[i].num_certs) {
        cert.set(kSets[i].certs[index], kSets[i].lens[index]);
      }
      break;
    }
  }

  return cert;
}

// Compare returns a value less than, equal to or greater than zero if |a| is
// lexicographically less than, equal to or greater than |b|, respectively.
static int Compare(StringPiece a, const unsigned char* b, size_t b_len) {
  size_t len = a.size();
  if (len > b_len) {
    len = b_len;
  }
  int n = memcmp(a.data(), b, len);
  if (n != 0) {
    return n;
  }

  if (a.size() < b_len) {
    return -1;
  } else if (a.size() > b_len) {
    return 1;
  }
  return 0;
}

bool CommonCertSetsQUIC::MatchCert(StringPiece cert,
                                   StringPiece common_set_hashes,
                                   uint64* out_hash,
                                   uint32* out_index) const {
  if (common_set_hashes.size() % sizeof(uint64) != 0) {
    return false;
  }

  for (size_t i = 0; i < common_set_hashes.size() / sizeof(uint64); i++) {
    uint64 hash;
    memcpy(&hash, common_set_hashes.data() + i*sizeof(uint64), sizeof(uint64));

    for (size_t j = 0; j < arraysize(kSets); j++) {
      if (kSets[j].hash != hash) {
        continue;
      }

      if (kSets[j].num_certs == 0) {
        continue;
      }

      // Binary search for a matching certificate.
      size_t min = 0;
      size_t max = kSets[j].num_certs - 1;
      while (max >= min) {
        size_t mid = min + ((max - min) / 2);
        int n = Compare(cert, kSets[j].certs[mid], kSets[j].lens[mid]);
        if (n < 0) {
          if (mid == 0) {
            break;
          }
          max = mid - 1;
        } else if (n > 0) {
          min = mid + 1;
        } else {
          *out_hash = hash;
          *out_index = mid;
          return true;
        }
      }
    }
  }

  return false;
}

}  // namespace net