You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by sh...@apache.org on 2015/01/30 21:03:53 UTC

trafficserver git commit: TS-3319: Checkpoint changes to support openssl 1.0.2 certificate callback.

Repository: trafficserver
Updated Branches:
  refs/heads/master 5826e48fa -> 2a8bb593f


TS-3319: Checkpoint changes to support openssl 1.0.2 certificate callback.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/2a8bb593
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/2a8bb593
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/2a8bb593

Branch: refs/heads/master
Commit: 2a8bb593fdd7ca9125efad76e27f3f17f5bca794
Parents: 5826e48
Author: shinrich <sh...@yahoo-inc.com>
Authored: Tue Jan 27 10:34:50 2015 -0600
Committer: shinrich <sh...@yahoo-inc.com>
Committed: Fri Jan 30 14:03:23 2015 -0600

----------------------------------------------------------------------
 CHANGES                                         |   2 +
 doc/reference/api/TSVConnReenable.en.rst        |   8 +-
 doc/reference/api/TSVConnTunnel.en.rst          |   4 +-
 example/ssl-sni-whitelist/ssl-sni-whitelist.cc  |   4 +-
 example/ssl-sni/ssl-sni.cc                      |  10 +-
 iocore/net/P_SSLNetVConnection.h                |  19 ++-
 iocore/net/SSLNetVConnection.cc                 |  82 ++++++----
 iocore/net/SSLUtils.cc                          | 160 ++++++++++++-------
 lib/ts/apidefs.h.in                             |   3 +-
 .../experimental/ssl_cert_loader/domain-tree.cc |  10 +-
 .../ssl_cert_loader/ssl-cert-loader.cc          |   3 +
 proxy/InkAPIInternal.h                          |   2 +-
 proxy/http/HttpDebugNames.cc                    |   4 +-
 13 files changed, 200 insertions(+), 111 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 14a8e40..14963f3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 5.3.0
 
+  *) [TS-3319] Adapt to OpenSSL 1.0.2 certificate callback.
+ 
   *) [TS-1435] return full content if client is a muti range request
     Author: Lars Svensson <la...@vmail.se>
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/doc/reference/api/TSVConnReenable.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/api/TSVConnReenable.en.rst b/doc/reference/api/TSVConnReenable.en.rst
index 92dfb80..4e6f393 100644
--- a/doc/reference/api/TSVConnReenable.en.rst
+++ b/doc/reference/api/TSVConnReenable.en.rst
@@ -28,12 +28,12 @@ Synopsis
 Description
 -----------
 
-   Reenable the SSL connection :arg:`svc`. If a plugin hook is called, ATS processing on that connnection will not resume until this is invoked for that connection.
+Reenable the SSL connection :arg:`svc`. If a plugin hook is called, ATS processing on that connnection will not resume until this is invoked for that connection.
 
-If the server running Traffic Server has the appropriate openSSL patch installed, the SNI callback can return ``SSL_TLSEXT_ERR_READ_AGAIN`` to stop the SSL handshake processing.  This results in ``SSL_accept`` returning ``SSL_ERROR_WANT_SNI_RESOLVE`` before completing the SSL handshake (only the client hello message will have been received).  Additional processing could reenable the virtual connection causing the ``SSL_accept`` to be called again to complete the handshake exchange.  In the case of a blind tunnel conversion, the SSL handshake will never be completed by Traffic Server.
+If the server is running openssl 1.0.1 with the appropraite patch installed or it is running openssl 1.0.2, the plugin writer can pause SSL handshake processing by not reenabling the connection.  Without the openSSL patch or running an openssl version older than 1.0.2, the handshake processing in ``SSL_accept`` will not be stopped even if the SNI callback does not reenable the connection.
 
-The plugin callbacks can halt the SSL handshake processing by not reenabling the connection (i.e., by not calling :c:func:`TSSslVConnReenable`).  If a plugin SNI callback does not reenable the connection, the global callback will return ``SSL_TLSEXT_ERR_READ_AGAIN``.
+Additional processing could reenable the virtual connection causing the ``SSL_accept`` to be called again to complete the handshake exchange.  In the case of a blind tunnel conversion, the SSL handshake will never be completed by Traffic Server.
 
