X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/ba86e143c7aeb0d70ea4c9d73a617a98f06f6baa..a28050f855e0011e0b6f1b395d65e3cebcb277a2:/src/src/tls-openssl.c diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index f1176a63e..bfdfe211f 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2017 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* Portions Copyright (c) The OpenSSL Project 1999 */ @@ -28,7 +28,7 @@ functions from the OpenSSL library. */ #ifndef DISABLE_OCSP # include #endif -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE # include "danessl.h" #endif @@ -51,7 +51,7 @@ functions from the OpenSSL library. */ # define EXIM_HAVE_RAND_PSEUDO #endif #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) -# define EXIM_HAVE_SHA256 +# define EXIM_HAVE_SHA256 /*MMMM*/ #endif /* @@ -81,7 +81,7 @@ functions from the OpenSSL library. */ || LIBRESSL_VERSION_NUMBER >= 0x20010000L # if !defined(OPENSSL_NO_ECDH) # if OPENSSL_VERSION_NUMBER >= 0x0090800fL -# define EXIM_HAVE_ECDH +# define EXIM_HAVE_ECDH /*MMMM*/ # endif # if OPENSSL_VERSION_NUMBER >= 0x10002000L # define EXIM_HAVE_OPENSSL_EC_NIST2NID @@ -94,6 +94,10 @@ functions from the OpenSSL library. */ # define DISABLE_OCSP #endif +#ifdef EXIM_HAVE_OPENSSL_CHECKHOST +# include +#endif + /* Structure for collecting random data for seeding. */ typedef struct randstuff { @@ -147,8 +151,8 @@ static BOOL reexpand_tls_files_for_sni = FALSE; typedef struct tls_ext_ctx_cb { uschar *certificate; uschar *privatekey; -#ifndef DISABLE_OCSP BOOL is_server; +#ifndef DISABLE_OCSP STACK_OF(X509) *verify_stack; /* chain for verifying the proof */ union { struct { @@ -228,14 +232,13 @@ return host ? FAIL : DEFER; -#ifdef EXIM_HAVE_EPHEM_RSA_KEX /************************************************* * Callback to generate RSA key * *************************************************/ /* Arguments: - s SSL connection + s SSL connection (not used) export not used keylength keylength @@ -270,7 +273,6 @@ if (!(rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL))) } return rsa_key; } -#endif @@ -510,7 +512,7 @@ return verify_callback(preverify_ok, x509ctx, &tls_in, } -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE /* This gets called *by* the dane library verify callback, which interposes itself. @@ -538,8 +540,21 @@ DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n", #endif if (preverify_ok == 1) - tls_out.dane_verified = - tls_out.certificate_verified = TRUE; + { + tls_out.dane_verified = tls_out.certificate_verified = TRUE; +#ifndef DISABLE_OCSP + if (client_static_cbinfo->u_ocsp.client.verify_store) + { /* client, wanting stapling */ + /* Add the server cert's signing chain as the one + for the verification of the OCSP stapled information. */ + + if (!X509_STORE_add_cert(client_static_cbinfo->u_ocsp.client.verify_store, + cert)) + ERR_clear_error(); + sk_X509_push(client_static_cbinfo->verify_stack, cert); + } +#endif + } else { int err = X509_STORE_CTX_get_error(x509ctx); @@ -551,7 +566,7 @@ else return preverify_ok; } -#endif /*EXPERIMENTAL_DANE*/ +#endif /*SUPPORT_DANE*/ /************************************************* @@ -889,7 +904,7 @@ We do not free the stack since it could be needed a second time for SNI handling. Separately we might try to replace using OCSP_basic_verify() - which seems to not -be a public interface into the OpenSSL library (there's no manual entry) - +be a public interface into the OpenSSL library (there's no manual entry) - But what with? We also use OCSP_basic_verify in the client stapling callback. And there we NEED it; we must verify that status... unless the library does it for us anyway? */ @@ -935,7 +950,7 @@ if (!OCSP_check_validity(thisupd, nextupd, EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX } supply_response: - cbinfo->u_ocsp.server.response = resp; + cbinfo->u_ocsp.server.response = resp; /*XXX stack?*/ return; bad: @@ -943,7 +958,7 @@ bad: { extern char ** environ; uschar ** p; - if (environ) for (p = USS environ; *p != NULL; p++) + if (environ) for (p = USS environ; *p; p++) if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0) { DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n"); @@ -977,8 +992,7 @@ if (!(x509 = X509_new())) goto err; where = US"generating pkey"; - /* deprecated, use RSA_generate_key_ex() */ -if (!(rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL))) +if (!(rsa = rsa_callback(NULL, 0, 1024))) goto err; where = US"assigning pkey"; @@ -1133,6 +1147,7 @@ else #ifndef DISABLE_OCSP if (cbinfo->is_server && cbinfo->u_ocsp.server.file) { + /*XXX stack*/ if (!expand_check(cbinfo->u_ocsp.server.file, US"tls_ocsp_file", &expanded, errstr)) return DEFER; @@ -1270,9 +1285,15 @@ static int tls_server_stapling_cb(SSL *s, void *arg) { const tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg; -uschar *response_der; +uschar *response_der; /*XXX blob */ int response_der_len; +/*XXX stack: use SSL_get_certificate() to see which cert; from that work +out which ocsp blob to send. Unfortunately, SSL_get_certificate is known +buggy in current OpenSSL; it returns the last cert loaded always rather than +the one actually presented. So we can't support a stack of OCSP proofs at +this time. */ + DEBUG(D_tls) debug_printf("Received TLS status request (OCSP stapling); %s response\n", cbinfo->u_ocsp.server.response ? "have" : "lack"); @@ -1282,7 +1303,7 @@ if (!cbinfo->u_ocsp.server.response) return SSL_TLSEXT_ERR_NOACK; response_der = NULL; -response_der_len = i2d_OCSP_RESPONSE(cbinfo->u_ocsp.server.response, +response_der_len = i2d_OCSP_RESPONSE(cbinfo->u_ocsp.server.response, /*XXX stack*/ &response_der); if (response_der_len <= 0) return SSL_TLSEXT_ERR_NOACK; @@ -1356,7 +1377,7 @@ if(!(bs = OCSP_response_get1_basic(rsp))) int status, reason; ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; - DEBUG(D_tls) bp = BIO_new_fp(stderr, BIO_NOCLOSE); + DEBUG(D_tls) bp = BIO_new_fp(debug_file, BIO_NOCLOSE); /*OCSP_RESPONSE_print(bp, rsp, 0); extreme debug: stapling content */ @@ -1367,10 +1388,12 @@ if(!(bs = OCSP_response_get1_basic(rsp))) cbinfo->u_ocsp.client.verify_store, 0)) <= 0) { tls_out.ocsp = OCSP_FAILED; - if (LOGGING(tls_cipher)) - log_write(0, LOG_MAIN, "Received TLS cert status response, itself unverifiable"); + if (LOGGING(tls_cipher)) log_write(0, LOG_MAIN, + "Received TLS cert status response, itself unverifiable: %s", + ERR_reason_error_string(ERR_peek_error())); BIO_printf(bp, "OCSP response verify failure\n"); ERR_print_errors(bp); + OCSP_RESPONSE_print(bp, rsp, 0); goto failed; } @@ -1474,7 +1497,7 @@ static int tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate, uschar *privatekey, #ifndef DISABLE_OCSP - uschar *ocsp_file, + uschar *ocsp_file, /*XXX stack, in server*/ #endif address_item *addr, tls_ext_ctx_cb ** cbp, uschar ** errstr) { @@ -1486,9 +1509,10 @@ tls_ext_ctx_cb * cbinfo; cbinfo = store_malloc(sizeof(tls_ext_ctx_cb)); cbinfo->certificate = certificate; cbinfo->privatekey = privatekey; +cbinfo->is_server = host==NULL; #ifndef DISABLE_OCSP cbinfo->verify_stack = NULL; -if ((cbinfo->is_server = host==NULL)) +if (!host) { cbinfo->u_ocsp.server.file = ocsp_file; cbinfo->u_ocsp.server.file_expanded = NULL; @@ -1577,9 +1601,15 @@ if (init_options) else DEBUG(D_tls) debug_printf("no SSL CTX options to set\n"); -/* Disable session cache unconditionally */ - +/* We'd like to disable session cache unconditionally, but foolish Outlook +Express clients then give up the first TLS connection and make a second one +(which works). Only when there is an IMAP service on the same machine. +Presumably OE is trying to use the cache for A on B. Leave it enabled for +now, until we work out a decent way of presenting control to the config. It +will never be used because we use a new context every time. */ +#ifdef notdef (void) SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); +#endif /* Initialize with DH parameters if supplied */ /* Initialize ECDH temp key parameter selection */ @@ -1730,6 +1760,9 @@ chain_from_pem_file(const uschar * file, STACK_OF(X509) * verify_stack) BIO * bp; X509 * x; +while (sk_X509_num(verify_stack) > 0) + X509_free(sk_X509_pop(verify_stack)); + if (!(bp = BIO_new_file(CS file, "r"))) return FALSE; while ((x = PEM_read_bio_X509(bp, NULL, 0, NULL))) sk_X509_push(verify_stack, x); @@ -1739,7 +1772,8 @@ return TRUE; -/* Called by both client and server startup +/* Called by both client and server startup; on the server possibly +repeated after a Server Name Indication. Arguments: sctx SSL_CTX* to initialise @@ -1801,7 +1835,7 @@ if (expcerts && *expcerts) ) { log_write(0, LOG_MAIN|LOG_PANIC, - "failed to load cert hain from %s", file); + "failed to load cert chain from %s", file); return DEFER; } #endif @@ -1831,9 +1865,9 @@ if (expcerts && *expcerts) { STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file); + SSL_CTX_set_client_CA_list(sctx, names); DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n", sk_X509_NAME_num(names)); - SSL_CTX_set_client_CA_list(sctx, names); } } } @@ -1944,7 +1978,7 @@ the error. */ rc = tls_init(&server_ctx, NULL, tls_dhparam, tls_certificate, tls_privatekey, #ifndef DISABLE_OCSP - tls_ocsp_file, + tls_ocsp_file, /*XXX stack*/ #endif NULL, &server_static_cbinfo, errstr); if (rc != OK) return rc; @@ -1972,7 +2006,7 @@ if (expciphers) optional, set up appropriately. */ tls_in.certificate_verified = FALSE; -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE tls_in.dane_verified = FALSE; #endif server_verify_callback_called = FALSE; @@ -2071,9 +2105,9 @@ DEBUG(D_tls) smtp_read_response()/ip_recv(). Hence no need to duplicate for _in and _out. */ -ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size); +if (!ssl_xfer_buffer) ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size); ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0; -ssl_xfer_eof = ssl_xfer_error = 0; +ssl_xfer_eof = ssl_xfer_error = FALSE; receive_getc = tls_getc; receive_getbuf = tls_getbuf; @@ -2131,7 +2165,7 @@ return OK; } -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE static int dane_tlsa_load(SSL * ssl, host_item * host, dns_answer * dnsa, uschar ** errstr) { @@ -2186,7 +2220,7 @@ if (found) log_write(0, LOG_MAIN, "DANE error: No usable TLSA records"); return DEFER; } -#endif /*EXPERIMENTAL_DANE*/ +#endif /*SUPPORT_DANE*/ @@ -2212,7 +2246,7 @@ Returns: OK on success int tls_client_start(int fd, host_item *host, address_item *addr, transport_instance * tb, -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE dns_answer * tlsa_dnsa, #endif uschar ** errstr) @@ -2229,13 +2263,13 @@ BOOL request_ocsp = FALSE; BOOL require_ocsp = FALSE; #endif -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE tls_out.tlsa_usage = 0; #endif #ifndef DISABLE_OCSP { -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE if ( tlsa_dnsa && ob->hosts_request_ocsp[0] == '*' && ob->hosts_request_ocsp[1] == '\0' @@ -2253,7 +2287,7 @@ tls_out.tlsa_usage = 0; verify_check_given_host(&ob->hosts_require_ocsp, host) == OK)) request_ocsp = TRUE; else -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE if (!request_ocsp) # endif request_ocsp = @@ -2272,8 +2306,23 @@ if (rc != OK) return rc; tls_out.certificate_verified = FALSE; client_verify_callback_called = FALSE; -if (!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers", - &expciphers, errstr)) +expciphers = NULL; +#ifdef SUPPORT_DANE +if (tlsa_dnsa) + { + /* We fall back to tls_require_ciphers if unset, empty or forced failure, but + other failures should be treated as problems. */ + if (ob->dane_require_tls_ciphers && + !expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers", + &expciphers, errstr)) + return FAIL; + if (expciphers && *expciphers == '\0') + expciphers = NULL; + } +#endif +if (!expciphers && + !expand_check(ob->tls_require_ciphers, US"tls_require_ciphers", + &expciphers, errstr)) return FAIL; /* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they @@ -2289,7 +2338,7 @@ if (expciphers) return tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr); } -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE if (tlsa_dnsa) { SSL_CTX_set_verify(client_ctx, @@ -2337,7 +2386,7 @@ if (ob->tls_sni) } } -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE if (tlsa_dnsa) if ((rc = dane_tlsa_load(client_ssl, host, tlsa_dnsa, errstr)) != OK) return rc; @@ -2346,7 +2395,7 @@ if (tlsa_dnsa) #ifndef DISABLE_OCSP /* Request certificate status at connection-time. If the server does OCSP stapling we will get the callback (set in tls_init()) */ -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE if (request_ocsp) { const uschar * s; @@ -2383,7 +2432,7 @@ alarm(ob->command_timeout); rc = SSL_connect(client_ssl); alarm(0); -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE if (tlsa_dnsa) DANESSL_cleanup(client_ssl); #endif @@ -2444,7 +2493,14 @@ if (error == SSL_ERROR_ZERO_RETURN) receive_ferror = smtp_ferror; receive_smtp_buffered = smtp_buffered; + if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN) + SSL_shutdown(server_ssl); + + sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free); SSL_free(server_ssl); + SSL_CTX_free(server_ctx); + server_static_cbinfo->verify_stack = NULL; + server_ctx = NULL; server_ssl = NULL; tls_in.active = -1; tls_in.bits = 0; @@ -2461,14 +2517,14 @@ else if (error == SSL_ERROR_SSL) { ERR_error_string(ERR_get_error(), ssl_errstring); log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring); - ssl_xfer_error = 1; + ssl_xfer_error = TRUE; return FALSE; } else if (error != SSL_ERROR_NONE) { DEBUG(D_tls) debug_printf("Got SSL error %d\n", error); - ssl_xfer_error = 1; + ssl_xfer_error = TRUE; return FALSE; } @@ -2678,15 +2734,19 @@ return len; daemon, to shut down the TLS library, without actually doing a shutdown (which would tamper with the SSL session in the parent process). -Arguments: TRUE if SSL_shutdown is to be called +Arguments: + shutdown 1 if TLS close-alert is to be sent, + 2 if also response to be waited for + Returns: nothing Used by both server-side and client-side TLS. */ void -tls_close(BOOL is_server, BOOL shutdown) +tls_close(BOOL is_server, int shutdown) { +SSL_CTX **ctxp = is_server ? &server_ctx : &client_ctx; SSL **sslp = is_server ? &server_ssl : &client_ssl; int *fdp = is_server ? &tls_in.active : &tls_out.active; @@ -2694,13 +2754,35 @@ if (*fdp < 0) return; /* TLS was not active */ if (shutdown) { - DEBUG(D_tls) debug_printf("tls_close(): shutting down SSL\n"); - SSL_shutdown(*sslp); + int rc; + DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n", + shutdown > 1 ? " (with response-wait)" : ""); + + if ( (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */ + && shutdown > 1) + { + alarm(2); + rc = SSL_shutdown(*sslp); /* wait for response */ + alarm(0); + } + + if (rc < 0) DEBUG(D_tls) + { + ERR_error_string(ERR_get_error(), ssl_errstring); + debug_printf("SSL_shutdown: %s\n", ssl_errstring); + } } +if (is_server) + { + sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free); + server_static_cbinfo->verify_stack = NULL; + } + +SSL_CTX_free(*ctxp); SSL_free(*sslp); +*ctxp = NULL; *sslp = NULL; - *fdp = -1; }