Add event for inbound cert visibility
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 23 Oct 2014 17:22:33 +0000 (18:22 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 25 Oct 2014 20:37:59 +0000 (21:37 +0100)
doc/doc-txt/ChangeLog
doc/doc-txt/experimental-spec.txt
src/src/globals.c
src/src/tls-gnu.c
src/src/tls-openssl.c
test/confs/5750
test/confs/5760
test/log/5750
test/log/5760

index 50a6e49b32256aee9e13c511dd0ac9b63048da86..ed4574729aabf31659843489cd2d8af3a6f64bd0 100644 (file)
@@ -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
index 1d3715f78cda4a9d8d1c8ee89eee9be3a1405aa5..faa64df68685d133acf8e2ea4999c8d7bda10dcd 100644 (file)
@@ -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
index 1eae4a8306e726a915b6aba5eecaad6d3f16b188..fb705d9d8a550cf01d2f8e368143f933cb3d78ba 100644 (file)
@@ -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 = {
index 20e11cae16e77a32181d18e5c8d5cb7ae10bec4f..1966c557dc0f440cc1b3d9c93caebd0344aed628 100644 (file)
@@ -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
 
index 13a3cd076301a15953f7ccfc551336c9bf66d214..4de3cad513428b1951e160b1b0a56d057d7fd257 100644 (file)
@@ -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",
index 8cfef31531dcd6a52caf6b1726c10ac364e80e29..3898530b435893d77493de4cffd209d1a6f54606 100644 (file)
@@ -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}}>
index b8cab04faa021fe86c5042a4964f82a7888c7a24..d07aa8d9046db2c51733c5a72a586e71d024eb11 100644 (file)
@@ -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}}>
index 9e85d1a40a1c0654365a161abd369c2da5ad1338..d08589257a007a689d4a171e26ec8d2dc0676ce1 100644 (file)
@@ -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
index 6d382cab4c077563dcda80f254e61223c649a1a7..691ccdae733177d232ff4787299391342bf7cfc2 100644 (file)
@@ -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: <<detail omitted>>
 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