* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2014 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
/* See the file NOTICE for conditions of use and distribution. */
/* Portions Copyright (c) The OpenSSL Project 1999 */
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#ifndef OPENSSL_NO_ECDH
+# include <openssl/ec.h>
+#endif
#ifndef DISABLE_OCSP
# include <openssl/ocsp.h>
#endif
&& (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
# define EXIM_HAVE_OPENSSL_CHECKHOST
# endif
+
+# 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
+# define EXIM_HAVE_OPENSSL_EC_NIST2NID
+# endif
+# endif
#endif
#if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP)
{ /* client, wanting stapling */
/* Add the server cert's signing chain as the one
for the verification of the OCSP stapled information. */
-
+
if (!X509_STORE_add_cert(client_static_cbinfo->u_ocsp.client.verify_store,
cert))
ERR_clear_error();
*/
static BOOL
-init_ecdh(SSL_CTX *sctx, host_item *host)
+init_ecdh(SSL_CTX * sctx, host_item * host)
{
+#ifdef OPENSSL_NO_ECDH
+return TRUE;
+#else
+
+EC_KEY * ecdh;
+uschar * exp_curve;
+int nid;
+BOOL rv;
+
if (host) /* No ECDH setup for clients, only for servers */
return TRUE;
-#ifndef SSL_CTX_set_tmp_ecdh
-/* No elliptic curve API in OpenSSL, skip it */
+# ifndef EXIM_HAVE_ECDH
DEBUG(D_tls)
debug_printf("No OpenSSL API to define ECDH parameters, skipping\n");
return TRUE;
-#else
-# ifndef NID_X9_62_prime256v1
-/* For now, stick to NIST P-256 to get "something" running.
-If that's not available, bail */
-DEBUG(D_tls)
- debug_printf("NIST P-256 EC curve not available, skipping ECDH setup\n");
-return TRUE;
# else
+
+if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve))
+ return FALSE;
+if (!exp_curve || !*exp_curve)
+ return TRUE;
+
+# ifdef EXIM_HAVE_OPENSSL_ECDH_AUTO
+/* check if new enough library to support auto ECDH temp key parameter selection */
+if (Ustrcmp(exp_curve, "auto") == 0)
{
- EC_KEY * ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
- BOOL rv;
+ DEBUG(D_tls) debug_printf(
+ "ECDH temp key parameter settings: OpenSSL 1.2+ autoselection\n");
+ SSL_CTX_set_ecdh_auto(sctx, 1);
+ return TRUE;
+ }
+# endif
- /* The "tmp" in the name here refers to setting a tempoary key
- not to the stability of the interface. */
+DEBUG(D_tls) debug_printf("ECDH: curve '%s'\n", exp_curve);
+if ( (nid = OBJ_sn2nid (CCS exp_curve)) == NID_undef
+# ifdef EXIM_HAVE_OPENSSL_EC_NIST2NID
+ && (nid = EC_curve_nist2nid(CCS exp_curve)) == NID_undef
+# endif
+ )
+ {
+ tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'",
+ exp_curve),
+ host, NULL);
+ return FALSE;
+ }
- if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) != 0))
- {
- DEBUG(D_tls) debug_printf("ECDH: enable NIST P-256 curve\n");
- }
- else
- tls_error(US"Error enabling NIST P-256 curve", host, NULL);
- EC_KEY_free(ecdh);
- return rv;
+if (!(ecdh = EC_KEY_new_by_curve_name(nid)))
+ {
+ tls_error(US"Unable to create ec curve", host, NULL);
+ return FALSE;
}
-# endif
-#endif
+
+/* The "tmp" in the name here refers to setting a temporary key
+not to the stability of the interface. */
+
+if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
+ tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), host, NULL);
+else
+ DEBUG(D_tls) debug_printf("ECDH: enabled '%s' curve\n", exp_curve);
+
+EC_KEY_free(ecdh);
+return !rv;
+
+# endif /*EXIM_HAVE_ECDH*/
+#endif /*OPENSSL_NO_ECDH*/
}
int response_der_len;
DEBUG(D_tls)
- debug_printf("Received TLS status request (OCSP stapling); %s response.",
+ debug_printf("Received TLS status request (OCSP stapling); %s response\n",
cbinfo->u_ocsp.server.response ? "have" : "lack");
tls_in.ocsp = OCSP_NOT_RESP;
if(!p)
{
/* Expect this when we requested ocsp but got none */
- if ( cbinfo->u_ocsp.client.verify_required
- && log_extra_selector & LX_tls_cipher)
+ if (cbinfo->u_ocsp.client.verify_required && LOGGING(tls_cipher))
log_write(0, LOG_MAIN, "Received TLS status callback, null content");
else
DEBUG(D_tls) debug_printf(" null\n");
if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
{
tls_out.ocsp = OCSP_FAILED;
- if (log_extra_selector & LX_tls_cipher)
+ if (LOGGING(tls_cipher))
log_write(0, LOG_MAIN, "Received TLS cert status response, parse error");
else
DEBUG(D_tls) debug_printf(" parse error\n");
if(!(bs = OCSP_response_get1_basic(rsp)))
{
tls_out.ocsp = OCSP_FAILED;
- if (log_extra_selector & LX_tls_cipher)
+ if (LOGGING(tls_cipher))
log_write(0, LOG_MAIN, "Received TLS cert status response, error parsing response");
else
DEBUG(D_tls) debug_printf(" error parsing response\n");
cbinfo->u_ocsp.client.verify_store, 0)) <= 0)
{
tls_out.ocsp = OCSP_FAILED;
- if (log_extra_selector & LX_tls_cipher)
+ if (LOGGING(tls_cipher))
log_write(0, LOG_MAIN, "Received TLS cert status response, itself unverifiable");
BIO_printf(bp, "OCSP response verify failure\n");
ERR_print_errors(bp);
DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
/* Initialize with DH parameters if supplied */
+/* Initialize ECDH temp key parameter selection */
if ( !init_dh(*ctxp, dhparam, host)
|| !init_ecdh(*ctxp, host)
)
{
int rc;
-/* stick to the old behaviour for compatibility if tls_verify_certificates is
+/* stick to the old behaviour for compatibility if tls_verify_certificates is
set but both tls_verify_hosts and tls_try_verify_hosts is not set. Check only
the specified host patterns if one of them is defined */
if (verify_check_given_host(&ob->tls_verify_cert_hostnames, host) == OK)
{
cbinfo->verify_cert_hostnames =
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
string_domain_utf8_to_alabel(host->name, NULL);
#else
host->name;