X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/9fc9357028c3ada0ca912e2f58d002d8f4c7a321..a7538db17824b7fd70c12ef7561a67b85d6f247e:/src/src/tls-gnu.c diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 266ab8909..b7eae1793 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -47,6 +47,10 @@ require current GnuTLS, then we'll drop support for the ancient libraries). # warning "GnuTLS library version too old; define DISABLE_OCSP in Makefile" # define DISABLE_OCSP #endif +#if GNUTLS_VERSION_NUMBER < 0x020a00 && defined(EXPERIMENTAL_TPDA) +# warning "GnuTLS library version too old; TPDA tls:cert event unsupported" +# undef EXPERIMENTAL_TPDA +#endif #ifndef DISABLE_OCSP # include @@ -115,6 +119,9 @@ typedef struct exim_gnutls_state { #ifdef EXPERIMENTAL_CERTNAMES uschar *exp_tls_verify_cert_hostnames; #endif +#ifdef EXPERIMENTAL_TPDA + uschar *event_action; +#endif tls_support *tlsp; /* set in tls_init() */ @@ -132,6 +139,9 @@ static const exim_gnutls_state_st exim_gnutls_state_init = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, #ifdef EXPERIMENTAL_CERTNAMES NULL, +#endif +#ifdef EXPERIMENTAL_TPDA + NULL, #endif NULL, NULL, 0, 0, 0, 0, @@ -144,7 +154,9 @@ context we're currently dealing with" pointer and rely upon being single-threaded to keep from processing data on an inbound TLS connection while talking to another TLS connection for an outbound check. This does mean that there's no way for heart-beats to be responded to, for the duration of the -second connection. */ +second connection. +XXX But see gnutls_session_get_ptr() +*/ static exim_gnutls_state_st state_server, state_client; @@ -174,18 +186,18 @@ static BOOL exim_gnutls_base_init_done = FALSE; the library logging; a value less than 0 disables the calls to set up logging callbacks. */ #ifndef EXIM_GNUTLS_LIBRARY_LOG_LEVEL -#define EXIM_GNUTLS_LIBRARY_LOG_LEVEL -1 +# define EXIM_GNUTLS_LIBRARY_LOG_LEVEL -1 #endif #ifndef EXIM_CLIENT_DH_MIN_BITS -#define EXIM_CLIENT_DH_MIN_BITS 1024 +# define EXIM_CLIENT_DH_MIN_BITS 1024 #endif /* With GnuTLS 2.12.x+ we have gnutls_sec_param_to_pk_bits() with which we can ask for a bit-strength. Without that, we stick to the constant we had before, for now. */ #ifndef EXIM_SERVER_DH_BITS_PRE2_12 -#define EXIM_SERVER_DH_BITS_PRE2_12 1024 +# define EXIM_SERVER_DH_BITS_PRE2_12 1024 #endif #define exim_gnutls_err_check(Label) do { \ @@ -1512,6 +1524,52 @@ return 0; #endif +#ifdef EXPERIMENTAL_TPDA +/* +We use this callback to get observability and detail-level control +for an exim client TLS connection, raising a TPDA tls:cert event +for each cert in the chain presented by the server. 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) +{ +const gnutls_datum * cert_list; +unsigned int cert_list_size = 0; +gnutls_x509_crt_t crt; +int rc; +exim_gnutls_state_st * state = gnutls_session_get_ptr(session); + +cert_list = gnutls_certificate_get_peers(session, &cert_list_size); +if (cert_list) + while (cert_list_size--) + { + rc = import_cert(&cert_list[cert_list_size], &crt); + if (rc != GNUTLS_E_SUCCESS) + { + DEBUG(D_tls) debug_printf("TLS: peer cert problem: depth %d: %s\n", + cert_list_size, gnutls_strerror(rc)); + break; + } + + state->tlsp->peercert = crt; + if (tpda_raise_event(state->event_action, + US"tls:cert", string_sprintf("%d", cert_list_size)) == DEFER) + { + log_write(0, LOG_MAIN, + "SSL verify denied by event-action: depth=%d", cert_list_size); + return 1; /* reject */ + } + state->tlsp->peercert = NULL; + } + +return 0; +} + +#endif @@ -1694,7 +1752,7 @@ Arguments: fd the fd of the connection host connected host (for messages) addr the first address (not used) - ob smtp transport options + tb transport (always smtp) Returns: OK/DEFER/FAIL (because using common functions), but for a client, DEFER and FAIL have the same meaning @@ -1703,9 +1761,10 @@ Returns: OK/DEFER/FAIL (because using common functions), int tls_client_start(int fd, host_item *host, address_item *addr ARG_UNUSED, - void *v_ob) + transport_instance *tb) { -smtp_transport_options_block *ob = v_ob; +smtp_transport_options_block *ob = + (smtp_transport_options_block *)tb->options_block; int rc; const char *error; exim_gnutls_state_st *state = NULL; @@ -1804,6 +1863,15 @@ if (request_ocsp) } #endif +#ifdef EXPERIMENTAL_TPDA +if (tb->tpda_event_action) + { + state->event_action = tb->tpda_event_action; + gnutls_session_set_ptr(state->session, state); + gnutls_certificate_set_verify_function(state->x509_cred, client_verify_cb); + } +#endif + gnutls_transport_set_ptr(state->session, (gnutls_transport_ptr)(long) fd); state->fd_in = fd; state->fd_out = fd;