X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;ds=inline;f=src%2Fsrc%2Ftls-openssl.c;h=9ddb16fc419b5340db74af341a1ddceb6147c5ac;hb=96751ae76e6c6db435f5a4f141511d6f973b6583;hp=4c61fc0e6b2270fbc78f3466d88fcf99b69ce46c;hpb=6d05006594ffacbfde1c8c4e759332873a702087;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 4c61fc0e6..9ddb16fc4 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -94,6 +94,10 @@ change this guard and punt the issue for a while longer. */ # define EXIM_HAVE_OPENSSL_CIPHER_GET_ID #endif +#if !defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x030000000L) +# define EXIM_HAVE_EXPORT_CHNL_BNGNG +#endif + #if !defined(LIBRESSL_VERSION_NUMBER) \ || LIBRESSL_VERSION_NUMBER >= 0x20010000L # if !defined(OPENSSL_NO_ECDH) @@ -111,11 +115,16 @@ change this guard and punt the issue for a while longer. */ # define OPENSSL_HAVE_KEYLOG_CB # define OPENSSL_HAVE_NUM_TICKETS # define EXIM_HAVE_OPENSSL_CIPHER_STD_NAME +# define EXIM_HAVE_EXP_CHNL_BNGNG # else # define OPENSSL_BAD_SRVR_OURCERT # endif #endif +#if !defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x010002000L) +# define EXIM_HAVE_EXPORT_CHNL_BNGNG +#endif + #if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP) # warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile" # define DISABLE_OCSP @@ -942,36 +951,35 @@ Returns: nothing */ static void -info_callback(SSL *s, int where, int ret) +info_callback(SSL * s, int where, int ret) { DEBUG(D_tls) { - const uschar * str; - - if (where & SSL_ST_CONNECT) - str = US"SSL_connect"; - else if (where & SSL_ST_ACCEPT) - str = US"SSL_accept"; - else - str = US"SSL info (undefined)"; + gstring * g = NULL; + + if (where & SSL_ST_CONNECT) g = string_append_listele(g, ',', US"SSL_connect"); + if (where & SSL_ST_ACCEPT) g = string_append_listele(g, ',', US"SSL_accept"); + if (where & SSL_CB_LOOP) g = string_append_listele(g, ',', US"state_chg"); + if (where & SSL_CB_EXIT) g = string_append_listele(g, ',', US"hshake_exit"); + if (where & SSL_CB_READ) g = string_append_listele(g, ',', US"read"); + if (where & SSL_CB_WRITE) g = string_append_listele(g, ',', US"write"); + if (where & SSL_CB_ALERT) g = string_append_listele(g, ',', US"alert"); + if (where & SSL_CB_HANDSHAKE_START) g = string_append_listele(g, ',', US"hshake_start"); + if (where & SSL_CB_HANDSHAKE_DONE) g = string_append_listele(g, ',', US"hshake_done"); if (where & SSL_CB_LOOP) - debug_printf("%s: %s\n", str, SSL_state_string_long(s)); + debug_printf("SSL %s: %s\n", g->s, SSL_state_string_long(s)); else if (where & SSL_CB_ALERT) - debug_printf("SSL3 alert %s:%s:%s\n", - str = where & SSL_CB_READ ? US"read" : US"write", + debug_printf("SSL %s %s:%s\n", g->s, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); else if (where & SSL_CB_EXIT) { - if (ret == 0) - debug_printf("%s: failed in %s\n", str, SSL_state_string_long(s)); - else if (ret < 0) - debug_printf("%s: error in %s\n", str, SSL_state_string_long(s)); + if (ret <= 0) + debug_printf("SSL %s: %s in %s\n", g->s, + ret == 0 ? "failed" : "error", SSL_state_string_long(s)); } - else if (where & SSL_CB_HANDSHAKE_START) - debug_printf("%s: hshake start: %s\n", str, SSL_state_string_long(s)); - else if (where & SSL_CB_HANDSHAKE_DONE) - debug_printf("%s: hshake done: %s\n", str, SSL_state_string_long(s)); + else if (where & (SSL_CB_HANDSHAKE_START | SSL_CB_HANDSHAKE_DONE)) + debug_printf("SSL %s: %s\n", g->s, SSL_state_string_long(s)); } } @@ -1468,12 +1476,12 @@ return; static void -ocsp_free_response_list(exim_openssl_state_st * cbinfo) +ocsp_free_response_list(exim_openssl_state_st * state) { -for (ocsp_resplist * olist = cbinfo->u_ocsp.server.olist; olist; +for (ocsp_resplist * olist = state->u_ocsp.server.olist; olist; olist = olist->next) OCSP_RESPONSE_free(olist->resp); -cbinfo->u_ocsp.server.olist = NULL; +state->u_ocsp.server.olist = NULL; } #endif /*!DISABLE_OCSP*/ @@ -1565,6 +1573,11 @@ else if (olist && !*olist) olist = NULL; + /* If doing a re-expand after SNI, avoid reloading the OCSP + responses when the list of filenames has not changed. + The creds-invali on content change wipes file_expanded, so that + always reloads here. */ + if ( state->u_ocsp.server.file_expanded && olist && (Ustrcmp(olist, state->u_ocsp.server.file_expanded) == 0)) { @@ -1909,6 +1922,9 @@ tls_server_creds_invalidate(void) { SSL_CTX_free(state_server.lib_state.lib_ctx); state_server.lib_state = null_tls_preload; +#ifndef DISABLE_OCSP +state_server.u_ocsp.server.file_expanded = NULL; +#endif } @@ -2194,7 +2210,9 @@ already exists. Might even need this selfsame callback, for reneg? */ SSL_CTX * ctx = state_server.lib_state.lib_ctx; SSL_CTX_set_info_callback(server_sni, SSL_CTX_get_info_callback(ctx)); SSL_CTX_set_mode(server_sni, SSL_CTX_get_mode(ctx)); + SSL_CTX_set_min_proto_version(server_sni, SSL3_VERSION); SSL_CTX_set_options(server_sni, SSL_CTX_get_options(ctx)); + SSL_CTX_clear_options(server_sni, ~SSL_CTX_get_options(ctx)); SSL_CTX_set_timeout(server_sni, SSL_CTX_get_timeout(ctx)); SSL_CTX_set_tlsext_servername_callback(server_sni, tls_servername_cb); SSL_CTX_set_tlsext_servername_arg(server_sni, state); @@ -2710,10 +2728,15 @@ if (init_options) } #endif - DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options); - if (!(SSL_CTX_set_options(ctx, init_options))) - return tls_error(string_sprintf( + SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); + DEBUG(D_tls) debug_printf("setting SSL CTX options: %016lx\n", init_options); + SSL_CTX_set_options(ctx, init_options); + { + ulong readback = SSL_CTX_clear_options(ctx, ~init_options); + if (readback != init_options) + return tls_error(string_sprintf( "SSL_CTX_set_option(%#lx)", init_options), host, NULL, errstr); + } } else DEBUG(D_tls) debug_printf("no SSL CTX options to set\n"); @@ -2754,7 +2777,7 @@ if (state->lib_state.conn_certs) else { #ifndef DISABLE_OCSP - if (!host) + if (!host) /* server */ { state->u_ocsp.server.file = ocsp_file; state->u_ocsp.server.file_expanded = NULL; @@ -3170,6 +3193,52 @@ tls_dump_keylog(SSL * ssl) } +/* Channel-binding info for authenticators +See description in https://paquier.xyz/postgresql-2/channel-binding-openssl/ +for pre-TLS1.3 +*/ + +static void +tls_get_channel_binding(SSL * ssl, tls_support * tlsp, const void * taintval) +{ +uschar c, * s; +size_t len; + +#ifdef EXIM_HAVE_EXPORT_CHNL_BNGNG +if (SSL_version(ssl) > TLS1_2_VERSION) + { + /* It's not documented by OpenSSL how big the output buffer must be. + The OpenSSL testcases use 80 bytes but don't say why. The GnuTLS impl only + serves out 32B. RFC 9266 says it is 32B. + Interop fails unless we use the same each end. */ + len = 32; + + tlsp->channelbind_exporter = TRUE; + taintval = GET_UNTAINTED; + if (SSL_export_keying_material(ssl, + s = store_get((int)len, taintval), len, + "EXPORTER-Channel-Binding", (size_t) 24, + NULL, 0, 0) != 1) + len = 0; + } +else +#endif + { + len = SSL_get_peer_finished(ssl, &c, 0); + len = SSL_get_peer_finished(ssl, s = store_get((int)len, taintval), len); + } + +if (len > 0) + { + int old_pool = store_pool; + store_pool = POOL_PERM; + tlsp->channelbinding = b64encode_taint(CUS s, (int)len, taintval); + store_pool = old_pool; + DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p %p\n", tlsp->channelbinding, tlsp); + } +} + + /************************************************* * Start a TLS session in a server * *************************************************/ @@ -3446,6 +3515,7 @@ else DEBUG(D_tls) adjust the input functions to read via TLS, and initialize things. */ #ifdef SSL_get_extms_support +/*XXX what does this return for tls1.3 ? */ tls_in.ext_master_secret = SSL_get_extms_support(ssl) == 1; #endif peer_cert(ssl, &tls_in, peerdn, sizeof(peerdn)); @@ -3478,19 +3548,7 @@ DEBUG(D_tls) tls_in.ourcert = crt ? X509_dup(crt) : NULL; } -/* Channel-binding info for authenticators -See description in https://paquier.xyz/postgresql-2/channel-binding-openssl/ */ - { - uschar c, * s; - size_t len = SSL_get_peer_finished(ssl, &c, 0); - int old_pool = store_pool; - - SSL_get_peer_finished(ssl, s = store_get((int)len, GET_UNTAINTED), len); - store_pool = POOL_PERM; - tls_in.channelbinding = b64encode_taint(CUS s, (int)len, GET_UNTAINTED); - store_pool = old_pool; - DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p\n", tls_in.channelbinding); - } +tls_get_channel_binding(ssl, &tls_in, GET_UNTAINTED); /* Only used by the server-side tls (tls_in), including tls_getc. Client-side (tls_out) reads (seem to?) go via @@ -4168,18 +4226,7 @@ tlsp->cipher_stdname = cipher_stdname_ssl(exim_client_ctx->ssl); } /*XXX will this work with continued-TLS? */ -/* Channel-binding info for authenticators */ - { - uschar c, * s; - size_t len = SSL_get_finished(exim_client_ctx->ssl, &c, 0); - int old_pool = store_pool; - - SSL_get_finished(exim_client_ctx->ssl, s = store_get((int)len, GET_TAINTED), len); - store_pool = POOL_PERM; - tlsp->channelbinding = b64encode_taint(CUS s, (int)len, GET_TAINTED); - store_pool = old_pool; - DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p %p\n", tlsp->channelbinding, tlsp); - } +tls_get_channel_binding(exim_client_ctx->ssl, tlsp, GET_TAINTED); tlsp->active.sock = cctx->sock; tlsp->active.tls_ctx = exim_client_ctx;