Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 27 additions & 19 deletions doc/admin-guide/logging/formatting.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -597,35 +597,43 @@ SSL / Encryption
~~~~~~~~~~~~~~~~

.. _cssn:
.. _cscert:
.. _cqssl:
.. _cqssr:
.. _cqssv:
.. _cqssc:
.. _cqssu:
.. _pqssl:
.. _pscert:

Fields which expose the use, or lack thereof, of specific SSL and encryption
features.

===== ============== ==========================================================
Field Source Description
===== ============== ==========================================================
cssn Client TLS SNI server name in client Hello message in TLS handshake.
Hello If no server name present in Hello, or the transaction
was not over TLS (over TCP), this field will contain
``-``.
cqssl Client Request SSL client request status indicates if this client
connection is over SSL.
cqssr Client Request SSL session ticket reused status; indicates if the current
request hit the SSL session ticket and avoided a full SSL
handshake.
cqssv Client Request SSL version used to communicate with the client.
cqssc Client Request SSL Cipher used by |TS| to communicate with the client.
cqssu Client Request SSL Elliptic Curve used by |TS| to communicate with the
client when using an ECDHE cipher.
pqssl Proxy Request Indicates whether the connection from |TS| to the origin
was over SSL or not.
===== ============== ==========================================================
====== ============== ==========================================================
Field Source Description
====== ============== ==========================================================
cssn Client TLS SNI server name in client Hello message in TLS handshake.
Hello If no server name present in Hello, or the transaction
was not over TLS (over TCP), this field will contain
``-``.
cscert Client Request 1 if |TS| requested certificate from client during TLS
handshake. 0 otherwise.
cqssl Client Request SSL client request status indicates if this client
connection is over SSL.
cqssr Client Request SSL session ticket reused status; indicates if the current
request hit the SSL session ticket and avoided a full SSL
handshake.
cqssv Client Request SSL version used to communicate with the client.
cqssc Client Request SSL Cipher used by |TS| to communicate with the client.
cqssu Client Request SSL Elliptic Curve used by |TS| to communicate with the
client when using an ECDHE cipher.
pqssl Proxy Request Indicates whether the connection from |TS| to the origin
was over SSL or not.
pscert Proxy Request 1 if origin requested certificate from |TS| during TLS
handshake but no client certificate was defined. 2 if origin
requested certificate from |TS| during TLS handshake and a
client certificate was defined. 0 otherwise.
====== ============== ==========================================================

.. _admin-logging-fields-status:

Expand Down
12 changes: 12 additions & 0 deletions iocore/net/I_NetVConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,18 @@ class NetVConnection : public VConnection, public PluginUserArgs<TS_USER_ARGS_VC
return nullptr;
}

virtual bool
peer_provided_cert() const
{
return false;
}

virtual int
provided_cert() const
{
return 0;
}

/** Structure holding user options. */
NetVCOptions options;

Expand Down
30 changes: 30 additions & 0 deletions iocore/net/P_SSLNetVConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,34 @@ class SSLNetVConnection : public UnixNetVConnection, public ALPNSupport, public
return SSL_get_servername(this->ssl, TLSEXT_NAMETYPE_host_name);
}

bool
peer_provided_cert() const override
{
X509 *cert = SSL_get_peer_certificate(this->ssl);
if (cert != nullptr) {
X509_free(cert);
return true;
} else {
return false;
}
}

int
provided_cert() const override
{
if (this->get_context() == NET_VCONNECTION_OUT) {
return this->sent_cert;
} else {
return 1;
}
}

void
set_sent_cert(int send_the_cert)
{
sent_cert = send_the_cert;
}

protected:
const IpEndpoint &
_getLocalEndpoint() override
Expand All @@ -460,6 +488,8 @@ class SSLNetVConnection : public UnixNetVConnection, public ALPNSupport, public

bool transparentPassThrough = false;

int sent_cert = 0;

/// The current hook.
/// @note For @C SSL_HOOKS_INVOKE, this is the hook to invoke.
class APIHook *curHook = nullptr;
Expand Down
16 changes: 16 additions & 0 deletions iocore/net/SSLClientUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ verify_callback(int signature_ok, X509_STORE_CTX *ctx)
return true;
}

