typedef struct {
SSL_CTX * ctx;
SSL * ssl;
+ gstring * corked;
} exim_openssl_client_tls_ctx;
static SSL_CTX *server_ctx = NULL;
msg = US ssl_errstring;
}
-if (errstr) *errstr = string_sprintf("(%s): %s", prefix, msg);
+msg = string_sprintf("(%s): %s", prefix, msg);
+DEBUG(D_tls) debug_printf("TLS error '%s'\n", msg);
+if (errstr) *errstr = msg;
return host ? FAIL : DEFER;
}
goto err;
where = US"generating pkey";
-if (!(rsa = rsa_callback(NULL, 0, 1024)))
+if (!(rsa = rsa_callback(NULL, 0, 2048)))
goto err;
where = US"assigning pkey";
if ((err = tls_add_certfile(sctx, cbinfo, expanded, errstr)))
return err;
- if (cbinfo->privatekey != NULL &&
- !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr))
+ if ( cbinfo->privatekey
+ && !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr))
return DEFER;
/* If expansion was forced to fail, key_expanded will be NULL. If the result
{
ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
DEBUG(D_tls) debug_printf("SSL_CTX_new() failed: %s\n", ssl_errstring);
- return SSL_TLSEXT_ERR_NOACK;
+ goto bad;
}
/* Not sure how many of these are actually needed, since SSL object
if ( !init_dh(server_sni, cbinfo->dhparam, NULL, &dummy_errstr)
|| !init_ecdh(server_sni, NULL, &dummy_errstr)
)
- return SSL_TLSEXT_ERR_NOACK;
+ goto bad;
if ( cbinfo->server_cipher_list
&& !SSL_CTX_set_cipher_list(server_sni, CS cbinfo->server_cipher_list))
- return SSL_TLSEXT_ERR_NOACK;
+ goto bad;
#ifndef DISABLE_OCSP
if (cbinfo->u_ocsp.server.file)
if ((rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE,
verify_callback_server, &dummy_errstr)) != OK)
- return SSL_TLSEXT_ERR_NOACK;
+ goto bad;
/* do this after setup_certs, because this can require the certs for verifying
OCSP information. */
if ((rc = tls_expand_session_files(server_sni, cbinfo, &dummy_errstr)) != OK)
- return SSL_TLSEXT_ERR_NOACK;
+ goto bad;
DEBUG(D_tls) debug_printf("Switching SSL context.\n");
SSL_set_SSL_CTX(s, server_sni);
-
return SSL_TLSEXT_ERR_OK;
+
+bad: return SSL_TLSEXT_ERR_ALERT_FATAL;
}
#endif /* EXIM_HAVE_OPENSSL_TLSEXT */
/* If verification is optional, don't fail if no certificate */
SSL_CTX_set_verify(sctx,
- SSL_VERIFY_PEER | (optional? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
+ SSL_VERIFY_PEER | (optional ? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
cert_vfy_cb);
}
}
DEBUG(D_tls) debug_printf("SSL_accept was successful\n");
+ERR_clear_error(); /* Even success can leave errors in the stack. Seen with
+ anon-authentication ciphersuite negociated. */
/* TLS has been set up. Adjust the input functions to read via TLS,
and initialize things. */
rc = store_pool;
store_pool = POOL_PERM;
exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx));
+exim_client_ctx->corked = NULL;
store_pool = rc;
#ifdef SUPPORT_DANE
case SSL_ERROR_ZERO_RETURN:
DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
- receive_getc = smtp_getc;
- receive_getbuf = smtp_getbuf;
- receive_get_cache = smtp_get_cache;
- receive_ungetc = smtp_ungetc;
- receive_feof = smtp_feof;
- receive_ferror = smtp_ferror;
- receive_smtp_buffered = smtp_buffered;
-
if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
SSL_shutdown(server_ssl);
-#ifndef DISABLE_OCSP
- sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
- server_static_cbinfo->verify_stack = NULL;
-#endif
- SSL_free(server_ssl);
- SSL_CTX_free(server_ctx);
- server_ctx = NULL;
- server_ssl = NULL;
- tls_in.active.sock = -1;
- tls_in.active.tls_ctx = NULL;
- tls_in.bits = 0;
- tls_in.cipher = NULL;
- tls_in.peerdn = NULL;
- tls_in.sni = NULL;
-
+ tls_close(NULL, TLS_NO_SHUTDOWN);
return FALSE;
/* Handle genuine errors */
tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more)
{
int outbytes, error, left;
-SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
-static gstring * corked = NULL;
+SSL * ssl = ct_ctx
+ ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
+static gstring * server_corked = NULL;
+gstring ** corkedp = ct_ctx
+ ? &((exim_openssl_client_tls_ctx *)ct_ctx)->corked : &server_corked;
+gstring * corked = *corkedp;
DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__,
buff, (unsigned long)len, more ? ", more" : "");
/* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when
"more" is notified. This hack is only ok if small amounts are involved AND only
one stream does it, in one context (i.e. no store reset). Currently it is used
-for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. */
-/*XXX + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's
-a store reset there. */
+for the responses to the received SMTP MAIL , RCPT, DATA sequence, only.
+We support callouts done by the server process by using a separate client
+context for the stashed information. */
+/* + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's
+a store reset there, so use POOL_PERM. */
+/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
if (!ct_ctx && (more || corked))
{
#endif
if (more)
+ {
+ *corkedp = corked;
return len;
+ }
buff = CUS corked->s;
len = corked->ptr;
- corked = NULL;
+ *corkedp = NULL;
}
for (left = len; left > 0;)
}
}
-#ifndef DISABLE_OCSP
if (!o_ctx) /* server side */
{
+#ifndef DISABLE_OCSP
sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
server_static_cbinfo->verify_stack = NULL;
- }
#endif
+ receive_getc = smtp_getc;
+ receive_getbuf = smtp_getbuf;
+ receive_get_cache = smtp_get_cache;
+ receive_ungetc = smtp_ungetc;
+ receive_feof = smtp_feof;
+ receive_ferror = smtp_ferror;
+ receive_smtp_buffered = smtp_buffered;
+ tls_in.active.tls_ctx = NULL;
+ tls_in.sni = NULL;
+ /* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
+ }
+
SSL_CTX_free(*ctxp);
SSL_free(*sslp);
*ctxp = NULL;