X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b8b1b5cb847ae5c40195584e321eb70afbdca113..93a6fce2ebf117f490d7ee11f066f75280d32386:/src/src/tls-openssl.c diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 9aa655e82..ee16bdc9e 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -123,10 +123,7 @@ typedef struct tls_ext_ctx_cb { uschar *server_cipher_list; /* only passed down to tls_error: */ host_item *host; - -#ifdef EXPERIMENTAL_CERTNAMES - uschar * verify_cert_hostnames; -#endif + const uschar * verify_cert_hostnames; #ifdef EXPERIMENTAL_EVENT uschar * event_action; #endif @@ -248,6 +245,7 @@ for(i= 0; idata.x509; X509_NAME_oneline(X509_get_subject_name(current_cert), CS name, sizeof(name)); + txt[sizeof(name)-1] = '\0'; debug_printf(" %s\n", name); } } @@ -301,10 +299,12 @@ uschar * yield; #endif X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt)); +txt[sizeof(txt)-1] = '\0'; if (state == 0) { - log_write(0, LOG_MAIN, "SSL verify error: depth=%d error=%s cert=%s", + log_write(0, LOG_MAIN, "[%s] SSL verify error: depth=%d error=%s cert=%s", + tlsp == &tls_out ? deliver_host_address : sender_host_address, depth, X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)), txt); @@ -339,8 +339,10 @@ else if (depth != 0) tlsp->peercert = X509_dup(cert); if ((yield = event_raise(ev, US"tls:cert", string_sprintf("%d", depth)))) { - log_write(0, LOG_MAIN, "SSL verify denied by event-action: " - "depth=%d cert=%s: %s", depth, txt, yield); + log_write(0, LOG_MAIN, "[%s] SSL verify denied by event-action: " + "depth=%d cert=%s: %s", + tlsp == &tls_out ? deliver_host_address : sender_host_address, + depth, txt, yield); *calledp = TRUE; if (!*optionalp) return 0; /* reject */ @@ -354,14 +356,11 @@ else if (depth != 0) } else { -#ifdef EXPERIMENTAL_CERTNAMES - uschar * verify_cert_hostnames; -#endif + const uschar * verify_cert_hostnames; tlsp->peerdn = txt; tlsp->peercert = X509_dup(cert); -#ifdef EXPERIMENTAL_CERTNAMES if ( tlsp == &tls_out && ((verify_cert_hostnames = client_static_cbinfo->verify_cert_hostnames))) /* client, wanting hostname check */ @@ -375,7 +374,7 @@ else # endif { int sep = 0; - uschar * list = verify_cert_hostnames; + const uschar * list = verify_cert_hostnames; uschar * name; int rc; while ((name = string_nextinlist(&list, &sep, NULL, 0))) @@ -385,7 +384,8 @@ else { if (rc < 0) { - log_write(0, LOG_MAIN, "SSL verify error: internal error\n"); + log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error", + tlsp == &tls_out ? deliver_host_address : sender_host_address); name = NULL; } break; @@ -393,7 +393,9 @@ else if (!name) { log_write(0, LOG_MAIN, - "SSL verify error: certificate name mismatch: \"%s\"\n", txt); + "[%s] SSL verify error: certificate name mismatch: \"%s\"", + tlsp == &tls_out ? deliver_host_address : sender_host_address, + txt); *calledp = TRUE; if (!*optionalp) return 0; /* reject */ @@ -405,7 +407,9 @@ else if (!tls_is_name_for_cert(verify_cert_hostnames, cert)) { log_write(0, LOG_MAIN, - "SSL verify error: certificate name mismatch: \"%s\"\n", txt); + "[%s] SSL verify error: certificate name mismatch: \"%s\"", + tlsp == &tls_out ? deliver_host_address : sender_host_address, + txt); *calledp = TRUE; if (!*optionalp) return 0; /* reject */ @@ -413,15 +417,16 @@ else "tls_try_verify_hosts)\n"); } # endif -#endif /*EXPERIMENTAL_CERTNAMES*/ #ifdef EXPERIMENTAL_EVENT ev = tlsp == &tls_out ? client_static_cbinfo->event_action : event_action; if (ev) if ((yield = event_raise(ev, US"tls:cert", US"0"))) { - log_write(0, LOG_MAIN, "SSL verify denied by event-action: " - "depth=0 cert=%s: %s", txt, yield); + log_write(0, LOG_MAIN, "[%s] SSL verify denied by event-action: " + "depth=0 cert=%s: %s", + tlsp == &tls_out ? deliver_host_address : sender_host_address, + txt, yield); *calledp = TRUE; if (!*optionalp) return 0; /* reject */ @@ -468,6 +473,7 @@ uschar * yield; #endif X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt)); +txt[sizeof(txt)-1] = '\0'; DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s\n", txt); tls_out.peerdn = txt; @@ -1289,9 +1295,7 @@ else /* client */ # endif #endif -#ifdef EXPERIMENTAL_CERTNAMES cbinfo->verify_cert_hostnames = NULL; -#endif /* Set up the RSA callback */ @@ -1375,50 +1379,65 @@ if (!expand_check(certs, US"tls_verify_certificates", &expcerts)) if (expcerts != NULL && *expcerts != '\0') { - struct stat statbuf; - 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) + if (Ustrcmp(expcerts, "system") == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "failed to stat %s for certificates", expcerts); - return DEFER; + /* Tell the library to use its compiled-in location for the system default + CA bundle, only */ + + if (!SSL_CTX_set_default_verify_paths(sctx)) + return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL); } else { - uschar *file, *dir; - if ((statbuf.st_mode & S_IFMT) == S_IFDIR) - { file = NULL; dir = expcerts; } + 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, + "failed to stat %s for certificates", expcerts); + return DEFER; + } else - { file = expcerts; dir = NULL; } - - /* If a certificate file is empty, the next function fails with an - unhelpful error message. If we skip it, we get the correct behaviour (no - 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)) - return tls_error(US"SSL_CTX_load_verify_locations", host, NULL); - - /* Load the list of CAs for which we will accept certs, for sending - to the client. This is only for the one-file tls_verify_certificates - variant. - 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 - 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) { - STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file); -DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n", - sk_X509_NAME_num(names)); - SSL_CTX_set_client_CA_list(sctx, names); + uschar *file, *dir; + if ((statbuf.st_mode & S_IFMT) == S_IFDIR) + { file = NULL; dir = expcerts; } + else + { file = expcerts; dir = NULL; } + + /* If a certificate file is empty, the next function fails with an + unhelpful error message. If we skip it, we get the correct behaviour (no + 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)) + return tls_error(US"SSL_CTX_load_verify_locations", host, NULL); + + /* Load the list of CAs for which we will accept certs, for sending + to the client. This is only for the one-file tls_verify_certificates + variant. + 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 + 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) + { + STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file); + DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n", + sk_X509_NAME_num(names)); + SSL_CTX_set_client_CA_list(sctx, names); + } } } @@ -1672,10 +1691,7 @@ return OK; static int tls_client_basic_ctx_init(SSL_CTX * ctx, - host_item * host, smtp_transport_options_block * ob -#ifdef EXPERIMENTAL_CERTNAMES - , tls_ext_ctx_cb * cbinfo -#endif + host_item * host, smtp_transport_options_block * ob, tls_ext_ctx_cb * cbinfo ) { int rc; @@ -1683,13 +1699,13 @@ int rc; 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 ( (!ob->tls_verify_hosts && !ob->tls_try_verify_hosts) - || (verify_check_this_host(&ob->tls_verify_hosts, NULL, - host->name, host->address, NULL) == OK) +if ( ( !ob->tls_verify_hosts + && (!ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts) + ) + || (verify_check_given_host(&ob->tls_verify_hosts, host) == OK) ) client_verify_optional = FALSE; -else if (verify_check_this_host(&ob->tls_try_verify_hosts, NULL, - host->name, host->address, NULL) == OK) +else if (verify_check_given_host(&ob->tls_try_verify_hosts, host) == OK) client_verify_optional = TRUE; else return OK; @@ -1698,15 +1714,12 @@ if ((rc = setup_certs(ctx, ob->tls_verify_certificates, ob->tls_crl, host, client_verify_optional, verify_callback_client)) != OK) return rc; -#ifdef EXPERIMENTAL_CERTNAMES -if (verify_check_this_host(&ob->tls_verify_cert_hostnames, NULL, - host->name, host->address, NULL) == OK) +if (verify_check_given_host(&ob->tls_verify_cert_hostnames, host) == OK) { cbinfo->verify_cert_hostnames = host->name; DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n", cbinfo->verify_cert_hostnames); } -#endif return OK; } @@ -1764,7 +1777,7 @@ if (found) return OK; log_write(0, LOG_MAIN, "DANE error: No usable TLSA records"); -return FAIL; +return DEFER; } #endif /*EXPERIMENTAL_DANE*/ @@ -1829,15 +1842,15 @@ tls_out.tlsa_usage = 0; } # endif - if ((require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp, - NULL, host->name, host->address, NULL) == OK)) + if ((require_ocsp = + verify_check_given_host(&ob->hosts_require_ocsp, host) == OK)) request_ocsp = TRUE; else # ifdef EXPERIMENTAL_DANE if (!request_ocsp) # endif - request_ocsp = verify_check_this_host(&ob->hosts_request_ocsp, - NULL, host->name, host->address, NULL) == OK; + request_ocsp = + verify_check_given_host(&ob->hosts_request_ocsp, host) == OK; } #endif @@ -1872,7 +1885,9 @@ if (expciphers != NULL) #ifdef EXPERIMENTAL_DANE if (tlsa_dnsa) { - SSL_CTX_set_verify(client_ctx, SSL_VERIFY_PEER, verify_callback_client_dane); + SSL_CTX_set_verify(client_ctx, + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + verify_callback_client_dane); if (!DANESSL_library_init()) return tls_error(US"library init", host, NULL); @@ -1883,11 +1898,8 @@ else #endif - if ((rc = tls_client_basic_ctx_init(client_ctx, host, ob -#ifdef EXPERIMENTAL_CERTNAMES - , client_static_cbinfo -#endif - )) != OK) + if ((rc = tls_client_basic_ctx_init(client_ctx, host, ob, client_static_cbinfo)) + != OK) return rc; if ((client_ssl = SSL_new(client_ctx)) == NULL) @@ -1938,11 +1950,9 @@ if (request_ocsp) { /* Re-eval now $tls_out_tlsa_usage is populated. If this means we avoid the OCSP request, we wasted the setup cost in tls_init(). */ - require_ocsp = verify_check_this_host(&ob->hosts_require_ocsp, - NULL, host->name, host->address, NULL) == OK; - request_ocsp = require_ocsp ? TRUE - : verify_check_this_host(&ob->hosts_request_ocsp, - NULL, host->name, host->address, NULL) == OK; + require_ocsp = verify_check_given_host(&ob->hosts_require_ocsp, host) == OK; + request_ocsp = require_ocsp + || verify_check_given_host(&ob->hosts_request_ocsp, host) == OK; } } # endif @@ -1984,6 +1994,7 @@ if (server_cert) { tls_out.peerdn = US X509_NAME_oneline(X509_get_subject_name(server_cert), CS txt, sizeof(txt)); + txt[sizeof(txt)-1] = '\0'; tls_out.peerdn = txt; /*XXX a static buffer... */ } else