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 <[email protected]>
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 = "[email protected]";
+
+ 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
[email protected].