static int
ssl_client_cert_callback(SSL *ssl, void * /*arg*/)
{
SSLNetVConnection *netvc = SSLNetVCAccess(ssl);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new callback function just for SSLNetVC 😢 Please create an issue for QUIC.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I don't see where to put this in the QUIC classes. Filed issue #6939.

SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
if (ctx) {
// Do not need to free either the cert or the ssl_ctx
// both are internal pointers
X509 *cert = SSL_CTX_get0_certificate(ctx);
netvc->set_sent_cert(cert != nullptr ? 2 : 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful to name the 0, 1, 2 values in some way. Perhaps an enum?

}
return 1;
}

SSL_CTX *
SSLInitClientContext(const SSLConfigParams *params)
{
Expand Down Expand Up @@ -192,6 +206,8 @@ SSLInitClientContext(const SSLConfigParams *params)
SSLConfigParams::init_ssl_ctx_cb(client_ctx, false);
}

SSL_CTX_set_cert_cb(client_ctx, ssl_client_cert_callback, nullptr);

return client_ctx;

fail:
Expand Down
25 changes: 16 additions & 9 deletions proxy/http/HttpSM.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1852,7 +1852,11 @@ HttpSM::state_http_server_open(int event, void *data)
case VC_EVENT_INACTIVITY_TIMEOUT:
case VC_EVENT_ACTIVE_TIMEOUT:
case VC_EVENT_ERROR:
case NET_EVENT_OPEN_FAILED:
case NET_EVENT_OPEN_FAILED: {
NetVConnection *vc = server_session->get_netvc();
if (vc) {
server_connection_provided_cert = vc->provided_cert();
}
t_state.current.state = HttpTransact::CONNECTION_ERROR;
// save the errno from the connect fail for future use (passed as negative value, flip back)
t_state.current.server->set_connect_fail(event == NET_EVENT_OPEN_FAILED ? -reinterpret_cast<intptr_t>(data) : ECONNABORTED);
Expand Down Expand Up @@ -1884,7 +1888,7 @@ HttpSM::state_http_server_open(int event, void *data)
call_transact_and_set_next_state(HttpTransact::HandleResponse);
}
return 0;

}
default:
Error("[HttpSM::state_http_server_open] Unknown event: %d", event);
ink_release_assert(0);
Expand Down Expand Up @@ -5520,13 +5524,16 @@ HttpSM::handle_http_server_open()
// server session's first transaction.
if (nullptr != server_session) {
NetVConnection *vc = server_session->get_netvc();
if (vc != nullptr && (vc->options.sockopt_flags != t_state.txn_conf->sock_option_flag_out ||
vc->options.packet_mark != t_state.txn_conf->sock_packet_mark_out ||
vc->options.packet_tos != t_state.txn_conf->sock_packet_tos_out)) {
vc->options.sockopt_flags = t_state.txn_conf->sock_option_flag_out;
vc->options.packet_mark = t_state.txn_conf->sock_packet_mark_out;
vc->options.packet_tos = t_state.txn_conf->sock_packet_tos_out;
vc->apply_options();
if (vc) {
server_connection_provided_cert = vc->provided_cert();
if (vc->options.sockopt_flags != t_state.txn_conf->sock_option_flag_out ||
vc->options.packet_mark != t_state.txn_conf->sock_packet_mark_out ||
vc->options.packet_tos != t_state.txn_conf->sock_packet_tos_out) {
vc->options.sockopt_flags = t_state.txn_conf->sock_option_flag_out;
vc->options.packet_mark = t_state.txn_conf->sock_packet_mark_out;
vc->options.packet_tos = t_state.txn_conf->sock_packet_tos_out;
vc->apply_options();
}
}
}

Expand Down
39 changes: 20 additions & 19 deletions proxy/http/HttpSM.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,25 +523,26 @@ class HttpSM : public Continuation, public PluginUserArgs<TS_USER_ARGS_TXN>
public:
// TODO: Now that bodies can be empty, should the body counters be set to -1 ? TS-2213
// Stats & Logging Info
int client_request_hdr_bytes = 0;
int64_t client_request_body_bytes = 0;
int server_request_hdr_bytes = 0;
int64_t server_request_body_bytes = 0;
int server_response_hdr_bytes = 0;
int64_t server_response_body_bytes = 0;
int client_response_hdr_bytes = 0;
int64_t client_response_body_bytes = 0;
int cache_response_hdr_bytes = 0;
int64_t cache_response_body_bytes = 0;
int pushed_response_hdr_bytes = 0;
int64_t pushed_response_body_bytes = 0;
bool client_tcp_reused = false;
bool client_ssl_reused = false;
bool client_connection_is_ssl = false;
bool is_internal = false;
bool server_connection_is_ssl = false;
bool is_waiting_for_full_body = false;
bool is_using_post_buffer = false;
int client_request_hdr_bytes = 0;
int64_t client_request_body_bytes = 0;
int server_request_hdr_bytes = 0;
int64_t server_request_body_bytes = 0;
int server_response_hdr_bytes = 0;
int64_t server_response_body_bytes = 0;
int client_response_hdr_bytes = 0;
int64_t client_response_body_bytes = 0;
int cache_response_hdr_bytes = 0;
int64_t cache_response_body_bytes = 0;
int pushed_response_hdr_bytes = 0;
int64_t pushed_response_body_bytes = 0;
int server_connection_provided_cert = 0;
bool client_tcp_reused = false;
bool client_ssl_reused = false;
bool client_connection_is_ssl = false;
bool is_internal = false;
bool server_connection_is_ssl = false;
bool is_waiting_for_full_body = false;
bool is_using_post_buffer = false;
std::optional<bool> mptcp_state; // Don't initialize, that marks it as "not defined".
const char *client_protocol = "-";
const char *client_sec_protocol = "-";
Expand Down
10 changes: 10 additions & 0 deletions proxy/logging/Log.cc
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,16 @@ Log::init_fields()
global_field_list.add(field, false);
field_symbol_hash.emplace("cssn", field);

field = new LogField("client_ssl_cert_provided", "cscert", LogField::STRING, &LogAccess::marshal_client_provided_cert,
reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
field_symbol_hash.emplace("cscert", field);

field = new LogField("proxy_ssl_cert_provided", "pscert", LogField::STRING, &LogAccess::marshal_proxy_provided_cert,
reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
field_symbol_hash.emplace("pscert", field);

field = new LogField("process_uuid", "puuid", LogField::STRING, &LogAccess::marshal_process_uuid,
reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
global_field_list.add(field, false);
Expand Down
38 changes: 38 additions & 0 deletions proxy/logging/LogAccess.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,44 @@ LogAccess::marshal_client_sni_server_name(char *buf)
return len;
}

/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
int
LogAccess::marshal_client_provided_cert(char *buf)
{
int provided_cert = 0;
if (m_http_sm) {
auto txn = m_http_sm->get_ua_txn();
if (txn) {
auto ssn = txn->get_proxy_ssn();
if (ssn) {
auto ssl = ssn->ssl();
if (ssl) {
provided_cert = ssl->client_provided_certificate();
}
}
}
}
if (buf) {
marshal_int(buf, provided_cert);
}
return INK_MIN_ALIGN;
}

/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
int
LogAccess::marshal_proxy_provided_cert(char *buf)
{
int provided_cert = 0;
if (m_http_sm) {
provided_cert = m_http_sm->server_connection_provided_cert;
}
if (buf) {
marshal_int(buf, provided_cert);
}
return INK_MIN_ALIGN;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/

Expand Down
2 changes: 2 additions & 0 deletions proxy/logging/LogAccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ class LogAccess
inkcoreapi int marshal_client_http_transaction_priority_dependence(char *); // INT
inkcoreapi int marshal_cache_lookup_url_canon(char *); // STR
inkcoreapi int marshal_client_sni_server_name(char *); // STR
inkcoreapi int marshal_client_provided_cert(char *); // INT
inkcoreapi int marshal_proxy_provided_cert(char *); // INT
inkcoreapi int marshal_version_build_number(char *); // STR
inkcoreapi int marshal_cache_read_retries(char *); // INT
inkcoreapi int marshal_cache_write_retries(char *); // INT
Expand Down
1 change: 1 addition & 0 deletions proxy/private/SSLProxySession.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ SSLProxySession::init(SSLNetVConnection const &new_vc)
std::memcpy(n, name, length);
_client_sni_server_name.reset(n);
}
_client_provided_cert = new_vc.peer_provided_cert();
}
7 changes: 7 additions & 0 deletions proxy/private/SSLProxySession.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,15 @@ class SSLProxySession
return _client_sni_server_name.get();
}

bool
client_provided_certificate() const
{
return _client_provided_cert;
}

void init(SSLNetVConnection const &new_vc);

private:
std::unique_ptr<char[]> _client_sni_server_name;
bool _client_provided_cert = false;
};
9 changes: 9 additions & 0 deletions tests/gold_tests/tls/gold/clientcert-accesslog.gold
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
404 http://127.0.0.1:``/case3 0 1
404 http://127.0.0.1:``/case4 0 0
404 http://127.0.0.1:``/case5 0 0
404 http://127.0.0.1:``/case6 0 0
404 http://127.0.0.1:``/case7 0 0
404 http://127.0.0.1:``/case8 0 0
404 http://127.0.0.1:``/case9 0 0
404 http://127.0.0.1:``/case11 0 1
404 http://127.0.0.1:``/case14 0 0
8 changes: 8 additions & 0 deletions tests/gold_tests/tls/gold/proxycert-accesslog.gold
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
200 https://127.0.0.1:``/ 2 0
502 https://127.0.0.1:``/ 2 0
404 https://127.0.0.1:``/ 2 0
502 https://127.0.0.1:``/ 2 0
200 https://127.0.0.1:``/ 2 0
502 https://127.0.0.1:``/ 2 0
404 https://127.0.0.1:``/ 2 0
502 https://127.0.0.1:``/ 2 0
8 changes: 8 additions & 0 deletions tests/gold_tests/tls/gold/proxycert2-accesslog.gold
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
200 https://127.0.0.1:``/ 2 0
502 https://127.0.0.1:``/ 2 0
200 https://127.0.0.1:``/ 2 0
502 https://127.0.0.1:``/ 2 0
404 https://127.0.0.1:``/ 2 0
502 https://127.0.0.1:``/ 2 0
502 https://127.0.0.1:``/ 1 0
502 https://127.0.0.1:``/ 1 0
Loading