# define EXIM_HAVE_OPENSSL_CHECKHOST
# define EXIM_HAVE_OPENSSL_DH_BITS
# define EXIM_HAVE_OPENSSL_TLS_METHOD
+# define EXIM_HAVE_OPENSSL_KEYLOG
+# define EXIM_HAVE_OPENSSL_CIPHER_GET_ID
# else
# define EXIM_NEED_OPENSSL_INIT
# endif
# endif
#endif
+#ifndef LIBRESSL_VERSION_NUMBER
+# if OPENSSL_VERSION_NUMBER >= 0x010101000L
+# define OPENSSL_HAVE_KEYLOG_CB
+# define OPENSSL_HAVE_NUM_TICKETS
+# define EXIM_HAVE_OPENSSL_CIPHER_STD_NAME
+# endif
+#endif
+
#if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP)
# warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile"
# define DISABLE_OCSP
# include <openssl/x509v3.h>
#endif
+#ifndef EXIM_HAVE_OPENSSL_CIPHER_STD_NAME
+# ifndef EXIM_HAVE_OPENSSL_CIPHER_GET_ID
+# define SSL_CIPHER_get_id(c) (c->id)
+# endif
+# include "tls-cipher-stdname.c"
+#endif
+
/*************************************************
* OpenSSL option parse *
*************************************************/
}
}
+#ifdef OPENSSL_HAVE_KEYLOG_CB
+static void
+keylog_callback(const SSL *ssl, const char *line)
+{
+DEBUG(D_tls) debug_printf("%.200s\n", line);
+}
+#endif
+
/*************************************************
level. */
DEBUG(D_tls) SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
+#ifdef OPENSSL_HAVE_KEYLOG_CB
+DEBUG(D_tls) SSL_CTX_set_keylog_callback(ctx, (void (*)())keylog_callback);
+#endif
/* Automatically re-try reads/writes after renegotiation. */
(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
else
DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
+#ifdef OPENSSL_HAVE_NUM_TICKETS
+SSL_CTX_set_num_tickets(ctx, 0); /* send no TLS1.3 stateful-tickets */
+#endif
+
/* We'd like to disable session cache unconditionally, but foolish Outlook
Express clients then give up the first TLS connection and make a second one
(which works). Only when there is an IMAP service on the same machine.
/*
Argument: pointer to an SSL structure for the connection
- buffer to use for answer
- size of buffer
pointer to number of bits for cipher
-Returns: nothing
+Returns: pointer to allocated string in perm-pool
*/
-static void
-construct_cipher_name(SSL *ssl, uschar *cipherbuf, int bsize, int *bits)
+static uschar *
+construct_cipher_name(SSL * ssl, int * bits)
{
+int pool = store_pool;
/* With OpenSSL 1.0.0a, 'c' 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 uschar * ver = CUS SSL_get_version(ssl);
const SSL_CIPHER * c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
+uschar * s;
SSL_CIPHER_get_bits(c, bits);
-string_format(cipherbuf, bsize, "%s:%s:%u", ver,
- SSL_CIPHER_get_name(c), *bits);
+store_pool = POOL_PERM;
+s = string_sprintf("%s:%s:%u", ver, SSL_CIPHER_get_name(c), *bits);
+store_pool = pool;
+DEBUG(D_tls) debug_printf("Cipher: %s\n", s);
+return s;
+}
+
+
+/* Get IETF-standard name for ciphersuite.
+Argument: pointer to an SSL structure for the connection
+Returns: pointer to string
+*/
-DEBUG(D_tls) debug_printf("Cipher: %s\n", cipherbuf);
+static const uschar *
+cipher_stdname_ssl(SSL * ssl)
+{
+#ifdef EXIM_HAVE_OPENSSL_CIPHER_STD_NAME
+return CUS SSL_CIPHER_standard_name(SSL_get_current_cipher(ssl));
+#else
+ushort id = 0xffff & SSL_CIPHER_get_id(SSL_get_current_cipher(ssl));
+return cipher_stdname(id >> 8, id & 0xff);
+#endif
}
uschar * expciphers;
tls_ext_ctx_cb * cbinfo;
static uschar peerdn[256];
-static uschar cipherbuf[256];
/* Check for previous activation */
peer_cert(server_ssl, &tls_in, peerdn, sizeof(peerdn));
-construct_cipher_name(server_ssl, cipherbuf, sizeof(cipherbuf), &tls_in.bits);
-tls_in.cipher = cipherbuf;
+tls_in.cipher = construct_cipher_name(server_ssl, &tls_in.bits);
+tls_in.cipher_stdname = cipher_stdname_ssl(server_ssl);
DEBUG(D_tls)
{
uschar buf[2048];
- if (SSL_get_shared_ciphers(server_ssl, CS buf, sizeof(buf)) != NULL)
+ if (SSL_get_shared_ciphers(server_ssl, CS buf, sizeof(buf)))
debug_printf("Shared ciphers: %s\n", buf);
+
+#ifdef EXIM_HAVE_OPENSSL_KEYLOG
+ {
+ BIO * bp = BIO_new(BIO_s_mem());
+ uschar * s;
+ int len;
+ SSL_SESSION_print_keylog(bp, SSL_get_session(server_ssl));
+ len = (int) BIO_get_mem_data(bp, CSS &s);
+ debug_printf("%.*s", len, s);
+ BIO_free(bp);
+ }
+#endif
}
/* Record the certificate we presented */
static uschar peerdn[256];
uschar * expciphers;
int rc;
-static uschar cipherbuf[256];
#ifndef DISABLE_OCSP
BOOL request_ocsp = FALSE;
return NULL;
}
-DEBUG(D_tls) debug_printf("SSL_connect succeeded\n");
+DEBUG(D_tls)
+ {
+ debug_printf("SSL_connect succeeded\n");
+#ifdef EXIM_HAVE_OPENSSL_KEYLOG
+ {
+ BIO * bp = BIO_new(BIO_s_mem());
+ uschar * s;
+ int len;
+ SSL_SESSION_print_keylog(bp, SSL_get_session(server_ssl));
+ len = (int) BIO_get_mem_data(bp, CSS &s);
+ debug_printf("%.*s", len, s);
+ BIO_free(bp);
+ }
+#endif
+ }
peer_cert(exim_client_ctx->ssl, tlsp, peerdn, sizeof(peerdn));
-construct_cipher_name(exim_client_ctx->ssl, cipherbuf, sizeof(cipherbuf), &tlsp->bits);
-tlsp->cipher = cipherbuf;
+tlsp->cipher = construct_cipher_name(exim_client_ctx->ssl, &tlsp->bits);
+tlsp->cipher_stdname = cipher_stdname_ssl(exim_client_ctx->ssl);
/* Record the certificate we presented */
{
int
tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more)
{
+size_t olen = len;
int outbytes, error;
SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
static gstring * corked = NULL;
"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. */
+/* + 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))
+if ((more || corked))
{
#ifdef EXPERIMENTAL_PIPE_CONNECT
int save_pool = store_pool;
return -1;
}
}
-return len;
+return olen;
}