X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Ftls-openssl.c;h=5e8c804e5789be729b892f0c6f8e5d7f4389104e;hp=78b28f5e84cabb9fe6210c92e68f235d4458d0d0;hb=da3ad30dcfbb4770835c2b7e165bb719f76cfc16;hpb=453a6645ece01ed49ff175d43d660daef435d301;ds=sidebyside diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 78b28f5e8..5e8c804e5 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -1,5 +1,3 @@ -/* $Cambridge: exim/src/src/tls-openssl.c,v 1.26 2010/06/05 10:34:29 pdp Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ @@ -349,6 +347,9 @@ level. */ SSL_CTX_set_info_callback(ctx, (void (*)())info_callback); +/* Automatically re-try reads/writes after renegotiation. */ +(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); + /* Apply administrator-supplied work-arounds. Historically we applied just one requested option, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS, but when bug 994 requested a second, we @@ -360,7 +361,7 @@ availability of the option value macros from OpenSSL. */ okay = tls_openssl_options_parse(openssl_options, &init_options); if (!okay) - return tls_error("openssl_options parsing failed", host, NULL); + return tls_error(US"openssl_options parsing failed", host, NULL); if (init_options) { @@ -438,9 +439,11 @@ static void construct_cipher_name(SSL *ssl) { static uschar cipherbuf[256]; -SSL_CIPHER *c; +/* With OpenSSL 1.0.0a, this needs to be const but the documentation doesn't +yet reflect that. It should be a safe change anyway, even 0.9.8 versions have +the accessor functions use const in the prototype. */ +const SSL_CIPHER *c; uschar *ver; -int bits; switch (ssl->session->ssl_version) { @@ -456,15 +459,27 @@ switch (ssl->session->ssl_version) ver = US"TLSv1"; break; +#ifdef TLS1_1_VERSION + case TLS1_1_VERSION: + ver = US"TLSv1.1"; + break; +#endif + +#ifdef TLS1_2_VERSION + case TLS1_2_VERSION: + ver = US"TLSv1.2"; + break; +#endif + default: ver = US"UNKNOWN"; } -c = SSL_get_current_cipher(ssl); -SSL_CIPHER_get_bits(c, &bits); +c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl); +SSL_CIPHER_get_bits(c, &tls_bits); string_format(cipherbuf, sizeof(cipherbuf), "%s:%s:%u", ver, - SSL_CIPHER_get_name(c), bits); + SSL_CIPHER_get_name(c), tls_bits); tls_cipher = cipherbuf; DEBUG(D_tls) debug_printf("Cipher: %s\n", cipherbuf); @@ -680,7 +695,19 @@ else if (verify_check_host(&tls_try_verify_hosts) == OK) /* Prepare for new connection */ if ((ssl = SSL_new(ctx)) == NULL) return tls_error(US"SSL_new", NULL, NULL); -SSL_clear(ssl); + +/* Warning: we used to SSL_clear(ssl) here, it was removed. + * + * With the SSL_clear(), we get strange interoperability bugs with + * OpenSSL 1.0.1b and TLS1.1/1.2. It looks as though this may be a bug in + * OpenSSL itself, as a clear should not lead to inability to follow protocols. + * + * The SSL_clear() call is to let an existing SSL* be reused, typically after + * session shutdown. In this case, we have a brand new object and there's no + * obvious reason to immediately clear it. I'm guessing that this was + * originally added because of incomplete initialisation which the clear fixed, + * in some historic release. + */ /* Set context and tell client to go ahead, except in the case of TLS startup on connection, where outputting anything now upsets the clients and tends to @@ -714,7 +741,7 @@ if (rc <= 0) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL); if (ERR_get_error() == 0) log_write(0, LOG_MAIN, - " => client disconnected cleanly (rejected our certificate?)\n"); + "TLS client disconnected cleanly (rejected our certificate?)"); return FAIL; } @@ -873,8 +900,8 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm) int error; int inbytes; - DEBUG(D_tls) debug_printf("Calling SSL_read(%lx, %lx, %u)\n", (long)ssl, - (long)ssl_xfer_buffer, ssl_xfer_buffer_size); + DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl, + ssl_xfer_buffer, ssl_xfer_buffer_size); if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout); inbytes = SSL_read(ssl, CS ssl_xfer_buffer, ssl_xfer_buffer_size); @@ -920,6 +947,7 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm) ssl_xfer_error = 1; return EOF; } + #ifndef DISABLE_DKIM dkim_exim_verify_feed(ssl_xfer_buffer, inbytes); #endif @@ -953,8 +981,8 @@ tls_read(uschar *buff, size_t len) int inbytes; int error; -DEBUG(D_tls) debug_printf("Calling SSL_read(%lx, %lx, %u)\n", (long)ssl, - (long)buff, (unsigned int)len); +DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl, + buff, (unsigned int)len); inbytes = SSL_read(ssl, CS buff, len); error = SSL_get_error(ssl, inbytes); @@ -996,10 +1024,10 @@ int outbytes; int error; int left = len; -DEBUG(D_tls) debug_printf("tls_do_write(%lx, %d)\n", (long)buff, left); +DEBUG(D_tls) debug_printf("tls_do_write(%p, %d)\n", buff, left); while (left > 0) { - DEBUG(D_tls) debug_printf("SSL_write(SSL, %lx, %d)\n", (long)buff, left); + DEBUG(D_tls) debug_printf("SSL_write(SSL, %p, %d)\n", buff, left); outbytes = SSL_write(ssl, CS buff, left); error = SSL_get_error(ssl, outbytes); DEBUG(D_tls) debug_printf("outbytes=%d error=%d\n", outbytes, error); @@ -1078,8 +1106,10 @@ Returns: nothing void tls_version_report(FILE *f) { -fprintf(f, "OpenSSL compile-time version: %s\n", OPENSSL_VERSION_TEXT); -fprintf(f, "OpenSSL runtime version: %s\n", SSLeay_version(SSLEAY_VERSION)); +fprintf(f, "Library version: OpenSSL: Compile: %s\n" + " Runtime: %s\n", + OPENSSL_VERSION_TEXT, + SSLeay_version(SSLEAY_VERSION)); } @@ -1175,70 +1205,97 @@ all options unless explicitly for DTLS, let the administrator choose which to apply. This list is current as of: - ==> 0.9.8n <== */ + ==> 1.0.1b <== */ static struct exim_openssl_option exim_openssl_options[] = { /* KEEP SORTED ALPHABETICALLY! */ #ifdef SSL_OP_ALL - { "all", SSL_OP_ALL }, + { US"all", SSL_OP_ALL }, #endif #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION - { "allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION }, + { US"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION }, #endif #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - { "cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE }, + { US"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE }, #endif #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - { "dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS }, + { US"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS }, #endif #ifdef SSL_OP_EPHEMERAL_RSA - { "ephemeral_rsa", SSL_OP_EPHEMERAL_RSA }, + { US"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA }, #endif #ifdef SSL_OP_LEGACY_SERVER_CONNECT - { "legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT }, + { US"legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT }, #endif #ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER - { "microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER }, + { US"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER }, #endif #ifdef SSL_OP_MICROSOFT_SESS_ID_BUG - { "microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG }, + { US"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG }, #endif #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING - { "msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING }, + { US"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING }, #endif #ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG - { "netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG }, + { US"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG }, #endif #ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG - { "netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG }, + { US"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG }, +#endif +#ifdef SSL_OP_NO_COMPRESSION + { US"no_compression", SSL_OP_NO_COMPRESSION }, #endif #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - { "no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION }, + { US"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION }, +#endif +#ifdef SSL_OP_NO_SSLv2 + { US"no_sslv2", SSL_OP_NO_SSLv2 }, +#endif +#ifdef SSL_OP_NO_SSLv3 + { US"no_sslv3", SSL_OP_NO_SSLv3 }, +#endif +#ifdef SSL_OP_NO_TICKET + { US"no_ticket", SSL_OP_NO_TICKET }, +#endif +#ifdef SSL_OP_NO_TLSv1 + { US"no_tlsv1", SSL_OP_NO_TLSv1 }, +#endif +#ifdef SSL_OP_NO_TLSv1_1 +#if SSL_OP_NO_TLSv1_1 == 0x00000400L + /* Error in chosen value in 1.0.1a; see first item in CHANGES for 1.0.1b */ +#warning OpenSSL 1.0.1a uses a bad value for SSL_OP_NO_TLSv1_1, ignoring +#else + { US"no_tlsv1_1", SSL_OP_NO_TLSv1_1 }, +#endif +#endif +#ifdef SSL_OP_NO_TLSv1_2 + { US"no_tlsv1_2", SSL_OP_NO_TLSv1_2 }, #endif #ifdef SSL_OP_SINGLE_DH_USE - { "single_dh_use", SSL_OP_SINGLE_DH_USE }, + { US"single_dh_use", SSL_OP_SINGLE_DH_USE }, #endif #ifdef SSL_OP_SINGLE_ECDH_USE - { "single_ecdh_use", SSL_OP_SINGLE_ECDH_USE }, + { US"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE }, #endif #ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG - { "ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG }, + { US"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG }, #endif #ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG - { "sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG }, + { US"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG }, #endif #ifdef SSL_OP_TLS_BLOCK_PADDING_BUG - { "tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG }, + { US"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG }, #endif #ifdef SSL_OP_TLS_D5_BUG - { "tls_d5_bug", SSL_OP_TLS_D5_BUG }, + { US"tls_d5_bug", SSL_OP_TLS_D5_BUG }, #endif #ifdef SSL_OP_TLS_ROLLBACK_BUG - { "tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG }, + { US"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG }, #endif }; static int exim_openssl_options_size = sizeof(exim_openssl_options)/sizeof(struct exim_openssl_option); + static BOOL tls_openssl_one_option_parse(uschar *name, long *value) { @@ -1286,12 +1343,9 @@ uschar *s, *end; uschar keep_c; BOOL adding, item_parsed; -/* We grandfather in as default the one option which we used to set always. */ -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS -result = SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; -#else result = 0L; -#endif +/* Prior to 4.78 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed + * from default because it increases BEAST susceptibility. */ if (option_spec == NULL) { @@ -1307,7 +1361,7 @@ for (s=option_spec; *s != '\0'; /**/) if (*s != '+' && *s != '-') { DEBUG(D_tls) debug_printf("malformed openssl option setting: " - "+ or - expected but found \"%s\"", s); + "+ or - expected but found \"%s\"\n", s); return FALSE; } adding = *s++ == '+'; @@ -1317,7 +1371,7 @@ for (s=option_spec; *s != '\0'; /**/) item_parsed = tls_openssl_one_option_parse(s, &item); if (!item_parsed) { - DEBUG(D_tls) debug_printf("openssl option setting unrecognised: \"%s\"", s); + DEBUG(D_tls) debug_printf("openssl option setting unrecognised: \"%s\"\n", s); return FALSE; } DEBUG(D_tls) debug_printf("openssl option, %s from %lx: %lx (%s)\n",