This is an automated email from the ASF dual-hosted git repository.

masaori pushed a commit to branch quic-latest
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/quic-latest by this push:
     new 5e3ca19  QUIC: Load multiple certs
5e3ca19 is described below

commit 5e3ca198bc73f493c1df3b97aae6ecb058adf06f
Author: Masaori Koshiba <masa...@apache.org>
AuthorDate: Wed Feb 20 12:16:14 2019 +0900

    QUIC: Load multiple certs
---
 iocore/net/QUICNetProcessor.cc   |   1 +
 iocore/net/QUICNetVConnection.cc |   4 +-
 iocore/net/SSLUtils.cc           |  75 ------------
 iocore/net/quic/QUICConfig.cc    | 255 ++++++++++++++++++++++++++++++++++-----
 iocore/net/quic/QUICConfig.h     |  32 ++++-
 iocore/net/quic/QUICGlobals.cc   |  63 +++++++++-
 iocore/net/quic/QUICGlobals.h    |   2 +
 7 files changed, 321 insertions(+), 111 deletions(-)

diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc
index 8c63668..5a2e373 100644
--- a/iocore/net/QUICNetProcessor.cc
+++ b/iocore/net/QUICNetProcessor.cc
@@ -63,6 +63,7 @@ QUICNetProcessor::start(int, size_t stacksize)
   // This initialization order matters ...
   // QUICInitializeLibrary();
   QUICConfig::startup();
+  QUICCertConfig::startup();
 
 #ifdef TLS1_3_VERSION_DRAFT_TXT
   // FIXME: remove this when TLS1_3_VERSION_DRAFT_TXT is removed
diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index 410b235..e8c7b53 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -240,10 +240,12 @@ QUICNetVConnection::start()
   this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM);
   // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 
1.3, but newer version may not
   if (this->direction() == NET_VCONNECTION_IN) {
+    QUICCertConfig::scoped_config server_cert;
+
     
this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::SERVER);
     
this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_in());
     this->_reset_token       = 
QUICStatelessResetToken(this->_quic_connection_id, params->instance_id());
-    this->_hs_protocol       = 
this->_setup_handshake_protocol(params->server_ssl_ctx());
+    this->_hs_protocol       = 
this->_setup_handshake_protocol(server_cert->ssl_default);
     this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, 
this->_reset_token, params->stateless_retry());
     this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_in());
     this->_schedule_ack_manager_periodic(params->max_ack_delay_in());
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index 7c7c7fe..c83b314 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -1557,81 +1557,6 @@ ssl_extract_certificate(const matcher_line *line_info, 
SSLMultiCertConfigParams
   return true;
 }
 
