Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/admin-guide/files/sni.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ valid_tls_versions_in This specifies the list of TLS protocols that will be
:ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`,
:ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The potential
values are TLSv1, TLSv1_1, TLSv1_2, and TLSv1_3. You must list all protocols that |TS|
should offer to the client when using this key. This key is only valid for openssl
1.1.0 and later. Older versions of openssl do not provide a hook early enough to update
should offer to the client when using this key. This key is only valid for OpenSSL
1.1.0 and later and BoringSSL. Older versions of OpenSSL do not provide a hook early enough to update
the SSL object. It is a syntax error for |TS| built against earlier versions.

client_cert The file containing the client certificate to use for the outbound connection.
Expand Down
138 changes: 138 additions & 0 deletions iocore/net/BoringSSLUtils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/** @file

@section license License

Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Borrowed from Envoy
// https://github.com/envoyproxy/envoy/blob/329b2491949fc52f4dc5c4a778ea158bfe6fe979/source/extensions/transport_sockets/tls/context_impl.cc#L962

#include "BoringSSLUtils.h"

#ifdef OPENSSL_IS_BORINGSSL
namespace BoringSSLUtils
{
bool
cbsContainsU16(CBS &cbs, uint16_t n)
{
while (CBS_len(&cbs) > 0) {
uint16_t v;
if (!CBS_get_u16(&cbs, &v)) {
return false;
}
if (v == n) {
return true;
}
}

return false;
}

bool
isCipherEnabled(SSL_CTX *ctx, uint16_t cipher_id, uint16_t client_version)
{
const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_id);
if (c == nullptr) {
return false;
}
// Skip TLS 1.2 only ciphersuites unless the client supports it.
if (SSL_CIPHER_get_min_version(c) > client_version) {
return false;
}
if (SSL_CIPHER_get_auth_nid(c) != NID_auth_ecdsa) {
return false;
}
for (const SSL_CIPHER *our_c : SSL_CTX_get_ciphers(ctx)) {
if (SSL_CIPHER_get_id(our_c) == SSL_CIPHER_get_id(c)) {
return true;
}
}
return false;
}

bool
isClientEcdsaCapable(const SSL_CLIENT_HELLO *ssl_client_hello)
{
CBS client_hello;
CBS_init(&client_hello, ssl_client_hello->client_hello, ssl_client_hello->client_hello_len);

// This is the TLSv1.3 case (TLSv1.2 on the wire and the supported_versions extensions present).
// We just need to look at signature algorithms.
const uint16_t client_version = ssl_client_hello->version;
if (client_version == TLS1_2_VERSION && true) {
// If the supported_versions extension is found then we assume that the client is competent
// enough that just checking the signature_algorithms is sufficient.
const uint8_t *supported_versions_data;
size_t supported_versions_len;
if (SSL_early_callback_ctx_extension_get(ssl_client_hello, TLSEXT_TYPE_supported_versions, &supported_versions_data,
&supported_versions_len)) {
const uint8_t *signature_algorithms_data;
size_t signature_algorithms_len;
if (SSL_early_callback_ctx_extension_get(ssl_client_hello, TLSEXT_TYPE_signature_algorithms, &signature_algorithms_data,
&signature_algorithms_len)) {
CBS signature_algorithms_ext, signature_algorithms;
CBS_init(&signature_algorithms_ext, signature_algorithms_data, signature_algorithms_len);
if (!CBS_get_u16_length_prefixed(&signature_algorithms_ext, &signature_algorithms) ||
CBS_len(&signature_algorithms_ext) != 0) {
return false;
}
if (cbsContainsU16(signature_algorithms, SSL_SIGN_ECDSA_SECP256R1_SHA256)) {
return true;
}
}

return false;
}
}

// Otherwise we are < TLSv1.3 and need to look at both the curves in the supported_groups for
// ECDSA and also for a compatible cipher suite. https://tools.ietf.org/html/rfc4492#section-5.1.1
const uint8_t *curvelist_data;
size_t curvelist_len;
if (!SSL_early_callback_ctx_extension_get(ssl_client_hello, TLSEXT_TYPE_supported_groups, &curvelist_data, &curvelist_len)) {
return false;
}

CBS curvelist;
CBS_init(&curvelist, curvelist_data, curvelist_len);

// We only support P256 ECDSA curves today.
if (!cbsContainsU16(curvelist, SSL_CURVE_SECP256R1)) {
return false;
}

// The client must have offered an ECDSA ciphersuite that we like.
CBS cipher_suites;
CBS_init(&cipher_suites, ssl_client_hello->cipher_suites, ssl_client_hello->cipher_suites_len);

while (CBS_len(&cipher_suites) > 0) {
uint16_t cipher_id;
if (!CBS_get_u16(&cipher_suites, &cipher_id)) {
return false;
}

SSL_CTX *ctx = SSL_get_SSL_CTX(ssl_client_hello->ssl);
if (isCipherEnabled(ctx, cipher_id, client_version)) {
return true;
}
}
return false;
}

} // namespace BoringSSLUtils
#endif
30 changes: 30 additions & 0 deletions iocore/net/BoringSSLUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/** @file

@section license License

Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <openssl/ssl.h>

#ifdef OPENSSL_IS_BORINGSSL
namespace BoringSSLUtils
{
bool isClientEcdsaCapable(const SSL_CLIENT_HELLO *ssl_client_hello);

} // namespace BoringSSLUtils
#endif
6 changes: 4 additions & 2 deletions iocore/net/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ libinknet_a_SOURCES = \
ALPNSupport.cc \
BIO_fastopen.cc \
BIO_fastopen.h \
BoringSSLUtils.cc \
BoringSSLUtils.h \
Connection.cc \
I_Net.h \
I_NetProcessor.h \
Expand All @@ -143,7 +145,7 @@ libinknet_a_SOURCES = \
P_Socks.h \
P_SSLCertLookup.h \
P_SSLConfig.h \
P_SSLSecret.h \
P_SSLSecret.h \
P_SSLNetAccept.h \
P_SSLNetProcessor.h \
P_SSLNetVConnection.h \
Expand Down Expand Up @@ -172,7 +174,7 @@ libinknet_a_SOURCES = \
SSLClientCoordinator.cc \
SSLClientUtils.cc \
SSLConfig.cc \
SSLSecret.cc \
SSLSecret.cc \
SSLDiags.cc \
SSLInternal.cc \
SSLNetAccept.cc \
Expand Down
24 changes: 19 additions & 5 deletions iocore/net/P_SSLCertLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ enum class SSLCertContextOption {
OPT_TUNNEL ///< Just tunnel, don't terminate.
};

/** Used to discern the context type when BoringSSL is used for the SSL implementation.
*/
enum class SSLCertContextType {
GENERIC, ///< Generic Context (can be either EC or RSA)
RSA, ///< RSA-based Context
EC ///< EC-based Context
};

/**
@brief Gather user provided settings from ssl_multicert.config in to this single struct
*/
Expand Down Expand Up @@ -100,14 +108,17 @@ struct SSLCertContext {
: ctx_mutex(), ctx(c, SSL_CTX_free), opt(SSLCertContextOption::OPT_NONE), userconfig(nullptr), keyblock(nullptr)
{
}
SSLCertContext(shared_SSL_CTX sc, shared_SSLMultiCertConfigParams u)
: ctx_mutex(), ctx(sc), opt(u->opt), userconfig(u), keyblock(nullptr)

SSLCertContext(shared_SSL_CTX sc, SSLCertContextType ctx_type, shared_SSLMultiCertConfigParams u)
: ctx_mutex(), ctx(sc), ctx_type(ctx_type), opt(u->opt), userconfig(u), keyblock(nullptr)
{
}
SSLCertContext(shared_SSL_CTX sc, shared_SSLMultiCertConfigParams u, shared_ssl_ticket_key_block kb)
: ctx_mutex(), ctx(sc), opt(u->opt), userconfig(u), keyblock(kb)

SSLCertContext(shared_SSL_CTX sc, SSLCertContextType ctx_type, shared_SSLMultiCertConfigParams u, shared_ssl_ticket_key_block kb)
: ctx_mutex(), ctx(sc), ctx_type(ctx_type), opt(u->opt), userconfig(u), keyblock(kb)
{
}

SSLCertContext(SSLCertContext const &other);
SSLCertContext &operator=(SSLCertContext const &other);
~SSLCertContext() {}
Expand All @@ -117,13 +128,16 @@ struct SSLCertContext {
void setCtx(shared_SSL_CTX sc);
void release();

SSLCertContextType ctx_type = SSLCertContextType::GENERIC;
SSLCertContextOption opt = SSLCertContextOption::OPT_NONE; ///< Special handling option.
shared_SSLMultiCertConfigParams userconfig = nullptr; ///< User provided settings
shared_ssl_ticket_key_block keyblock = nullptr; ///< session keys associated with this address
};

struct SSLCertLookup : public ConfigInfo {
SSLContextStorage *ssl_storage;
SSLContextStorage *ec_storage;

shared_SSL_CTX ssl_default;
bool is_valid = true;

Expand All @@ -141,7 +155,7 @@ struct SSLCertLookup : public ConfigInfo {
Exact matches have priority, then wildcards. Only destination based matches are checked.
@return @c A pointer to the matched context, @c nullptr if no match is found.
*/
SSLCertContext *find(const std::string &name) const;
SSLCertContext *find(const std::string &name, SSLCertContextType ctxType = SSLCertContextType::GENERIC) const;

// Return the last-resort default TLS context if there is no name or address match.
SSL_CTX *
Expand Down
28 changes: 22 additions & 6 deletions iocore/net/P_SSLUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class SSLNetVConnection;

typedef int ssl_error_t;

#ifndef OPENSSL_IS_BORING
#ifndef OPENSSL_IS_BORINGSSL
typedef int ssl_curve_id;
#else
typedef uint16_t ssl_curve_id;
Expand All @@ -51,6 +51,15 @@ typedef uint16_t ssl_curve_id;
// Return the SSL Curve ID associated to the specified SSL connection
ssl_curve_id SSLGetCurveNID(SSL *ssl);

enum class SSLCertContextType;

struct SSLLoadingContext {
SSL_CTX *ctx;
SSLCertContextType ctx_type;

explicit SSLLoadingContext(SSL_CTX *c, SSLCertContextType ctx_type) : ctx(c), ctx_type(ctx_type) {}
};

/**
@brief Load SSL certificates from ssl_multicert.config and setup SSLCertLookup for SSLCertificateConfig
*/
Expand All @@ -59,22 +68,29 @@ class SSLMultiCertConfigLoader
public:
struct CertLoadData {
std::vector<std::string> cert_names_list, key_list, ca_list, ocsp_list;
std::vector<SSLCertContextType> cert_type_list;
};
SSLMultiCertConfigLoader(const SSLConfigParams *p) : _params(p) {}
virtual ~SSLMultiCertConfigLoader(){};

bool load(SSLCertLookup *lookup);

virtual SSL_CTX *default_server_ssl_ctx();
virtual SSL_CTX *init_server_ssl_ctx(CertLoadData const &data, const SSLMultiCertConfigParams *sslMultCertSettings,
std::set<std::string> &names);

static bool load_certs(SSL_CTX *ctx, CertLoadData const &data, const SSLConfigParams *params,
virtual std::vector<SSLLoadingContext> init_server_ssl_ctx(CertLoadData const &data,
const SSLMultiCertConfigParams *sslMultCertSettings,
std::set<std::string> &names);

static bool load_certs(SSL_CTX *ctx, const std::vector<std::string> &cert_names_list,
const std::vector<std::string> &key_names_list, CertLoadData const &data, const SSLConfigParams *params,
const SSLMultiCertConfigParams *sslMultCertSettings);

bool load_certs_and_cross_reference_names(std::vector<X509 *> &cert_list, CertLoadData &data, const SSLConfigParams *params,
const SSLMultiCertConfigParams *sslMultCertSettings,
std::set<std::string> &common_names,
std::unordered_map<int, std::set<std::string>> &unique_names);
std::unordered_map<int, std::set<std::string>> &unique_names,
SSLCertContextType *certType);

static bool set_session_id_context(SSL_CTX *ctx, const SSLConfigParams *params,
const SSLMultiCertConfigParams *sslMultCertSettings);

Expand All @@ -87,7 +103,7 @@ class SSLMultiCertConfigLoader
const SSLConfigParams *_params;

bool _store_single_ssl_ctx(SSLCertLookup *lookup, const shared_SSLMultiCertConfigParams &sslMultCertSettings, shared_SSL_CTX ctx,
std::set<std::string> &names);
SSLCertContextType ctx_type, std::set<std::string> &names);

private:
virtual const char *_debug_tag() const;
Expand Down
Loading