UniqueSSLContext CreateSSLContext()

in src/server/tls_util.cc [118:224]


UniqueSSLContext CreateSSLContext(const Config *config, const SSL_METHOD *method) {
  if (config->tls_cert_file.empty() || config->tls_key_file.empty()) {
    error("Both tls-cert-file and tls-key-file must be specified while TLS is enabled");
    return nullptr;
  }

  auto ssl_ctx = UniqueSSLContext(method);
  if (!ssl_ctx) {
    error("Failed to construct SSL context: {}", fmt::streamed(SSLErrors{}));
    return nullptr;
  }

  auto proto_status = ParseSSLProtocols(config->tls_protocols);
  if (!proto_status) {
    error("{}", proto_status.Msg());
    return nullptr;
  }

  auto ctx_options = *proto_status;

#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
  ctx_options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif
#ifdef SSL_OP_NO_COMPRESSION
  ctx_options |= SSL_OP_NO_COMPRESSION;
#endif
#ifdef SSL_OP_NO_CLIENT_RENEGOTIATION
  ctx_options |= SSL_OP_NO_CLIENT_RENEGOTIATION;
#endif

  if (config->tls_prefer_server_ciphers) {
    ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
  }

  SSL_CTX_set_options(ssl_ctx.get(), ctx_options);

  SSL_CTX_set_mode(ssl_ctx.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

  if (config->tls_session_caching) {
    SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_SERVER);
    SSL_CTX_set_timeout(ssl_ctx.get(), config->tls_session_cache_timeout);
    SSL_CTX_sess_set_cache_size(ssl_ctx.get(), config->tls_session_cache_size);

    const char *session_id = "kvrocks";
    SSL_CTX_set_session_id_context(ssl_ctx.get(), (const unsigned char *)session_id, strlen(session_id));
  } else {
    SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_OFF);
  }

  if (config->tls_auth_clients == TLS_AUTH_CLIENTS_NO) {
    SSL_CTX_set_verify(ssl_ctx.get(), SSL_VERIFY_NONE, nullptr);
  } else if (config->tls_auth_clients == TLS_AUTH_CLIENTS_OPTIONAL) {
    SSL_CTX_set_verify(ssl_ctx.get(), SSL_VERIFY_PEER, nullptr);
  } else {
    SSL_CTX_set_verify(ssl_ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
  }

  auto ca_file = config->tls_ca_cert_file.empty() ? nullptr : config->tls_ca_cert_file.c_str();
  auto ca_dir = config->tls_ca_cert_dir.empty() ? nullptr : config->tls_ca_cert_dir.c_str();
  if (ca_file || ca_dir) {
    if (SSL_CTX_load_verify_locations(ssl_ctx.get(), ca_file, ca_dir) != 1) {
      error("Failed to load CA certificates: {}", fmt::streamed(SSLErrors{}));
      return nullptr;
    }
  } else if (config->tls_auth_clients != TLS_AUTH_CLIENTS_NO) {
    error("Either tls-ca-cert-file or tls-ca-cert-dir must be specified while tls-auth-clients is enabled");
    return nullptr;
  }

  if (SSL_CTX_use_certificate_chain_file(ssl_ctx.get(), config->tls_cert_file.c_str()) != 1) {
    error("Failed to load SSL certificate file: {}", fmt::streamed(SSLErrors{}));
    return nullptr;
  }

  if (!config->tls_key_file_pass.empty()) {
    SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx.get(), static_cast<void *>(const_cast<Config *>(config)));
    SSL_CTX_set_default_passwd_cb(ssl_ctx.get(), [](char *buf, int size, int, void *cfg) -> int {
      strncpy(buf, static_cast<const Config *>(cfg)->tls_key_file_pass.c_str(), size);
      buf[size - 1] = '\0';
      return static_cast<int>(strlen(buf));
    });
  }

  if (SSL_CTX_use_PrivateKey_file(ssl_ctx.get(), config->tls_key_file.c_str(), SSL_FILETYPE_PEM) != 1) {
    error("Failed to load SSL private key file: {}", fmt::streamed(SSLErrors{}));
    return nullptr;
  }

  if (SSL_CTX_check_private_key(ssl_ctx.get()) != 1) {
    error("Failed to check the loaded private key: {}", fmt::streamed(SSLErrors{}));
    return nullptr;
  }

  if (!config->tls_ciphers.empty() && !SSL_CTX_set_cipher_list(ssl_ctx.get(), config->tls_ciphers.c_str())) {
    error("Failed to set SSL ciphers: {}", fmt::streamed(SSLErrors{}));
    return nullptr;
  }

#ifdef SSL_OP_NO_TLSv1_3
  if (!config->tls_ciphersuites.empty() && !SSL_CTX_set_ciphersuites(ssl_ctx.get(), config->tls_ciphersuites.c_str())) {
    error("Failed to set SSL ciphersuites: {}", fmt::streamed(SSLErrors{}));
    return nullptr;
  }
#endif

  return ssl_ctx;
}