X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/3386088d5af4d4c61faa12ae29560e2c5bd43304..bc3c7bb7d4aba3e563434e5627fe1f2176aa18c0:/src/src/tls-openssl.c diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 21e086e65..83594c973 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -22,6 +22,9 @@ functions from the OpenSSL library. */ #include #include #include +#ifndef OPENSSL_NO_ECDH +# include +#endif #ifndef DISABLE_OCSP # include #endif @@ -38,6 +41,18 @@ functions from the OpenSSL library. */ #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 @@ -59,6 +74,18 @@ functions from the OpenSSL library. */ && (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 +# if OPENSSL_VERSION_NUMBER < 0x10100000L +# define EXIM_HAVE_OPENSSL_ECDH_AUTO +# endif +# define EXIM_HAVE_OPENSSL_EC_NIST2NID +# endif +# endif #endif #if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP) @@ -139,7 +166,7 @@ typedef struct tls_ext_ctx_cb { /* only passed down to tls_error: */ host_item *host; const uschar * verify_cert_hostnames; -#ifdef EXPERIMENTAL_EVENT +#ifndef DISABLE_EVENT uschar * event_action; #endif } tls_ext_ctx_cb; @@ -212,6 +239,7 @@ else +#ifdef EXIM_HAVE_EPHEM_RSA_KEX /************************************************* * Callback to generate RSA key * *************************************************/ @@ -229,10 +257,22 @@ static RSA * 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_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", @@ -241,6 +281,7 @@ if (rsa_key == NULL) } return rsa_key; } +#endif @@ -269,7 +310,7 @@ for(i= 0; ievent_action : event_action; if (ev) { + DEBUG(D_tls) debug_printf("verify_event: %s %d\n", what, depth); old_cert = tlsp->peercert; tlsp->peercert = X509_dup(cert); /* NB we do not bother setting peerdn */ @@ -331,15 +373,17 @@ May be called multiple times for different issues with a certificate, even for a given "depth" in the certificate chain. Arguments: - state current yes/no state as 1/0 - x509ctx certificate information. - client TRUE for client startup, FALSE for server startup + preverify_ok current yes/no state as 1/0 + x509ctx certificate information. + tlsp per-direction (client vs. server) support data + calledp has-been-called flag + optionalp verification-is-optional flag -Returns: 1 if verified, 0 if not +Returns: 0 if verification should fail, otherwise 1 */ static int -verify_callback(int state, X509_STORE_CTX *x509ctx, +verify_callback(int preverify_ok, X509_STORE_CTX *x509ctx, tls_support *tlsp, BOOL *calledp, BOOL *optionalp) { X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx); @@ -349,7 +393,7 @@ uschar dn[256]; X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn)); dn[sizeof(dn)-1] = '\0'; -if (state == 0) +if (preverify_ok == 0) { log_write(0, LOG_MAIN, "[%s] SSL verify error: depth=%d error=%s cert=%s", tlsp == &tls_out ? deliver_host_address : sender_host_address, @@ -375,13 +419,13 @@ else if (depth != 0) { /* 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(); } #endif -#ifdef EXPERIMENTAL_EVENT +#ifndef DISABLE_EVENT if (verify_event(tlsp, cert, depth, dn, calledp, optionalp, US"SSL")) return 0; /* reject, with peercert set */ #endif @@ -407,7 +451,7 @@ else uschar * name; int rc; while ((name = string_nextinlist(&list, &sep, NULL, 0))) - if ((rc = X509_check_host(cert, name, 0, + if ((rc = X509_check_host(cert, CCS name, 0, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS | X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS, NULL))) @@ -441,7 +485,7 @@ else } } -#ifdef EXPERIMENTAL_EVENT +#ifndef DISABLE_EVENT if (verify_event(tlsp, cert, depth, dn, calledp, optionalp, US"SSL")) return 0; /* reject, with peercert set */ #endif @@ -456,15 +500,17 @@ return 1; /* accept, at least for this level */ } static int -verify_callback_client(int state, X509_STORE_CTX *x509ctx) +verify_callback_client(int preverify_ok, X509_STORE_CTX *x509ctx) { -return verify_callback(state, x509ctx, &tls_out, &client_verify_callback_called, &client_verify_optional); +return verify_callback(preverify_ok, x509ctx, &tls_out, + &client_verify_callback_called, &client_verify_optional); } static int -verify_callback_server(int state, X509_STORE_CTX *x509ctx) +verify_callback_server(int preverify_ok, X509_STORE_CTX *x509ctx) { -return verify_callback(state, x509ctx, &tls_in, &server_verify_callback_called, &server_verify_optional); +return verify_callback(preverify_ok, x509ctx, &tls_in, + &server_verify_callback_called, &server_verify_optional); } @@ -474,11 +520,11 @@ return verify_callback(state, x509ctx, &tls_in, &server_verify_callback_called, itself. */ static int -verify_callback_client_dane(int state, X509_STORE_CTX * x509ctx) +verify_callback_client_dane(int preverify_ok, X509_STORE_CTX * x509ctx) { X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx); uschar dn[256]; -#ifdef EXPERIMENTAL_EVENT +#ifndef DISABLE_EVENT int depth = X509_STORE_CTX_get_error_depth(x509ctx); BOOL dummy_called, optional = FALSE; #endif @@ -486,18 +532,27 @@ BOOL dummy_called, optional = FALSE; X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn)); dn[sizeof(dn)-1] = '\0'; -DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s\n", dn); +DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n", + preverify_ok ? "ok":"BAD", depth, dn); -#ifdef EXPERIMENTAL_EVENT +#ifndef DISABLE_EVENT if (verify_event(&tls_out, cert, depth, dn, &dummy_called, &optional, US"DANE")) return 0; /* reject, with peercert set */ #endif -if (state == 1) +if (preverify_ok == 1) tls_out.dane_verified = tls_out.certificate_verified = TRUE; -return 1; +else + { + 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) + preverify_ok = 1; + } +return preverify_ok; } #endif /*EXPERIMENTAL_DANE*/ @@ -644,42 +699,74 @@ Returns: TRUE if OK (nothing to set up, or setup worked) */ 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*/ } @@ -810,7 +897,7 @@ bad: { 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"); @@ -873,7 +960,7 @@ if (cbinfo->privatekey != NULL && of the expansion is an empty string, ignore it also, and assume the private key is in the same file as the certificate. */ -if (expanded != NULL && *expanded != 0) +if (expanded && *expanded) { DEBUG(D_tls) debug_printf("tls_privatekey file %s\n", expanded); if (!SSL_CTX_use_PrivateKey_file(sctx, CS expanded, SSL_FILETYPE_PEM)) @@ -882,21 +969,22 @@ if (expanded != NULL && *expanded != 0) } #ifndef DISABLE_OCSP -if (cbinfo->is_server && cbinfo->u_ocsp.server.file != NULL) +if (cbinfo->is_server && cbinfo->u_ocsp.server.file) { if (!expand_check(cbinfo->u_ocsp.server.file, US"tls_ocsp_file", &expanded)) return DEFER; - if (expanded != NULL && *expanded != 0) + if (expanded && *expanded) { DEBUG(D_tls) debug_printf("tls_ocsp_file %s\n", expanded); - if (cbinfo->u_ocsp.server.file_expanded && - (Ustrcmp(expanded, cbinfo->u_ocsp.server.file_expanded) == 0)) + if ( cbinfo->u_ocsp.server.file_expanded + && (Ustrcmp(expanded, cbinfo->u_ocsp.server.file_expanded) == 0)) + { + DEBUG(D_tls) debug_printf(" - value unchanged, using existing values\n"); + } + else { - DEBUG(D_tls) - debug_printf("tls_ocsp_file value unchanged, using existing values.\n"); - } else { - ocsp_load_response(sctx, cbinfo, expanded); + ocsp_load_response(sctx, cbinfo, expanded); } } } @@ -1066,8 +1154,7 @@ len = SSL_get_tlsext_status_ocsp_resp(s, &p); 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"); @@ -1077,7 +1164,7 @@ if(!p) 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"); @@ -1087,7 +1174,7 @@ if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len))) 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"); @@ -1118,27 +1205,37 @@ if(!(bs = OCSP_response_get1_basic(rsp))) 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); - 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, @@ -1153,7 +1250,6 @@ if(!(bs = OCSP_response_get1_basic(rsp))) 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 { @@ -1164,24 +1260,24 @@ if(!(bs = OCSP_response_get1_basic(rsp))) 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); } @@ -1240,14 +1336,14 @@ else cbinfo->dhparam = dhparam; cbinfo->server_cipher_list = NULL; cbinfo->host = host; -#ifdef EXPERIMENTAL_EVENT +#ifndef DISABLE_EVENT cbinfo->event_action = NULL; #endif 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()); @@ -1261,10 +1357,9 @@ when OpenSSL is built without SSLv2 support. 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 @@ -1321,6 +1416,7 @@ else 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) @@ -1369,9 +1465,10 @@ else /* client */ 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 */ @@ -1472,26 +1569,18 @@ uschar *expcerts, *expcrl; if (!expand_check(certs, US"tls_verify_certificates", &expcerts)) return DEFER; -if (expcerts != NULL && *expcerts != '\0') +if (expcerts && *expcerts) { - if (Ustrcmp(expcerts, "system") == 0) - { - /* Tell the library to use its compiled-in location for the system default - CA bundle, only */ + /* Tell the library to use its compiled-in location for the system default + CA bundle. Then add the ones specified in the config, if any. */ - if (!SSL_CTX_set_default_verify_paths(sctx)) - return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL); - } - else + if (!SSL_CTX_set_default_verify_paths(sctx)) + return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL); + + if (Ustrcmp(expcerts, "system") != 0) { struct stat statbuf; - /* Tell the library to use its compiled-in location for the system default - CA bundle. Those given by the exim config are additional to these */ - - if (!SSL_CTX_set_default_verify_paths(sctx)) - return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL); - if (Ustat(expcerts, &statbuf) < 0) { log_write(0, LOG_MAIN|LOG_PANIC, @@ -1511,8 +1600,8 @@ if (expcerts != NULL && *expcerts != '\0') certificates are recognized, but the error message is still misleading (it says no certificate was supplied.) But this is better. */ - if ((file == NULL || statbuf.st_size > 0) && - !SSL_CTX_load_verify_locations(sctx, CS file, CS dir)) + if ( (!file || statbuf.st_size > 0) + && !SSL_CTX_load_verify_locations(sctx, CS file, CS dir)) return tls_error(US"SSL_CTX_load_verify_locations", host, NULL); /* Load the list of CAs for which we will accept certs, for sending @@ -1521,15 +1610,16 @@ if (expcerts != NULL && *expcerts != '\0') If a list isn't loaded into the server, but some verify locations are set, the server end appears to make a wildcard reqest for client certs. - Meanwhile, the client library as deafult behaviour *ignores* the list + Meanwhile, the client library as default behaviour *ignores* the list we send over the wire - see man SSL_CTX_set_client_cert_cb. Because of this, and that the dir variant is likely only used for the public-CA bundle (not for a private CA), not worth fixing. */ - if (file != NULL) + if (file) { STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file); - DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n", + + DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n", sk_X509_NAME_num(names)); SSL_CTX_set_client_CA_list(sctx, names); } @@ -1538,20 +1628,20 @@ if (expcerts != NULL && *expcerts != '\0') /* Handle a certificate revocation list. */ - #if OPENSSL_VERSION_NUMBER > 0x00907000L +#if OPENSSL_VERSION_NUMBER > 0x00907000L /* This bit of code is now the version supplied by Lars Mainka. (I have - * merely reformatted it into the Exim code style.) + merely reformatted it into the Exim code style.) - * "From here I changed the code to add support for multiple crl's - * in pem format in one file or to support hashed directory entries in - * pem format instead of a file. This method now uses the library function - * X509_STORE_load_locations to add the CRL location to the SSL context. - * OpenSSL will then handle the verify against CA certs and CRLs by - * itself in the verify callback." */ + "From here I changed the code to add support for multiple crl's + in pem format in one file or to support hashed directory entries in + pem format instead of a file. This method now uses the library function + X509_STORE_load_locations to add the CRL location to the SSL context. + OpenSSL will then handle the verify against CA certs and CRLs by + itself in the verify callback." */ if (!expand_check(crl, US"tls_crl", &expcrl)) return DEFER; - if (expcrl != NULL && *expcrl != 0) + if (expcrl && *expcrl) { struct stat statbufcrl; if (Ustat(expcrl, &statbufcrl) < 0) @@ -1587,7 +1677,7 @@ if (expcerts != NULL && *expcerts != '\0') } } - #endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ +#endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ /* If verification is optional, don't fail if no certificate */ @@ -1793,7 +1883,7 @@ tls_client_basic_ctx_init(SSL_CTX * ctx, ) { 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 */ @@ -1815,7 +1905,7 @@ if ((rc = setup_certs(ctx, ob->tls_verify_certificates, 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; @@ -2026,8 +2116,7 @@ if (ob->tls_sni) 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 } @@ -2067,7 +2156,7 @@ if (request_ocsp) } #endif -#ifdef EXPERIMENTAL_EVENT +#ifndef DISABLE_EVENT client_static_cbinfo->event_action = tb->event_action; #endif @@ -2503,8 +2592,13 @@ i = (i + 7) / 8; 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) @@ -2698,6 +2792,9 @@ result = 0L; #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) {