X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Ftls-openssl.c;h=17cc72133daf5e1afd9f2aed0678c59d37a52eb2;hb=2c9a0e86055f1e86ca5cdde421f5f8c9a48b0194;hp=de9c659a6ce8efdc67c682f38132b603efbf4afa;hpb=3bcbbbe2697819d248259b1938ffd52d2bf4090b;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index de9c659a6..17cc72133 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -46,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]; @@ -273,51 +275,85 @@ DEBUG(D_tls) debug_printf("SSL info: %s\n", SSL_state_string_long(s)); /* If dhparam is set, expand it, and load up the parameters for DH encryption. Arguments: - dhparam DH parameter file + dhparam DH parameter file or fixed parameter identity string host connected host, if client; NULL if server Returns: TRUE if OK (nothing to set up, or setup worked) */ static BOOL -init_dh(uschar *dhparam, host_item *host) +init_dh(SSL_CTX *sctx, uschar *dhparam, host_item *host) { -BOOL yield = TRUE; BIO *bio; DH *dh; uschar *dhexpanded; +const char *pem; if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded)) return FALSE; -if (dhexpanded == NULL) return TRUE; - -if ((bio = BIO_new_file(CS dhexpanded, "r")) == NULL) +if (dhexpanded == NULL || *dhexpanded == '\0') { - tls_error(string_sprintf("could not read dhparams file %s", dhexpanded), - host, (uschar *)strerror(errno)); - yield = FALSE; + bio = BIO_new_mem_buf(CS std_dh_prime_default(), -1); } -else +else if (dhexpanded[0] == '/') { - if ((dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)) == NULL) + bio = BIO_new_file(CS dhexpanded, "r"); + if (bio == NULL) { tls_error(string_sprintf("could not read dhparams file %s", dhexpanded), - host, NULL); - yield = FALSE; + host, US strerror(errno)); + return FALSE; } - else + } +else + { + if (Ustrcmp(dhexpanded, "none") == 0) { - 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); + DEBUG(D_tls) debug_printf("Requested no DH parameters.\n"); + return TRUE; + } + + pem = std_dh_prime_named(dhexpanded); + if (!pem) + { + tls_error(string_sprintf("Unknown standard DH prime \"%s\"", dhexpanded), + host, US strerror(errno)); + return FALSE; } + bio = BIO_new_mem_buf(CS pem, -1); + } + +dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); +if (dh == NULL) + { BIO_free(bio); + tls_error(string_sprintf("Could not read tls_dhparams \"%s\"", dhexpanded), + host, NULL); + return FALSE; } -return yield; +/* Even if it is larger, we silently return success rather than cause things + * to fail out, so that a too-large DH will not knock out all TLS; it's a + * debatable choice. */ +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(sctx, dh); + DEBUG(D_tls) + debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n", + dhexpanded ? dhexpanded : US"default", 8*DH_size(dh)); + } + +DH_free(dh); +BIO_free(bio); + +return TRUE; } @@ -608,6 +644,9 @@ OCSP information. */ rc = tls_expand_session_files(ctx_sni, cbinfo); if (rc != OK) return SSL_TLSEXT_ERR_NOACK; +rc = init_dh(ctx_sni, cbinfo->dhparam, NULL); +if (rc != OK) return SSL_TLSEXT_ERR_NOACK; + DEBUG(D_tls) debug_printf("Switching SSL context.\n"); SSL_set_SSL_CTX(s, ctx_sni); @@ -705,7 +744,13 @@ list of available digests. */ EVP_add_digest(EVP_sha256()); #endif -/* Create a context */ +/* Create a context. +The OpenSSL docs in 1.0.1b have not been updated to clarify TLS variant +negotiation in the different methods; as far as I can tell, the only +*_{server,client}_method which allows negotiation is SSLv23, which exists even +when OpenSSL is built without SSLv2 support. +By disabling with openssl_options, we can let admins re-enable with the +existing knob. */ ctx = SSL_CTX_new((host == NULL)? SSLv23_server_method() : SSLv23_client_method()); @@ -768,7 +813,7 @@ else /* Initialize with DH parameters if supplied */ -if (!init_dh(dhparam, host)) return DEFER; +if (!init_dh(ctx, dhparam, host)) return DEFER; /* Set up certificate and key (and perhaps OCSP info) */ @@ -1244,12 +1289,22 @@ if (sni) { if (!expand_check(sni, US"tls_sni", &tls_sni)) return FAIL; - if (!Ustrlen(tls_sni)) + if (tls_sni == NULL) + { + DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n"); + } + else if (!Ustrlen(tls_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 } } @@ -1497,6 +1552,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. * *************************************************/ @@ -1761,6 +1882,9 @@ BOOL adding, item_parsed; result = 0L; /* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed * from default because it increases BEAST susceptibility. */ +#ifdef SSL_OP_NO_SSLv2 +result |= SSL_OP_NO_SSLv2; +#endif if (option_spec == NULL) {