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 2019/06/11 19:13:12 UTC
[trafficserver] branch master updated: Added cert_reporting_tool
plugin based off example/client_context_dump
This is an automated email from the ASF dual-hosted git repository.
shinrich 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 7f933d2 Added cert_reporting_tool plugin based off example/client_context_dump
7f933d2 is described below
commit 7f933d232cf869b1ec7f9533484e13be0e8ae193
Author: dyrock <ze...@gmail.com>
AuthorDate: Fri Jun 7 15:27:14 2019 -0500
Added cert_reporting_tool plugin based off example/client_context_dump
---
doc/admin-guide/plugins/cert_reporting_tool.en.rst | 44 +++++
doc/admin-guide/plugins/index.en.rst | 4 +
plugins/Makefile.am | 1 +
.../experimental/cert_reporting_tool/Makefile.inc | 19 +++
plugins/experimental/cert_reporting_tool/README | 15 ++
.../cert_reporting_tool/cert_reporting_tool.cc | 190 +++++++++++++++++++++
6 files changed, 273 insertions(+)
diff --git a/doc/admin-guide/plugins/cert_reporting_tool.en.rst b/doc/admin-guide/plugins/cert_reporting_tool.en.rst
new file mode 100644
index 0000000..ecce028
--- /dev/null
+++ b/doc/admin-guide/plugins/cert_reporting_tool.en.rst
@@ -0,0 +1,44 @@
+.. _admin-plugins-cert-reporting-tool:
+
+Cert Reporting Tool Plugin
+**************************
+
+.. 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.
+
+Description
+===========
+
+The ``cert reporting tool`` can examine and log loaded certificates information like SAN and expiration date.
+User will send plugin message to trigger the reporting/logging.
+
+The log format for ``cert_reporting_tool.log`` is as followed:
+[time] [Lookup Name] [Subject] [SAN] [serial] [NotAfter]
+
+Plugin Configuration
+====================
+.. program:: cert_reporting_tool.so
+
+* Simply put the name `cert_reporting_tool.so` in plugin.config
+
+* ``traffic_ctl`` command.
+ ``traffic_ctl plugin msg cert_reporting_tool.client 1`` - Triggers reporting/logging for client certs.
+
+Example Usage
+=============
+Start traffic server with cert_reporting_tool loaded, then use traffic_ctl to send plugin message:
+``traffic_ctl plugin msg cert_reporting_tool.client 1``
diff --git a/doc/admin-guide/plugins/index.en.rst b/doc/admin-guide/plugins/index.en.rst
index da38b3c..3d422dc 100644
--- a/doc/admin-guide/plugins/index.en.rst
+++ b/doc/admin-guide/plugins/index.en.rst
@@ -147,6 +147,7 @@ directory of the |TS| source tree. Experimental plugins can be compiled by passi
Balancer <balancer.en>
Buffer Upload <buffer_upload.en>
Certifier <certifier.en>
+ Cert Reporting Tool <cert_reporting_tool.en>
Collapsed-Forwarding <collapsed_forwarding.en>
GeoIP ACL <geoip_acl.en>
FQ Pacing <fq_pacing.en>
@@ -181,6 +182,9 @@ directory of the |TS| source tree. Experimental plugins can be compiled by passi
:doc:`Certifier <certifier.en>`
Manages and/or generates certificates for incoming HTTPS requests.
+:doc:`Cert Reporting Tool <cert_reporting_tool.en>`
+ Examines and logs information on loaded certificates.
+
:doc:`Collapsed-Forwarding <collapsed_forwarding.en>`
Allows to Collapse multiple Concurrent requests by downloading once from the Origin and serving
all clients in parallel.
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index c00a4fb..b5e7d17 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -57,6 +57,7 @@ include experimental/balancer/Makefile.inc
include experimental/buffer_upload/Makefile.inc
include experimental/cache_range_requests/Makefile.inc
include experimental/certifier/Makefile.inc
+include experimental/cert_reporting_tool/Makefile.inc
include experimental/collapsed_forwarding/Makefile.inc
include experimental/cookie_remap/Makefile.inc
include experimental/custom_redirect/Makefile.inc
diff --git a/plugins/experimental/cert_reporting_tool/Makefile.inc b/plugins/experimental/cert_reporting_tool/Makefile.inc
new file mode 100644
index 0000000..73fb186
--- /dev/null
+++ b/plugins/experimental/cert_reporting_tool/Makefile.inc
@@ -0,0 +1,19 @@
+# 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.
+
+pkglib_LTLIBRARIES += experimental/cert_reporting_tool/cert_reporting_tool.la
+
+experimental_cert_reporting_tool_cert_reporting_tool_la_SOURCES = experimental/cert_reporting_tool/cert_reporting_tool.cc
diff --git a/plugins/experimental/cert_reporting_tool/README b/plugins/experimental/cert_reporting_tool/README
new file mode 100644
index 0000000..c9f2788
--- /dev/null
+++ b/plugins/experimental/cert_reporting_tool/README
@@ -0,0 +1,15 @@
+ATS (Apache Traffic Server) Cert Reporting Tool Plugin
+
+General description
+-------------------
+
+This plugin can be used to examine loaded certificates and logs related information onto disk.
+
+The log format is as followed:
+[time] [Lookup Name] [Subject] [SAN] [serial] [NotAfter]
+
+To use the plugin, simply supply the name in plugin.config:
+Example: cert_reporting_tool.so
+
+And then send plugin messages to trigger reports/logs:
+Example: `traffic_ctl plugin msg cert_reporting_tool.client 1` to log all client certificates.
diff --git a/plugins/experimental/cert_reporting_tool/cert_reporting_tool.cc b/plugins/experimental/cert_reporting_tool/cert_reporting_tool.cc
new file mode 100644
index 0000000..5c94f01
--- /dev/null
+++ b/plugins/experimental/cert_reporting_tool/cert_reporting_tool.cc
@@ -0,0 +1,190 @@
+/** @cert_reporting_tool.cc
+ Cert reporting tool collects and logs TLS certificate/context related information.
+ @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 <stdio.h>
+#include <cstring>
+#include <string>
+#include <string_view>
+
+#ifdef OPENSSL_NO_SSL_INTERN
+#undef OPENSSL_NO_SSL_INTERN
+#endif
+
+#include <openssl/opensslv.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "ts/ts.h"
+#include "tscpp/util/TextView.h"
+
+#define PLUGIN_NAME "cert_reporting_tool"
+TSTextLogObject cert_reporting_log;
+
+char *
+asn1_string_extract(ASN1_STRING *s)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x010100000
+ return reinterpret_cast<char *>(const_cast<unsigned char *>(ASN1_STRING_get0_data(s)));
+#else
+ return reinterpret_cast<char *>(ASN1_STRING_data(s));
+#endif
+}
+
+// For 1.0.2, needs access to internal structure
+// For 1.1.0 and 1.1.1, use API
+void
+dump_context(const char *ca_path, const char *ck_path)
+{
+ SSL_CTX *ctx = reinterpret_cast<SSL_CTX *>(TSSslClientContextFindByName(ca_path, ck_path));
+ if (ctx) {
+ SSL *s = SSL_new(ctx);
+ if (s) {
+ char *data = nullptr;
+ long length = 0;
+ std::string subject_s, san_s, serial_s, time_s;
+ X509 *cert = SSL_get_certificate(s);
+ if (cert) {
+ // Retrieve state info and write to log object
+ // expiration date, serial number, common name, and subject alternative names
+ const ASN1_TIME *not_after = X509_get_notAfter(cert);
+ const ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+ X509_NAME *subject_name = X509_get_subject_name(cert);
+
+ // Subject name
+ BIO *subject_bio = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(subject_bio, subject_name, 0, XN_FLAG_RFC2253);
+ length = BIO_get_mem_data(subject_bio, &data);
+ if (length > 0 && data) {
+ subject_s = std::string(data, length);
+ }
+ data = nullptr;
+ BIO_free(subject_bio);
+
+ // Subject Alternative Name
+ GENERAL_NAMES *names = static_cast<GENERAL_NAMES *>(X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
+ if (names) {
+ unsigned count = sk_GENERAL_NAME_num(names);
+ for (unsigned i = 0; i < count; ++i) {
+ GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
+ data = nullptr;
+ length = 0;
+ switch (name->type) {
+ case (GEN_EMAIL): {
+ data = asn1_string_extract(name->d.rfc822Name);
+ length = ASN1_STRING_length(name->d.rfc822Name);
+ break;
+ }
+ case (GEN_DNS): {
+ data = asn1_string_extract(name->d.dNSName);
+ length = ASN1_STRING_length(name->d.dNSName);
+ break;
+ }
+ case (GEN_URI): {
+ data = asn1_string_extract(name->d.uniformResourceIdentifier);
+ length = ASN1_STRING_length(name->d.uniformResourceIdentifier);
+ break;
+ }
+ default:
+ break;
+ }
+ if (data) {
+ san_s.append(data, length);
+ san_s.push_back(',');
+ }
+ }
+ if (san_s.back() == ',') {
+ san_s.pop_back();
+ }
+ }
+
+ // Serial number
+ int64_t sn = 0;
+#if OPENSSL_VERSION_NUMBER >= 0x010100000
+ ASN1_INTEGER_get_int64(&sn, serial);
+#else
+ sn = ASN1_INTEGER_get(serial);
+#endif
+ if (sn != 0 && sn != -1) {
+ serial_s = std::to_string(sn);
+ }
+
+ // Expiration
+ BIO *time_bio = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(time_bio, not_after);
+ length = BIO_get_mem_data(time_bio, &data);
+ time_s = std::string(data, length);
+ BIO_free(time_bio);
+ TSDebug(PLUGIN_NAME, "LookupName: %s:%s, Subject: %s. SAN: %s. Serial: %s. NotAfter: %s.", ca_path, ck_path,
+ subject_s.c_str(), san_s.c_str(), serial_s.c_str(), time_s.c_str());
+ TSTextLogObjectWrite(cert_reporting_log, "LookupName: %s:%s, Subject: %s. SAN: %s. Serial: %s. NotAfter: %s.", ca_path,
+ ck_path, subject_s.c_str(), san_s.c_str(), serial_s.c_str(), time_s.c_str());
+ }
+ }
+ SSL_free(s);
+ }
+}
+
+// Plugin Message Continuation
+int
+CB_context_dump(TSCont, TSEvent, void *edata)
+{
+ TSPluginMsg *msg = static_cast<TSPluginMsg *>(edata);
+ static constexpr std::string_view PLUGIN_PREFIX("cert_reporting_tool."_sv);
+
+ std::string_view tag(msg->tag, strlen(msg->tag));
+
+ if (tag.substr(0, PLUGIN_PREFIX.size()) == PLUGIN_PREFIX) {
+ tag.remove_prefix(PLUGIN_PREFIX.size());
+ if (tag == "client") {
+ // Grab all keys by API and dump to log file according to arg passed in
+ int count = 0;
+ TSSslClientContextsNamesGet(0, nullptr, &count);
+ if (count > 0) {
+ char const **results = static_cast<char const **>(malloc(sizeof(const char *) * count));
+ TSSslClientContextsNamesGet(count, results, nullptr);
+ for (int i = 0; i < count; i += 2) {
+ dump_context(results[i], results[i + 1]);
+ }
+ }
+ }
+ }
+ TSTextLogObjectFlush(cert_reporting_log);
+ return TS_SUCCESS;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+ TSPluginRegistrationInfo info;
+
+ info.plugin_name = PLUGIN_NAME;
+ info.vendor_name = "Apache Software Foundation";
+ info.support_email = "dev@trafficserver.apache.org";
+
+ if (TSPluginRegister(&info) != TS_SUCCESS) {
+ TSError("[%s] Plugin registration failed", PLUGIN_NAME);
+ return;
+ }
+ if (TSTextLogObjectCreate(PLUGIN_NAME, TS_LOG_MODE_ADD_TIMESTAMP, &cert_reporting_log) != TS_SUCCESS || !cert_reporting_log) {
+ TSError("[%s] Failed to create log file", PLUGIN_NAME);
+ return;
+ }
+ TSDebug(PLUGIN_NAME, "Initialized.");
+ TSLifecycleHookAdd(TS_LIFECYCLE_MSG_HOOK, TSContCreate(CB_context_dump, nullptr));
+}