| // 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 "quic/core/crypto/common_cert_set.h" |
| |
| #include <cstddef> |
| |
| #include "absl/base/macros.h" |
| #include "absl/strings/string_view.h" |
| #include "quic/core/quic_utils.h" |
| |
| namespace quic { |
| |
| namespace common_cert_set_2 { |
| #include "quic/core/crypto/common_cert_set_2.c" |
| } |
| |
| namespace common_cert_set_3 { |
| #include "quic/core/crypto/common_cert_set_3.c" |
| } |
| |
| namespace { |
| |
| 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_t hash; |
| }; |
| |
| const CertSet kSets[] = { |
| { |
| common_cert_set_2::kNumCerts, |
| common_cert_set_2::kCerts, |
| common_cert_set_2::kLens, |
| common_cert_set_2::kHash, |
| }, |
| { |
| common_cert_set_3::kNumCerts, |
| common_cert_set_3::kCerts, |
| common_cert_set_3::kLens, |
| common_cert_set_3::kHash, |
| }, |
| }; |
| |
| const uint64_t kSetHashes[] = { |
| common_cert_set_2::kHash, |
| common_cert_set_3::kHash, |
| }; |
| |
| // 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. |
| int Compare(absl::string_view 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; |
| } |
| |
| // CommonCertSetsQUIC implements the CommonCertSets interface using the default |
| // certificate sets. |
| class CommonCertSetsQUIC : public CommonCertSets { |
| public: |
| // CommonCertSets interface. |
| absl::string_view GetCommonHashes() const override { |
| return absl::string_view(reinterpret_cast<const char*>(kSetHashes), |
| sizeof(uint64_t) * ABSL_ARRAYSIZE(kSetHashes)); |
| } |
| |
| absl::string_view GetCert(uint64_t hash, uint32_t index) const override { |
| for (size_t i = 0; i < ABSL_ARRAYSIZE(kSets); i++) { |
| if (kSets[i].hash == hash) { |
| if (index < kSets[i].num_certs) { |
| return absl::string_view( |
| reinterpret_cast<const char*>(kSets[i].certs[index]), |
| kSets[i].lens[index]); |
| } |
| break; |
| } |
| } |
| |
| return absl::string_view(); |
| } |
| |
| bool MatchCert(absl::string_view cert, |
| absl::string_view common_set_hashes, |
| uint64_t* out_hash, |
| uint32_t* out_index) const override { |
| if (common_set_hashes.size() % sizeof(uint64_t) != 0) { |
| return false; |
| } |
| |
| for (size_t i = 0; i < common_set_hashes.size() / sizeof(uint64_t); i++) { |
| uint64_t hash; |
| memcpy(&hash, common_set_hashes.data() + i * sizeof(uint64_t), |
| sizeof(uint64_t)); |
| |
| for (size_t j = 0; j < ABSL_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; |
| } |
| |
| CommonCertSetsQUIC() {} |
| CommonCertSetsQUIC(const CommonCertSetsQUIC&) = delete; |
| CommonCertSetsQUIC& operator=(const CommonCertSetsQUIC&) = delete; |
| ~CommonCertSetsQUIC() override {} |
| }; |
| |
| } // anonymous namespace |
| |
| CommonCertSets::~CommonCertSets() {} |
| |
| // static |
| const CommonCertSets* CommonCertSets::GetInstanceQUIC() { |
| static CommonCertSetsQUIC* certs = new CommonCertSetsQUIC(); |
| return certs; |
| } |
| |
| } // namespace quic |