X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/f985398df595fe154270458be5a9f1fe11530358..ef2e5890df09193717f9d345ffaaa406e2d8aae7:/src/src/tls-openssl.c diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index c02e42bbf..0c7772921 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -1642,11 +1642,24 @@ return OK; * One-time init credentials for server and client * **************************************************/ +static void +normalise_ciphers(uschar ** ciphers, const uschar * pre_expansion_ciphers) +{ +uschar * s = *ciphers; + +if (!s || !Ustrchr(s, '_')) return; /* no change needed */ + +if (s == pre_expansion_ciphers) + s = string_copy(s); /* get writable copy */ + +for (uschar * t = s; *t; t++) if (*t == '_') *t = '-'; +*ciphers = s; +} + static int server_load_ciphers(SSL_CTX * ctx, exim_openssl_state_st * state, uschar * ciphers, uschar ** errstr) { -for (uschar * s = ciphers; *s; s++ ) if (*s == '_') *s = '-'; DEBUG(D_tls) debug_printf("required ciphers: %s\n", ciphers); if (!SSL_CTX_set_cipher_list(ctx, CS ciphers)) return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr); @@ -1798,6 +1811,7 @@ else if (opt_set_and_noexpand(tls_require_ciphers)) { DEBUG(D_tls) debug_printf("TLS: preloading cipher list for server\n"); + normalise_ciphers(&tls_require_ciphers, tls_require_ciphers); if (server_load_ciphers(ctx, &state_server, tls_require_ciphers, &dummy_errstr) == OK) state_server.lib_state.pri_string = TRUE; @@ -1953,7 +1967,11 @@ typedef struct { /* Session ticket encryption key */ const EVP_CIPHER * aes_cipher; uschar aes_key[32]; /* size needed depends on cipher. aes_128 implies 128/8 = 16? */ +# if OPENSSL_VERSION_NUMBER < 0x30000000L const EVP_MD * hmac_hash; +# else + const uschar * hmac_hashname; +# endif uschar hmac_key[16]; time_t renew; time_t expire; @@ -1982,7 +2000,11 @@ if (RAND_bytes(exim_tk.name+1, sizeof(exim_tk.name)-1) <= 0) return; exim_tk.name[0] = 'E'; exim_tk.aes_cipher = EVP_aes_256_cbc(); +# if OPENSSL_VERSION_NUMBER < 0x30000000L exim_tk.hmac_hash = EVP_sha256(); +# else +exim_tk.hmac_hashname = US "sha256"; +# endif exim_tk.expire = t + ssl_session_timeout; exim_tk.renew = t + ssl_session_timeout/2; } @@ -2002,10 +2024,49 @@ return memcmp(name, exim_tk.name, sizeof(exim_tk.name)) == 0 ? &exim_tk : NULL; } + +static int +tk_hmac_init( +# if OPENSSL_VERSION_NUMBER < 0x30000000L + HMAC_CTX * hctx, +#else + EVP_MAC_CTX * hctx, +#endif + exim_stek * key + ) +{ +/*XXX will want these dependent on the ssl session strength */ +# if OPENSSL_VERSION_NUMBER < 0x30000000L + HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key), + key->hmac_hash, NULL); +#else + { + OSSL_PARAM params[3]; + uschar * hk = string_copy(key->hmac_hashname); /* need nonconst */ + params[0] = OSSL_PARAM_construct_octet_string("key", key->hmac_key, sizeof(key->hmac_key)); + params[1] = OSSL_PARAM_construct_utf8_string("digest", CS hk, 0); + params[2] = OSSL_PARAM_construct_end(); + if (EVP_MAC_CTX_set_params(hctx, params) == 0) + { + DEBUG(D_tls) debug_printf("EVP_MAC_CTX_set_params: %s\n", + ERR_reason_error_string(ERR_get_error())); + return 0; /* error in mac initialisation */ + } +} +#endif +return 1; +} + /* Callback for session tickets, on server */ static int ticket_key_callback(SSL * ssl, uschar key_name[16], - uschar * iv, EVP_CIPHER_CTX * c_ctx, HMAC_CTX * hctx, int enc) + uschar * iv, EVP_CIPHER_CTX * c_ctx, +# if OPENSSL_VERSION_NUMBER < 0x30000000L + HMAC_CTX * hctx, +#else + EVP_MAC_CTX * hctx, +#endif + int enc) { tls_support * tlsp = state_server.tlsp; exim_stek * key; @@ -2023,9 +2084,7 @@ if (enc) memcpy(key_name, key->name, 16); DEBUG(D_tls) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - time(NULL)); - /*XXX will want these dependent on the ssl session strength */ - HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key), - key->hmac_hash, NULL); + if (tk_hmac_init(hctx, key) == 0) return 0; EVP_EncryptInit_ex(c_ctx, key->aes_cipher, NULL, key->aes_key, iv); DEBUG(D_tls) debug_printf("ticket created\n"); @@ -2048,8 +2107,7 @@ else return 0; } - HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key), - key->hmac_hash, NULL); + if (tk_hmac_init(hctx, key) == 0) return 0; EVP_DecryptInit_ex(c_ctx, key->aes_cipher, NULL, key->aes_key, iv); DEBUG(D_tls) debug_printf("ticket usable, STEK expire " TIME_T_FMT "\n", key->expire - now); @@ -2062,7 +2120,7 @@ else return key->renew < now ? 2 : 1; } } -#endif +#endif /* !DISABLE_TLS_RESUME */ @@ -2464,7 +2522,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) { tls_out.ocsp = OCSP_FAILED; DEBUG(D_tls) ERR_print_errors(bp); - log_write(0, LOG_MAIN, "Server OSCP dates invalid"); + log_write(0, LOG_MAIN, "OCSP dates invalid"); goto failed; } @@ -3134,9 +3192,12 @@ else if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers, errstr)) return FAIL; - if ( expciphers - && (rc = server_load_ciphers(ctx, &state_server, expciphers, errstr)) != OK) - return rc; + if (expciphers) + { + normalise_ciphers(&expciphers, tls_require_ciphers); + if ((rc = server_load_ciphers(ctx, &state_server, expciphers, errstr)) != OK) + return rc; + } } /* If this is a host for which certificate verification is mandatory or @@ -3174,9 +3235,15 @@ else skip_certs: ; #ifndef DISABLE_TLS_RESUME +# if OPENSSL_VERSION_NUMBER < 0x30000000L SSL_CTX_set_tlsext_ticket_key_cb(ctx, ticket_key_callback); /* despite working, appears to always return failure, so ignoring */ +# else +SSL_CTX_set_tlsext_ticket_key_evp_cb(ctx, ticket_key_callback); +/* despite working, appears to always return failure, so ignoring */ +# endif #endif + #ifdef OPENSSL_HAVE_NUM_TICKETS # ifndef DISABLE_TLS_RESUME SSL_CTX_set_num_tickets(ctx, tls_in.host_resumable ? 1 : 0); @@ -3244,6 +3311,7 @@ if (rc <= 0) case SSL_ERROR_ZERO_RETURN: DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr); + (void) event_raise(event_action, US"tls:fail:connect", *errstr); if (SSL_get_shutdown(ssl) == SSL_RECEIVED_SHUTDOWN) SSL_shutdown(ssl); @@ -3261,8 +3329,9 @@ if (rc <= 0) || r == SSL_R_VERSION_TOO_LOW #endif || r == SSL_R_UNKNOWN_PROTOCOL || r == SSL_R_UNSUPPORTED_PROTOCOL) - s = string_sprintf("%s (%s)", s, SSL_get_version(ssl)); + s = string_sprintf("(%s)", SSL_get_version(ssl)); (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : s, errstr); + (void) event_raise(event_action, US"tls:fail:connect", *errstr); return FAIL; } @@ -3273,6 +3342,7 @@ if (rc <= 0) if (!errno) { *errstr = US"SSL_accept: TCP connection closed by peer"; + (void) event_raise(event_action, US"tls:fail:connect", *errstr); return FAIL; } DEBUG(D_tls) debug_printf(" - syscall %s\n", strerror(errno)); @@ -3281,6 +3351,7 @@ if (rc <= 0) sigalrm_seen ? US"timed out" : ERR_peek_error() ? NULL : string_sprintf("ret %d", error), errstr); + (void) event_raise(event_action, US"tls:fail:connect", *errstr); return FAIL; } } @@ -3831,21 +3902,25 @@ if (conn_args->dane) return FALSE; if (expciphers && *expciphers == '\0') expciphers = NULL; + + normalise_ciphers(&expciphers, ob->dane_require_tls_ciphers); } #endif -if (!expciphers && - !expand_check(ob->tls_require_ciphers, US"tls_require_ciphers", +if (!expciphers) + { + if (!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers", &expciphers, errstr)) - return FALSE; + return FALSE; -/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they -are separated by underscores. So that I can use either form in my tests, and -also for general convenience, we turn underscores into hyphens here. */ + /* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they + are separated by underscores. So that I can use either form in my tests, and + also for general convenience, we turn underscores into hyphens here. */ + + normalise_ciphers(&expciphers, ob->tls_require_ciphers); + } if (expciphers) { - uschar *s = expciphers; - while (*s) { if (*s == '_') *s = '-'; s++; } DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers); if (!SSL_CTX_set_cipher_list(exim_client_ctx->ctx, CS expciphers)) { @@ -4508,12 +4583,9 @@ if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers, if (!(expciphers && *expciphers)) return NULL; -/* normalisation ripped from above */ -s = expciphers; -while (*s != 0) { if (*s == '_') *s = '-'; s++; } +normalise_ciphers(&expciphers, tls_require_ciphers); err = NULL; - if (lib_ctx_new(&ctx, NULL, &err) == OK) { DEBUG(D_tls)