* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2012 */
+/* Copyright (c) University of Cambridge 1995 - 2013 */
/* See the file NOTICE for conditions of use and distribution. */
/* Portions Copyright (c) The OpenSSL Project 1999 */
tls_ext_ctx_cb *server_static_cbinfo = NULL;
static int
-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional, BOOL client);
+setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional,
+ int (*cert_vfy_cb)(int, X509_STORE_CTX *) );
/* Callbacks */
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
/*XXX JGH: this looks bogus - we set "verified" first time through, which
will be for the root CS cert (calls work down the chain). Why should it
not be on the last call, where we're setting peerdn?
+
+To test: set up a chain anchored by a good root-CA but with a bad server cert.
+Does certificate_verified get set?
*/
if (!*calledp) tlsp->certificate_verified = TRUE;
*calledp = TRUE;
}
#endif
-rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE, FALSE);
+rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE, verify_callback_server);
if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
/* do this after setup_certs, because this can require the certs for verifying
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 SSL_CIPHER *c;
-uschar *ver;
-
-switch (ssl->session->ssl_version)
- {
- case SSL2_VERSION:
- ver = US"SSLv2";
- break;
-
- case SSL3_VERSION:
- ver = US"SSLv3";
- break;
-
- case TLS1_VERSION:
- ver = US"TLSv1";
- break;
-
-#ifdef TLS1_1_VERSION
- case TLS1_1_VERSION:
- ver = US"TLSv1.1";
- break;
-#endif
-
-#ifdef TLS1_2_VERSION
- case TLS1_2_VERSION:
- ver = US"TLSv1.2";
- break;
-#endif
+const uschar *ver;
- default:
- ver = US"UNKNOWN";
- }
+ver = (const uschar *)SSL_get_version(ssl);
c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
SSL_CIPHER_get_bits(c, bits);
host NULL in a server; the remote host in a client
optional TRUE if called from a server for a host in tls_try_verify_hosts;
otherwise passed as FALSE
- client TRUE if called for client startup, FALSE for server startup
+ cert_vfy_cb Callback function for certificate verification
Returns: OK/DEFER/FAIL
*/
static int
-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional, BOOL client)
+setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional,
+ int (*cert_vfy_cb)(int, X509_STORE_CTX *) )
{
uschar *expcerts, *expcrl;
SSL_CTX_set_verify(sctx,
SSL_VERIFY_PEER | (optional? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
- client ? verify_callback_client : verify_callback_server);
+ cert_vfy_cb);
}
return OK;
if (verify_check_host(&tls_verify_hosts) == OK)
{
- rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL, FALSE, FALSE);
+ rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
+ FALSE, verify_callback_server);
if (rc != OK) return rc;
server_verify_optional = FALSE;
}
else if (verify_check_host(&tls_try_verify_hosts) == OK)
{
- rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL, TRUE, FALSE);
+ rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
+ TRUE, verify_callback_server);
if (rc != OK) return rc;
server_verify_optional = TRUE;
}
dh_min_bits minimum number of bits acceptable in server's DH prime
(unused in OpenSSL)
timeout startup timeout
+ verify_hosts mandatory client verification
+ try_verify_hosts optional client verification
Returns: OK on success
FAIL otherwise - note that tls_error() will not give DEFER
#ifdef EXPERIMENTAL_OCSP
uschar *hosts_require_ocsp,
#endif
- int dh_min_bits ARG_UNUSED, int timeout)
+ int dh_min_bits ARG_UNUSED, int timeout,
+ uschar *verify_hosts, uschar *try_verify_hosts)
{
static uschar txt[256];
uschar *expciphers;
return tls_error(US"SSL_CTX_set_cipher_list", host, NULL);
}
-rc = setup_certs(client_ctx, verify_certs, crl, host, FALSE, TRUE);
-if (rc != OK) return rc;
+/* 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_hosts == NULL) && (try_verify_hosts == NULL)) ||
+ (verify_check_host(&verify_hosts) == OK))
+ {
+ rc = setup_certs(client_ctx, verify_certs, crl, host, FALSE, verify_callback_client);
+ if (rc != OK) return rc;
+ client_verify_optional = FALSE;
+ }
+else if (verify_check_host(&try_verify_hosts) == OK)
+ {
+ rc = setup_certs(client_ctx, verify_certs, crl, host, TRUE, verify_callback_client);
+ if (rc != OK) return rc;
+ client_verify_optional = TRUE;
+ }
if ((client_ssl = SSL_new(client_ctx)) == NULL) return tls_error(US"SSL_new", host, NULL);
SSL_set_session_id_context(client_ssl, sid_ctx, Ustrlen(sid_ctx));
it can result in serious failures, including crashing with a SIGSEGV. So
report the version found by the compiler and the run-time version.
+Note: some OS vendors backport security fixes without changing the version
+number/string, and the version date remains unchanged. The _build_ date
+will change, so we can more usefully assist with version diagnosis by also
+reporting the build date.
+
Arguments: a FILE* to print the results to
Returns: nothing
*/
tls_version_report(FILE *f)
{
fprintf(f, "Library version: OpenSSL: Compile: %s\n"
- " Runtime: %s\n",
+ " Runtime: %s\n"
+ " : %s\n",
OPENSSL_VERSION_TEXT,
- SSLeay_version(SSLEAY_VERSION));
+ SSLeay_version(SSLEAY_VERSION),
+ SSLeay_version(SSLEAY_BUILT_ON));
+/* third line is 38 characters for the %s and the line is 73 chars long;
+the OpenSSL output includes a "built on: " prefix already. */
}
{
unsigned int r;
int i, needed_len;
+static pid_t pidlast = 0;
+pid_t pidnow;
uschar *p;
uschar smallbuf[sizeof(r)];
if (max <= 1)
return 0;
+pidnow = getpid();
+if (pidnow != pidlast)
+ {
+ /* Although OpenSSL documents that "OpenSSL makes sure that the PRNG state
+ is unique for each thread", this doesn't apparently apply across processes,
+ so our own warning from vaguely_random_number_fallback() applies here too.
+ Fix per PostgreSQL. */
+ if (pidlast != 0)
+ RAND_cleanup();
+ pidlast = pidnow;
+ }
+
/* OpenSSL auto-seeds from /dev/random, etc, but this a double-check. */
if (!RAND_status())
{
to apply.
This list is current as of:
- ==> 1.0.1b <== */
+ ==> 1.0.1b <==
+Plus SSL_OP_SAFARI_ECDHE_ECDSA_BUG from 2013-June patch/discussion on openssl-dev
+*/
static struct exim_openssl_option exim_openssl_options[] = {
/* KEEP SORTED ALPHABETICALLY! */
#ifdef SSL_OP_ALL
#ifdef SSL_OP_NO_TLSv1_2
{ US"no_tlsv1_2", SSL_OP_NO_TLSv1_2 },
#endif
+#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
+ { US"safari_ecdhe_ecdsa_bug", SSL_OP_SAFARI_ECDHE_ECDSA_BUG },
+#endif
#ifdef SSL_OP_SINGLE_DH_USE
{ US"single_dh_use", SSL_OP_SINGLE_DH_USE },
#endif