*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2019 */
*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2019 */
/* See the file NOTICE for conditions of use and distribution. */
/* Portions Copyright (c) The OpenSSL Project 1999 */
/* See the file NOTICE for conditions of use and distribution. */
/* Portions Copyright (c) The OpenSSL Project 1999 */
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
{ US"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION },
#endif
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
{ US"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE },
#endif
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
{ US"allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION },
#endif
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
{ US"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE },
#endif
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
{ US"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
#endif
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
{ US"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
#endif
#ifdef SSL_OP_EPHEMERAL_RSA
{ US"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA },
#endif
#ifdef SSL_OP_EPHEMERAL_RSA
{ US"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA },
#endif
#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
{ US"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG },
#endif
#ifdef 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_COMPRESSION
{ US"no_compression", SSL_OP_NO_COMPRESSION },
#endif
#ifdef SSL_OP_NO_RENEGOTIATION
{ US"no_renegotiation", SSL_OP_NO_RENEGOTIATION },
#endif
#ifdef SSL_OP_NO_RENEGOTIATION
{ US"no_renegotiation", SSL_OP_NO_RENEGOTIATION },
#endif
#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
{ US"safari_ecdhe_ecdsa_bug", SSL_OP_SAFARI_ECDHE_ECDSA_BUG },
#endif
#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
{ US"safari_ecdhe_ecdsa_bug", SSL_OP_SAFARI_ECDHE_ECDSA_BUG },
#endif
#ifdef SSL_OP_TLS_ROLLBACK_BUG
{ US"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG },
#endif
#ifdef SSL_OP_TLS_ROLLBACK_BUG
{ US"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG },
#endif
builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
# endif
# ifdef SSL_OP_NO_TLSv1_3
builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
# endif
# ifdef SSL_OP_NO_TLSv1_3
/* Manage the keysets used for encrypting the session tickets, on the server. */
typedef struct { /* Session ticket encryption key */
/* Manage the keysets used for encrypting the session tickets, on the server. */
typedef struct { /* Session ticket encryption key */
if (!tls_openssl_options_parse(openssl_options, &init_options))
return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
if (!tls_openssl_options_parse(openssl_options, &init_options))
return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
/* Should the server offer session resumption? */
if (!host && verify_check_host(&tls_resumption_hosts) == OK)
{
/* Should the server offer session resumption? */
if (!host && verify_check_host(&tls_resumption_hosts) == OK)
{
unhelpful error message. If we skip it, we get the correct behaviour (no
certificates are recognized, but the error message is still misleading (it
says no certificate was supplied). But this is better. */
unhelpful error message. If we skip it, we get the correct behaviour (no
certificates are recognized, but the error message is still misleading (it
says no certificate was supplied). But this is better. */
&& !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
return tls_error(US"SSL_CTX_load_verify_locations", host, NULL, errstr);
&& !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
return tls_error(US"SSL_CTX_load_verify_locations", host, NULL, errstr);
- /* Load the list of CAs for which we will accept certs, for sending
- to the client. This is only for the one-file tls_verify_certificates
- variant.
+ /* On the server load the list of CAs for which we will accept certs, for
+ sending to the client. This is only for the one-file
+ tls_verify_certificates variant.
If a list isn't loaded into the server, but some verify locations are set,
the server end appears to make a wildcard request for client certs.
Meanwhile, the client library as default behaviour *ignores* the list
If a list isn't loaded into the server, but some verify locations are set,
the server end appears to make a wildcard request for client certs.
Meanwhile, the client library as default behaviour *ignores* the list
DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n",
sk_X509_NAME_num(names));
}
DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n",
sk_X509_NAME_num(names));
}
SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, ticket_key_callback);
/* despite working, appears to always return failure, so ignoring */
#endif
#ifdef OPENSSL_HAVE_NUM_TICKETS
SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, ticket_key_callback);
/* despite working, appears to always return failure, so ignoring */
#endif
#ifdef OPENSSL_HAVE_NUM_TICKETS
SSL_CTX_set_num_tickets(server_ctx, tls_in.host_resumable ? 1 : 0);
# else
SSL_CTX_set_num_tickets(server_ctx, 0); /* send no TLS1.3 stateful-tickets */
SSL_CTX_set_num_tickets(server_ctx, tls_in.host_resumable ? 1 : 0);
# else
SSL_CTX_set_num_tickets(server_ctx, 0); /* send no TLS1.3 stateful-tickets */
- unsigned long e = ERR_peek_error();
- if (ERR_GET_REASON(e) == SSL_R_WRONG_VERSION_NUMBER)
+ int r = ERR_GET_REASON(ERR_peek_error());
+ if ( r == SSL_R_WRONG_VERSION_NUMBER
+#ifdef SSL_R_VERSION_TOO_LOW
+ || 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(server_ssl));
(void) tls_error(s, NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
return FAIL;
s = string_sprintf("%s (%s)", s, SSL_get_version(server_ssl));
(void) tls_error(s, NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
return FAIL;
- (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
+ (void) tls_error(US"SSL_accept", NULL,
+ sigalrm_seen ? US"timed out"
+ : ERR_peek_error() ? NULL : string_sprintf("ret %d", error),
+ errstr);
ERR_clear_error(); /* Even success can leave errors in the stack. Seen with
anon-authentication ciphersuite negotiated. */
ERR_clear_error(); /* Even success can leave errors in the stack. Seen with
anon-authentication ciphersuite negotiated. */
uschar c, * s;
size_t len = SSL_get_peer_finished(server_ssl, &c, 0);
int old_pool = store_pool;
uschar c, * s;
size_t len = SSL_get_peer_finished(server_ssl, &c, 0);
int old_pool = store_pool;
SSL_get_peer_finished(server_ssl, s = store_get((int)len, FALSE), len);
store_pool = POOL_PERM;
tls_in.channelbinding = b64encode_taint(CUS s, (int)len, FALSE);
SSL_get_peer_finished(server_ssl, s = store_get((int)len, FALSE), len);
store_pool = POOL_PERM;
tls_in.channelbinding = b64encode_taint(CUS s, (int)len, FALSE);
/* On the client, get any stashed session for the given IP from hints db
and apply it to the ssl-connection for attempted resumption. */
/* On the client, get any stashed session for the given IP from hints db
and apply it to the ssl-connection for attempted resumption. */
tlsp->resumption |= RESUME_CLIENT_REQUESTED;
DEBUG(D_tls) debug_printf("checking for resumable session for %s\n", key);
tlsp->resumption |= RESUME_CLIENT_REQUESTED;
DEBUG(D_tls) debug_printf("checking for resumable session for %s\n", key);
- if ((dbm_file = dbfn_open(US"tls", O_RDONLY, &dbblock, FALSE, FALSE)))
+ if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
{
/* key for the db is the IP */
if ((dt = dbfn_read_with_length(dbm_file, key, &len)))
{
/* key for the db is the IP */
if ((dt = dbfn_read_with_length(dbm_file, key, &len)))
tls_client_ctx_resume_prehandshake(exim_client_ctx, tlsp, ob, host);
#endif
tls_client_ctx_resume_prehandshake(exim_client_ctx, tlsp, ob, host);
#endif
if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
errstr))
return FALSE;
if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
errstr))
return FALSE;
uschar c, * s;
size_t len = SSL_get_finished(exim_client_ctx->ssl, &c, 0);
int old_pool = store_pool;
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, TRUE), len);
store_pool = POOL_PERM;
tlsp->channelbinding = b64encode_taint(CUS s, (int)len, TRUE);
SSL_get_finished(exim_client_ctx->ssl, s = store_get((int)len, TRUE), len);
store_pool = POOL_PERM;
tlsp->channelbinding = b64encode_taint(CUS s, (int)len, TRUE);
DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
ssl_xfer_buffer, ssl_xfer_buffer_size);
DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
ssl_xfer_buffer, ssl_xfer_buffer_size);
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
MIN(ssl_xfer_buffer_size, lim));
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
MIN(ssl_xfer_buffer_size, lim));
DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl,
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);
inbytes = SSL_read(ssl, CS buff, len);
error = SSL_get_error(ssl, inbytes);
for (int left = len; left > 0;)
{
DEBUG(D_tls) debug_printf("SSL_write(%p, %p, %d)\n", ssl, buff, left);
for (int left = len; left > 0;)
{
DEBUG(D_tls) debug_printf("SSL_write(%p, %p, %d)\n", ssl, 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);
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);