blob: 06c694000cf22b2d0989bd93351661e15252c819 [file] [log] [blame]
// Copyright 2020 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/proof_source_x509.h"
#include <memory>
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "quic/core/crypto/certificate_view.h"
#include "quic/core/crypto/crypto_protocol.h"
#include "quic/core/quic_data_writer.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "common/quiche_endian.h"
namespace quic {
std::unique_ptr<ProofSourceX509> ProofSourceX509::Create(
QuicReferenceCountedPointer<Chain> default_chain,
CertificatePrivateKey default_key) {
std::unique_ptr<ProofSourceX509> result(new ProofSourceX509());
if (!result->AddCertificateChain(default_chain, std::move(default_key))) {
return nullptr;
}
result->default_certificate_ = &result->certificates_.front();
return result;
}
void ProofSourceX509::GetProof(
const QuicSocketAddress& /*server_address*/,
const QuicSocketAddress& /*client_address*/,
const std::string& hostname,
const std::string& server_config,
QuicTransportVersion /*transport_version*/,
absl::string_view chlo_hash,
std::unique_ptr<ProofSource::Callback> callback) {
QuicCryptoProof proof;
size_t payload_size = sizeof(kProofSignatureLabel) + sizeof(uint32_t) +
chlo_hash.size() + server_config.size();
auto payload = std::make_unique<char[]>(payload_size);
QuicDataWriter payload_writer(payload_size, payload.get(),
quiche::Endianness::HOST_BYTE_ORDER);
bool success = payload_writer.WriteBytes(kProofSignatureLabel,
sizeof(kProofSignatureLabel)) &&
payload_writer.WriteUInt32(chlo_hash.size()) &&
payload_writer.WriteStringPiece(chlo_hash) &&
payload_writer.WriteStringPiece(server_config);
if (!success) {
callback->Run(/*ok=*/false, nullptr, proof, nullptr);
return;
}
Certificate* certificate = GetCertificate(hostname);
proof.signature =
certificate->key.Sign(absl::string_view(payload.get(), payload_size),
SSL_SIGN_RSA_PSS_RSAE_SHA256);
callback->Run(/*ok=*/!proof.signature.empty(), certificate->chain, proof,
nullptr);
}
QuicReferenceCountedPointer<ProofSource::Chain> ProofSourceX509::GetCertChain(
const QuicSocketAddress& /*server_address*/,
const QuicSocketAddress& /*client_address*/,
const std::string& hostname) {
return GetCertificate(hostname)->chain;
}
void ProofSourceX509::ComputeTlsSignature(
const QuicSocketAddress& /*server_address*/,
const QuicSocketAddress& /*client_address*/,
const std::string& hostname,
uint16_t signature_algorithm,
absl::string_view in,
std::unique_ptr<ProofSource::SignatureCallback> callback) {
std::string signature =
GetCertificate(hostname)->key.Sign(in, signature_algorithm);
callback->Run(/*ok=*/!signature.empty(), signature, nullptr);
}
ProofSource::TicketCrypter* ProofSourceX509::GetTicketCrypter() {
return nullptr;
}
bool ProofSourceX509::AddCertificateChain(
QuicReferenceCountedPointer<Chain> chain,
CertificatePrivateKey key) {
if (chain->certs.empty()) {
QUIC_BUG << "Empty certificate chain supplied.";
return false;
}
std::unique_ptr<CertificateView> leaf =
CertificateView::ParseSingleCertificate(chain->certs[0]);
if (leaf == nullptr) {
QUIC_BUG << "Unable to parse X.509 leaf certificate in the supplied chain.";
return false;
}
if (!key.MatchesPublicKey(*leaf)) {
QUIC_BUG << "Private key does not match the leaf certificate.";
return false;
}
certificates_.push_front(Certificate{
chain,
std::move(key),
});
Certificate* certificate = &certificates_.front();
for (absl::string_view host : leaf->subject_alt_name_domains()) {
certificate_map_[std::string(host)] = certificate;
}
return true;
}
ProofSourceX509::Certificate* ProofSourceX509::GetCertificate(
const std::string& hostname) const {
auto it = certificate_map_.find(hostname);
if (it != certificate_map_.end()) {
return it->second;
}
auto dot_pos = hostname.find('.');
if (dot_pos != std::string::npos) {
std::string wildcard = absl::StrCat("*", hostname.substr(dot_pos));
it = certificate_map_.find(wildcard);
if (it != certificate_map_.end()) {
return it->second;
}
}
return default_certificate_;
}
} // namespace quic