-// TODO: remove this function and setup SSL_CTX for QUIC somehow
-bool
-SSLParseCertificateConfiguration(const SSLConfigParams *params, SSL_CTX 
*ssl_ctx)
-{
-  char *tok_state = nullptr;
-  char *line      = nullptr;
-  ats_scoped_str file_buf;
-  unsigned line_num = 0;
-  matcher_line line_info;
-
-  const matcher_tags sslCertTags = {nullptr, nullptr, nullptr, nullptr, 
nullptr, nullptr, false};
-
-  Note("loading SSL certificate configuration from %s", 
params->configFilePath);
-
-  if (params->configFilePath) {
-    file_buf = readIntoBuffer(params->configFilePath, __func__, nullptr);
-  }
-
-  if (!file_buf) {
-    Error("failed to read SSL certificate configuration from %s", 
params->configFilePath);
-    return false;
-  }
-
-  // Optionally elevate/allow file access to read root-only
-  // certificates. The destructor will drop privilege for us.
-  uint32_t elevate_setting = 0;
-  REC_ReadConfigInteger(elevate_setting, 
"proxy.config.ssl.cert.load_elevated");
-  ElevateAccess elevate_access(elevate_setting ? ElevateAccess::FILE_PRIVILEGE 
: 0);
-
-  line = tokLine(file_buf, &tok_state);
-  while (line != nullptr) {
-    line_num++;
-
-    // Skip all blank spaces at beginning of line.
-    while (*line && isspace(*line)) {
-      line++;
-    }
-
-    if (*line != '\0' && *line != '#') {
-      SSLMultiCertConfigParams sslMultiCertSettings;
-      const char *errPtr;
-
-      errPtr = parseConfigLine(line, &line_info, &sslCertTags);
-
-      if (errPtr != nullptr) {
-        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s: discarding %s entry at 
line %d: %s", __func__, params->configFilePath,
-                         line_num, errPtr);
-      } else {
-        if (ssl_extract_certificate(&line_info, sslMultiCertSettings)) {
-          // There must be a certificate specified unless the tunnel action is 
set
-          if (sslMultiCertSettings.cert || sslMultiCertSettings.opt != 
SSLCertContext::OPT_TUNNEL) {
-            if (SSL_CTX_use_PrivateKey_file(ssl_ctx, 
sslMultiCertSettings.key.get(), SSL_FILETYPE_PEM) != 1) {
-              Error("Couldn't load private_key: %s", 
sslMultiCertSettings.key.get());
-              return false;
-            }
-
-            if (SSL_CTX_use_certificate_chain_file(ssl_ctx, 
sslMultiCertSettings.cert.get()) != 1) {
-              Error("Couldn't load cert: %s", sslMultiCertSettings.cert.get());
-              return false;
-            }
-
-            return true;
-
-          } else {
-            Warning("No ssl_cert_name specified and no tunnel action set");
-          }
-        }
-      }
-    }
-
-    line = tokLine(nullptr, &tok_state);
-  }
-  return true;
-}
-
 bool
 SSLMultiCertConfigLoader::load(SSLCertLookup *lookup)
 {
diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc
index 8ec9e4f..139df1a 100644
--- a/iocore/net/quic/QUICConfig.cc
+++ b/iocore/net/quic/QUICConfig.cc
@@ -28,10 +28,13 @@
 #include <records/I_RecHttp.h>
 
 #include "P_SSLConfig.h"
+#include "P_OCSPStapling.h"
 
 #include "QUICGlobals.h"
 #include "QUICTransportParameters.h"
 
+#define QUICConfDebug(fmt, ...) Debug("quic_conf", fmt, ##__VA_ARGS__)
+
 // OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte 
strings)
 // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html
 // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ?
@@ -40,6 +43,7 @@ static constexpr std::string_view 
QUIC_ALPN_PROTO_LIST("\5hq-18"sv);
 
 int QUICConfig::_config_id                   = 0;
 int QUICConfigParams::_connection_table_size = 65521;
+int QUICCertConfig::_config_id               = 0;
 
 static SSL_CTX *
 quic_new_ssl_ctx()
@@ -71,29 +75,6 @@ quic_new_ssl_ctx()
 }
 
 static SSL_CTX *
-quic_init_server_ssl_ctx(const QUICConfigParams *params)
-{
-  SSL_CTX *ssl_ctx = quic_new_ssl_ctx();
-
-  SSLConfig::scoped_config ssl_params;
-  SSLParseCertificateConfiguration(ssl_params, ssl_ctx);
-
-  if (SSL_CTX_check_private_key(ssl_ctx) != 1) {
-    Error("check private key failed");
-  }
-
-  SSL_CTX_set_alpn_select_cb(ssl_ctx, QUIC::ssl_select_next_protocol, nullptr);
-
-  if (params->server_supported_groups() != nullptr) {
-    if (SSL_CTX_set1_groups_list(ssl_ctx, params->server_supported_groups()) 
!= 1) {
-      Error("SSL_CTX_set1_groups_list failed");
-    }
-  }
-
-  return ssl_ctx;
-}
-
-static SSL_CTX *
 quic_init_client_ssl_ctx(const QUICConfigParams *params)
 {
   SSL_CTX *ssl_ctx = quic_new_ssl_ctx();
@@ -125,7 +106,6 @@ QUICConfigParams::~QUICConfigParams()
   this->_server_supported_groups = (char 
*)ats_free_null(this->_server_supported_groups);
   this->_client_supported_groups = (char 
*)ats_free_null(this->_client_supported_groups);
 
-  SSL_CTX_free(this->_server_ssl_ctx);
   SSL_CTX_free(this->_client_ssl_ctx);
 };
 
