// 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/third_party/quiche/src/quic/core/crypto/common_cert_set.h"

#include <cstddef>

#include "base/macros.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_singleton.h"

namespace quic {

namespace common_cert_set_2 {
#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set_2.c"
}

namespace common_cert_set_3 {
#include "net/third_party/quiche/src/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(QuicStringPiece 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.
  QuicStringPiece GetCommonHashes() const override {
    return QuicStringPiece(reinterpret_cast<const char*>(kSetHashes),
                           sizeof(uint64_t) * QUIC_ARRAYSIZE(kSetHashes));
  }

  QuicStringPiece GetCert(uint64_t hash, uint32_t index) const override {
    for (size_t i = 0; i < QUIC_ARRAYSIZE(kSets); i++) {
      if (kSets[i].hash == hash) {
        if (index < kSets[i].num_certs) {
          return QuicStringPiece(
              reinterpret_cast<const char*>(kSets[i].certs[index]),
              kSets[i].lens[index]);
        }
        break;
      }
    }

    return QuicStringPiece();
  }

  bool MatchCert(QuicStringPiece cert,
                 QuicStringPiece 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 < QUIC_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;
  }

  static CommonCertSetsQUIC* GetInstance() {
    return QuicSingleton<CommonCertSetsQUIC>::get();
  }

 private:
  CommonCertSetsQUIC() {}
  CommonCertSetsQUIC(const CommonCertSetsQUIC&) = delete;
  CommonCertSetsQUIC& operator=(const CommonCertSetsQUIC&) = delete;
  ~CommonCertSetsQUIC() override {}

  friend QuicSingletonFriend<CommonCertSetsQUIC>;
};

}  // anonymous namespace

CommonCertSets::~CommonCertSets() {}

// static
const CommonCertSets* CommonCertSets::GetInstanceQUIC() {
  return CommonCertSetsQUIC::GetInstance();
}

}  // namespace quic
