From: Jeremy Harris Date: Thu, 23 Oct 2014 17:22:33 +0000 (+0100) Subject: Add event for inbound cert visibility X-Git-Tag: exim-4_85_RC1~32 X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/723fe533c452eb258a5a7e0b808d714bbbc7cb01 Add event for inbound cert visibility --- diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 50a6e49b3..ed4574729 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -55,7 +55,9 @@ JH/08 Rename the TPDA expermimental facility to Event Actions. The #ifdef is EXPERIMENTAL_EVENT, the main-configuration and transport options both become "event_action", the variables become $event_name, $event_data and $event_defer_errno. There is a new variable $verify_mode, usable in - routers, transports and related events. + routers, transports and related events. The tls:cert event is now also + raised for inbound connections, if the main configuration event_action + option is defined. Exim version 4.84 diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt index 1d3715f78..faa64df68 100644 --- a/doc/doc-txt/experimental-spec.txt +++ b/doc/doc-txt/experimental-spec.txt @@ -791,7 +791,7 @@ expansion is done. The current list of events is: msg:fail:internal after main per recipient tcp:connect before transport per connection tcp:close after transport per connection - tls:cert before transport per certificate in verification chain + tls:cert before both per certificate in verification chain smtp:connect after transport per connection The expansion is called for all event types, and should use the $event_name @@ -852,6 +852,10 @@ following will be forced: No other use is made of the result string. +Known issues: +- the tls:cert event is only called for the cert chain elements + received over the wire, with GnuTLS. OpenSSL gives the entire + chain including thse loaded locally. Redis Lookup diff --git a/src/src/globals.c b/src/src/globals.c index 1eae4a830..fb705d9d8 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -668,6 +668,13 @@ uschar *errors_copy = NULL; int error_handling = ERRORS_SENDER; uschar *errors_reply_to = NULL; int errors_sender_rc = EXIT_FAILURE; +#ifdef EXPERIMENTAL_EVENT +uschar *event_action = NULL; /* expansion for delivery events */ +uschar *event_data = NULL; /* auxilary data variable for event */ +int event_defer_errno = 0; +uschar *event_name = NULL; /* event name variable */ +#endif + gid_t exim_gid = EXIM_GID; BOOL exim_gid_set = TRUE; /* This gid is always set */ @@ -1336,13 +1343,6 @@ int thismessage_size_limit = 0; int timeout_frozen_after = 0; BOOL timestamps_utc = FALSE; -#ifdef EXPERIMENTAL_EVENT -uschar *event_action = NULL; /* expansion for delivery events */ -uschar *event_data = NULL; /* auxilary data variable for event */ -int event_defer_errno = 0; -uschar *event_name = NULL; /* event name variable */ -#endif - transport_instance *transports = NULL; transport_instance transport_defaults = { diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 20e11cae1..1966c557d 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -1545,15 +1545,15 @@ return 0; #ifdef EXPERIMENTAL_EVENT /* We use this callback to get observability and detail-level control -for an exim client TLS connection, raising a tls:cert event -for each cert in the chain presented by the server. Any event +for an exim TLS connection (either direction), raising a tls:cert event +for each cert in the chain presented by the peer. Any event can deny verification. Return 0 for the handshake to continue or non-zero to terminate. */ static int -client_verify_cb(gnutls_session_t session) +verify_cb(gnutls_session_t session) { const gnutls_datum * cert_list; unsigned int cert_list_size = 0; @@ -1664,6 +1664,15 @@ else gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE); } +#ifdef EXPERIMENTAL_EVENT +if (event_action) + { + state->event_action = event_action; + gnutls_session_set_ptr(state->session, state); + gnutls_certificate_set_verify_function(state->x509_cred, verify_cb); + } +#endif + /* Register SNI handling; always, even if not in tls_certificate, so that the expansion variable $tls_sni is always available. */ @@ -1890,7 +1899,7 @@ if (tb->event_action) { state->event_action = tb->event_action; gnutls_session_set_ptr(state->session, state); - gnutls_certificate_set_verify_function(state->x509_cred, client_verify_cb); + gnutls_certificate_set_verify_function(state->x509_cred, verify_cb); } #endif diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 13a3cd076..4de3cad51 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -287,6 +287,7 @@ verify_callback(int state, X509_STORE_CTX *x509ctx, { X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx); int depth = X509_STORE_CTX_get_error_depth(x509ctx); +uschar * ev; static uschar txt[256]; X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt)); @@ -323,11 +324,11 @@ else if (depth != 0) } #endif #ifdef EXPERIMENTAL_EVENT - if (tlsp == &tls_out && client_static_cbinfo->event_action) + ev = tlsp == &tls_out ? client_static_cbinfo->event_action : event_action; + if (ev) { tlsp->peercert = X509_dup(cert); - if (event_raise(client_static_cbinfo->event_action, - US"tls:cert", string_sprintf("%d", depth)) == DEFER) + if (event_raise(ev, US"tls:cert", string_sprintf("%d", depth)) == DEFER) { log_write(0, LOG_MAIN, "SSL verify denied by event-action: " "depth=%d cert=%s", depth, txt); @@ -392,10 +393,9 @@ else #endif /*EXPERIMENTAL_CERTNAMES*/ #ifdef EXPERIMENTAL_EVENT - if (tlsp == &tls_out) - { - if (event_raise(client_static_cbinfo->event_action, - US"tls:cert", US"0") == DEFER) + ev = tlsp == &tls_out ? client_static_cbinfo->event_action : event_action; + if (ev) + if (event_raise(ev, US"tls:cert", US"0") == DEFER) { log_write(0, LOG_MAIN, "SSL verify denied by event-action: " "depth=0 cert=%s", txt); @@ -403,7 +403,6 @@ else *calledp = TRUE; return 0; /* reject */ } - } #endif DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n", diff --git a/test/confs/5750 b/test/confs/5750 index 8cfef3153..3898530b4 100644 --- a/test/confs/5750 +++ b/test/confs/5750 @@ -29,10 +29,19 @@ tls_privatekey = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.e tls_verify_hosts = * tls_verify_certificates = DIR/aux-fixed/exim-ca/example.com/server2.example.com/ca_chain.pem +event_action = ${acl {server_cert_log}} + # begin acl +server_cert_log: + accept condition = ${if eq {tls:cert}{$event_name}} + logwrite = [$sender_host_address] \ + depth=$event_data \ + ${certextract{subject}{$tls_in_peercert}} + accept + ev_tls: accept logwrite = $event_name depth=$event_data \ <${certextract {subject} {$tls_out_peercert}}> diff --git a/test/confs/5760 b/test/confs/5760 index b8cab04fa..d07aa8d90 100644 --- a/test/confs/5760 +++ b/test/confs/5760 @@ -29,10 +29,19 @@ tls_privatekey = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.e tls_verify_hosts = * tls_verify_certificates = DIR/aux-fixed/exim-ca/example.com/server2.example.com/ca_chain.pem +event_action = ${acl {server_cert_log}} + # begin acl +server_cert_log: + accept condition = ${if eq {tls:cert}{$event_name}} + logwrite = [$sender_host_address] \ + depth=$event_data \ + ${certextract{subject}{$tls_in_peercert}} + accept + ev_tls: accept logwrite = $event_name depth=$event_data \ <${certextract {subject} {$tls_out_peercert}}> diff --git a/test/log/5750 b/test/log/5750 index 9e85d1a40..d08589257 100644 --- a/test/log/5750 +++ b/test/log/5750 @@ -40,7 +40,9 @@ ******** SERVER ******** 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 +1999-03-02 09:44:33 [127.0.0.1] depth=0 CN=server2.example.com 1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (recv): A TLS fatal alert has been received.: Certificate is bad 1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (send): The specified session has been invalidated for some reason. 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex +1999-03-02 09:44:33 [127.0.0.1] depth=0 CN=server2.example.com 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 DN="CN=server2.example.com" S=sss id=E10HmaY-0005vi-00@myhost.test.ex diff --git a/test/log/5760 b/test/log/5760 index 6d382cab4..691ccdae7 100644 --- a/test/log/5760 +++ b/test/log/5760 @@ -47,4 +47,7 @@ 1999-03-02 09:44:33 TLS error on connection from localhost (myhost.test.ex) [127.0.0.1] (SSL_accept): error: <> 1999-03-02 09:44:33 TLS client disconnected cleanly (rejected our certificate?) 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex +1999-03-02 09:44:33 [127.0.0.1] depth=2 CN=clica CA,O=example.com +1999-03-02 09:44:33 [127.0.0.1] depth=1 CN=clica Signing Cert,O=example.com +1999-03-02 09:44:33 [127.0.0.1] depth=0 CN=server2.example.com 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 DN="/CN=server2.example.com" S=sss id=E10HmaY-0005vi-00@myhost.test.ex