@@ -194,7 +174,6 @@ QUICConfigParams::initialize()
   REC_EstablishStaticConfigInt32U(this->_cc_persistent_congestion_threshold,
                                   
"proxy.config.quic.congestion_control.persistent_congestion_threshold");
 
-  this->_server_ssl_ctx = quic_init_server_ssl_ctx(this);
   this->_client_ssl_ctx = quic_init_client_ssl_ctx(this);
 }
 
@@ -375,12 +354,6 @@ QUICConfigParams::client_supported_groups() const
 }
 
 SSL_CTX *
-QUICConfigParams::server_ssl_ctx() const
-{
-  return this->_server_ssl_ctx;
-}
-
-SSL_CTX *
 QUICConfigParams::client_ssl_ctx() const
 {
   return this->_client_ssl_ctx;
@@ -489,3 +462,223 @@ QUICConfig::release(QUICConfigParams *params)
 {
   configProcessor.release(_config_id, params);
 }
+
+//
+// QUICCertConfig
+//
+void
+QUICCertConfig::startup()
+{
+  reconfigure();
+}
+
+void
+QUICCertConfig::reconfigure()
+{
+  SSLConfig::scoped_config params;
+  SSLCertLookup *lookup = new SSLCertLookup();
+
+  QUICMultiCertConfigLoader loader(params);
+  loader.load(lookup);
+
+  _config_id = configProcessor.set(_config_id, lookup);
+}
+
+SSLCertLookup *
+QUICCertConfig::acquire()
+{
+  return static_cast<SSLCertLookup *>(configProcessor.get(_config_id));
+}
+
+void
+QUICCertConfig::release(SSLCertLookup *lookup)
+{
+  configProcessor.release(_config_id, lookup);
+}
+
+//
+// QUICMultiCertConfigLoader
+//
+SSL_CTX *
+QUICMultiCertConfigLoader::default_server_ssl_ctx()
+{
+  return quic_new_ssl_ctx();
+}
+
+SSL_CTX *
+QUICMultiCertConfigLoader::init_server_ssl_ctx(std::vector<X509 *> &cert_list, 
const SSLMultiCertConfigParams *multi_cert_params)
+{
+  const SSLConfigParams *params = this->_params;
+
+  SSL_CTX *ctx = this->default_server_ssl_ctx();
+
+  if (multi_cert_params) {
+    if (multi_cert_params->dialog) {
+      // TODO: dialog support
+    }
+
+    if (multi_cert_params->cert) {
+      if (!SSLMultiCertConfigLoader::load_certs(ctx, cert_list, params, 
multi_cert_params)) {
+        goto fail;
+      }
+    }
+
+    // SSL_CTX_load_verify_locations() builds the cert chain from the
+    // serverCACertFilename if that is not nullptr.  Otherwise, it uses the 
hashed
+    // symlinks in serverCACertPath.
+    //
+    // if ssl_ca_name is NOT configured for this cert in ssl_multicert.config
+    //     AND
+    // if proxy.config.ssl.CA.cert.filename and proxy.config.ssl.CA.cert.path
+    //     are configured
+    //   pass that file as the chain (include all certs in that file)
+    // else if proxy.config.ssl.CA.cert.path is configured (and
+    //       proxy.config.ssl.CA.cert.filename is nullptr)
+    //   use the hashed symlinks in that directory to build the chain
+    if (!multi_cert_params->ca && params->serverCACertPath != nullptr) {
+      if ((!SSL_CTX_load_verify_locations(ctx, params->serverCACertFilename, 
params->serverCACertPath)) ||
+          (!SSL_CTX_set_default_verify_paths(ctx))) {
+        Error("invalid CA Certificate file or CA Certificate path");
+        goto fail;
+      }
+    }
+  }
+
+  if (params->clientCertLevel != 0) {
+    // TODO: client cert support
+  }
+
+  if (!SSLMultiCertConfigLoader::set_session_id_context(ctx, params, 
multi_cert_params)) {
+    goto fail;
+  }
+
+  if (params->server_tls13_cipher_suites != nullptr) {
+    if (!SSL_CTX_set_ciphersuites(ctx, params->server_tls13_cipher_suites)) {
+      Error("invalid tls server cipher suites in records.config");
+      goto fail;
+    }
+  }
+
+  if (params->server_groups_list != nullptr) {
+    if (!SSL_CTX_set1_groups_list(ctx, params->server_groups_list)) {
+      Error("invalid groups list for server in records.config");
+      goto fail;
+    }
+  }
+
+  // SSL_CTX_set_info_callback(ctx, ssl_callback_info);
+
+  SSL_CTX_set_alpn_select_cb(ctx, QUIC::ssl_select_next_protocol, nullptr);
+
+  if (SSLConfigParams::ssl_ocsp_enabled) {
+    QUICConfDebug("SSL OCSP Stapling is enabled");
+    SSL_CTX_set_tlsext_status_cb(ctx, ssl_callback_ocsp_stapling);
+    const char *cert_name = multi_cert_params ? multi_cert_params->cert.get() 
: nullptr;
+
+    for (auto cert : cert_list) {
+      if (!ssl_stapling_init_cert(ctx, cert, cert_name)) {
+        Warning("failed to configure SSL_CTX for OCSP Stapling info for 
certificate at %s", cert_name);
+      }
+    }
+  } else {
+    QUICConfDebug("SSL OCSP Stapling is disabled");
+  }
+
+  if (SSLConfigParams::init_ssl_ctx_cb) {
+    SSLConfigParams::init_ssl_ctx_cb(ctx, true);
+  }
+
+  return ctx;
+
+fail:
+  SSLReleaseContext(ctx);
+  for (auto cert : cert_list) {
+    X509_free(cert);
+  }
+
+  return nullptr;
+}
+
+SSL_CTX *
+QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const 
SSLMultiCertConfigParams *multi_cert_params)
+{
+  std::vector<X509 *> cert_list;
+  SSL_CTX *ctx                   = this->init_server_ssl_ctx(cert_list, 
multi_cert_params);
+  ssl_ticket_key_block *keyblock = nullptr;
+  bool inserted                  = false;
+
+  if (!ctx || !multi_cert_params) {
+    lookup->is_valid = false;
+    return nullptr;
+  }
+
+  const char *certname = multi_cert_params->cert.get();
+  for (auto cert : cert_list) {
+    if (0 > SSLMultiCertConfigLoader::check_server_cert_now(cert, certname)) {
+      /* At this point, we know cert is bad, and we've already printed a
+         descriptive reason as to why cert is bad to the log file */
+      QUICConfDebug("Marking certificate as NOT VALID: %s", certname);
+      lookup->is_valid = false;
+    }
+  }
+
+  // Index this certificate by the specified IP(v6) address. If the address is 
"*", make it the default context.
+  if (multi_cert_params->addr) {
+    if (strcmp(multi_cert_params->addr, "*") == 0) {
+      if (lookup->insert(multi_cert_params->addr, SSLCertContext(ctx, 
multi_cert_params->opt, keyblock)) >= 0) {
+        inserted            = true;
+        lookup->ssl_default = ctx;
+        this->_set_handshake_callbacks(ctx);
+      }
+    } else {
+      IpEndpoint ep;
+
+      if (ats_ip_pton(multi_cert_params->addr, &ep) == 0) {
+        QUICConfDebug("mapping '%s' to certificate %s", (const char 
*)multi_cert_params->addr, (const char *)certname);
+        if (lookup->insert(ep, SSLCertContext(ctx, multi_cert_params->opt, 
keyblock)) >= 0) {
+          inserted = true;
+        }
+      } else {
+        Error("'%s' is not a valid IPv4 or IPv6 address", (const char 
*)multi_cert_params->addr);
+        lookup->is_valid = false;
+      }
+    }
+  }
+
+  // Insert additional mappings. Note that this maps multiple keys to the same 
value, so when
+  // this code is updated to reconfigure the SSL certificates, it will need 
some sort of
+  // refcounting or alternate way of avoiding double frees.
+  QUICConfDebug("importing SNI names from %s", (const char *)certname);
+  for (auto cert : cert_list) {
+    if (SSLMultiCertConfigLoader::index_certificate(lookup, 
SSLCertContext(ctx, multi_cert_params->opt), cert, certname)) {
+      inserted = true;
+    }
+  }
+
+  if (inserted) {
+    if (SSLConfigParams::init_ssl_ctx_cb) {
+      SSLConfigParams::init_ssl_ctx_cb(ctx, true);
+    }
+  }
+
+  if (!inserted) {
+    SSLReleaseContext(ctx);
+    ctx = nullptr;
+  }
+
+  for (auto &i : cert_list) {
+    X509_free(i);
+  }
+
+  return ctx;
+}
+
+void
+QUICMultiCertConfigLoader::_set_handshake_callbacks(SSL_CTX *ssl_ctx)
+{
+  SSL_CTX_set_cert_cb(ssl_ctx, QUIC::ssl_cert_cb, nullptr);
+  SSL_CTX_set_tlsext_servername_callback(ssl_ctx, QUIC::ssl_sni_cb);
+
+  // Set client hello callback if needed
+  // SSL_CTX_set_client_hello_cb(ctx, QUIC::ssl_client_hello_cb, nullptr);
+}
diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h
index f40e012..4ab237a 100644
--- a/iocore/net/quic/QUICConfig.h
+++ b/iocore/net/quic/QUICConfig.h
@@ -26,6 +26,8 @@
 #include <openssl/ssl.h>
 
 #include "ProxyConfig.h"
+#include "P_SSLCertLookup.h"
+#include "P_SSLUtils.h"
 
 class QUICConfigParams : public ConfigInfo
 {
@@ -45,7 +47,6 @@ public:
   const char *client_supported_groups() const;
   const char *session_file() const;
 
-  SSL_CTX *server_ssl_ctx() const;
   SSL_CTX *client_ssl_ctx() const;
 
   // Transport Parameters
@@ -101,8 +102,6 @@ private:
   char *_client_supported_groups = nullptr;
   char *_session_file            = nullptr;
 
-  // TODO: integrate with SSLCertLookup or SNIConfigParams
-  SSL_CTX *_server_ssl_ctx = nullptr;
   SSL_CTX *_client_ssl_ctx = nullptr;
 
   // Transport Parameters
@@ -156,3 +155,30 @@ public:
 private:
   static int _config_id;
 };
+
+class QUICCertConfig
+{
+public:
+  static void startup();
+  static void reconfigure();
+  static SSLCertLookup *acquire();
+  static void release(SSLCertLookup *lookup);
+
+  using scoped_config = ConfigProcessor::scoped_config<QUICCertConfig, 
SSLCertLookup>;
+
+private:
+  static int _config_id;
+};
+
+class QUICMultiCertConfigLoader : public SSLMultiCertConfigLoader
+{
+public:
+  QUICMultiCertConfigLoader(const SSLConfigParams *p) : 
SSLMultiCertConfigLoader(p) {}
+
+  virtual SSL_CTX *default_server_ssl_ctx() override;
+  virtual SSL_CTX *init_server_ssl_ctx(std::vector<X509 *> &cert_list, const 
SSLMultiCertConfigParams *multi_cert_params) override;
+
+private:
+  virtual SSL_CTX *_store_ssl_ctx(SSLCertLookup *lookup, const 
SSLMultiCertConfigParams *multi_cert_params) override;
+  virtual void _set_handshake_callbacks(SSL_CTX *ssl_ctx) override;
+};
diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc
index 0520f3e..611bddb 100644
--- a/iocore/net/quic/QUICGlobals.cc
+++ b/iocore/net/quic/QUICGlobals.cc
@@ -26,10 +26,14 @@
 #include <cstring>
 
 #include "P_SSLNextProtocolSet.h"
+
 #include "QUICStats.h"
 #include "QUICConfig.h"
 #include "QUICConnection.h"
 
+#define QUICGlobalDebug(fmt, ...) Debug("quic_global", fmt, ##__VA_ARGS__)
+#define QUICGlobalQCDebug(qc, fmt, ...) Debug("quic_global", "[%s] " fmt, 
qc->cids().data(), ##__VA_ARGS__)
+
 RecRawStatBlock *quic_rsb;
 
 int QUIC::ssl_quic_qc_index  = -1;
@@ -67,7 +71,7 @@ QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session)
   QUICConfig::scoped_config params;
   auto file = BIO_new_file(params->session_file(), "w");
   if (file == nullptr) {
-    Debug("quic_global", "Could not write TLS session in %s", 
params->session_file());
+    QUICGlobalDebug("Could not write TLS session in %s", 
params->session_file());
     return 0;
   }
 