-Without the openSSL patch, the handshake processing in ``SSL_accept`` will not be stopped even if the SNI callback does not reenable the connection.
+This call does appropriate locking and scheduling, so it is safe to call from another thread.
 
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/doc/reference/api/TSVConnTunnel.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/api/TSVConnTunnel.en.rst b/doc/reference/api/TSVConnTunnel.en.rst
index 982e1d4..0f3b8e7 100644
--- a/doc/reference/api/TSVConnTunnel.en.rst
+++ b/doc/reference/api/TSVConnTunnel.en.rst
@@ -29,7 +29,7 @@ Synopsis
 Description
 -----------
 
-   Set the SSL connection :arg:`svc` to convert to a blind tunnel.  Can be called from the TS_VCONN_PRE_ACCEPT_HOOK or the TS_SSL_SNI_HOOK.
+Set the SSL connection :arg:`svc` to convert to a blind tunnel.  Can be called from the TS_VCONN_PRE_ACCEPT_HOOK or the TS_SSL_SNI_HOOK/TS_SSL_CERT_HOOK.
 
-For this to work from the TS_SSL_SNI_HOOK, the openSSL patch must be applied which adds the ability to break out of the SSL_accept processing by returning SSL_TLSEXT_ERR_READ_AGAIN.
+For this to work from the TS_SSL_SNI_HOOK/TS_SSL_CERT_HOOK, either the server must be running openssl 1.0.2 or a version of openssl 1.0.1 with the appropriate patch installed.
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/example/ssl-sni-whitelist/ssl-sni-whitelist.cc
----------------------------------------------------------------------
diff --git a/example/ssl-sni-whitelist/ssl-sni-whitelist.cc b/example/ssl-sni-whitelist/ssl-sni-whitelist.cc
index b6e37f5..e417a7e 100644
--- a/example/ssl-sni-whitelist/ssl-sni-whitelist.cc
+++ b/example/ssl-sni-whitelist/ssl-sni-whitelist.cc
@@ -27,7 +27,7 @@
 # include <memory.h>
 # include <inttypes.h>
 # include <ts/ts.h>
-# include <ink_config.h>
+# include <ts/ink_config.h>
 # include <tsconfig/TsValue.h>
 # include <openssl/ssl.h>
 # include <getopt.h>
@@ -142,7 +142,7 @@ TSPluginInit(int argc, const char *argv[])
   } else if (0 == (cb_sni = TSContCreate(&CB_servername_whitelist, TSMutexCreate()))) {
     TSError(PCP "Failed to create SNI callback.");
   } else {
-    TSHttpHookAdd(TS_SSL_SNI_HOOK, cb_sni);
+    TSHttpHookAdd(TS_SSL_CERT_HOOK, cb_sni);
     success = true;
   }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/example/ssl-sni/ssl-sni.cc
----------------------------------------------------------------------
diff --git a/example/ssl-sni/ssl-sni.cc b/example/ssl-sni/ssl-sni.cc
index 8eebc73..490b4fe 100644
--- a/example/ssl-sni/ssl-sni.cc
+++ b/example/ssl-sni/ssl-sni.cc
@@ -30,7 +30,7 @@
 # include <memory.h>
 # include <inttypes.h>
 # include <ts/ts.h>
-# include <ink_config.h>
+# include <ts/ink_config.h>
 # include <tsconfig/TsValue.h>
 # include <openssl/ssl.h>
 # include <getopt.h>
