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

paziz 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 f0588dd  Client verify callback with client verify hook
f0588dd is described below

commit f0588ddbaac742d73666e73cb3150e5f1cb72f48
Author: Syeda Persia Aziz <persia.a...@yahoo.com>
AuthorDate: Sun Nov 12 22:15:14 2017 -0600

    Client verify callback with client verify hook
---
 doc/developer-guide/api/types/TSHttpHookID.en.rst |   2 +
 example/Makefile.am                               |   4 +-
 example/verify_cert/verify_cert.cc                | 119 ++++++++++++++++++++++
 iocore/net/P_SSLNetVConnection.h                  |   9 ++
 iocore/net/SSLNetVConnection.cc                   |  25 ++++-
 iocore/net/SSLUtils.cc                            |  13 ++-
 lib/ts/apidefs.h.in                               |   4 +-
 proxy/InkAPIInternal.h                            |   1 +
 proxy/InkAPITest.cc                               |   1 +
 proxy/http/HttpDebugNames.cc                      |   2 +
 10 files changed, 173 insertions(+), 7 deletions(-)

diff --git a/doc/developer-guide/api/types/TSHttpHookID.en.rst 
b/doc/developer-guide/api/types/TSHttpHookID.en.rst
index 5d5a835..85c6f02 100644
--- a/doc/developer-guide/api/types/TSHttpHookID.en.rst
+++ b/doc/developer-guide/api/types/TSHttpHookID.en.rst
@@ -78,6 +78,8 @@ Enumeration Members
 
 .. c:macro:: TSHttpHookID TS_SSL_SERVERNAME_HOOK
 
+.. c:macro:: TSHttpHookID TS_SSL_VERIFY_CLIENT_HOOK
+
 .. c:macro:: TSHttpHookID TS_SSL_LAST_HOOK
 
 .. c:macro:: TSHttpHookID TS_HTTP_LAST_HOOK
diff --git a/example/Makefile.am b/example/Makefile.am
index 27621e3..c79c3a3 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -60,7 +60,8 @@ example_Plugins = \
        thread_1.la \
        txn_data_sink.la \
        version.la \
-       disable_http2.la
+       disable_http2.la \
+       verify_cert.la
 
 example_Plugins += \
        cppapi/AsyncHttpFetch.la \
@@ -123,6 +124,7 @@ ssl_sni_la_LIBADD = $(libtsconfig)
 ssl_sni_whitelist_la_SOURCES = ssl_sni_whitelist/ssl_sni_whitelist.cc
 ssl_sni_whitelist_la_LIBADD = $(libtsconfig)
 disable_http2_la_SOURCES = disable_http2/disable_http2.cc
+verify_cert_la_SOURCES = verify_cert/verify_cert.cc
 statistic_la_SOURCES = statistic/statistic.cc
 thread_1_la_SOURCES = thread_1/thread_1.c
 txn_data_sink_la_SOURCES = txn_data_sink/txn_data_sink.c