@@ -76,6 +80,63 @@ QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session)
   return 0;
 }
 
+int
+QUIC::ssl_cert_cb(SSL *ssl, void * /*arg*/)
+{
+  SSL_CTX *ctx       = nullptr;
+  SSLCertContext *cc = nullptr;
+  QUICCertConfig::scoped_config lookup;
+  const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  QUICConnection *qc     = static_cast<QUICConnection *>(SSL_get_ex_data(ssl, 
QUIC::ssl_quic_qc_index));
+
+  if (servername == nullptr) {
+    servername = "";
+  }
+  QUICGlobalQCDebug(qc, "SNI=%s", servername);
+
+  // The incoming SSL_CTX is either the one mapped from the inbound IP address 
or the default one. If we
+  // don't find a name-based match at this point, we *do not* want to mess 
with the context because we've
+  // already made a best effort to find the best match.
+  if (likely(servername)) {
+    cc = lookup->find((char *)servername);
+    if (cc && cc->ctx) {
+      ctx = cc->ctx;
+    }
+  }
+
+  // If there's no match on the server name, try to match on the peer address.
+  if (ctx == nullptr) {
+    QUICFiveTuple five_tuple = qc->five_tuple();
+    IpEndpoint ip            = five_tuple.destination();
+    cc                       = lookup->find(ip);
+
+    if (cc && cc->ctx) {
+      ctx = cc->ctx;
+    }
+  }
+
+  bool found = true;
+  if (ctx != nullptr) {
+    SSL_set_SSL_CTX(ssl, ctx);
+  } else {
+    found = false;
+  }
+
+  ctx = SSL_get_SSL_CTX(ssl);
+
+  QUICGlobalQCDebug(qc, "%s SSL_CTX %p for requested name '%s'", found ? 
"found" : "using", ctx, servername);
+
+  return 1;
+}
+
+int
+QUIC::ssl_sni_cb(SSL *ssl, int * /*ad*/, void * /*arg*/)
+{
+  // XXX: add SNIConfig support ?
+  // XXX: add TRANSPORT_BLIND_TUNNEL support ?
+  return 1;
+}
+
 void
 QUIC::_register_stats()
 {
diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h
index 4da21d1..cd4ac54 100644
--- a/iocore/net/quic/QUICGlobals.h
+++ b/iocore/net/quic/QUICGlobals.h
@@ -34,6 +34,8 @@ public:
   static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, 
unsigned char *outlen, const unsigned char *in,
                                       unsigned inlen, void *);
   static int ssl_client_new_session(SSL *ssl, SSL_SESSION *session);
+  static int ssl_cert_cb(SSL *ssl, void *arg);
+  static int ssl_sni_cb(SSL *ssl, int *ad, void *arg);
 
   static int ssl_quic_qc_index;
   static int ssl_quic_tls_index;

Reply via email to