@@ -130,7 +130,7 @@ TSPluginInit(int argc, const char *argv[])
 {
   bool success = false;
   TSPluginRegistrationInfo info;
-  TSCont cb_sni = 0; // sni callback continuation
+  TSCont cb_cert = 0; // Certificate callback continuation
   static const struct option longopt[] = {
     { const_cast<char *>("config"), required_argument, NULL, 'c' },
     { NULL, no_argument, NULL, '\0' }
@@ -162,10 +162,10 @@ TSPluginInit(int argc, const char *argv[])
     TSError(PCP "requires Traffic Server 2.0 or later.");
   } else if (0 > Load_Configuration()) {
     TSError(PCP "Failed to load config file.");
-  } else if (0 == (cb_sni = TSContCreate(&CB_servername, TSMutexCreate()))) {
-    TSError(PCP "Failed to create SNI callback.");
+  } else if (0 == (cb_cert = TSContCreate(&CB_servername, TSMutexCreate()))) {
+    TSError(PCP "Failed to create cert callback.");
   } else {
-    TSHttpHookAdd(TS_SSL_SNI_HOOK, cb_sni);
+    TSHttpHookAdd(TS_SSL_CERT_HOOK, cb_cert);
     success = true;
   }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/iocore/net/P_SSLNetVConnection.h
----------------------------------------------------------------------
diff --git a/iocore/net/P_SSLNetVConnection.h b/iocore/net/P_SSLNetVConnection.h
index dc4f081..be69ee4 100644
--- a/iocore/net/P_SSLNetVConnection.h
+++ b/iocore/net/P_SSLNetVConnection.h
@@ -183,6 +183,12 @@ public:
   // Returns true if all the hooks reenabled
   bool callHooks(TSHttpHookID eventId);
 
+  // Returns true if we have already called at
+  // least some of the hooks
+  bool calledHooks(TSHttpHookID /* eventId */) {
+    return (this->sslHandshakeHookState != HANDSHAKE_HOOKS_PRE);
+  }
+
 private:
   SSLNetVConnection(const SSLNetVConnection &);
   SSLNetVConnection & operator =(const SSLNetVConnection &);
@@ -208,12 +214,13 @@ private:
     SSL_HOOKS_DONE    ///< All hooks have been called and completed
   } sslPreAcceptHookState;
 
-  enum {
-    SNI_HOOKS_INIT,
-    SNI_HOOKS_ACTIVE,
-    SNI_HOOKS_DONE,
-    SNI_HOOKS_CONTINUE
-  } sslSNIHookState;
+  enum SSLHandshakeHookState {
+    HANDSHAKE_HOOKS_PRE,
+    HANDSHAKE_HOOKS_CERT,
+    HANDSHAKE_HOOKS_POST,
+    HANDSHAKE_HOOKS_INVOKE,
+    HANDSHAKE_HOOKS_DONE
+  } sslHandshakeHookState;
 
   const SSLNextProtocolSet * npnSet;
   Continuation * npnEndpoint;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/iocore/net/SSLNetVConnection.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index 235257a..470f433 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -774,7 +774,7 @@ SSLNetVConnection::SSLNetVConnection():
   handShakeHolder(NULL),
   handShakeReader(NULL),
   sslPreAcceptHookState(SSL_HOOKS_INIT),
