* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
/* See the file NOTICE for conditions of use and distribution. */
/* Portions Copyright (c) The OpenSSL Project 1999 */
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
# define EXIM_HAVE_OPENSSL_TLSEXT
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+# define EXIM_HAVE_RSA_GENKEY_EX
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# define EXIM_HAVE_OCSP_RESP_COUNT
+#else
+# define EXIM_HAVE_EPHEM_RSA_KEX
+# define EXIM_HAVE_RAND_PSEUDO
+#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+# define EXIM_HAVE_SHA256
+#endif
/*
* X509_check_host provides sane certificate hostname checking, but was added
&& (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
# define EXIM_HAVE_OPENSSL_CHECKHOST
# endif
+#endif
+#if !defined(LIBRESSL_VERSION_NUMBER) \
+ || LIBRESSL_VERSION_NUMBER >= 0x20010000L
# if !defined(OPENSSL_NO_ECDH)
# if OPENSSL_VERSION_NUMBER >= 0x0090800fL
# define EXIM_HAVE_ECDH
# endif
# if OPENSSL_VERSION_NUMBER >= 0x10002000L
-# define EXIM_HAVE_OPENSSL_ECDH_AUTO
+# if OPENSSL_VERSION_NUMBER < 0x10100000L
+# define EXIM_HAVE_OPENSSL_ECDH_AUTO
+# endif
# define EXIM_HAVE_OPENSSL_EC_NIST2NID
# endif
# endif
+#ifdef EXIM_HAVE_EPHEM_RSA_KEX
/*************************************************
* Callback to generate RSA key *
*************************************************/
rsa_callback(SSL *s, int export, int keylength)
{
RSA *rsa_key;
+#ifdef EXIM_HAVE_RSA_GENKEY_EX
+BIGNUM *bn = BN_new();
+#endif
+
export = export; /* Shut picky compilers up */
DEBUG(D_tls) debug_printf("Generating %d bit RSA key...\n", keylength);
+
+#ifdef EXIM_HAVE_RSA_GENKEY_EX
+if ( !BN_set_word(bn, (unsigned long)RSA_F4)
+ || !(rsa_key = RSA_new())
+ || !RSA_generate_key_ex(rsa_key, keylength, bn, NULL)
+ )
+#else
rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL);
if (rsa_key == NULL)
+#endif
+
{
ERR_error_string(ERR_get_error(), ssl_errstring);
log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (RSA_generate_key): %s",
}
return rsa_key;
}
+#endif
int err = X509_STORE_CTX_get_error(x509ctx);
DEBUG(D_tls)
debug_printf(" - err %d '%s'\n", err, X509_verify_cert_error_string(err));
- if (err = X509_V_ERR_APPLICATION_VERIFICATION)
+ if (err == X509_V_ERR_APPLICATION_VERIFICATION)
preverify_ok = 1;
}
return preverify_ok;
{
extern char ** environ;
uschar ** p;
- for (p = USS environ; *p != NULL; p++)
+ if (environ) for (p = USS environ; *p != NULL; p++)
if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0)
{
DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n");
log_write(0, LOG_MAIN, "Received TLS cert status response, itself unverifiable");
BIO_printf(bp, "OCSP response verify failure\n");
ERR_print_errors(bp);
- i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
- goto out;
+ goto failed;
}
BIO_printf(bp, "OCSP response well-formed and signed OK\n");
+ /*XXX So we have a good stapled OCSP status. How do we know
+ it is for the cert of interest? OpenSSL 1.1.0 has a routine
+ OCSP_resp_find_status() which matches on a cert id, which presumably
+ we should use. Making an id needs OCSP_cert_id_new(), which takes
+ issuerName, issuerKey, serialNumber. Are they all in the cert?
+
+ For now, carry on blindly accepting the resp. */
+
{
- STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
OCSP_SINGLERESP * single;
+#ifdef EXIM_HAVE_OCSP_RESP_COUNT
+ if (OCSP_resp_count(bs) != 1)
+#else
+ STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
if (sk_OCSP_SINGLERESP_num(sresp) != 1)
+#endif
{
tls_out.ocsp = OCSP_FAILED;
log_write(0, LOG_MAIN, "OCSP stapling "
"with multiple responses not handled");
- i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
- goto out;
+ goto failed;
}
single = OCSP_resp_get0(bs, 0);
status = OCSP_single_get0_status(single, &reason, &rev,
tls_out.ocsp = OCSP_FAILED;
DEBUG(D_tls) ERR_print_errors(bp);
log_write(0, LOG_MAIN, "Server OSCP dates invalid");
- i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
}
else
{
case V_OCSP_CERTSTATUS_GOOD:
tls_out.ocsp = OCSP_VFIED;
i = 1;
- break;
+ goto good;
case V_OCSP_CERTSTATUS_REVOKED:
tls_out.ocsp = OCSP_FAILED;
log_write(0, LOG_MAIN, "Server certificate revoked%s%s",
reason != -1 ? "; reason: " : "",
reason != -1 ? OCSP_crl_reason_str(reason) : "");
DEBUG(D_tls) time_print(bp, "Revocation Time", rev);
- i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
break;
default:
tls_out.ocsp = OCSP_FAILED;
log_write(0, LOG_MAIN,
"Server certificate status unknown, in OCSP stapling");
- i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
break;
}
}
- out:
+ failed:
+ i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
+ good:
BIO_free(bp);
}
SSL_load_error_strings(); /* basic set up */
OpenSSL_add_ssl_algorithms();
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+#ifdef EXIM_HAVE_SHA256
/* SHA256 is becoming ever more popular. This makes sure it gets added to the
list of available digests. */
EVP_add_digest(EVP_sha256());
By disabling with openssl_options, we can let admins re-enable with the
existing knob. */
-*ctxp = SSL_CTX_new((host == NULL)?
- SSLv23_server_method() : SSLv23_client_method());
+*ctxp = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method());
-if (*ctxp == NULL) return tls_error(US"SSL_CTX_new", host, NULL);
+if (!*ctxp) return tls_error(US"SSL_CTX_new", host, NULL);
/* It turns out that we need to seed the random number generator this early in
order to get the full complement of ciphers to work. It took me roughly a day
cbinfo->verify_cert_hostnames = NULL;
+#ifdef EXIM_HAVE_EPHEM_RSA_KEX
/* Set up the RSA callback */
-
SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback);
+#endif
/* Finally, set the timeout, and we are done */
DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tls_out.sni);
SSL_set_tlsext_host_name(client_ssl, tls_out.sni);
#else
- DEBUG(D_tls)
- debug_printf("OpenSSL at build-time lacked SNI support, ignoring \"%s\"\n",
+ log_write(0, LOG_MAIN, "SNI unusable with this OpenSSL library version; ignoring \"%s\"\n",
tls_out.sni);
#endif
}
switch (error)
{
case SSL_ERROR_SSL:
- ERR_error_string(ERR_get_error(), ssl_errstring);
- log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring);
- return -1;
+ ERR_error_string(ERR_get_error(), ssl_errstring);
+ log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring);
+ return -1;
case SSL_ERROR_NONE:
- left -= outbytes;
- buff += outbytes;
- break;
+ left -= outbytes;
+ buff += outbytes;
+ break;
case SSL_ERROR_ZERO_RETURN:
- log_write(0, LOG_MAIN, "SSL channel closed on write");
- return -1;
+ log_write(0, LOG_MAIN, "SSL channel closed on write");
+ return -1;
case SSL_ERROR_SYSCALL:
- log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
- sender_fullhost ? sender_fullhost : US"<unknown>",
- strerror(errno));
+ log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
+ sender_fullhost ? sender_fullhost : US"<unknown>",
+ strerror(errno));
+ return -1;
default:
- log_write(0, LOG_MAIN, "SSL_write error %d", error);
- return -1;
+ log_write(0, LOG_MAIN, "SSL_write error %d", error);
+ return -1;
}
}
return len;
if (i < needed_len)
needed_len = i;
+#ifdef EXIM_HAVE_RAND_PSEUDO
/* We do not care if crypto-strong */
i = RAND_pseudo_bytes(smallbuf, needed_len);
+#else
+i = RAND_bytes(smallbuf, needed_len);
+#endif
+
if (i < 0)
{
DEBUG(D_all)
#ifdef SSL_OP_NO_SSLv2
result |= SSL_OP_NO_SSLv2;
#endif
+#ifdef SSL_OP_SINGLE_DH_USE
+result |= SSL_OP_SINGLE_DH_USE;
+#endif
if (option_spec == NULL)
{
keep_c = *end;
*end = '\0';
item_parsed = tls_openssl_one_option_parse(s, &item);
+ *end = keep_c;
if (!item_parsed)
{
DEBUG(D_tls) debug_printf("openssl option setting unrecognised: \"%s\"\n", s);
result |= item;
else
result &= ~item;
- *end = keep_c;
s = end;
}