X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/3f7eeb86e15557a030b86e90d62708e96d68c023..a3c1395faebdb088bcef9cdb55bb42a791433ccd:/src/src/tls-openssl.c diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 9ead7945d..ebc5a6255 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 - 2009 */ +/* Copyright (c) University of Cambridge 1995 - 2012 */ /* See the file NOTICE for conditions of use and distribution. */ /* This module provides the TLS (aka SSL) support for Exim using the OpenSSL @@ -29,6 +29,10 @@ functions from the OpenSSL library. */ #define EXIM_OCSP_MAX_AGE (-1L) #endif +#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) +#define EXIM_HAVE_OPENSSL_TLSEXT +#endif + /* Structure for collecting random data for seeding. */ typedef struct randstuff { @@ -42,7 +46,9 @@ static BOOL verify_callback_called = FALSE; static const uschar *sid_ctx = US"exim"; static SSL_CTX *ctx = NULL; +#ifdef EXIM_HAVE_OPENSSL_TLSEXT static SSL_CTX *ctx_sni = NULL; +#endif static SSL *ssl = NULL; static char ssl_errstring[256]; @@ -77,7 +83,9 @@ static int setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional); /* Callbacks */ +#ifdef EXIM_HAVE_OPENSSL_TLSEXT static int tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg); +#endif #ifdef EXPERIMENTAL_OCSP static int tls_stapling_cb(SSL *s, void *arg); #endif @@ -302,10 +310,19 @@ else } else { - SSL_CTX_set_tmp_dh(ctx, dh); - DEBUG(D_tls) - debug_printf("Diffie-Hellman initialized from %s with %d-bit key\n", - dhexpanded, 8*DH_size(dh)); + if ((8*DH_size(dh)) > tls_dh_max_bits) + { + DEBUG(D_tls) + debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d", + 8*DH_size(dh), tls_dh_max_bits); + } + else + { + SSL_CTX_set_tmp_dh(ctx, dh); + DEBUG(D_tls) + debug_printf("Diffie-Hellman initialized from %s with %d-bit key\n", + dhexpanded, 8*DH_size(dh)); + } DH_free(dh); } BIO_free(bio); @@ -540,6 +557,7 @@ Arguments: Returns: SSL_TLSEXT_ERR_{OK,ALERT_WARNING,ALERT_FATAL,NOACK} */ +#ifdef EXIM_HAVE_OPENSSL_TLSEXT static int tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg) { @@ -606,6 +624,7 @@ SSL_set_SSL_CTX(s, ctx_sni); return SSL_TLSEXT_ERR_OK; } +#endif /* EXIM_HAVE_OPENSSL_TLSEXT */ @@ -768,7 +787,7 @@ rc = tls_expand_session_files(ctx, cbinfo); if (rc != OK) return rc; /* If we need to handle SNI, do so */ -#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) +#ifdef EXIM_HAVE_OPENSSL_TLSEXT if (host == NULL) { #ifdef EXPERIMENTAL_OCSP @@ -1006,11 +1025,6 @@ a TLS session. Arguments: require_ciphers allowed ciphers - ------------------------------------------------------ - require_mac list of allowed MACs ) Not used - require_kx list of allowed key_exchange methods ) for - require_proto list of allowed protocols ) OpenSSL - ------------------------------------------------------ Returns: OK on success DEFER for errors before the start of the negotiation @@ -1019,8 +1033,7 @@ Returns: OK on success */ int -tls_server_start(uschar *require_ciphers, uschar *require_mac, - uschar *require_kx, uschar *require_proto) +tls_server_start(const uschar *require_ciphers) { int rc; uschar *expciphers; @@ -1050,8 +1063,9 @@ if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers)) return FAIL; /* 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. */ +were historically separated by underscores. So that I can use either form in my +tests, and also for general convenience, we turn underscores into hyphens here. +*/ if (expciphers != NULL) { @@ -1185,11 +1199,6 @@ Argument: verify_certs file for certificate verify crl file containing CRL require_ciphers list of allowed ciphers - ------------------------------------------------------ - require_mac list of allowed MACs ) Not used - require_kx list of allowed key_exchange methods ) for - require_proto list of allowed protocols ) OpenSSL - ------------------------------------------------------ timeout startup timeout Returns: OK on success @@ -1201,8 +1210,7 @@ int tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam, uschar *certificate, uschar *privatekey, uschar *sni, uschar *verify_certs, uschar *crl, - uschar *require_ciphers, uschar *require_mac, uschar *require_kx, - uschar *require_proto, int timeout) + uschar *require_ciphers, int timeout) { static uschar txt[256]; uschar *expciphers; @@ -1251,8 +1259,14 @@ if (sni) tls_sni = NULL; else { +#ifdef EXIM_HAVE_OPENSSL_TLSEXT DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tls_sni); SSL_set_tlsext_host_name(ssl, tls_sni); +#else + DEBUG(D_tls) + debug_printf("OpenSSL at build-time lacked SNI support, ignoring \"%s\"\n", + tls_sni); +#endif } } @@ -1500,6 +1514,72 @@ tls_active = -1; +/************************************************* +* Let tls_require_ciphers be checked at startup * +*************************************************/ + +/* The tls_require_ciphers option, if set, must be something which the +library can parse. + +Returns: NULL on success, or error message +*/ + +uschar * +tls_validate_require_cipher(void) +{ +SSL_CTX *ctx; +uschar *s, *expciphers, *err; + +/* this duplicates from tls_init(), we need a better "init just global +state, for no specific purpose" singleton function of our own */ + +SSL_load_error_strings(); +OpenSSL_add_ssl_algorithms(); +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) +/* SHA256 is becoming ever more popular. This makes sure it gets added to the +list of available digests. */ +EVP_add_digest(EVP_sha256()); +#endif + +if (!(tls_require_ciphers && *tls_require_ciphers)) + return NULL; + +if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers)) + return US"failed to expand tls_require_ciphers"; + +if (!(expciphers && *expciphers)) + return NULL; + +/* normalisation ripped from above */ +s = expciphers; +while (*s != 0) { if (*s == '_') *s = '-'; s++; } + +err = NULL; + +ctx = SSL_CTX_new(SSLv23_server_method()); +if (!ctx) + { + ERR_error_string(ERR_get_error(), ssl_errstring); + return string_sprintf("SSL_CTX_new() failed: %s", ssl_errstring); + } + +DEBUG(D_tls) + debug_printf("tls_require_ciphers expands to \"%s\"\n", expciphers); + +if (!SSL_CTX_set_cipher_list(ctx, CS expciphers)) + { + ERR_error_string(ERR_get_error(), ssl_errstring); + err = string_sprintf("SSL_CTX_set_cipher_list(%s) failed", expciphers); + } + +SSL_CTX_free(ctx); + +return err; +} + + + + /************************************************* * Report the library versions. * *************************************************/ @@ -1527,7 +1607,7 @@ fprintf(f, "Library version: OpenSSL: Compile: %s\n" /************************************************* -* Pseudo-random number generation * +* Random number generation * *************************************************/ /* Pseudo-random number generation. The result is not expected to be @@ -1542,7 +1622,7 @@ Returns a random number in range [0, max-1] */ int -pseudo_random_number(int max) +vaguely_random_number(int max) { unsigned int r; int i, needed_len; @@ -1578,7 +1658,14 @@ if (i < needed_len) needed_len = i; /* We do not care if crypto-strong */ -(void) RAND_pseudo_bytes(smallbuf, needed_len); +i = RAND_pseudo_bytes(smallbuf, needed_len); +if (i < 0) + { + DEBUG(D_all) + debug_printf("OpenSSL RAND_pseudo_bytes() not supported by RAND method, using fallback.\n"); + return vaguely_random_number_fallback(max); + } + r = 0; for (p = smallbuf; needed_len; --needed_len, ++p) { @@ -1755,7 +1842,7 @@ uschar keep_c; BOOL adding, item_parsed; result = 0L; -/* Prior to 4.78 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed +/* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed * from default because it increases BEAST susceptibility. */ if (option_spec == NULL)