-  sslSNIHookState(SNI_HOOKS_INIT),
+  sslHandshakeHookState(HANDSHAKE_HOOKS_PRE),
   npnSet(NULL),
   npnEndpoint(NULL)
 {
@@ -1044,8 +1044,14 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
 
 // This value is only defined in openssl has been patched to
 // enable the sni callback to break out of the SSL_accept processing
-#ifdef SSL_ERROR_WANT_SNI_RESOLVE
+#ifdef SSL_ERROR_WANT_SNI_RESOLVE 
+  case SSL_ERROR_WANT_X509_LOOKUP:
+    return EVENT_CONT;
   case SSL_ERROR_WANT_SNI_RESOLVE:
+#elif SSL_ERROR_WANT_X509_LOOKUP
+  case SSL_ERROR_WANT_X509_LOOKUP:
+#endif
+#if defined(SSL_ERROR_WANT_SNI_RESOLVE) || defined(SSL_ERROR_WANT_X509_LOOKUP)
     if (this->attributes == HttpProxyPort::TRANSPORT_BLIND_TUNNEL ||
         TS_SSL_HOOK_OP_TUNNEL == hookOpRequested) {
       this->attributes = HttpProxyPort::TRANSPORT_BLIND_TUNNEL;
@@ -1059,7 +1065,6 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
 #endif
 
   case SSL_ERROR_WANT_ACCEPT:
-  case SSL_ERROR_WANT_X509_LOOKUP:
     return EVENT_CONT;
 
   case SSL_ERROR_SSL:
@@ -1212,11 +1217,27 @@ void
 SSLNetVConnection::reenable(NetHandler* nh) {
   if (this->sslPreAcceptHookState != SSL_HOOKS_DONE) {
     this->sslPreAcceptHookState = SSL_HOOKS_INVOKE;
+    this->readReschedule(nh);
   } else {
-    // Reenabling from the SNI callback
-    this->sslSNIHookState = SNI_HOOKS_CONTINUE;
+    // Reenabling from the handshake callback
+    //
+    // Originally, we would wait for the callback to go again to execute additinonal
+    // hooks, but since the callbacks are associated with the context and the context
+    // can be replaced by the plugin, it didn't seem reasonable to assume that the
+    // callback would be executed again.  So we walk through the rest of the hooks
+    // here in the reenable.
+    if (curHook != NULL) {
+      curHook = curHook->next();
+      if (curHook != NULL) { 
+        // Invoke the hook
+        curHook->invoke(TS_SSL_CERT_HOOK, this);
+      }
+    }
+    if (curHook == NULL) {
+      this->sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
+      this->readReschedule(nh);
+    }
   }
-  this->readReschedule(nh);
 }
 
 
@@ -1237,33 +1258,38 @@ SSLNetVConnection::sslContextSet(void* ctx) {
 bool
 SSLNetVConnection::callHooks(TSHttpHookID eventId)
 {
-  // Only dealing with the SNI hook so far
-  ink_assert(eventId == TS_SSL_SNI_HOOK);
-
-  if (this->sslSNIHookState == SNI_HOOKS_INIT) {
-    curHook = ssl_hooks->get(TS_SSL_SNI_INTERNAL_HOOK);
+  // Only dealing with the SNI/CERT hook so far. 
+  // TS_SSL_SNI_HOOK and TS_SSL_CERT_HOOK are the same value
+  ink_assert(eventId == TS_SSL_CERT_HOOK);
+
+  // First time through, set the type of the hook that is currently
+  // being invoked
+  if (this->sslHandshakeHookState == HANDSHAKE_HOOKS_PRE) {
+    this->sslHandshakeHookState = HANDSHAKE_HOOKS_CERT;
   }
-  else if (curHook != NULL) {
-    curHook = curHook->next();
-  }
-  bool reenabled = true;
-  while (curHook && reenabled) {
-    // Must reset to a completed state for each invocation
-    this->sslSNIHookState = SNI_HOOKS_DONE;
-
-    // Invoke the hook
-    curHook->invoke(TS_SSL_SNI_HOOK, this);
 
-    // If it did not re-enable, return the code to
-    // stop the accept processing
-    if (this->sslSNIHookState == SNI_HOOKS_DONE) {
-      reenabled = false;
-    }
-    else {
-      // Otherwise, look for the next plugin code
+  if (this->sslHandshakeHookState == HANDSHAKE_HOOKS_CERT && eventId == TS_SSL_CERT_HOOK) {
+    if (curHook != NULL) {
       curHook = curHook->next();
+    } else {
+      curHook = ssl_hooks->get(TS_SSL_CERT_INTERNAL_HOOK);
     }
+  } 
+  else {
+    // Not in the right state, or no plugins registered for this hook
+    // reenable and continue
+    return true;
+  }
+
+  bool reenabled = true;
+  SSLHandshakeHookState holdState = this->sslHandshakeHookState;
+  if (curHook != NULL) {
+    // Otherwise, we have plugin hooks to run
+    this->sslHandshakeHookState = HANDSHAKE_HOOKS_INVOKE;
+    curHook->invoke(eventId, this);
+    reenabled = (this->sslHandshakeHookState != HANDSHAKE_HOOKS_INVOKE);
   }
+  this->sslHandshakeHookState = holdState;
   return reenabled;
 }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/iocore/net/SSLUtils.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index 9d704d5..e16b7e3 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -275,32 +275,25 @@ ssl_rm_cached_session(SSL_CTX *ctx, SSL_SESSION *sess)
   session_cache->removeSession(sid);
 }
 
-
-
 #if TS_USE_TLS_SNI
-
-static int
-ssl_servername_callback(SSL * ssl, int * ad, void * /*arg*/)
+int 
+set_context_cert(SSL *ssl) 
 {
   SSL_CTX *           ctx = NULL;
   SSLCertContext *    cc = NULL;
-  // Fetching the lookup via the callback arg allows for race
-  // condition with reconfigure
-  //SSLCertLookup *     lookup = (SSLCertLookup *) arg;
   SSLCertLookup *lookup = SSLCertificateConfig::acquire();
   const char *        servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
   SSLNetVConnection * netvc = (SSLNetVConnection *)SSL_get_app_data(ssl);
   bool found = true;
-  bool reenabled;
-  int retval = SSL_TLSEXT_ERR_OK;
+  int retval = 1;
 
-  Debug("ssl", "ssl_servername_callback ssl=%p ad=%d server=%s handshake_complete=%d", ssl, *ad, servername,
+  Debug("ssl", "set_context_cert ssl=%p server=%s handshake_complete=%d", ssl, servername,
     netvc->getSSLHandShakeComplete());
 
   // catch the client renegotiation early on
   if (SSLConfigParams::ssl_allow_client_renegotiation == false && netvc->getSSLHandShakeComplete()) {
-    Debug("ssl", "ssl_servername_callback trying to renegotiate from the client");
-    retval = SSL_TLSEXT_ERR_ALERT_FATAL;
+    Debug("ssl", "set_context_cert trying to renegotiate from the client");
+    retval = 0; // Error 
     goto done;
   }
 
@@ -311,14 +304,9 @@ ssl_servername_callback(SSL * ssl, int * ad, void * /*arg*/)
     cc = lookup->find((char *)servername);
     if (cc && cc->ctx) ctx = cc->ctx;
     if (cc && SSLCertContext::OPT_TUNNEL == cc->opt && netvc->get_is_transparent()) {
-#ifdef SSL_TLSEXT_ERR_READ_AGAIN
       netvc->attributes = HttpProxyPort::TRANSPORT_BLIND_TUNNEL;
       netvc->setSSLHandShakeComplete(true);
-      retval = SSL_TLSEXT_ERR_READ_AGAIN;
-#else
-      Error("Must have openssl patch to support OPT_TUNNEL from SNI callback");
-      retval = SSL_TLSEXT_ERR_ALERT_FATAL;
-#endif
+      retval = -1;
       goto done;
     }
   }
@@ -341,53 +329,101 @@ ssl_servername_callback(SSL * ssl, int * ad, void * /*arg*/)
   }
 
   ctx = SSL_get_SSL_CTX(ssl);
-  Debug("ssl", "ssl_servername_callback %s SSL context %p for requested name '%s'", found ? "found" : "using", ctx, servername);
+  Debug("ssl", "ssl_cert_callback %s SSL context %p for requested name '%s'", found ? "found" : "using", ctx, servername);
 
   if (ctx == NULL) {
-    retval = SSL_TLSEXT_ERR_NOACK;
+    retval = 0;
     goto done;
   }
+done:
+  SSLCertificateConfig::release(lookup);
+  return retval;
+}
+
+// Use the certificate callback for openssl 1.0.2 and greater
+// otherwise use the SNI callback
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+/**
+ * Called before either the server or the client certificate is used
+ * Return 1 on success, 0 on error, or -1 to pause
+ */
+static int
+ssl_cert_callback(SSL * ssl, void * /*arg*/)
+{
+  SSLNetVConnection * netvc = (SSLNetVConnection *)SSL_get_app_data(ssl);
+  bool reenabled;
+  int retval =  1;
+
+  // Do the common certificate lookup only once.  If we pause
+  // and restart processing, do not execute the common logic again
+  if (!netvc->calledHooks(TS_SSL_CERT_HOOK)) {
+    retval = set_context_cert(ssl); 
+    if (retval != 1) {
+      return retval;
+    }
+  }
+
+  // Call the plugin cert code
+  reenabled = netvc->callHooks(TS_SSL_CERT_HOOK);
+  // If it did not re-enable, return the code to
+  // stop the accept processing
+  if (!reenabled){
+    retval = -1; // Pause
+  }
+
+  // Return 1 for success, 0 for error, or -1 to pause
+  return retval;
+}
+#else
+static int
+ssl_servername_callback(SSL * ssl, int * /* ad */, void * /*arg*/)
+{
+  SSLNetVConnection * netvc = (SSLNetVConnection *)SSL_get_app_data(ssl);
+  bool reenabled;
+  int retval = 1;
+
+  // Do the common certificate lookup only once.  If we pause
+  // and restart processing, do not execute the common logic again
+  if (!netvc->calledHooks(TS_SSL_CERT_HOOK)) {
+    retval = set_context_cert(ssl); 
+    if (retval != 1) {
+      goto done;
+    }
+  }
 
   // Call the plugin SNI code
   reenabled = netvc->callHooks(TS_SSL_SNI_HOOK);
   // If it did not re-enable, return the code to
   // stop the accept processing
   if (!reenabled){
+    retval = -1;
+  }
+
+done:
+  // Map 1 to SSL_TLSEXT_ERR_OK
+  // Map 0 to SSL_TLSEXT_ERR_ALERT_FATAL
+  // Map -1 to SSL_TLSEXT_ERR_READ_AGAIN, if present
+  switch (retval) {
+  case 1:
+    retval = SSL_TLSEXT_ERR_OK;
+    break;
+  case -1:
 #ifdef SSL_TLSEXT_ERR_READ_AGAIN
     retval = SSL_TLSEXT_ERR_READ_AGAIN;
 #else
-    Error("Must have openssl patch to support OPT_TUNNEL from SNI callback");
+    Error("Cannot pause SNI processsing with this version of openssl");
     retval = SSL_TLSEXT_ERR_ALERT_FATAL;
 #endif
-    goto done;
+    break;
+  case 0:
+  default:
+    retval = SSL_TLSEXT_ERR_ALERT_FATAL;
+    break;
   }
-
-done:
-  SSLCertificateConfig::release(lookup);
-  // We need to return one of the SSL_TLSEXT_ERR constants. If we return an
-  // error, we can fill in *ad with an alert code to propgate to the
-  // client, see SSL_AD_*.
   return retval;
 }
-
-#endif /* TS_USE_TLS_SNI */
-
-static SSL_CTX *
-ssl_context_enable_sni(SSL_CTX * ctx, SSLCertLookup * /*lookup*/)
-{
-#if TS_USE_TLS_SNI
-  if (ctx) {
-    Debug("ssl", "setting SNI callbacks with for ctx %p", ctx);
-    SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_callback);
-    // Possible race conditions against reconfigure here
-    // Better to use the SSLCertificate.acquire function to access the
-    // lookup data structure safely
-    //SSL_CTX_set_tlsext_servername_arg(ctx, lookup);
-  }
-
+#endif
 #endif /* TS_USE_TLS_SNI */
-  return ctx;
-}
 
 /* Build 2048-bit MODP Group with 256-bit Prime Order Subgroup from RFC 5114 */
 static DH *get_dh2048()
@@ -1643,20 +1679,28 @@ ssl_callback_info(const SSL *ssl, int where, int ret)
   }
 }
 
-static bool
+static void 
+setSslHandshakeCallbacks(SSL_CTX *ctx) {
+  // Make sure the callbacks are set 
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+  SSL_CTX_set_cert_cb(ctx, ssl_cert_callback, NULL);
+#else
+  SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_callback);
+#endif
+}
+
+static SSL_CTX *
 ssl_store_ssl_context(
     const SSLConfigParams * params,
     SSLCertLookup *         lookup,
     const ssl_user_config & sslMultCertSettings)
 {
-  SSL_CTX *   ctx;
+  SSL_CTX *   ctx = SSLInitServerContext(params, sslMultCertSettings);
   ats_scoped_str  certpath;
   ats_scoped_str  session_key_path;
 
-  ctx = ssl_context_enable_sni(SSLInitServerContext(params, sslMultCertSettings), lookup);
-  if (!ctx) {
-    return false;
-  }
+  // The certificate callbacks are set by the caller only 
+  // for the default certificate
 
   SSL_CTX_set_info_callback(ctx, ssl_callback_info);
 
@@ -1728,7 +1772,7 @@ ssl_store_ssl_context(
     SSLConfigParams::init_ssl_ctx_cb(ctx, true);
   }
 
-  return true;
+  return ctx;
 }
 
 static bool
