diff --git a/doc/admin-guide/logging/formatting.en.rst b/doc/admin-guide/logging/formatting.en.rst index 5b98f0b5612..93df61c8f10 100644 --- a/doc/admin-guide/logging/formatting.en.rst +++ b/doc/admin-guide/logging/formatting.en.rst @@ -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: diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h index 97df42ceb21..bda63a57659 100644 --- a/iocore/net/I_NetVConnection.h +++ b/iocore/net/I_NetVConnection.h @@ -657,6 +657,18 @@ class NetVConnection : public VConnection, public PluginUserArgsssl, 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 @@ -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; diff --git a/iocore/net/SSLClientUtils.cc b/iocore/net/SSLClientUtils.cc index 918db0a057f..012db75b624 100644 --- a/iocore/net/SSLClientUtils.cc +++ b/iocore/net/SSLClientUtils.cc @@ -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); + 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); + } + return 1; +} + SSL_CTX * SSLInitClientContext(const SSLConfigParams *params) { @@ -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: diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 6e6c153a0c2..5f4f9fa288c 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -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(data) : ECONNABORTED); @@ -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); @@ -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(); + } } } diff --git a/proxy/http/HttpSM.h b/proxy/http/HttpSM.h index 0a6b7d2e95c..befb4e5d828 100644 --- a/proxy/http/HttpSM.h +++ b/proxy/http/HttpSM.h @@ -523,25 +523,26 @@ class HttpSM : public Continuation, public PluginUserArgs 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 mptcp_state; // Don't initialize, that marks it as "not defined". const char *client_protocol = "-"; const char *client_sec_protocol = "-"; diff --git a/proxy/logging/Log.cc b/proxy/logging/Log.cc index 4d46f6db7d5..33da376d053 100644 --- a/proxy/logging/Log.cc +++ b/proxy/logging/Log.cc @@ -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(&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(&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(&LogAccess::unmarshal_str)); global_field_list.add(field, false); diff --git a/proxy/logging/LogAccess.cc b/proxy/logging/LogAccess.cc index 5a0680dacdc..6aeae95b6bc 100644 --- a/proxy/logging/LogAccess.cc +++ b/proxy/logging/LogAccess.cc @@ -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; +} /*------------------------------------------------------------------------- -------------------------------------------------------------------------*/ diff --git a/proxy/logging/LogAccess.h b/proxy/logging/LogAccess.h index e5c14cbba30..9b14644f3ec 100644 --- a/proxy/logging/LogAccess.h +++ b/proxy/logging/LogAccess.h @@ -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 diff --git a/proxy/private/SSLProxySession.cc b/proxy/private/SSLProxySession.cc index 544d0afb1c7..e2b10857b1d 100644 --- a/proxy/private/SSLProxySession.cc +++ b/proxy/private/SSLProxySession.cc @@ -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(); } diff --git a/proxy/private/SSLProxySession.h b/proxy/private/SSLProxySession.h index 37e572f0a74..8974b6c8e3d 100644 --- a/proxy/private/SSLProxySession.h +++ b/proxy/private/SSLProxySession.h @@ -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 _client_sni_server_name; + bool _client_provided_cert = false; }; diff --git a/tests/gold_tests/tls/gold/clientcert-accesslog.gold b/tests/gold_tests/tls/gold/clientcert-accesslog.gold new file mode 100644 index 00000000000..7ac3617255c --- /dev/null +++ b/tests/gold_tests/tls/gold/clientcert-accesslog.gold @@ -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 diff --git a/tests/gold_tests/tls/gold/proxycert-accesslog.gold b/tests/gold_tests/tls/gold/proxycert-accesslog.gold new file mode 100644 index 00000000000..130f1ac7c9e --- /dev/null +++ b/tests/gold_tests/tls/gold/proxycert-accesslog.gold @@ -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 diff --git a/tests/gold_tests/tls/gold/proxycert2-accesslog.gold b/tests/gold_tests/tls/gold/proxycert2-accesslog.gold new file mode 100644 index 00000000000..4aaa66a8f59 --- /dev/null +++ b/tests/gold_tests/tls/gold/proxycert2-accesslog.gold @@ -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 diff --git a/tests/gold_tests/tls/tls_client_cert.test.py b/tests/gold_tests/tls/tls_client_cert.test.py index 89a1f9b4248..1ef2e8be4a8 100644 --- a/tests/gold_tests/tls/tls_client_cert.test.py +++ b/tests/gold_tests/tls/tls_client_cert.test.py @@ -17,8 +17,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import subprocess - Test.Summary = ''' Test different combinations of TLS handshake hooks to ensure they are applied consistently. ''' @@ -30,6 +28,7 @@ server = Test.MakeOriginServer("server", ssl=True, options = { "--clientCA": cafile, "--clientverify": ""}, clientcert="{0}/signed-foo.pem".format(Test.RunDirectory), clientkey="{0}/signed-foo.key".format(Test.RunDirectory)) server2 = Test.MakeOriginServer("server2", ssl=True, options = { "--clientCA": cafile2, "--clientverify": ""}, clientcert="{0}/signed2-bar.pem".format(Test.RunDirectory), clientkey="{0}/signed-bar.key".format(Test.RunDirectory)) server3 = Test.MakeOriginServer("server3") +server4 = Test.MakeOriginServer("server4") server.Setup.Copy("ssl/signer.pem") server.Setup.Copy("ssl/signer2.pem") server.Setup.Copy("ssl/signed-foo.pem") @@ -96,6 +95,18 @@ ts.Disk.sni_yaml.AddLine( ' client_key: {0}/signed-bar.key'.format(ts.Variables.SSLDir)) +ts.Disk.logging_yaml.AddLines( +''' +logging: + formats: + - name: testformat + format: '% % % %' + logs: + - mode: ascii + format: testformat + filename: squid +'''.split("\n") +) # Should succeed tr = Test.AddTestRun("Connect with first client cert to first server") @@ -170,20 +181,6 @@ tr2.Processes.Default.Env = ts.Env tr2.Processes.Default.ReturnCode = 0 -# Parking this as a ready tester on a meaningless process -# Stall the test runs until the sni reload has completed -# At that point the new sni settings are ready to go -def sni_reload_done(tsenv): - def done_reload(process, hasRunFor, **kw): - cmd = "grep 'sni.yaml finished loading' {0} | wc -l | sed -e 's/ //g'> {1}/test.out".format(ts.Disk.diags_log.Name, Test.RunDirectory) - retval = subprocess.run(cmd, shell=True, env=tsenv) - if retval.returncode == 0: - cmd ="if [ -f {0}/test.out -a \"`cat {0}/test.out`\" = \"2\" ] ; then true; else false; fi".format(Test.RunDirectory) - retval = subprocess.run(cmd, shell = True, env=tsenv) - return retval.returncode == 0 - - return done_reload - tr2reload = Test.AddTestRun("Reload config") tr2reload.StillRunningAfter = ts tr2reload.StillRunningAfter = server @@ -197,7 +194,7 @@ def done_reload(process, hasRunFor, **kw): #Should succeed tr3bar = Test.AddTestRun("Make request with other bar cert to first server") # Wait for the reload to complete -tr3bar.Processes.Default.StartBefore(server3, ready=sni_reload_done(ts.Env)) +tr3bar.Processes.Default.StartBefore(server3, ready=When.FileContains(ts.Disk.diags_log.Name, 'sni.yaml finished loading', 2)) tr3bar.StillRunningAfter = ts tr3bar.StillRunningAfter = server tr3bar.StillRunningAfter = server2 @@ -293,3 +290,11 @@ def done_reload(process, hasRunFor, **kw): tr4fail.Processes.Default.Command = 'curl -H host:example.com http://127.0.0.1:{0}/case2'.format(ts.Variables.port) tr4fail.Processes.Default.ReturnCode = 0 tr4fail.Processes.Default.Streams.stdout = Testers.ContainsExpression("Could Not Connect", "Check response") + +tr = Test.AddTestRun("Wait for the access log to write out") +tr.Processes.Default.StartBefore(server4, ready=When.FileExists(ts.Disk.squid_log)) +tr.StillRunningAfter = ts +tr.Processes.Default.Command = 'echo "log file exists"' +tr.Processes.Default.ReturnCode = 0 + +ts.Disk.squid_log.Content = "gold/proxycert-accesslog.gold" diff --git a/tests/gold_tests/tls/tls_client_cert2.test.py b/tests/gold_tests/tls/tls_client_cert2.test.py index eeeda8bc76f..b2a535aca5c 100644 --- a/tests/gold_tests/tls/tls_client_cert2.test.py +++ b/tests/gold_tests/tls/tls_client_cert2.test.py @@ -26,6 +26,7 @@ cafile2 = "{0}/signer2.pem".format(Test.RunDirectory) server = Test.MakeOriginServer("server", ssl=True, options = { "--clientCA": cafile, "--clientverify": ""}, clientcert="{0}/signed-foo.pem".format(Test.RunDirectory), clientkey="{0}/signed-foo.key".format(Test.RunDirectory)) server2 = Test.MakeOriginServer("server2", ssl=True, options = { "--clientCA": cafile2, "--clientverify": ""}, clientcert="{0}/signed2-bar.pem".format(Test.RunDirectory), clientkey="{0}/signed-bar.key".format(Test.RunDirectory)) +server4 = Test.MakeOriginServer("server4") server.Setup.Copy("ssl/signer.pem") server.Setup.Copy("ssl/signer2.pem") server.Setup.Copy("ssl/signed-foo.pem") @@ -95,6 +96,18 @@ ' client_key: {0}/signed-foo.key'.format(ts.Variables.SSLDir), ]) +ts.Disk.logging_yaml.AddLines( +''' +logging: + formats: + - name: testformat + format: '% % % %' + logs: + - mode: ascii + format: testformat + filename: squid +'''.split("\n") +) # Should succeed tr = Test.AddTestRun("bob.bar.com to server 1") @@ -170,3 +183,11 @@ trfail.Processes.Default.Command = 'curl -H host:random.foo.com http://127.0.0.1:{0}/case1'.format(ts.Variables.port) trfail.Processes.Default.ReturnCode = 0 trfail.Processes.Default.Streams.stdout = Testers.ContainsExpression("Could Not Connect", "Check response") + +tr = Test.AddTestRun("Wait for the access log to write out") +tr.Processes.Default.StartBefore(server4, ready=When.FileExists(ts.Disk.squid_log)) +tr.StillRunningAfter = ts +tr.Processes.Default.Command = 'echo "Log file exists"' +tr.Processes.Default.ReturnCode = 0 + +ts.Disk.squid_log.Content = "gold/proxycert2-accesslog.gold" diff --git a/tests/gold_tests/tls/tls_client_verify.test.py b/tests/gold_tests/tls/tls_client_verify.test.py index 7663015e7c7..bc3d5549b01 100644 --- a/tests/gold_tests/tls/tls_client_verify.test.py +++ b/tests/gold_tests/tls/tls_client_verify.test.py @@ -17,14 +17,16 @@ # See the License for the specific language governing permissions and # limitations under the License. + Test.Summary = ''' Test various options for requiring certificate from client for mutual authentication TLS ''' -ts = Test.MakeATSProcess("ts", select_ports=True, enable_tls=True) +ts = Test.MakeATSProcess("ts", command="traffic_manager", select_ports=True, enable_tls=True) cafile = "{0}/signer.pem".format(Test.RunDirectory) cafile2 = "{0}/signer2.pem".format(Test.RunDirectory) server = Test.MakeOriginServer("server") +server2 = Test.MakeOriginServer("server2") request_header = {"headers": "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""} response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""} @@ -71,6 +73,19 @@ ' verify_client: STRICT', ]) +ts.Disk.logging_yaml.AddLines( +''' +logging: + formats: + - name: testformat + format: '% % % %' + logs: + - mode: ascii + format: testformat + filename: squid +'''.split("\n") +) + # to foo.com w/o client cert. Should fail tr = Test.AddTestRun("Connect to foo.com without cert") tr.Processes.Default.StartBefore(Test.Processes.ts) @@ -85,7 +100,7 @@ tr.Setup.Copy("ssl/server.key") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'foo.com:{0}:127.0.0.1' https://foo.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'foo.com:{0}:127.0.0.1' https://foo.com:{0}/case2".format(ts.Variables.ssl_port) # Should fail with badly signed certs tr.Processes.Default.ReturnCode = 35 @@ -94,14 +109,14 @@ tr.Setup.Copy("ssl/signed-foo.key") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-foo.pem --key ./signed-foo.key --resolve 'foo.com:{0}:127.0.0.1' https://foo.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-foo.pem --key ./signed-foo.key --resolve 'foo.com:{0}:127.0.0.1' https://foo.com:{0}/case3".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response") tr = Test.AddTestRun("Connect to bob.bar.com without cert") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case4".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.All = Testers.ExcludesExpression("alert", "TLS handshake should succeed") @@ -110,7 +125,7 @@ tr.Setup.Copy("ssl/signed-bar.key") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bob-bar.pem --key ./signed-bar.key --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bob-bar.pem --key ./signed-bar.key --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case5".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response") @@ -119,14 +134,14 @@ tr.Setup.Copy("ssl/server.key") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bob.bar.com:{0}:127.0.0.1' https://bob.bar.com:{0}/case6".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response") tr = Test.AddTestRun("Connect to bob.foo.com without cert") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case7".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.All = Testers.ExcludesExpression("alert", "TLS handshake should succeed") @@ -135,7 +150,7 @@ tr.Setup.Copy("ssl/signed-foo.key") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bob-foo.pem --key ./signed-foo.key --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bob-foo.pem --key ./signed-foo.key --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case8".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response") @@ -144,14 +159,14 @@ tr.Setup.Copy("ssl/server.key") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bob.foo.com:{0}:127.0.0.1' https://bob.foo.com:{0}/case9".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "Check response") tr = Test.AddTestRun("Connect to bar.com without cert") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case10".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 35 tr = Test.AddTestRun("Connect to bar.com with cert") @@ -159,7 +174,7 @@ tr.Setup.Copy("ssl/signed-bar.key") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bar.pem --key ./signed-bar.key --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./signed-bar.pem --key ./signed-bar.key --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case11".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.All = Testers.ExcludesExpression("error", "TLS handshake should succeed") @@ -168,7 +183,7 @@ tr.Setup.Copy("ssl/server.key") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --cert ./server.pem --key ./server.key --resolve 'bar.com:{0}:127.0.0.1' https://bar.com:{0}/case12".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 35 @@ -176,11 +191,21 @@ tr = Test.AddTestRun("Connect to bob.com without cert, should fail") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.com:{0}:127.0.0.1' https://bob.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.com:{0}:127.0.0.1' https://bob.com:{0}/case13".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 35 tr = Test.AddTestRun("Connect to bob.com.com without cert, should succeed") tr.StillRunningAfter = ts tr.StillRunningAfter = server -tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.com.com:{0}:127.0.0.1' https://bob.com.com:{0}/case1".format(ts.Variables.ssl_port) +tr.Processes.Default.Command = "curl --tls-max 1.2 -k --resolve 'bob.com.com:{0}:127.0.0.1' https://bob.com.com:{0}/case14".format(ts.Variables.ssl_port) tr.Processes.Default.ReturnCode = 0 + +tr = Test.AddTestRun("Wait for the access log to write out") +tr.Processes.Default.StartBefore(server2, ready=When.FileExists(ts.Disk.squid_log)) +tr.StillRunningAfter = ts +tr.StillRunningAfter = server +tr.StillRunningAfter = server2 +tr.Processes.Default.Command = 'echo "Log file exists"' +tr.Processes.Default.ReturnCode = 0 + +ts.Disk.squid_log.Content = "gold/clientcert-accesslog.gold" diff --git a/tests/gold_tests/tls/tls_tunnel.test.py b/tests/gold_tests/tls/tls_tunnel.test.py index 69359a3d58c..384aca32bb5 100644 --- a/tests/gold_tests/tls/tls_tunnel.test.py +++ b/tests/gold_tests/tls/tls_tunnel.test.py @@ -16,7 +16,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import subprocess Test.Summary = ''' Test tunneling based on SNI ''' @@ -184,25 +183,11 @@ trreload.Processes.Default.Env = ts.Env trreload.Processes.Default.ReturnCode = 0 -# Parking this as a ready tester on a meaningless process -# Stall the test runs until the sni reload has completed -# At that point the new sni settings are ready to go -def sni_reload_done(tsenv): - def done_reload(process, hasRunFor, **kw): - cmd = "grep 'sni.yaml finished loading' {0} | wc -l | sed -e 's/ //g' > {1}/test.out".format(ts.Disk.diags_log.Name, Test.RunDirectory) - retval = subprocess.run(cmd, shell=True, env=tsenv) - if retval.returncode == 0: - cmd ="if [ -f {0}/test.out -a \"`cat {0}/test.out`\" = \"2\" ] ; then true; else false; fi".format(Test.RunDirectory) - retval = subprocess.run(cmd, shell = True, env=tsenv) - return retval.returncode == 0 - - return done_reload - # Should termimate on traffic_server (not tunnel) tr = Test.AddTestRun("foo.com no Tunnel-test") tr.StillRunningAfter = ts # Wait for the reload to complete by running the sni_reload_done test -tr.Processes.Default.StartBefore(server2, ready=sni_reload_done(ts.Env)) +tr.Processes.Default.StartBefore(server2, ready=When.FileContains(ts.Disk.diags_log.Name, 'sni.yaml finished loading', 2)) tr.Processes.Default.Command = "curl -v --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format(ts.Variables.ssl_port) tr.Processes.Default.Streams.All += Testers.ContainsExpression("Not Found on Accelerato", "Terminates on on Traffic Server") tr.Processes.Default.Streams.All += Testers.ContainsExpression("ATS", "Terminate on Traffic Server")