You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2019/02/27 23:36:09 UTC
[trafficserver] branch master updated: Cleanup: Loading certs by
SSLMultiCertConfigLoader
This is an automated email from the ASF dual-hosted git repository.
masaori pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new aecfd52 Cleanup: Loading certs by SSLMultiCertConfigLoader
aecfd52 is described below
commit aecfd526d784d3469cdb0437067ba0e09a5a26d0
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Wed Feb 20 10:33:03 2019 +0900
Cleanup: Loading certs by SSLMultiCertConfigLoader
---
iocore/net/P_SSLCertLookup.h | 3 +-
iocore/net/P_SSLConfig.h | 10 +-
iocore/net/P_SSLUtils.h | 75 ++++++--
iocore/net/SSLConfig.cc | 3 +-
iocore/net/SSLStats.cc | 4 +-
iocore/net/SSLUtils.cc | 428 +++++++++++++++++++++++--------------------
6 files changed, 301 insertions(+), 222 deletions(-)
diff --git a/iocore/net/P_SSLCertLookup.h b/iocore/net/P_SSLCertLookup.h
index 65d278a..475d05d 100644
--- a/iocore/net/P_SSLCertLookup.h
+++ b/iocore/net/P_SSLCertLookup.h
@@ -23,8 +23,9 @@
#pragma once
+#include <openssl/ssl.h>
+
#include "ProxyConfig.h"
-#include "P_SSLUtils.h"
struct SSLConfigParams;
struct SSLContextStorage;
diff --git a/iocore/net/P_SSLConfig.h b/iocore/net/P_SSLConfig.h
index 14b7b9f..39058b6 100644
--- a/iocore/net/P_SSLConfig.h
+++ b/iocore/net/P_SSLConfig.h
@@ -30,13 +30,15 @@
****************************************************************************/
#pragma once
+#include <openssl/rand.h>
+
+#include "tscore/ink_inet.h"
+#include "tscore/IpMap.h"
+
#include "ProxyConfig.h"
+
#include "SSLSessionCache.h"
-#include "tscore/ink_inet.h"
-#include <openssl/rand.h>
-#include "P_SSLCertLookup.h"
#include "YamlSNIConfig.h"
-#include <tscore/IpMap.h>
struct SSLCertLookup;
struct ssl_ticket_key_block;
diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h
index a61d8bc..3e3de60 100644
--- a/iocore/net/P_SSLUtils.h
+++ b/iocore/net/P_SSLUtils.h
@@ -21,10 +21,6 @@
#pragma once
-#include "tscore/ink_config.h"
-#include "tscore/Diags.h"
-#include "P_SSLClientUtils.h"
-
#define OPENSSL_THREAD_DEFINES
// BoringSSL does not have this include file
@@ -33,37 +29,88 @@
#endif
#include <openssl/ssl.h>
+#include "tscore/ink_config.h"
+#include "tscore/Diags.h"
+
+#include "P_SSLClientUtils.h"
+#include "P_SSLCertLookup.h"
+
struct SSLConfigParams;
-struct SSLCertLookup;
class SSLNetVConnection;
typedef int ssl_error_t;
-// Create a default SSL server context.
-SSL_CTX *SSLDefaultServerContext();
+/**
+ @brief Gather user provided settings from ssl_multicert.config in to this single struct
+ */
+struct SSLMultiCertConfigParams {
+ SSLMultiCertConfigParams() : opt(SSLCertContext::OPT_NONE)
+ {
+ REC_ReadConfigInt32(session_ticket_enabled, "proxy.config.ssl.server.session_ticket.enable");
+ }
+
+ int session_ticket_enabled; ///< session ticket enabled
+ ats_scoped_str addr; ///< IPv[64] address to match
+ ats_scoped_str cert; ///< certificate
+ ats_scoped_str first_cert; ///< the first certificate name when multiple cert files are in 'ssl_cert_name'
+ ats_scoped_str ca; ///< CA public certificate
+ ats_scoped_str key; ///< Private key
+ ats_scoped_str dialog; ///< Private key dialog
+ ats_scoped_str servername; ///< Destination server
+ SSLCertContext::Option opt; ///< SSLCertContext special handling option
+};
+
+/**
+ @brief Load SSL certificates from ssl_multicert.config and setup SSLCertLookup for SSLCertificateConfig
+ */
+class SSLMultiCertConfigLoader
+{
+public:
+ SSLMultiCertConfigLoader(const SSLConfigParams *p) : _params(p) {}
+
+ bool load(SSLCertLookup *lookup);
+
+ virtual SSL_CTX *default_server_ssl_ctx();
+ virtual SSL_CTX *init_server_ssl_ctx(std::vector<X509 *> &certList, const SSLMultiCertConfigParams *sslMultCertSettings);
+
+ static bool load_certs(SSL_CTX *ctx, std::vector<X509 *> &certList, const SSLConfigParams *params,
+ const SSLMultiCertConfigParams *ssl_multi_cert_params);
+ static bool set_session_id_context(SSL_CTX *ctx, const SSLConfigParams *params,
+ const SSLMultiCertConfigParams *sslMultCertSettings);
+
+ static bool index_certificate(SSLCertLookup *lookup, SSLCertContext const &cc, X509 *cert, const char *certname);
+ static int check_server_cert_now(X509 *cert, const char *certname);
+ static void clear_pw_references(SSL_CTX *ssl_ctx);
+
+protected:
+ const SSLConfigParams *_params;
+
+private:
+ virtual SSL_CTX *_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiCertConfigParams *ssl_multi_cert_params);
+ virtual void _set_handshake_callbacks(SSL_CTX *ctx);
+};
// Create a new SSL server context fully configured.
+// Used by TS API (TSSslServerContextCreate)
SSL_CTX *SSLCreateServerContext(const SSLConfigParams *params);
+// Release SSL_CTX and the associated data. This works for both
+// client and server contexts and gracefully accepts nullptr.
+// Used by TS API (TSSslContextDestroy)
+void SSLReleaseContext(SSL_CTX *ctx);
+
// Initialize the SSL library.
void SSLInitializeLibrary();
// Initialize SSL library based on configuration settings
void SSLPostConfigInitialize();
-// Release SSL_CTX and the associated data. This works for both
-// client and server contexts and gracefully accepts nullptr.
-void SSLReleaseContext(SSL_CTX *ctx);
-
// Wrapper functions to SSL I/O routines
ssl_error_t SSLWriteBuffer(SSL *ssl, const void *buf, int64_t nbytes, int64_t &nwritten);
ssl_error_t SSLReadBuffer(SSL *ssl, void *buf, int64_t nbytes, int64_t &nread);
ssl_error_t SSLAccept(SSL *ssl);
ssl_error_t SSLConnect(SSL *ssl);
-// Load the SSL certificate configuration.
-bool SSLParseCertificateConfiguration(const SSLConfigParams *params, SSLCertLookup *lookup);
-
// Attach a SSL NetVC back pointer to a SSL session.
void SSLNetVCAttach(SSL *ssl, SSLNetVConnection *vc);
diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc
index d822ce4..51855b4 100644
--- a/iocore/net/SSLConfig.cc
+++ b/iocore/net/SSLConfig.cc
@@ -518,7 +518,8 @@ SSLCertificateConfig::reconfigure()
ink_hrtime_sleep(HRTIME_SECONDS(secs));
}
- SSLParseCertificateConfiguration(params, lookup);
+ SSLMultiCertConfigLoader loader(params);
+ loader.load(lookup);
if (!lookup->is_valid) {
retStatus = false;
diff --git a/iocore/net/SSLStats.cc b/iocore/net/SSLStats.cc
index c748b94..b15e40d 100644
--- a/iocore/net/SSLStats.cc
+++ b/iocore/net/SSLStats.cc
@@ -26,6 +26,7 @@
#include <openssl/err.h>
#include "P_SSLConfig.h"
+#include "P_SSLUtils.h"
RecRawStatBlock *ssl_rsb = nullptr;
std::unordered_map<std::string, intptr_t> cipher_map;
@@ -206,7 +207,8 @@ SSLInitializeStatistics()
// filtered by proxy.config.ssl.server.cipher_suite. This keeps the set of cipher suites stable across
// configuration reloads and works for the case where we honor the client cipher preference.
- ctx = SSLDefaultServerContext();
+ SSLMultiCertConfigLoader loader(nullptr);
+ ctx = loader.default_server_ssl_ctx();
ssl = SSL_new(ctx);
ciphers = SSL_get_ciphers(ssl);
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index 1e48bf2..20bd0ea 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -95,36 +95,6 @@ static constexpr char SSL_CERT_SEPARATE_DELIM = ',';
#endif
#endif
-/*
- * struct ssl_user_config: gather user provided settings from ssl_multicert.config in to this single struct
- * ssl_ticket_enabled - session ticket enabled
- * ssl_cert_name - certificate
- * dest_ip - IPv[64] address to match
- * ssl_cert_name - certificate
- * first_cert - the first certificate name when multiple cert files are in 'ssl_cert_name'
- * ssl_ca_name - CA public certificate
- * ssl_key_name - Private key
- * ticket_key_name - session key file. [key_name (16Byte) + HMAC_secret (16Byte) + AES_key (16Byte)]
- * ssl_key_dialog - Private key dialog
- * servername - Destination server
- */
-struct ssl_user_config {
- ssl_user_config() : opt(SSLCertContext::OPT_NONE)
- {
- REC_ReadConfigInt32(session_ticket_enabled, "proxy.config.ssl.server.session_ticket.enable");
- }
-
- int session_ticket_enabled;
- ats_scoped_str addr;
- ats_scoped_str cert;
- ats_scoped_str first_cert;
- ats_scoped_str ca;
- ats_scoped_str key;
- ats_scoped_str dialog;
- ats_scoped_str servername;
- SSLCertContext::Option opt;
-};
-
SSLSessionCache *session_cache; // declared extern in P_SSLConfig.h
#if TS_HAVE_OPENSSL_SESSION_TICKETS
@@ -1022,7 +992,7 @@ SSLInitializeLibrary()
}
SSL_CTX *
-SSLDefaultServerContext()
+SSLMultiCertConfigLoader::default_server_ssl_ctx()
{
return SSL_CTX_new(SSLv23_server_method());
}
@@ -1064,19 +1034,22 @@ SSLPrivateKeyHandler(SSL_CTX *ctx, const SSLConfigParams *params, const std::str
return true;
}
-static int
-SSLCheckServerCertNow(X509 *cert, const char *certname)
+/**
+ returns 0 on OK or negative value on failure and update log as appropriate.
+
+ Will check:
+ - if file exists, and has read permissions
+ - for truncation or other PEM read fail
+ - current time is between notBefore and notAfter dates of certificate
+ if anything is not kosher, a negative value is returned and appropriate error logged.
+
+ @static
+ */
+int
+SSLMultiCertConfigLoader::check_server_cert_now(X509 *cert, const char *certname)
{
int timeCmpValue;
- // SSLCheckServerCertNow() - returns 0 on OK or negative value on failure
- // and update log as appropriate.
- // Will check:
- // - if file exists, and has read permissions
- // - for truncation or other PEM read fail
- // - current time is between notBefore and notAfter dates of certificate
- // if anything is not kosher, a negative value is returned and appropriate error logged.
-
if (!cert) {
// a truncated certificate would fall into here
Error("invalid certificate %s: file is truncated or corrupted", certname);
@@ -1122,11 +1095,14 @@ asn1_strdup(ASN1_STRING *s)
return ats_strndup((const char *)ASN1_STRING_get0_data(s), ASN1_STRING_length(s));
}
-// Given a certificate and it's corresponding SSL_CTX context, insert hash
-// table aliases for subject CN and subjectAltNames DNS without wildcard,
-// insert trie aliases for those with wildcard.
-static bool
-ssl_index_certificate(SSLCertLookup *lookup, SSLCertContext const &cc, X509 *cert, const char *certname)
+/**
+ Given a certificate and it's corresponding SSL_CTX context, insert hash
+ table aliases for subject CN and subjectAltNames DNS without wildcard,
+ insert trie aliases for those with wildcard.
+ @static
+*/
+bool
+SSLMultiCertConfigLoader::index_certificate(SSLCertLookup *lookup, SSLCertContext const &cc, X509 *cert, const char *certname)
{
X509_NAME *subject = nullptr;
bool inserted = false;
@@ -1232,8 +1208,8 @@ ssl_callback_info(const SSL *ssl, int where, int ret)
}
}
-static void
-ssl_set_handshake_callbacks(SSL_CTX *ctx)
+void
+SSLMultiCertConfigLoader::_set_handshake_callbacks(SSL_CTX *ctx)
{
// Make sure the callbacks are set
#if TS_USE_CERT_CB
@@ -1275,16 +1251,17 @@ setClientCertLevel(SSL *ssl, uint8_t certLevel)
SSL_set_verify_depth(ssl, params->verify_depth); // might want to make configurable at some point.
}
+/**
+ Initialize SSL_CTX for server
+ This is public function because of used by SSLCreateServerContext.
+ */
SSL_CTX *
-SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config *sslMultCertSettings, std::vector<X509 *> &cert_list)
+SSLMultiCertConfigLoader::init_server_ssl_ctx(std::vector<X509 *> &cert_list, const SSLMultiCertConfigParams *sslMultCertSettings)
{
+ const SSLConfigParams *params = this->_params;
+
int server_verify_client;
- SSL_CTX *ctx = SSLDefaultServerContext();
- EVP_MD_CTX *digest = EVP_MD_CTX_new();
- STACK_OF(X509_NAME) *ca_list = nullptr;
- unsigned char hash_buf[EVP_MAX_MD_SIZE];
- unsigned int hash_len = 0;
- const char *setting_cert = sslMultCertSettings ? sslMultCertSettings->cert.get() : nullptr;
+ SSL_CTX *ctx = this->default_server_ssl_ctx();
// disable selected protocols
SSL_CTX_set_options(ctx, params->ssl_ctx_options);
@@ -1366,84 +1343,9 @@ SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config *sslMu
}
if (sslMultCertSettings->cert) {
- SimpleTokenizer cert_tok((const char *)sslMultCertSettings->cert, SSL_CERT_SEPARATE_DELIM);
- SimpleTokenizer key_tok((sslMultCertSettings->key ? (const char *)sslMultCertSettings->key : ""), SSL_CERT_SEPARATE_DELIM);
-
- if (sslMultCertSettings->key && cert_tok.getNumTokensRemaining() != key_tok.getNumTokensRemaining()) {
- Error("the number of certificates in ssl_cert_name and ssl_key_name doesn't match");
+ if (!SSLMultiCertConfigLoader::load_certs(ctx, cert_list, params, sslMultCertSettings)) {
goto fail;
}
- SimpleTokenizer ca_tok("", SSL_CERT_SEPARATE_DELIM);
- if (sslMultCertSettings->ca) {
- ca_tok.setString(sslMultCertSettings->ca);
- if (cert_tok.getNumTokensRemaining() != ca_tok.getNumTokensRemaining()) {
- Error("the number of certificates in ssl_cert_name and ssl_ca_name doesn't match");
- goto fail;
- }
- }
-
- for (const char *certname = cert_tok.getNext(); certname; certname = cert_tok.getNext()) {
- std::string completeServerCertPath = Layout::relative_to(params->serverCertPathOnly, certname);
- scoped_BIO bio(BIO_new_file(completeServerCertPath.c_str(), "r"));
- X509 *cert = nullptr;
- if (bio) {
- cert = PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr);
- }
- if (!bio || !cert) {
- SSLError("failed to load certificate chain from %s", completeServerCertPath.c_str());
- goto fail;
- }
- if (!SSL_CTX_use_certificate(ctx, cert)) {
- SSLError("Failed to assign cert from %s to SSL_CTX", completeServerCertPath.c_str());
- X509_free(cert);
- goto fail;
- }
-
- // Load up any additional chain certificates
- SSL_CTX_add_extra_chain_cert_bio(ctx, bio);
-
- const char *keyPath = key_tok.getNext();
- if (!SSLPrivateKeyHandler(ctx, params, completeServerCertPath, keyPath)) {
- goto fail;
- }
-
- cert_list.push_back(cert);
- if (SSLConfigParams::load_ssl_file_cb) {
- SSLConfigParams::load_ssl_file_cb(completeServerCertPath.c_str(), CONFIG_FLAG_UNVERSIONED);
- }
-
- // Must load all the intermediate certificates before starting the next chain
-
- // First, load any CA chains from the global chain file. This should probably
- // eventually be a comma separated list too. For now we will load it in all chains even
- // though it only makes sense in one chain
- if (params->serverCertChainFilename) {
- ats_scoped_str completeServerCertChainPath(
- Layout::relative_to(params->serverCertPathOnly, params->serverCertChainFilename));
- if (!SSL_CTX_add_extra_chain_cert_file(ctx, completeServerCertChainPath)) {
- SSLError("failed to load global certificate chain from %s", (const char *)completeServerCertChainPath);
- goto fail;
- }
- if (SSLConfigParams::load_ssl_file_cb) {
- SSLConfigParams::load_ssl_file_cb(completeServerCertChainPath, CONFIG_FLAG_UNVERSIONED);
- }
- }
-
- // Now, load any additional certificate chains specified in this entry.
- if (sslMultCertSettings->ca) {
- const char *ca_name = ca_tok.getNext();
- if (ca_name != nullptr) {
- ats_scoped_str completeServerCertChainPath(Layout::relative_to(params->serverCertPathOnly, ca_name));
- if (!SSL_CTX_add_extra_chain_cert_file(ctx, completeServerCertChainPath)) {
- SSLError("failed to load certificate chain from %s", (const char *)completeServerCertChainPath);
- goto fail;
- }
- if (SSLConfigParams::load_ssl_file_cb) {
- SSLConfigParams::load_ssl_file_cb(completeServerCertChainPath, CONFIG_FLAG_UNVERSIONED);
- }
- }
- }
- }
}
// SSL_CTX_load_verify_locations() builds the cert chain from the
@@ -1497,50 +1399,7 @@ SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config *sslMu
SSL_CTX_set_verify_depth(ctx, params->verify_depth); // might want to make configurable at some point.
}
- // Set the list of CA's to send to client if we ask for a client
- // certificate
- if (params->serverCACertFilename) {
- ca_list = SSL_load_client_CA_file(params->serverCACertFilename);
- if (ca_list) {
- SSL_CTX_set_client_CA_list(ctx, ca_list);
- }
- }
-
- if (EVP_DigestInit_ex(digest, evp_md_func, nullptr) == 0) {
- SSLError("EVP_DigestInit_ex failed");
- goto fail;
- }
-
- if (nullptr != setting_cert) {
- Debug("ssl", "Using '%s' in hash for session id context", sslMultCertSettings->cert.get());
- if (EVP_DigestUpdate(digest, sslMultCertSettings->cert, strlen(setting_cert)) == 0) {
- SSLError("EVP_DigestUpdate failed");
- goto fail;
- }
- }
-
- if (ca_list != nullptr) {
- size_t num_certs = sk_X509_NAME_num(ca_list);
-
- for (size_t i = 0; i < num_certs; i++) {
- X509_NAME *name = sk_X509_NAME_value(ca_list, i);
- if (X509_NAME_digest(name, evp_md_func, hash_buf /* borrow our final hash buffer. */, &hash_len) == 0 ||
- EVP_DigestUpdate(digest, hash_buf, hash_len) == 0) {
- SSLError("Adding X509 name to digest failed");
- goto fail;
- }
- }
- }
-
- if (EVP_DigestFinal_ex(digest, hash_buf, &hash_len) == 0) {
- SSLError("EVP_DigestFinal_ex failed");
- goto fail;
- }
- EVP_MD_CTX_free(digest);
- digest = nullptr;
-
- if (SSL_CTX_set_session_id_context(ctx, hash_buf, hash_len) == 0) {
- SSLError("SSL_CTX_set_session_id_context failed");
+ if (!SSLMultiCertConfigLoader::set_session_id_context(ctx, params, sslMultCertSettings)) {
goto fail;
}
@@ -1574,13 +1433,9 @@ SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config *sslMu
}
ssl_context_enable_ecdh(ctx);
-#define SSL_CLEAR_PW_REFERENCES(CTX) \
- { \
- SSL_CTX_set_default_passwd_cb(CTX, nullptr); \
- SSL_CTX_set_default_passwd_cb_userdata(CTX, nullptr); \
- }
+
if (sslMultCertSettings && sslMultCertSettings->dialog) {
- SSL_CLEAR_PW_REFERENCES(ctx);
+ SSLMultiCertConfigLoader::clear_pw_references(ctx);
}
SSL_CTX_set_info_callback(ctx, ssl_callback_info);
@@ -1596,10 +1451,11 @@ SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config *sslMu
if (SSLConfigParams::ssl_ocsp_enabled) {
Debug("ssl", "SSL OCSP Stapling is enabled");
SSL_CTX_set_tlsext_status_cb(ctx, ssl_callback_ocsp_stapling);
+ const char *cert_name = sslMultCertSettings ? sslMultCertSettings->cert.get() : nullptr;
for (auto cert : cert_list) {
- if (!ssl_stapling_init_cert(ctx, cert, setting_cert)) {
- Warning("failed to configure SSL_CTX for OCSP Stapling info for certificate at %s", setting_cert);
+ 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 {
@@ -1614,13 +1470,11 @@ SSLInitServerContext(const SSLConfigParams *params, const ssl_user_config *sslMu
if (SSLConfigParams::init_ssl_ctx_cb) {
SSLConfigParams::init_ssl_ctx_cb(ctx, true);
}
+
return ctx;
fail:
- if (digest) {
- EVP_MD_CTX_free(digest);
- }
- SSL_CLEAR_PW_REFERENCES(ctx)
+ SSLMultiCertConfigLoader::clear_pw_references(ctx);
SSLReleaseContext(ctx);
for (auto cert : cert_list) {
X509_free(cert);
@@ -1632,21 +1486,24 @@ fail:
SSL_CTX *
SSLCreateServerContext(const SSLConfigParams *params)
{
+ SSLMultiCertConfigLoader loader(params);
std::vector<X509 *> cert_list;
- SSL_CTX *ctx = SSLInitServerContext(params, nullptr, cert_list);
+
+ SSL_CTX *ctx = loader.init_server_ssl_ctx(cert_list, nullptr);
ink_assert(cert_list.empty());
+
return ctx;
}
/**
Insert SSLCertContext (SSL_CTX ans options) into SSLCertLookup with key.
- Do NOT call SSL_CTX_set_* functions from here. SSL_CTX should be set up by SSLInitServerContext().
+ Do NOT call SSL_CTX_set_* functions from here. SSL_CTX should be set up by SSLMultiCertConfigLoader::init_server_ssl_ctx().
*/
-static SSL_CTX *
-ssl_store_ssl_context(const SSLConfigParams *params, SSLCertLookup *lookup, const ssl_user_config *sslMultCertSettings)
+SSL_CTX *
+SSLMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiCertConfigParams *sslMultCertSettings)
{
std::vector<X509 *> cert_list;
- SSL_CTX *ctx = SSLInitServerContext(params, sslMultCertSettings, cert_list);
+ SSL_CTX *ctx = this->init_server_ssl_ctx(cert_list, sslMultCertSettings);
ssl_ticket_key_block *keyblock = nullptr;
bool inserted = false;
@@ -1657,7 +1514,7 @@ ssl_store_ssl_context(const SSLConfigParams *params, SSLCertLookup *lookup, cons
const char *certname = sslMultCertSettings->cert.get();
for (auto cert : cert_list) {
- if (0 > SSLCheckServerCertNow(cert, certname)) {
+ 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 */
Debug("ssl", "Marking certificate as NOT VALID: %s", certname);
@@ -1676,7 +1533,7 @@ ssl_store_ssl_context(const SSLConfigParams *params, SSLCertLookup *lookup, cons
if (lookup->insert(sslMultCertSettings->addr, SSLCertContext(ctx, sslMultCertSettings->opt, keyblock)) >= 0) {
inserted = true;
lookup->ssl_default = ctx;
- ssl_set_handshake_callbacks(ctx);
+ this->_set_handshake_callbacks(ctx);
}
} else {
IpEndpoint ep;
@@ -1705,7 +1562,7 @@ ssl_store_ssl_context(const SSLConfigParams *params, SSLCertLookup *lookup, cons
// refcounting or alternate way of avoiding double frees.
Debug("ssl", "importing SNI names from %s", (const char *)certname);
for (auto cert : cert_list) {
- if (ssl_index_certificate(lookup, SSLCertContext(ctx, sslMultCertSettings->opt), cert, certname)) {
+ if (SSLMultiCertConfigLoader::index_certificate(lookup, SSLCertContext(ctx, sslMultCertSettings->opt), cert, certname)) {
inserted = true;
}
}
@@ -1729,7 +1586,7 @@ ssl_store_ssl_context(const SSLConfigParams *params, SSLCertLookup *lookup, cons
}
static bool
-ssl_extract_certificate(const matcher_line *line_info, ssl_user_config &sslMultCertSettings)
+ssl_extract_certificate(const matcher_line *line_info, SSLMultiCertConfigParams &sslMultCertSettings)
{
for (int i = 0; i < MATCHER_MAX_TOKENS; ++i) {
const char *label;
@@ -1792,8 +1649,10 @@ ssl_extract_certificate(const matcher_line *line_info, ssl_user_config &sslMultC
}
bool
-SSLParseCertificateConfiguration(const SSLConfigParams *params, SSLCertLookup *lookup)
+SSLMultiCertConfigLoader::load(SSLCertLookup *lookup)
{
+ const SSLConfigParams *params = this->_params;
+
char *tok_state = nullptr;
char *line = nullptr;
ats_scoped_str file_buf;
@@ -1829,7 +1688,7 @@ SSLParseCertificateConfiguration(const SSLConfigParams *params, SSLCertLookup *l
}
if (*line != '\0' && *line != '#') {
- ssl_user_config sslMultiCertSettings;
+ SSLMultiCertConfigParams sslMultiCertSettings;
const char *errPtr;
errPtr = parseConfigLine(line, &line_info, &sslCertTags);
@@ -1841,7 +1700,7 @@ SSLParseCertificateConfiguration(const SSLConfigParams *params, SSLCertLookup *l
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) {
- ssl_store_ssl_context(params, lookup, &sslMultiCertSettings);
+ this->_store_ssl_ctx(lookup, &sslMultiCertSettings);
} else {
Warning("No ssl_cert_name specified and no tunnel action set");
}
@@ -1856,9 +1715,9 @@ SSLParseCertificateConfiguration(const SSLConfigParams *params, SSLCertLookup *l
// bootstrap the SSL handshake so that we can subsequently do the SNI lookup to switch to the real
// context.
if (lookup->ssl_default == nullptr) {
- ssl_user_config sslMultiCertSettings;
+ SSLMultiCertConfigParams sslMultiCertSettings;
sslMultiCertSettings.addr = ats_strdup("*");
- if (ssl_store_ssl_context(params, lookup, &sslMultiCertSettings) == nullptr) {
+ if (this->_store_ssl_ctx(lookup, &sslMultiCertSettings) == nullptr) {
Error("failed set default context");
return false;
}
@@ -1988,3 +1847,170 @@ SSLConnect(SSL *ssl)
return ssl_error;
}
+
+/**
+ Load certificats to SSL_CTX
+ @static
+ */
+bool
+SSLMultiCertConfigLoader::load_certs(SSL_CTX *ctx, std::vector<X509 *> &cert_list, const SSLConfigParams *params,
+ const SSLMultiCertConfigParams *sslMultCertSettings)
+{
+ SimpleTokenizer cert_tok((const char *)sslMultCertSettings->cert, SSL_CERT_SEPARATE_DELIM);
+ SimpleTokenizer key_tok((sslMultCertSettings->key ? (const char *)sslMultCertSettings->key : ""), SSL_CERT_SEPARATE_DELIM);
+
+ if (sslMultCertSettings->key && cert_tok.getNumTokensRemaining() != key_tok.getNumTokensRemaining()) {
+ Error("the number of certificates in ssl_cert_name and ssl_key_name doesn't match");
+ return false;
+ }
+ SimpleTokenizer ca_tok("", SSL_CERT_SEPARATE_DELIM);
+ if (sslMultCertSettings->ca) {
+ ca_tok.setString(sslMultCertSettings->ca);
+ if (cert_tok.getNumTokensRemaining() != ca_tok.getNumTokensRemaining()) {
+ Error("the number of certificates in ssl_cert_name and ssl_ca_name doesn't match");
+ return false;
+ }
+ }
+
+ for (const char *certname = cert_tok.getNext(); certname; certname = cert_tok.getNext()) {
+ std::string completeServerCertPath = Layout::relative_to(params->serverCertPathOnly, certname);
+ scoped_BIO bio(BIO_new_file(completeServerCertPath.c_str(), "r"));
+ X509 *cert = nullptr;
+ if (bio) {
+ cert = PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr);
+ }
+ if (!bio || !cert) {
+ SSLError("failed to load certificate chain from %s", completeServerCertPath.c_str());
+ return false;
+ }
+ if (!SSL_CTX_use_certificate(ctx, cert)) {
+ SSLError("Failed to assign cert from %s to SSL_CTX", completeServerCertPath.c_str());
+ X509_free(cert);
+ return false;
+ }
+
+ // Load up any additional chain certificates
+ SSL_CTX_add_extra_chain_cert_bio(ctx, bio);
+
+ const char *keyPath = key_tok.getNext();
+ if (!SSLPrivateKeyHandler(ctx, params, completeServerCertPath, keyPath)) {
+ return false;
+ }
+
+ cert_list.push_back(cert);
+ if (SSLConfigParams::load_ssl_file_cb) {
+ SSLConfigParams::load_ssl_file_cb(completeServerCertPath.c_str(), CONFIG_FLAG_UNVERSIONED);
+ }
+
+ // Must load all the intermediate certificates before starting the next chain
+
+ // First, load any CA chains from the global chain file. This should probably
+ // eventually be a comma separated list too. For now we will load it in all chains even
+ // though it only makes sense in one chain
+ if (params->serverCertChainFilename) {
+ ats_scoped_str completeServerCertChainPath(Layout::relative_to(params->serverCertPathOnly, params->serverCertChainFilename));
+ if (!SSL_CTX_add_extra_chain_cert_file(ctx, completeServerCertChainPath)) {
+ SSLError("failed to load global certificate chain from %s", (const char *)completeServerCertChainPath);
+ return false;
+ }
+ if (SSLConfigParams::load_ssl_file_cb) {
+ SSLConfigParams::load_ssl_file_cb(completeServerCertChainPath, CONFIG_FLAG_UNVERSIONED);
+ }
+ }
+
+ // Now, load any additional certificate chains specified in this entry.
+ if (sslMultCertSettings->ca) {
+ const char *ca_name = ca_tok.getNext();
+ if (ca_name != nullptr) {
+ ats_scoped_str completeServerCertChainPath(Layout::relative_to(params->serverCertPathOnly, ca_name));
+ if (!SSL_CTX_add_extra_chain_cert_file(ctx, completeServerCertChainPath)) {
+ SSLError("failed to load certificate chain from %s", (const char *)completeServerCertChainPath);
+ return false;
+ }
+ if (SSLConfigParams::load_ssl_file_cb) {
+ SSLConfigParams::load_ssl_file_cb(completeServerCertChainPath, CONFIG_FLAG_UNVERSIONED);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ Set session_id context for session reuse
+ @static
+ */
+bool
+SSLMultiCertConfigLoader::set_session_id_context(SSL_CTX *ctx, const SSLConfigParams *params,
+ const SSLMultiCertConfigParams *sslMultCertSettings)
+{
+ EVP_MD_CTX *digest = EVP_MD_CTX_new();
+ STACK_OF(X509_NAME) *ca_list = nullptr;
+ unsigned char hash_buf[EVP_MAX_MD_SIZE];
+ unsigned int hash_len = 0;
+ const char *setting_cert = sslMultCertSettings ? sslMultCertSettings->cert.get() : nullptr;
+ bool result = false;
+
+ // Set the list of CA's to send to client if we ask for a client certificate
+ if (params->serverCACertFilename) {
+ ca_list = SSL_load_client_CA_file(params->serverCACertFilename);
+ if (ca_list) {
+ SSL_CTX_set_client_CA_list(ctx, ca_list);
+ }
+ }
+
+ if (EVP_DigestInit_ex(digest, evp_md_func, nullptr) == 0) {
+ SSLError("EVP_DigestInit_ex failed");
+ goto fail;
+ }
+
+ if (nullptr != setting_cert) {
+ Debug("ssl", "Using '%s' in hash for session id context", sslMultCertSettings->cert.get());
+ if (EVP_DigestUpdate(digest, sslMultCertSettings->cert, strlen(setting_cert)) == 0) {
+ SSLError("EVP_DigestUpdate failed");
+ goto fail;
+ }
+ }
+
+ if (ca_list != nullptr) {
+ size_t num_certs = sk_X509_NAME_num(ca_list);
+
+ for (size_t i = 0; i < num_certs; i++) {
+ X509_NAME *name = sk_X509_NAME_value(ca_list, i);
+ if (X509_NAME_digest(name, evp_md_func, hash_buf /* borrow our final hash buffer. */, &hash_len) == 0 ||
+ EVP_DigestUpdate(digest, hash_buf, hash_len) == 0) {
+ SSLError("Adding X509 name to digest failed");
+ goto fail;
+ }
+ }
+ }
+
+ if (EVP_DigestFinal_ex(digest, hash_buf, &hash_len) == 0) {
+ SSLError("EVP_DigestFinal_ex failed");
+ goto fail;
+ }
+
+ if (SSL_CTX_set_session_id_context(ctx, hash_buf, hash_len) == 0) {
+ SSLError("SSL_CTX_set_session_id_context failed");
+ goto fail;
+ }
+
+ result = true;
+
+fail:
+ EVP_MD_CTX_free(digest);
+
+ return result;
+}
+
+/**
+ Clear password in SSL_CTX
+ @static
+ */
+void
+SSLMultiCertConfigLoader::clear_pw_references(SSL_CTX *ssl_ctx)
+{
+ SSL_CTX_set_default_passwd_cb(ssl_ctx, nullptr);
+ SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, nullptr);
+}