@@ -1848,7 +1892,7 @@ SSLParseCertificateConfiguration(const SSLConfigParams * params, SSLCertLookup *
                      __func__, params->configFilePath, line_num, errPtr);
       } else {
         if (ssl_extract_certificate(&line_info, sslMultiCertSettings)) {
-          if (!ssl_store_ssl_context(params, lookup, sslMultiCertSettings)) {
+          if (ssl_store_ssl_context(params, lookup, sslMultiCertSettings) == NULL) {
             Error("failed to load SSL certificate specification from %s line %u",
                 params->configFilePath, line_num);
           }
@@ -1869,9 +1913,11 @@ SSLParseCertificateConfiguration(const SSLConfigParams * params, SSLCertLookup *
   if (lookup->ssl_default == NULL) {
     ssl_user_config sslMultiCertSettings;
     sslMultiCertSettings.addr = ats_strdup("*");
-    ssl_store_ssl_context(params, lookup, sslMultiCertSettings);
+    SSL_CTX *ctx = ssl_store_ssl_context(params, lookup, sslMultiCertSettings);
+    if (ctx != NULL) {
+      setSslHandshakeCallbacks(ctx);
+    }
   }
-
   return true;
 }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/lib/ts/apidefs.h.in
----------------------------------------------------------------------
diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in
index 7530ac6..1b04211 100644
--- a/lib/ts/apidefs.h.in
+++ b/lib/ts/apidefs.h.in
@@ -287,7 +287,8 @@ extern "C"
     TS_SSL_FIRST_HOOK,
     TS_VCONN_PRE_ACCEPT_HOOK = TS_SSL_FIRST_HOOK,
     TS_SSL_SNI_HOOK,
-    TS_SSL_LAST_HOOK = TS_SSL_SNI_HOOK,
+    TS_SSL_CERT_HOOK = TS_SSL_SNI_HOOK,
+    TS_SSL_LAST_HOOK = TS_SSL_CERT_HOOK,
     TS_HTTP_LAST_HOOK
   } TSHttpHookID;
   #define TS_HTTP_READ_REQUEST_PRE_REMAP_HOOK TS_HTTP_PRE_REMAP_HOOK  /* backwards compat */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/plugins/experimental/ssl_cert_loader/domain-tree.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ssl_cert_loader/domain-tree.cc b/plugins/experimental/ssl_cert_loader/domain-tree.cc
index 31e8fd7..8cc1eb1 100644
--- a/plugins/experimental/ssl_cert_loader/domain-tree.cc
+++ b/plugins/experimental/ssl_cert_loader/domain-tree.cc
@@ -97,8 +97,8 @@ DomainNameTree::DomainNameNode *DomainNameTree::find(std::string key, bool best_
   }
 
   bool set_iter = false;
-  std::deque<DomainNameNode *>::iterator sibPtr;
   DomainNameNode *current_node = root;
+  std::deque<DomainNameNode *>::iterator sibPtr, endPtr;
 
   while (current_node != NULL) {
     bool partial_match = false;
@@ -110,6 +110,7 @@ DomainNameTree::DomainNameNode *DomainNameTree::find(std::string key, bool best_
         if (NULL == first || retval->order < first->order) {
           first = retval;
         }
+        current_node = NULL;
         break;
       } else if (relative < 0) {
         retval = current_node;
@@ -122,12 +123,15 @@ DomainNameTree::DomainNameNode *DomainNameTree::find(std::string key, bool best_
     if (partial_match) {
       // Check out the children, maybe there is something better there
       sibPtr = current_node->children.begin();
+      endPtr = current_node->children.end();
       set_iter = true;
-      if (sibPtr == current_node->children.end()) break;  // We are done
+      if (sibPtr == endPtr) {
+        break;  // We are done
+      }
       current_node = *(sibPtr++);
     } else { // No match here.  Look at next sibling?
       // Is there another sibling to look at?
-      if (set_iter && sibPtr != current_node->children.end()) {
+      if (set_iter && sibPtr != endPtr) {
         current_node = *(sibPtr++);
       } else {	// No more siblings to check, give it up.
         break;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc b/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc
index c7a5843..1cfeab6 100644
--- a/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc
+++ b/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc
@@ -440,6 +440,7 @@ CB_servername(TSCont /*contp*/, TSEvent /*event*/, void *edata)
   SSL *ssl = reinterpret_cast<SSL *>(sslobj);
   const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
 
+  TSDebug(PN, "SNI callback %s", servername);
   if (servername != NULL) {
     // Is there a certificated loaded up for this name
     DomainNameTree::DomainNameNode *node = Lookup.tree.findFirstMatch(servername);
@@ -492,6 +493,7 @@ TSPluginInit(int argc, const char *argv[])
   TSCont cb_pa = 0; // pre-accept callback continuation
   TSCont cb_lc = 0; // life cycle callback continuuation
   TSCont cb_sni = 0; // SNI callback continuuation
+  TSCont cb_sni2 = 0; // SNI callback continuuation
   static const struct option longopt[] = {
     { const_cast<char *>("config"), required_argument, NULL, 'c' },
     { NULL, no_argument, NULL, '\0' }
@@ -532,6 +534,7 @@ TSPluginInit(int argc, const char *argv[])
     TSLifecycleHookAdd(TS_LIFECYCLE_PORTS_INITIALIZED_HOOK, cb_lc);
     TSHttpHookAdd(TS_VCONN_PRE_ACCEPT_HOOK, cb_pa);
     TSHttpHookAdd(TS_SSL_SNI_HOOK, cb_sni);
+    TSHttpHookAdd(TS_SSL_SNI_HOOK, cb_sni2);
     success = true;
   }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/proxy/InkAPIInternal.h
----------------------------------------------------------------------
diff --git a/proxy/InkAPIInternal.h b/proxy/InkAPIInternal.h
index 49dc0bf..f87dd89 100644
--- a/proxy/InkAPIInternal.h
+++ b/proxy/InkAPIInternal.h
@@ -299,7 +299,7 @@ class HttpAPIHooks : public FeatureAPIHooks<TSHttpHookID, TS_HTTP_LAST_HOOK>
 typedef enum {
   TS_SSL_INTERNAL_FIRST_HOOK,
   TS_VCONN_PRE_ACCEPT_INTERNAL_HOOK = TS_SSL_INTERNAL_FIRST_HOOK,
-  TS_SSL_SNI_INTERNAL_HOOK,
+  TS_SSL_CERT_INTERNAL_HOOK,
   TS_SSL_INTERNAL_LAST_HOOK
 } TSSslHookInternalID;
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2a8bb593/proxy/http/HttpDebugNames.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpDebugNames.cc b/proxy/http/HttpDebugNames.cc
index 7a85f6e..04388e4 100644
--- a/proxy/http/HttpDebugNames.cc
+++ b/proxy/http/HttpDebugNames.cc
@@ -482,8 +482,8 @@ HttpDebugNames::get_api_hook_name(TSHttpHookID t)
     return "TS_HTTP_LAST_HOOK";
   case TS_VCONN_PRE_ACCEPT_HOOK:
     return "TS_VCONN_PRE_ACCEPT_HOOK";
-  case TS_SSL_SNI_HOOK:
-    return "TS_SSL_SNI_HOOK";
+  case TS_SSL_CERT_HOOK:
+    return "TS_SSL_CERT_HOOK";
   }
 
   return "unknown hook";