// Copyright (c) 2019 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 "quiche/quic/core/crypto/tls_server_connection.h"

#include "absl/strings/string_view.h"
#include "openssl/ssl.h"
#include "quiche/quic/core/crypto/proof_source.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_flag_utils.h"
#include "quiche/quic/platform/api/quic_flags.h"

namespace quic {

TlsServerConnection::TlsServerConnection(SSL_CTX* ssl_ctx, Delegate* delegate,
                                         QuicSSLConfig ssl_config)
    : TlsConnection(ssl_ctx, delegate->ConnectionDelegate(),
                    std::move(ssl_config)),
      delegate_(delegate) {
  // By default, cert verify callback is not installed on ssl(), so only need to
  // UpdateCertVerifyCallback() if client_cert_mode is not kNone.
  if (TlsConnection::ssl_config().client_cert_mode != ClientCertMode::kNone) {
    UpdateCertVerifyCallback();
  }
}

// static
bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx(
    ProofSource* proof_source) {
  bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::CreateSslCtx();

  // Server does not request/verify client certs by default. Individual server
  // connections may call SSL_set_custom_verify on their SSL object to request
  // client certs.

  SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(),
                                         &TlsExtServernameCallback);
  SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), &SelectAlpnCallback, nullptr);
  // We don't actually need the TicketCrypter here, but we need to know
  // whether it's set.
  if (proof_source->GetTicketCrypter()) {
    QUIC_CODE_COUNT(quic_session_tickets_enabled);
    SSL_CTX_set_ticket_aead_method(ssl_ctx.get(),
                                   &TlsServerConnection::kSessionTicketMethod);
  } else {
    QUIC_CODE_COUNT(quic_session_tickets_disabled);
  }

  SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);

  SSL_CTX_set_select_certificate_cb(
      ssl_ctx.get(), &TlsServerConnection::EarlySelectCertCallback);
  SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE);
  return ssl_ctx;
}

void TlsServerConnection::SetCertChain(
    const std::vector<CRYPTO_BUFFER*>& cert_chain) {
  SSL_set_chain_and_key(ssl(), cert_chain.data(), cert_chain.size(), nullptr,
                        &TlsServerConnection::kPrivateKeyMethod);
}

void TlsServerConnection::SetClientCertMode(ClientCertMode client_cert_mode) {
  if (ssl_config().client_cert_mode == client_cert_mode) {
    return;
  }

  mutable_ssl_config().client_cert_mode = client_cert_mode;
  UpdateCertVerifyCallback();
}

void TlsServerConnection::UpdateCertVerifyCallback() {
  const ClientCertMode client_cert_mode = ssl_config().client_cert_mode;
  if (client_cert_mode == ClientCertMode::kNone) {
    SSL_set_custom_verify(ssl(), SSL_VERIFY_NONE, nullptr);
    return;
  }

  int mode = SSL_VERIFY_PEER;
  if (client_cert_mode == ClientCertMode::kRequire) {
    mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  } else {
    QUICHE_DCHECK_EQ(client_cert_mode, ClientCertMode::kRequest);
  }
  SSL_set_custom_verify(ssl(), mode, &VerifyCallback);
}

const SSL_PRIVATE_KEY_METHOD TlsServerConnection::kPrivateKeyMethod{
    &TlsServerConnection::PrivateKeySign,
    nullptr,  // decrypt
    &TlsServerConnection::PrivateKeyComplete,
};

// static
TlsServerConnection* TlsServerConnection::ConnectionFromSsl(SSL* ssl) {
  return static_cast<TlsServerConnection*>(
      TlsConnection::ConnectionFromSsl(ssl));
}

// static
ssl_select_cert_result_t TlsServerConnection::EarlySelectCertCallback(
    const SSL_CLIENT_HELLO* client_hello) {
  return ConnectionFromSsl(client_hello->ssl)
      ->delegate_->EarlySelectCertCallback(client_hello);
}

// static
int TlsServerConnection::TlsExtServernameCallback(SSL* ssl, int* out_alert,
                                                  void* /*arg*/) {
  return ConnectionFromSsl(ssl)->delegate_->TlsExtServernameCallback(out_alert);
}

// static
int TlsServerConnection::SelectAlpnCallback(SSL* ssl, const uint8_t** out,
                                            uint8_t* out_len, const uint8_t* in,
                                            unsigned in_len, void* /*arg*/) {
  return ConnectionFromSsl(ssl)->delegate_->SelectAlpn(out, out_len, in,
                                                       in_len);
}

// static
ssl_private_key_result_t TlsServerConnection::PrivateKeySign(
    SSL* ssl, uint8_t* out, size_t* out_len, size_t max_out, uint16_t sig_alg,
    const uint8_t* in, size_t in_len) {
  return ConnectionFromSsl(ssl)->delegate_->PrivateKeySign(
      out, out_len, max_out, sig_alg,
      absl::string_view(reinterpret_cast<const char*>(in), in_len));
}

// static
ssl_private_key_result_t TlsServerConnection::PrivateKeyComplete(
    SSL* ssl, uint8_t* out, size_t* out_len, size_t max_out) {
  return ConnectionFromSsl(ssl)->delegate_->PrivateKeyComplete(out, out_len,
                                                               max_out);
}

// static
const SSL_TICKET_AEAD_METHOD TlsServerConnection::kSessionTicketMethod{
    TlsServerConnection::SessionTicketMaxOverhead,
    TlsServerConnection::SessionTicketSeal,
    TlsServerConnection::SessionTicketOpen,
};

// static
size_t TlsServerConnection::SessionTicketMaxOverhead(SSL* ssl) {
  return ConnectionFromSsl(ssl)->delegate_->SessionTicketMaxOverhead();
}

// static
int TlsServerConnection::SessionTicketSeal(SSL* ssl, uint8_t* out,
                                           size_t* out_len, size_t max_out_len,
                                           const uint8_t* in, size_t in_len) {
  return ConnectionFromSsl(ssl)->delegate_->SessionTicketSeal(
      out, out_len, max_out_len,
      absl::string_view(reinterpret_cast<const char*>(in), in_len));
}

// static
enum ssl_ticket_aead_result_t TlsServerConnection::SessionTicketOpen(
    SSL* ssl, uint8_t* out, size_t* out_len, size_t max_out_len,
    const uint8_t* in, size_t in_len) {
  return ConnectionFromSsl(ssl)->delegate_->SessionTicketOpen(
      out, out_len, max_out_len,
      absl::string_view(reinterpret_cast<const char*>(in), in_len));
}

}  // namespace quic
