X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/67791ce4a0ae39a79aab22157d587d774190ac61..a7538db17824b7fd70c12ef7561a67b85d6f247e:/src/src/tls-openssl.c diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index bcca506e0..c031b8e4d 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -116,6 +116,9 @@ typedef struct tls_ext_ctx_cb { #ifdef EXPERIMENTAL_CERTNAMES uschar * verify_cert_hostnames; #endif +#ifdef EXPERIMENTAL_TPDA + uschar * event_action; +#endif } tls_ext_ctx_cb; /* should figure out a cleanup of API to handle state preserved per @@ -262,6 +265,9 @@ when asked. We get here only if a certificate has been received. Handling of optional verification for this case is done when requesting SSL to verify, by setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT in the non-optional case. +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. @@ -275,6 +281,7 @@ verify_callback(int state, X509_STORE_CTX *x509ctx, tls_support *tlsp, BOOL *calledp, BOOL *optionalp) { X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx); +int depth = X509_STORE_CTX_get_error_depth(x509ctx); static uschar txt[256]; X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt)); @@ -282,7 +289,7 @@ X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt)); if (state == 0) { log_write(0, LOG_MAIN, "SSL verify error: depth=%d error=%s cert=%s", - X509_STORE_CTX_get_error_depth(x509ctx), + depth, X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)), txt); tlsp->certificate_verified = FALSE; @@ -296,10 +303,9 @@ if (state == 0) "tls_try_verify_hosts)\n"); } -else if (X509_STORE_CTX_get_error_depth(x509ctx) != 0) +else if (depth != 0) { - DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n", - X509_STORE_CTX_get_error_depth(x509ctx), txt); + DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n", depth, txt); #ifndef DISABLE_OCSP if (tlsp == &tls_out && client_static_cbinfo->u_ocsp.client.verify_store) { /* client, wanting stapling */ @@ -310,6 +316,23 @@ else if (X509_STORE_CTX_get_error_depth(x509ctx) != 0) cert)) ERR_clear_error(); } +#endif +#ifdef EXPERIMENTAL_TPDA + if (tlsp == &tls_out && client_static_cbinfo->event_action) + { + tlsp->peercert = X509_dup(cert); + if (tpda_raise_event(client_static_cbinfo->event_action, + US"tls:cert", string_sprintf("%d", depth)) == DEFER) + { + log_write(0, LOG_MAIN, "SSL verify denied by event-action: " + "depth=%d cert=%s", depth, txt); + tlsp->certificate_verified = FALSE; + *calledp = TRUE; + return 0; /* reject */ + } + X509_free(tlsp->peercert); + tlsp->peercert = NULL; + } #endif } else @@ -327,13 +350,25 @@ else /* client, wanting hostname check */ # if OPENSSL_VERSION_NUMBER >= 0x010100000L || OPENSSL_VERSION_NUMBER >= 0x010002000L +# ifndef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS +# define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0 +# endif { int sep = 0; uschar * list = verify_cert_hostnames; uschar * name; - while (name = string_nextinlist(&list, &sep, NULL, 0)) - if (X509_check_host(cert, name, 0, 0)) + int rc; + while ((name = string_nextinlist(&list, &sep, NULL, 0))) + if ((rc = X509_check_host(cert, name, 0, + X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS))) + { + if (rc < 0) + { + log_write(0, LOG_MAIN, "SSL verify error: internal error\n"); + name = NULL; + } break; + } if (!name) { log_write(0, LOG_MAIN, @@ -349,6 +384,21 @@ else return 0; /* reject */ } # endif +#endif /*EXPERIMENTAL_CERTNAMES*/ + +#ifdef EXPERIMENTAL_TPDA + if (tlsp == &tls_out) + { + if (tpda_raise_event(client_static_cbinfo->event_action, + US"tls:cert", US"0") == DEFER) + { + log_write(0, LOG_MAIN, "SSL verify denied by event-action: " + "depth=0 cert=%s", txt); + tlsp->certificate_verified = FALSE; + *calledp = TRUE; + return 0; /* reject */ + } + } #endif DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n", @@ -357,7 +407,7 @@ else *calledp = TRUE; } -return 1; /* accept */ +return 1; /* accept, at least for this level */ } static int @@ -424,14 +474,11 @@ const char *pem; if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded)) return FALSE; -if (dhexpanded == NULL || *dhexpanded == '\0') - { +if (!dhexpanded || !*dhexpanded) bio = BIO_new_mem_buf(CS std_dh_prime_default(), -1); - } else if (dhexpanded[0] == '/') { - bio = BIO_new_file(CS dhexpanded, "r"); - if (bio == NULL) + if (!(bio = BIO_new_file(CS dhexpanded, "r"))) { tls_error(string_sprintf("could not read dhparams file %s", dhexpanded), host, US strerror(errno)); @@ -446,8 +493,7 @@ else return TRUE; } - pem = std_dh_prime_named(dhexpanded); - if (!pem) + if (!(pem = std_dh_prime_named(dhexpanded))) { tls_error(string_sprintf("Unknown standard DH prime \"%s\"", dhexpanded), host, US strerror(errno)); @@ -456,8 +502,7 @@ else bio = BIO_new_mem_buf(CS pem, -1); } -dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); -if (dh == NULL) +if (!(dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL))) { BIO_free(bio); tls_error(string_sprintf("Could not read tls_dhparams \"%s\"", dhexpanded), @@ -758,8 +803,7 @@ if (!reexpand_tls_files_for_sni) not confident that memcpy wouldn't break some internal reference counting. Especially since there's a references struct member, which would be off. */ -server_sni = SSL_CTX_new(SSLv23_server_method()); -if (!server_sni) +if (!(server_sni = SSL_CTX_new(SSLv23_server_method()))) { ERR_error_string(ERR_get_error(), ssl_errstring); DEBUG(D_tls) debug_printf("SSL_CTX_new() failed: %s\n", ssl_errstring); @@ -793,8 +837,8 @@ OCSP information. */ rc = tls_expand_session_files(server_sni, cbinfo); if (rc != OK) return SSL_TLSEXT_ERR_NOACK; -rc = init_dh(server_sni, cbinfo->dhparam, NULL); -if (rc != OK) return SSL_TLSEXT_ERR_NOACK; +if (!init_dh(server_sni, cbinfo->dhparam, NULL)) + return SSL_TLSEXT_ERR_NOACK; DEBUG(D_tls) debug_printf("Switching SSL context.\n"); SSL_set_SSL_CTX(s, server_sni); @@ -882,7 +926,7 @@ if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len))) { tls_out.ocsp = OCSP_FAILED; if (log_extra_selector & LX_tls_cipher) - log_write(0, LOG_MAIN, "Received TLS status response, parse error"); + log_write(0, LOG_MAIN, "Received TLS cert status response, parse error"); else DEBUG(D_tls) debug_printf(" parse error\n"); return 0; @@ -892,7 +936,7 @@ if(!(bs = OCSP_response_get1_basic(rsp))) { tls_out.ocsp = OCSP_FAILED; if (log_extra_selector & LX_tls_cipher) - log_write(0, LOG_MAIN, "Received TLS status response, error parsing response"); + log_write(0, LOG_MAIN, "Received TLS cert status response, error parsing response"); else DEBUG(D_tls) debug_printf(" error parsing response\n"); OCSP_RESPONSE_free(rsp); @@ -922,6 +966,8 @@ 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) + 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; @@ -1024,7 +1070,7 @@ tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate, long init_options; int rc; BOOL okay; -tls_ext_ctx_cb *cbinfo; +tls_ext_ctx_cb * cbinfo; cbinfo = store_malloc(sizeof(tls_ext_ctx_cb)); cbinfo->certificate = certificate; @@ -1040,7 +1086,11 @@ else cbinfo->u_ocsp.client.verify_store = NULL; #endif cbinfo->dhparam = dhparam; +cbinfo->server_cipher_list = NULL; cbinfo->host = host; +#ifdef EXPERIMENTAL_TPDA +cbinfo->event_action = NULL; +#endif SSL_load_error_strings(); /* basic set up */ OpenSSL_add_ssl_algorithms(); @@ -1537,7 +1587,7 @@ Argument: fd the fd of the connection host connected host (for messages) addr the first address - ob smtp transport options + tb transport (always smtp) Returns: OK on success FAIL otherwise - note that tls_error() will not give DEFER @@ -1546,9 +1596,10 @@ Returns: OK on success int tls_client_start(int fd, host_item *host, address_item *addr, - void *v_ob) + transport_instance *tb) { -smtp_transport_options_block * ob = v_ob; +smtp_transport_options_block * ob = + (smtp_transport_options_block *)tb->options_block; static uschar txt[256]; uschar *expciphers; X509* server_cert; @@ -1663,6 +1714,10 @@ if (request_ocsp) } #endif +#ifdef EXPERIMENTAL_TPDA +client_static_cbinfo->event_action = tb->tpda_event_action; +#endif + /* There doesn't seem to be a built-in timeout on connection. */ DEBUG(D_tls) debug_printf("Calling SSL_connect\n");