X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Ftls-gnu.c;h=b14bca4831e0f43200ae533d4558ba735b2cd436;hb=a75ebe0dcc5faeb915cacb0d9db66d2475789116;hp=4a3e1651ee979716738068eb748ce3d73dbefd49;hpb=ea19ad2276a93548c8a799b1466fd7996c48be04;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 4a3e1651e..b14bca483 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -145,7 +145,7 @@ builtin_macro_create(US"_HAVE_TLS_OCSP"); # ifdef SUPPORT_SRV_OCSP_STACK builtin_macro_create(US"_HAVE_TLS_OCSP_LIST"); # endif -#ifdef EXIM_HAVE_INOTIFY +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) builtin_macro_create(US"_HAVE_TLS_CA_CACHE"); # endif } @@ -345,6 +345,53 @@ tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when, #endif +/************************************************* +* Handle TLS error * +*************************************************/ + +/* Called from lots of places when errors occur before actually starting to do +the TLS handshake, that is, while the session is still in clear. Always returns +DEFER for a server and FAIL for a client so that most calls can use "return +tls_error(...)" to do this processing and then give an appropriate return. A +single function is used for both server and client, because it is called from +some shared functions. + +Argument: + prefix text to include in the logged error + msg additional error string (may be NULL) + usually obtained from gnutls_strerror() + host NULL if setting up a server; + the connected host if setting up a client + errstr pointer to returned error string + +Returns: OK/DEFER/FAIL +*/ + +static int +tls_error(const uschar *prefix, const uschar *msg, const host_item *host, + uschar ** errstr) +{ +if (errstr) + *errstr = string_sprintf("(%s)%s%s", prefix, msg ? ": " : "", msg ? msg : US""); +return host ? FAIL : DEFER; +} + + +static int +tls_error_gnu(const uschar *prefix, int err, const host_item *host, + uschar ** errstr) +{ +return tls_error(prefix, US gnutls_strerror(err), host, errstr); +} + +static int +tls_error_sys(const uschar *prefix, int err, const host_item *host, + uschar ** errstr) +{ +return tls_error(prefix, US strerror(err), host, errstr); +} + + /* ------------------------------------------------------------------------ */ /* Initialisation */ @@ -379,9 +426,10 @@ return FALSE; #endif -static void -tls_g_init(void) +static int +tls_g_init(uschar ** errstr) { +int rc; DEBUG(D_tls) debug_printf("GnuTLS global init required\n"); #if defined(HAVE_GNUTLS_PKCS11) && !defined(GNUTLS_AUTO_PKCS11_MANUAL) @@ -393,12 +441,12 @@ To prevent this, we init PKCS11 first, which is the documented approach. */ if (!gnutls_allow_auto_pkcs11) if ((rc = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL))) - return tls_error_gnu(US"gnutls_pkcs11_init", rc, host, errstr); + return tls_error_gnu(US"gnutls_pkcs11_init", rc, NULL, errstr); #endif #ifndef GNUTLS_AUTO_GLOBAL_INIT if ((rc = gnutls_global_init())) - return tls_error_gnu(US"gnutls_global_init", rc, host, errstr); + return tls_error_gnu(US"gnutls_global_init", rc, NULL, errstr); #endif #if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0 @@ -416,6 +464,7 @@ if (tls_ocsp_file && (gnutls_buggy_ocsp = tls_is_buggy_ocsp())) #endif exim_gnutls_base_init_done = TRUE; +return OK; } @@ -432,10 +481,11 @@ tls_per_lib_daemon_tick(void) static void tls_per_lib_daemon_init(void) { +uschar * dummy_errstr; static BOOL once = FALSE; if (!exim_gnutls_base_init_done) - tls_g_init(); + tls_g_init(&dummy_errstr); if (!once) { @@ -456,54 +506,6 @@ if (!once) } /* ------------------------------------------------------------------------ */ -/* Static functions */ - -/************************************************* -* Handle TLS error * -*************************************************/ - -/* Called from lots of places when errors occur before actually starting to do -the TLS handshake, that is, while the session is still in clear. Always returns -DEFER for a server and FAIL for a client so that most calls can use "return -tls_error(...)" to do this processing and then give an appropriate return. A -single function is used for both server and client, because it is called from -some shared functions. - -Argument: - prefix text to include in the logged error - msg additional error string (may be NULL) - usually obtained from gnutls_strerror() - host NULL if setting up a server; - the connected host if setting up a client - errstr pointer to returned error string - -Returns: OK/DEFER/FAIL -*/ - -static int -tls_error(const uschar *prefix, const uschar *msg, const host_item *host, - uschar ** errstr) -{ -if (errstr) - *errstr = string_sprintf("(%s)%s%s", prefix, msg ? ": " : "", msg ? msg : US""); -return host ? FAIL : DEFER; -} - - -static int -tls_error_gnu(const uschar *prefix, int err, const host_item *host, - uschar ** errstr) -{ -return tls_error(prefix, US gnutls_strerror(err), host, errstr); -} - -static int -tls_error_sys(const uschar *prefix, int err, const host_item *host, - uschar ** errstr) -{ -return tls_error(prefix, US strerror(err), host, errstr); -} - /************************************************* * Deal with logging errors during I/O * @@ -927,7 +929,7 @@ return OK; -/* Create and install a selfsigned certificate, for use in server mode */ +/* Create and install a selfsigned certificate, for use in server mode. */ static int tls_install_selfsign(exim_gnutls_state_st * state, uschar ** errstr) @@ -944,6 +946,7 @@ rc = GNUTLS_E_NO_CERTIFICATE_FOUND; if (TRUE) goto err; #endif +DEBUG(D_tls) debug_printf("TLS: generating selfsigned server cert\n"); where = US"initialising pkey"; if ((rc = gnutls_x509_privkey_init(&pkey))) goto err; @@ -968,7 +971,7 @@ now = 1; if ( (rc = gnutls_x509_crt_set_version(cert, 3)) || (rc = gnutls_x509_crt_set_serial(cert, &now, sizeof(now))) || (rc = gnutls_x509_crt_set_activation_time(cert, now = time(NULL))) - || (rc = gnutls_x509_crt_set_expiration_time(cert, now + 60 * 60)) /* 1 hr */ + || (rc = gnutls_x509_crt_set_expiration_time(cert, (long)2 * 60 * 60)) /* 2 hour */ || (rc = gnutls_x509_crt_set_key(cert, pkey)) || (rc = gnutls_x509_crt_set_dn_by_oid(cert, @@ -1419,26 +1422,25 @@ return gnutls_priority_init( (gnutls_priority_t *) &state->lib_state.pri_cache, CCS p, errpos); } -static void +static unsigned tls_server_creds_init(void) { uschar * dummy_errstr; +unsigned lifetime = 0; state_server.lib_state = null_tls_preload; if (gnutls_certificate_allocate_credentials( (gnutls_certificate_credentials_t *) &state_server.lib_state.x509_cred)) { state_server.lib_state.x509_cred = NULL; - return; + return lifetime; } creds_basic_init(state_server.lib_state.x509_cred, TRUE); -#ifdef EXIM_HAVE_INOTIFY +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) /* If tls_certificate has any $ indicating expansions, it is not good. If tls_privatekey is set but has $, not good. Likewise for tls_ocsp_file. -If all good (and tls_certificate set), load the cert(s). Do not try -to handle selfsign generation for now (tls_certificate null/empty; -XXX will want to do that later though) due to the lifetime/expiry issue. */ +If all good (and tls_certificate set), load the cert(s). */ if ( opt_set_and_noexpand(tls_certificate) # ifndef DISABLE_OCSP @@ -1468,6 +1470,18 @@ if ( opt_set_and_noexpand(tls_certificate) state_server.lib_state.conn_certs = TRUE; } } +else if ( !tls_certificate && !tls_privatekey +# ifndef DISABLE_OCSP + && !tls_ocsp_file +# endif + ) + { /* Generate & preload a selfsigned cert. No files to watch. */ + if ((tls_install_selfsign(&state_server, &dummy_errstr)) == OK) + { + state_server.lib_state.conn_certs = TRUE; + lifetime = f.running_in_test_harness ? 2 : 60 * 60; /* 1 hour */ + } + } else DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n"); @@ -1480,7 +1494,7 @@ if (opt_set_and_noexpand(tls_verify_certificates)) DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n"); if (creds_load_cabundle(&state_server, tls_verify_certificates, NULL, &dummy_errstr) != OK) - return; + return lifetime; state_server.lib_state.cabundle = TRUE; /* If CAs loaded and tls_crl is non-empty and has no $, load it */ @@ -1491,7 +1505,7 @@ if (opt_set_and_noexpand(tls_verify_certificates)) { DEBUG(D_tls) debug_printf("TLS: preloading CRL for server\n"); if (creds_load_crl(&state_server, tls_crl, &dummy_errstr) != OK) - return; + return lifetime; state_server.lib_state.crl = TRUE; } } @@ -1518,6 +1532,7 @@ if (!tls_require_ciphers || opt_set_and_noexpand(tls_require_ciphers)) } else DEBUG(D_tls) debug_printf("TLS: not preloading cipher list for server\n"); +return lifetime; } @@ -1532,8 +1547,9 @@ exim_gnutls_state_st tpt_dummy_state; host_item * dummy_host = (host_item *)1; uschar * dummy_errstr; -if (!exim_gnutls_base_init_done) - tls_g_init(); +if ( !exim_gnutls_base_init_done + && tls_g_init(&dummy_errstr) != OK) + return; ob->tls_preload = null_tls_preload; if (gnutls_certificate_allocate_credentials( @@ -1547,7 +1563,7 @@ creds_basic_init(ob->tls_preload.x509_cred, FALSE); tpt_dummy_state.session = NULL; tpt_dummy_state.lib_state = ob->tls_preload; -#ifdef EXIM_HAVE_INOTIFY +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) if ( opt_set_and_noexpand(ob->tls_certificate) && opt_unset_or_noexpand(ob->tls_privatekey)) { @@ -1611,7 +1627,7 @@ depends on DANE or plain usage. */ } -#ifdef EXIM_HAVE_INOTIFY +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) /* Invalidate the creds cached, by dropping the current ones. Call when we notice one of the source files has changed. */ @@ -1937,8 +1953,9 @@ exim_gnutls_state_st * state; int rc; size_t sz; -if (!exim_gnutls_base_init_done) - tls_g_init(); +if ( !exim_gnutls_base_init_done + && (rc = tls_g_init(errstr)) != OK) + return rc; if (host) { @@ -1986,7 +2003,7 @@ state->tls_require_ciphers = require_ciphers; state->host = host; /* This handles the variables that might get re-expanded after TLS SNI; -that's tls_certificate, tls_privatekey, tls_verify_certificates, tls_crl */ +tls_certificate, tls_privatekey, tls_verify_certificates, tls_crl */ DEBUG(D_tls) debug_printf("Expanding various TLS configuration options for session credentials\n");