You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2012/12/14 06:46:24 UTC
git commit: TS-1500: Allow SSL certificates to be selected per-port
Updated Branches:
refs/heads/master 3e6359ee5 -> 129d7719e
TS-1500: Allow SSL certificates to be selected per-port
Allow the dest_ip specifier in ssl_multicert.config to match on the
IP address and the port. We select the longest match.
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/129d7719
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/129d7719
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/129d7719
Branch: refs/heads/master
Commit: 129d7719ece8c1114ad629466e84bd3c40937516
Parents: 3e6359e
Author: James Peach <jp...@apache.org>
Authored: Sat Dec 8 10:54:44 2012 -0800
Committer: James Peach <jp...@apache.org>
Committed: Thu Dec 13 21:38:58 2012 -0800
----------------------------------------------------------------------
CHANGES | 3 +
iocore/net/SSLCertLookup.cc | 23 +++++++-
iocore/net/SSLConfig.cc | 6 ++-
iocore/net/SSLNetVConnection.cc | 18 ++-----
iocore/net/SSLUtils.cc | 21 +++++---
iocore/net/test_certlookup.cc | 67 +++++++++++++++++++++++-
proxy/config/ssl_multicert.config.default | 6 ++
7 files changed, 117 insertions(+), 27 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/129d7719/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index cd29051..144173e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache Traffic Server 3.3.1
+
+ *) [TS-1500] let ssl_multicert.config specify sslcert per port
+
*) [TS-1621] Adopt ConfigUpdateHandler pattern
Author: Ethan Lai <yz...@yahoo.com>
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/129d7719/iocore/net/SSLCertLookup.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLCertLookup.cc b/iocore/net/SSLCertLookup.cc
index bb22b3a..b804d51 100644
--- a/iocore/net/SSLCertLookup.cc
+++ b/iocore/net/SSLCertLookup.cc
@@ -35,7 +35,7 @@
struct SSLAddressLookupKey
{
explicit
- SSLAddressLookupKey(const IpEndpoint& ip)
+ SSLAddressLookupKey(const IpEndpoint& ip) : sep(0)
{
static const char hextab[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
@@ -45,10 +45,11 @@ struct SSLAddressLookupKey
uint16_t port = ntohs(ip.port());
// For IP addresses, the cache key is the hex address with the port concatenated. This makes the lookup
- // insensitive to address formatting and also allow the longest match semantic to product different matches
+ // insensitive to address formatting and also allow the longest match semantic to produce different matches
// if there is a certificate on the port.
nbytes = ats_ip_to_hex(&ip.sa, key, sizeof(key));
if (port) {
+ sep = nbytes;
key[nbytes++] = '.';
key[nbytes++] = hextab[ (port >> 12) & 0x000F ];
key[nbytes++] = hextab[ (port >> 8) & 0x000F ];
@@ -59,9 +60,12 @@ struct SSLAddressLookupKey
}
const char * get() const { return key; }
+ void split() { key[sep] = '\0'; }
+ void unsplit() { key[sep] = '.'; }
private:
char key[(TS_IP6_SIZE * 2) /* hex addr */ + 1 /* dot */ + 4 /* port */ + 1 /* NULL */];
+ unsigned char sep; // offset of address/port separator
};
struct SSLContextStorage
@@ -107,8 +111,21 @@ SSLCertLookup::findInfoInHash(const char * address) const
SSL_CTX *
SSLCertLookup::findInfoInHash(const IpEndpoint& address) const
{
+ SSL_CTX * ctx;
SSLAddressLookupKey key(address);
- return this->ssl_storage->lookup(key.get());
+
+ // First try the full address.
+ if ((ctx = this->ssl_storage->lookup(key.get()))) {
+ return ctx;
+ }
+
+ // If that failed, try the address without the port.
+ if (address.port()) {
+ key.split();
+ return this->ssl_storage->lookup(key.get());
+ }
+
+ return NULL;
}
bool
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/129d7719/iocore/net/SSLConfig.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc
index c91860e..4549e73 100644
--- a/iocore/net/SSLConfig.cc
+++ b/iocore/net/SSLConfig.cc
@@ -110,7 +110,7 @@ set_paths_helper(const char *path, const char *filename, char **final_path, char
}
if (final_filename) {
- *final_filename = filename ? ats_strdup(Layout::get()->relative_to(path, filename)) : NULL;
+ *final_filename = filename ? Layout::get()->relative_to(path, filename) : NULL;
}
}
@@ -167,7 +167,7 @@ SSLConfigParams::initialize()
char *cert_chain = NULL;
IOCORE_ReadConfigStringAlloc(cert_chain, "proxy.config.ssl.server.cert_chain.filename");
- set_paths_helper(serverCertRelativePath, cert_chain, &serverCertPathOnly, &serverCertChainPath);
+ set_paths_helper(serverCertRelativePath, cert_chain, NULL, &serverCertChainPath);
ats_free(cert_chain);
IOCORE_ReadConfigStringAlloc(multicert_config_file, "proxy.config.ssl.server.multicert.filename");
@@ -259,6 +259,8 @@ SSLCertificateConfig::reconfigure()
if (SSLParseCertificateConfiguration(params, lookup)) {
configid = configProcessor.set(configid, lookup);
+ } else {
+ delete lookup;
}
}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/129d7719/iocore/net/SSLNetVConnection.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index 6fe9f6c..1af06d4 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -450,24 +450,14 @@ SSLNetVConnection::free(EThread * t) {
int
SSLNetVConnection::sslStartHandShake(int event, int &err)
{
- IpEndpoint ip;
-
if (event == SSL_EVENT_SERVER) {
if (this->ssl == NULL) {
- SSL_CTX * ctx;
- int namelen = sizeof(ip);
SSLCertificateConfig::scoped_config lookup;
- safe_getsockname(get_socket(), &ip.sa, &namelen);
-
- ip.port() = 0; // XXX certificate lookup can't check the port yet; TS-1500
- ctx = lookup->findInfoInHash(ip);
- Debug("ssl", "IP context is %p, default context %p", ctx, lookup->defaultContext());
- if (ctx == NULL) {
- ctx = lookup->defaultContext();
- }
-
- this->ssl = make_ssl_connection(ctx, this);
+ // Attach the default SSL_CTX to this SSL session. The default context is never going to be able
+ // to negotiate a SSL session, but it's enough to trampoline us into the SNI callback where we
+ // can select the right server certificate.
+ this->ssl = make_ssl_connection(lookup->defaultContext(), this);
if (this->ssl == NULL) {
Debug("ssl", "SSLNetVConnection::sslServerHandShakeEvent, ssl create failed");
SSLError("SSL_StartHandShake");
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/129d7719/iocore/net/SSLUtils.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index e7d8d50..030f170 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -22,10 +22,7 @@
#include "ink_config.h"
#include "libts.h"
#include "I_Layout.h"
-#include "P_EventSystem.h"
-#include "P_SSLUtils.h"
-#include "P_SSLConfig.h"
-#include "P_SSLCertLookup.h"
+#include "P_Net.h"
#include <openssl/err.h>
#include <openssl/bio.h>
@@ -123,9 +120,10 @@ end:
static int
ssl_servername_callback(SSL * ssl, int * ad, void * arg)
{
- SSL_CTX * ctx = NULL;
- SSLCertLookup * lookup = (SSLCertLookup *) arg;
- const char * servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ SSL_CTX * ctx = NULL;
+ SSLCertLookup * lookup = (SSLCertLookup *) arg;
+ const char * servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ SSLNetVConnection * netvc = (SSLNetVConnection *)SSL_get_app_data(ssl);
Debug("ssl", "ssl=%p ad=%d lookup=%p server=%s", ssl, *ad, lookup, servername);
@@ -136,6 +134,15 @@ ssl_servername_callback(SSL * ssl, int * ad, void * arg)
ctx = lookup->findInfoInHash((char *)servername);
}
+ // If there's no match on the server name, try to match on the peer address.
+ if (ctx == NULL) {
+ IpEndpoint ip;
+ int namelen = sizeof(ip);
+
+ safe_getsockname(netvc->get_socket(), &ip.sa, &namelen);
+ ctx = lookup->findInfoInHash(ip);
+ }
+
if (ctx != NULL) {
SSL_set_SSL_CTX(ssl, ctx);
}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/129d7719/iocore/net/test_certlookup.cc
----------------------------------------------------------------------
diff --git a/iocore/net/test_certlookup.cc b/iocore/net/test_certlookup.cc
index bd0a1f8..c5b60ae 100644
--- a/iocore/net/test_certlookup.cc
+++ b/iocore/net/test_certlookup.cc
@@ -25,6 +25,15 @@
#include "ts/TestBox.h"
#include <fstream>
+static IpEndpoint
+make_endpoint(const char * address)
+{
+ IpEndpoint ip;
+
+ assert(ats_ip_pton(address, &ip) == 0);
+ return ip;
+}
+
REGRESSION_TEST(SSLCertificateLookup)(RegressionTest* t, int atype, int * pstatus)
{
TestBox box(t, pstatus);
@@ -69,12 +78,69 @@ REGRESSION_TEST(SSLCertificateLookup)(RegressionTest* t, int atype, int * pstatu
box.check(lookup.findInfoInHash("www.bar.com") == NULL, "host lookup for www.bar.com");
}
+REGRESSION_TEST(SSLAddressLookup)(RegressionTest* t, int atype, int * pstatus)
+{
+ TestBox box(t, pstatus);
+ SSLCertLookup lookup;
+
+ struct {
+ SSL_CTX * ip6;
+ SSL_CTX * ip6p;
+ SSL_CTX * ip4;
+ SSL_CTX * ip4p;
+ } context;
+
+ struct {
+ IpEndpoint ip6;
+ IpEndpoint ip6p;
+ IpEndpoint ip4;
+ IpEndpoint ip4p;
+ } endpoint;
+
+ context.ip6 = SSL_CTX_new(SSLv23_server_method());
+ context.ip6p = SSL_CTX_new(SSLv23_server_method());
+ context.ip4 = SSL_CTX_new(SSLv23_server_method());
+ context.ip4p = SSL_CTX_new(SSLv23_server_method());
+
+ endpoint.ip6 = make_endpoint("fe80::7ed1:c3ff:fe90:2582");
+ endpoint.ip6p = make_endpoint("[fe80::7ed1:c3ff:fe90:2582]:80");
+ endpoint.ip4 = make_endpoint("10.0.0.5");
+ endpoint.ip4p = make_endpoint("10.0.0.5:80");
+
+ box = REGRESSION_TEST_PASSED;
+
+ // For each combination of address with port and address without port, make sure that we find the
+ // the most specific match (ie. find the context with the port if it is available) ...
+
+ box.check(lookup.insert(context.ip6, endpoint.ip6), "insert IPv6 address");
+ box.check(lookup.findInfoInHash(endpoint.ip6) == context.ip6, "IPv6 exact match lookup");
+ box.check(lookup.findInfoInHash(endpoint.ip6p) == context.ip6, "IPv6 exact match lookup w/ port");
+
+ box.check(lookup.insert(context.ip6p, endpoint.ip6p), "insert IPv6 address w/ port");
+ box.check(lookup.findInfoInHash(endpoint.ip6) == context.ip6, "IPv6 longest match lookup");
+ box.check(lookup.findInfoInHash(endpoint.ip6p) == context.ip6p, "IPv6 longest match lookup w/ port");
+
+ box.check(lookup.insert(context.ip4, endpoint.ip4), "insert IPv4 address");
+ box.check(lookup.findInfoInHash(endpoint.ip4) == context.ip4, "IPv4 exact match lookup");
+ box.check(lookup.findInfoInHash(endpoint.ip4p) == context.ip4, "IPv4 exact match lookup w/ port");
+
+ box.check(lookup.insert(context.ip4p, endpoint.ip4p), "insert IPv4 address w/ port");
+ box.check(lookup.findInfoInHash(endpoint.ip4) == context.ip4, "IPv4 longest match lookup");
+ box.check(lookup.findInfoInHash(endpoint.ip4p) == context.ip4p, "IPv4 longest match lookup w/ port");
+}
+
static unsigned
load_hostnames_csv(const char * fname, SSLCertLookup& lookup)
{
std::fstream infile(fname, std::ios_base::in);
unsigned count = 0;
+ // SSLCertLookup correctly handles indexing the same certificate
+ // with multiple names, an it's way faster to load a lot of names
+ // if we don't need a new context every time.
+
+ SSL_CTX * ctx = SSL_CTX_new(SSLv23_server_method());
+
// The input should have 2 comma-separated fields; this is the format that you get when
// you download the top 1M sites from alexa.
//
@@ -88,7 +154,6 @@ load_hostnames_csv(const char * fname, SSLCertLookup& lookup)
while (!infile.eof()) {
std::string line;
std::string::size_type pos;
- SSL_CTX * ctx = SSL_CTX_new(SSLv23_server_method());
infile >> line;
if (line.empty()) {
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/129d7719/proxy/config/ssl_multicert.config.default
----------------------------------------------------------------------
diff --git a/proxy/config/ssl_multicert.config.default b/proxy/config/ssl_multicert.config.default
index de05832..be60994 100644
--- a/proxy/config/ssl_multicert.config.default
+++ b/proxy/config/ssl_multicert.config.default
@@ -22,6 +22,11 @@
# '*', the certificate will be used as the default fallback if no
# other match can be made.
#
+# The address specified here can contain a port specifier, in which
+# case the corresponding certificate will only match for connections
+# accepted on the specified port. IPv6 addresses must be enclosed by
+# square brackets if they have a port, eg, [::1]:80.
+#
# ssl_key_name=FILENAME
# The name of the file containg the private key for this certificate.
# If the key is contained in the certificate file, this field can be
@@ -39,4 +44,5 @@
# ssl_cert_name=foo.pem
# dest_ip=* ssl_cert_name=bar.pem ssl_key_name=barKey.pem
# dest_ip=209.131.48.79 ssl_cert_name=server.pem ssl_key_name=serverKey.pem
+# dest_ip=10.0.0.1:99 ssl_cert_name=port99.pem