diff --git a/example/verify_cert/verify_cert.cc 
b/example/verify_cert/verify_cert.cc
new file mode 100644
index 0000000..ac17338
--- /dev/null
+++ b/example/verify_cert/verify_cert.cc
@@ -0,0 +1,119 @@
+/** @file
+
+  SSL Preaccept test plugin.
+
+  Implements blind tunneling based on the client IP address
+  The client ip addresses are specified in the plugin's
+  config file as an array of IP addresses or IP address ranges under the
+  key "client-blind-tunnel"
+
+  @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 <cstdio>
+#include <memory.h>
+#include <cinttypes>
+#include <ts/ts.h>
+#include <tsconfig/TsValue.h>
+#include <openssl/ssl.h>
+#include <getopt.h>
+
+using ts::config::Configuration;
+using ts::config::Value;
+
+#define PLUGIN_NAME "verify_cert"
+#define PCP "[" PLUGIN_NAME "] "
+
+namespace
+{
+static void
+debug_certificate(const char *msg, X509_NAME *name)
+{
+  BIO *bio;
+
+  if (name == NULL) {
+    return;
+  }
+
+  bio = BIO_new(BIO_s_mem());
+  if (bio == NULL) {
+    return;
+  }
+
+  if (X509_NAME_print_ex(bio, name, 0 /* indent */, XN_FLAG_ONELINE) > 0) {
+    long len;
+    char *ptr;
+    len = BIO_get_mem_data(bio, &ptr);
+    TSDebug(PLUGIN_NAME, "%s %.*s", msg, (int)len, ptr);
+  }
+
+  BIO_free(bio);
+}
+
+int
+CB_clientcert(TSCont /* contp */, TSEvent /* event */, void *edata)
+{
+  TSVConn ssl_vc         = reinterpret_cast<TSVConn>(edata);
+  TSSslConnection sslobj = TSVConnSSLConnectionGet(ssl_vc);
+  SSL *ssl               = reinterpret_cast<SSL *>(sslobj);
+  X509 *cert             = SSL_get_peer_certificate(ssl);
+  TSDebug(PLUGIN_NAME, "plugin verify_cert verifying client certificate");
+  if (cert) {
+    debug_certificate("client certificate subject CN is %s", 
X509_get_subject_name(cert));
+    debug_certificate("client certificate issuer CN is %s", 
X509_get_issuer_name(cert));
+    X509_free(cert);
+  }
+  // All done, reactivate things
+  TSVConnReenable(ssl_vc);
+  return TS_SUCCESS;
+}
+
+} // Anon namespace
+
+// Called by ATS as our initialization point
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  bool success = false;
+  TSPluginRegistrationInfo info;
+  TSCont cb_cert                       = nullptr; // Certificate callback 
continuation
+  static const struct option longopt[] = {
+    {const_cast<char *>("config"), required_argument, nullptr, 'c'}, {nullptr, 
no_argument, nullptr, '\0'},
+  };
+
+  info.plugin_name   = PLUGIN_NAME;
+  info.vendor_name   = "Apache Software Foundation";
+  info.support_email = "d...@trafficserver.apache.org";
+
+  if (TS_SUCCESS != TSPluginRegister(&info)) {
+    TSError(PCP "registration failed");
+  } else if (nullptr == (cb_cert = TSContCreate(&CB_clientcert, 
TSMutexCreate()))) {
+    TSError(PCP "Failed to create cert callback");
+  } else {
+    TSHttpHookAdd(TS_SSL_VERIFY_CLIENT_HOOK, cb_cert);
+    success = true;
+  }
+
+  if (!success) {
+    TSError(PCP "not initialized");
+  }
+  TSDebug(PLUGIN_NAME, "Plugin %s", success ? "online" : "offline");
+
+  return;
+}
diff --git a/iocore/net/P_SSLNetVConnection.h b/iocore/net/P_SSLNetVConnection.h
index 805b231..94f14b1 100644
--- a/iocore/net/P_SSLNetVConnection.h
+++ b/iocore/net/P_SSLNetVConnection.h
@@ -255,6 +255,13 @@ public:
         }
       }
       break;
+    case HANDSHAKE_HOOKS_CLIENT_CERT:
+    case HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
+      if (eventId == TS_EVENT_SSL_VERIFY_CLIENT || eventId == 
TS_EVENT_VCONN_PRE_ACCEPT) {
+        retval = true;
+      }
+      break;
+
     case HANDSHAKE_HOOKS_DONE:
       retval = true;
       break;
@@ -335,6 +342,8 @@ private:
     HANDSHAKE_HOOKS_SNI,
     HANDSHAKE_HOOKS_CERT,
     HANDSHAKE_HOOKS_CERT_INVOKE,
+    HANDSHAKE_HOOKS_CLIENT_CERT,
+    HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE,
     HANDSHAKE_HOOKS_DONE
   } sslHandshakeHookState = HANDSHAKE_HOOKS_PRE;
 
diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index cb96af0..6a04822 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -1030,7 +1030,8 @@ int
 SSLNetVConnection::sslServerHandShakeEvent(int &err)
 {
   // Continue on if we are in the invoked state.  The hook has not yet 
reenabled
-  if (sslHandshakeHookState == HANDSHAKE_HOOKS_CERT_INVOKE || 
sslHandshakeHookState == HANDSHAKE_HOOKS_PRE_INVOKE) {
+  if (sslHandshakeHookState == HANDSHAKE_HOOKS_CERT_INVOKE || 
sslHandshakeHookState == HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE ||
+      sslHandshakeHookState == HANDSHAKE_HOOKS_PRE_INVOKE) {
     return SSL_WAIT_FOR_HOOK;
   }
 
@@ -1423,7 +1424,10 @@ SSLNetVConnection::reenable(NetHandler *nh)
   }
   if (curHook != nullptr) {
     // Invoke the hook and return, wait for next reenable
-    if (sslHandshakeHookState == HANDSHAKE_HOOKS_CERT) {
+    if (sslHandshakeHookState == HANDSHAKE_HOOKS_CLIENT_CERT) {
+      sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE;
+      curHook->invoke(TS_EVENT_SSL_VERIFY_CLIENT, this);
+    } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_CERT) {
       sslHandshakeHookState = HANDSHAKE_HOOKS_CERT_INVOKE;
       curHook->invoke(TS_EVENT_SSL_CERT, this);
     } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_SNI) {
@@ -1446,6 +1450,10 @@ SSLNetVConnection::reenable(NetHandler *nh)
       break;
     case HANDSHAKE_HOOKS_CERT:
     case HANDSHAKE_HOOKS_CERT_INVOKE:
+      sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_CERT;
+      break;
+    case HANDSHAKE_HOOKS_CLIENT_CERT:
+    case HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
       sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
       break;
     default:
@@ -1474,7 +1482,8 @@ bool
 SSLNetVConnection::callHooks(TSEvent eventId)
 {
   // Only dealing with the SNI/CERT hook so far.
-  ink_assert(eventId == TS_EVENT_SSL_CERT || eventId == 
TS_EVENT_SSL_SERVERNAME || eventId == TS_EVENT_SSL_SERVER_VERIFY_HOOK);
+  ink_assert(eventId == TS_EVENT_SSL_CERT || eventId == 
TS_EVENT_SSL_SERVERNAME || eventId == TS_EVENT_SSL_SERVER_VERIFY_HOOK ||
+             eventId == TS_EVENT_SSL_VERIFY_CLIENT);
   Debug("ssl", "callHooks sslHandshakeHookState=%d", 
this->sslHandshakeHookState);
 
   // Move state if it is appropriate
@@ -1523,11 +1532,19 @@ SSLNetVConnection::callHooks(TSEvent eventId)
       curHook = curHook->next();
     }
     if (curHook == nullptr) {
-      this->sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
+      this->sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_CERT;
     } else {
       this->sslHandshakeHookState = HANDSHAKE_HOOKS_CERT_INVOKE;
     }
     break;
+  case HANDSHAKE_HOOKS_CLIENT_CERT:
+  case HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
+    if (!curHook) {
+      curHook = ssl_hooks->get(TS_SSL_VERIFY_CLIENT_INTERNAL_HOOK);
+    } else {
+      curHook = curHook->next();
+    }
+    break;
   default:
     curHook                     = nullptr;
     this->sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index 12c0532..e7cd113 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -427,6 +427,17 @@ ssl_cert_callback(SSL *ssl, void * /*arg*/)
   return retval;
 }
 
+static int
+ssl_verify_client_callback(int preverify_ok, X509_STORE_CTX *ctx)
+{
+  Debug("ssl", "ssl verify callback");
+  auto *ssl                = static_cast<SSL 
*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
+  SSLNetVConnection *netvc = SSLNetVCAccess(ssl);
+
+  netvc->callHooks(TS_EVENT_SSL_VERIFY_CLIENT);
+  return SSL_TLSEXT_ERR_OK;
+}
+
 /*
  * Cannot stop this callback. Always reeneabled
  */
@@ -1722,7 +1733,7 @@ SSLInitServerContext(const SSLConfigParams *params, const 
ssl_user_config *sslMu
       server_verify_client = SSL_VERIFY_NONE;
       Error("illegal client certification level %d in records.config", 
server_verify_client);
     }
-    SSL_CTX_set_verify(ctx, server_verify_client, nullptr);
+    SSL_CTX_set_verify(ctx, server_verify_client, ssl_verify_client_callback);
     SSL_CTX_set_verify_depth(ctx, params->verify_depth); // might want to make 
configurable at some point.
   }
 
diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in
index a34d2dc..0889181 100644
--- a/lib/ts/apidefs.h.in
+++ b/lib/ts/apidefs.h.in
@@ -291,6 +291,7 @@ typedef enum {
   TS_SSL_CERT_HOOK = TS_SSL_SNI_HOOK,
   TS_SSL_SERVERNAME_HOOK,
   TS_SSL_SERVER_VERIFY_HOOK,
+  TS_SSL_VERIFY_CLIENT_HOOK,
   TS_SSL_SESSION_HOOK,
   TS_SSL_LAST_HOOK = TS_SSL_SESSION_HOOK,
   TS_HTTP_LAST_HOOK
@@ -457,7 +458,8 @@ typedef enum {
   TS_EVENT_INTERNAL_60202                       = 60202,
   TS_EVENT_SSL_CERT                             = 60203,
   TS_EVENT_SSL_SERVERNAME                       = 60204,
-  TS_EVENT_SSL_SERVER_VERIFY_HOOK               = 60205
+  TS_EVENT_SSL_SERVER_VERIFY_HOOK               = 60205,
+  TS_EVENT_SSL_VERIFY_CLIENT                    = 60206
 } TSEvent;
 #define TS_EVENT_HTTP_READ_REQUEST_PRE_REMAP TS_EVENT_HTTP_PRE_REMAP /* 
backwards compat */
 
diff --git a/proxy/InkAPIInternal.h b/proxy/InkAPIInternal.h
index 9d5544c..34c23be 100644
--- a/proxy/InkAPIInternal.h
+++ b/proxy/InkAPIInternal.h
@@ -282,6 +282,7 @@ typedef enum {
   TS_SSL_CERT_INTERNAL_HOOK,
   TS_SSL_SERVERNAME_INTERNAL_HOOK,
   TS_SSL_SERVER_VERIFY_INTERNAL_HOOK,
+  TS_SSL_VERIFY_CLIENT_INTERNAL_HOOK,
   TS_SSL_SESSION_INTERNAL_HOOK,
   TS_SSL_INTERNAL_LAST_HOOK
 } TSSslHookInternalID;
diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index 3f62d1f..12b6aae 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -5544,6 +5544,7 @@ typedef enum {
   ORIG_TS_SSL_SNI_HOOK,
   ORIG_TS_SSL_SERVERNAME_HOOK,
   ORIG_TS_SSL_SERVER_VERIFY_HOOK,
+  ORIG_TS_SSL_VERIFY_CLIENT_HOOK,
   ORIG_TS_SSL_SESSION_HOOK,
   ORIG_TS_SSL_LAST_HOOK = ORIG_TS_SSL_SESSION_HOOK,
   ORIG_TS_HTTP_LAST_HOOK
diff --git a/proxy/http/HttpDebugNames.cc b/proxy/http/HttpDebugNames.cc
index b72a50c..e135eef 100644
--- a/proxy/http/HttpDebugNames.cc
+++ b/proxy/http/HttpDebugNames.cc
@@ -466,6 +466,8 @@ HttpDebugNames::get_api_hook_name(TSHttpHookID t)
     return "TS_SSL_SERVERNAME_HOOK";
   case TS_SSL_SERVER_VERIFY_HOOK:
     return "TS_SSL_SERVER_VERIFY_HOOK";
+  case TS_SSL_VERIFY_CLIENT_HOOK:
+    return "TS_SSL_VERIFY_CLIENT_HOOK";
   case TS_SSL_SESSION_HOOK:
     return "TS_SSL_SESSION_HOOK";
   }

-- 
To stop receiving notification emails like this one, please contact
pa...@apache.org.

Reply via email to