diff options
author | Jeremy Harris <jgh146exb@wizmail.org> | 2014-05-20 21:25:10 +0100 |
---|---|---|
committer | Jeremy Harris <jgh146exb@wizmail.org> | 2014-05-20 21:25:10 +0100 |
commit | e51c7be22dfccad376659a1a46cee93c9979bbf7 (patch) | |
tree | 3a6facf5bd5b51f1b3e21c62736ae04bc7504099 /src | |
parent | 2e6afa4f11972312d3dbb9bb1d4f4bf585a3cdd2 (diff) |
Support optional server certificate name checking. Bug 1479
Enable EXPERIMENTAL_CERTNAMES to include.
Diffstat (limited to 'src')
-rw-r--r-- | src/src/EDITME | 4 | ||||
-rw-r--r-- | src/src/config.h.defaults | 1 | ||||
-rw-r--r-- | src/src/exim.c | 3 | ||||
-rw-r--r-- | src/src/functions.h | 7 | ||||
-rw-r--r-- | src/src/tls-gnu.c | 131 | ||||
-rw-r--r-- | src/src/tls-openssl.c | 69 | ||||
-rw-r--r-- | src/src/tls.c | 74 | ||||
-rw-r--r-- | src/src/tlscert-gnu.c | 5 | ||||
-rw-r--r-- | src/src/tlscert-openssl.c | 10 | ||||
-rw-r--r-- | src/src/transports/smtp.c | 7 | ||||
-rw-r--r-- | src/src/transports/smtp.h | 15 |
11 files changed, 279 insertions, 47 deletions
diff --git a/src/src/EDITME b/src/src/EDITME index 7d58af744..83ca43cd1 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -485,6 +485,10 @@ EXIM_MONITOR=eximon.bin # Uncomment the following line to enable Experimental Proxy Protocol # EXPERIMENTAL_PROXY=yes +# Uncomment the following line to enable support for checking certiticate +# ownership +# EXPERIMENTAL_CERTNAMES=yes + ############################################################################### # THESE ARE THINGS YOU MIGHT WANT TO SPECIFY # diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 69df842e7..3ab73d861 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -165,6 +165,7 @@ it's a default value. */ /* EXPERIMENTAL features */ #define EXPERIMENTAL_BRIGHTMAIL +#define EXPERIMENTAL_CERTNAMES #define EXPERIMENTAL_DCC #define EXPERIMENTAL_DMARC #define EXPERIMENTAL_OCSP diff --git a/src/src/exim.c b/src/src/exim.c index ded12fa34..bca6cc8a4 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -831,6 +831,9 @@ fprintf(f, "Support for:"); #ifdef EXPERIMENTAL_REDIS fprintf(f, " Experimental_Redis"); #endif +#ifdef EXPERIMENTAL_CERTNAMES + fprintf(f, " Experimental_Certnames"); +#endif fprintf(f, "\n"); fprintf(f, "Lookups (built-in):"); diff --git a/src/src/functions.h b/src/src/functions.h index 741b632a9..a6257a913 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -59,10 +59,13 @@ extern int tls_ungetc(int); extern int tls_write(BOOL, const uschar *, size_t); extern uschar *tls_validate_require_cipher(void); extern void tls_version_report(FILE *); -#ifndef USE_GNUTLS +# ifndef USE_GNUTLS extern BOOL tls_openssl_options_parse(uschar *, long *); -#endif +# endif extern uschar * tls_field_from_dn(uschar *, uschar *); +# ifdef EXPERIMENTAL_CERTNAMES +extern BOOL tls_is_name_for_cert(uschar *, void *); +# endif #endif /*SUPPORT_TLS*/ diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 3c926c0d4..af43686e4 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -60,7 +60,12 @@ Changes: /* Values for verify_requirement */ -enum peer_verify_requirement { VERIFY_NONE, VERIFY_OPTIONAL, VERIFY_REQUIRED }; +enum peer_verify_requirement + { VERIFY_NONE, VERIFY_OPTIONAL, VERIFY_REQUIRED +#ifdef EXPERIMENTAL_CERTNAMES + ,VERIFY_WITHHOST +#endif + }; /* This holds most state for server or client; with this, we can set up an outbound TLS-enabled connection in an ACL callout, while not stomping all @@ -95,6 +100,7 @@ typedef struct exim_gnutls_state { const uschar *tls_verify_certificates; const uschar *tls_crl; const uschar *tls_require_ciphers; + uschar *exp_tls_certificate; uschar *exp_tls_privatekey; uschar *exp_tls_sni; @@ -102,6 +108,9 @@ typedef struct exim_gnutls_state { uschar *exp_tls_crl; uschar *exp_tls_require_ciphers; uschar *exp_tls_ocsp_file; +#ifdef EXPERIMENTAL_CERTNAMES + uschar *exp_tls_verify_cert_hostnames; +#endif tls_support *tlsp; /* set in tls_init() */ @@ -117,6 +126,9 @@ static const exim_gnutls_state_st exim_gnutls_state_init = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#ifdef EXPERIMENTAL_CERTNAMES + NULL, +#endif NULL, NULL, 0, 0, 0, 0, }; @@ -178,18 +190,18 @@ before, for now. */ #define expand_check_tlsvar(Varname) expand_check(state->Varname, US #Varname, &state->exp_##Varname) #if GNUTLS_VERSION_NUMBER >= 0x020c00 -#define HAVE_GNUTLS_SESSION_CHANNEL_BINDING -#define HAVE_GNUTLS_SEC_PARAM_CONSTANTS -#define HAVE_GNUTLS_RND +# define HAVE_GNUTLS_SESSION_CHANNEL_BINDING +# define HAVE_GNUTLS_SEC_PARAM_CONSTANTS +# define HAVE_GNUTLS_RND /* The security fix we provide with the gnutls_allow_auto_pkcs11 option * (4.82 PP/09) introduces a compatibility regression. The symbol simply * isn't available sometimes, so this needs to become a conditional * compilation; the sanest way to deal with this being a problem on * older OSes is to block it in the Local/Makefile with this compiler * definition */ -#ifndef AVOID_GNUTLS_PKCS11 -#define HAVE_GNUTLS_PKCS11 -#endif /* AVOID_GNUTLS_PKCS11 */ +# ifndef AVOID_GNUTLS_PKCS11 +# define HAVE_GNUTLS_PKCS11 +# endif /* AVOID_GNUTLS_PKCS11 */ #endif @@ -294,10 +306,16 @@ tls_error(when, msg, state->host); * Set various Exim expansion vars * *************************************************/ -#define exim_gnutls_cert_err(Label) do { \ - if (rc != GNUTLS_E_SUCCESS) { \ - DEBUG(D_tls) debug_printf("TLS: cert problem: %s: %s\n", (Label), gnutls_strerror(rc)); \ - return rc; } } while (0) +#define exim_gnutls_cert_err(Label) \ + do \ + { \ + if (rc != GNUTLS_E_SUCCESS) \ + { \ + DEBUG(D_tls) debug_printf("TLS: cert problem: %s: %s\n", \ + (Label), gnutls_strerror(rc)); \ + return rc; \ + } \ + } while (0) static int import_cert(const gnutls_datum * cert, gnutls_x509_crt_t * crtp) @@ -1220,7 +1238,7 @@ if (cert_list == NULL || cert_list_size == 0) { DEBUG(D_tls) debug_printf("TLS: no certificate from peer (%p & %d)\n", cert_list, cert_list_size); - if (state->verify_requirement == VERIFY_REQUIRED) + if (state->verify_requirement >= VERIFY_REQUIRED) return tls_error(US"certificate verification failed", "no certificate received from peer", state->host); return OK; @@ -1232,17 +1250,23 @@ if (ct != GNUTLS_CRT_X509) const char *ctn = gnutls_certificate_type_get_name(ct); DEBUG(D_tls) debug_printf("TLS: peer cert not X.509 but instead \"%s\"\n", ctn); - if (state->verify_requirement == VERIFY_REQUIRED) + if (state->verify_requirement >= VERIFY_REQUIRED) return tls_error(US"certificate verification not possible, unhandled type", ctn, state->host); return OK; } -#define exim_gnutls_peer_err(Label) do { \ - if (rc != GNUTLS_E_SUCCESS) { \ - DEBUG(D_tls) debug_printf("TLS: peer cert problem: %s: %s\n", (Label), gnutls_strerror(rc)); \ - if (state->verify_requirement == VERIFY_REQUIRED) { return tls_error((Label), gnutls_strerror(rc), state->host); } \ - return OK; } } while (0) +#define exim_gnutls_peer_err(Label) \ + do { \ + if (rc != GNUTLS_E_SUCCESS) \ + { \ + DEBUG(D_tls) debug_printf("TLS: peer cert problem: %s: %s\n", \ + (Label), gnutls_strerror(rc)); \ + if (state->verify_requirement >= VERIFY_REQUIRED) \ + return tls_error((Label), gnutls_strerror(rc), state->host); \ + return OK; \ + } \ + } while (0) rc = import_cert(&cert_list[0], &crt); exim_gnutls_peer_err(US"cert 0"); @@ -1306,7 +1330,9 @@ else /* Handle the result of verification. INVALID seems to be set as well as REVOKED, but leave the test for both. */ -if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) +if (rc < 0 || + verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED) + ) { state->peer_cert_verified = FALSE; if (!*error) @@ -1314,21 +1340,42 @@ if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) ? "certificate revoked" : "certificate invalid"; DEBUG(D_tls) - debug_printf("TLS certificate verification failed (%s): peerdn=%s\n", + debug_printf("TLS certificate verification failed (%s): peerdn=\"%s\"\n", *error, state->peerdn ? state->peerdn : US"<unset>"); - if (state->verify_requirement == VERIFY_REQUIRED) + if (state->verify_requirement >= VERIFY_REQUIRED) { - gnutls_alert_send(state->session, GNUTLS_AL_FATAL, GNUTLS_A_BAD_CERTIFICATE); + gnutls_alert_send(state->session, + GNUTLS_AL_FATAL, GNUTLS_A_BAD_CERTIFICATE); return FALSE; } DEBUG(D_tls) debug_printf("TLS verify failure overridden (host in tls_try_verify_hosts)\n"); } + else { +#ifdef EXPERIMENTAL_CERTNAMES + if (state->verify_requirement == VERIFY_WITHHOST) + { + int sep = 0; + uschar * list = state->exp_tls_verify_cert_hostnames; + uschar * name; + while (name = string_nextinlist(&list, &sep, NULL, 0)) + if (gnutls_x509_crt_check_hostname(state->tlsp->peercert, CS name)) + break; + if (!name) + { + DEBUG(D_tls) + debug_printf("TLS certificate verification failed: cert name mismatch\n"); + gnutls_alert_send(state->session, + GNUTLS_AL_FATAL, GNUTLS_A_BAD_CERTIFICATE); + return FALSE; + } + } +#endif state->peer_cert_verified = TRUE; - DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=%s\n", + DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=\"%s\"\n", state->peerdn ? state->peerdn : US"<unset>"); } @@ -1517,19 +1564,22 @@ optional, set up appropriately. */ if (verify_check_host(&tls_verify_hosts) == OK) { - DEBUG(D_tls) debug_printf("TLS: a client certificate will be required.\n"); + DEBUG(D_tls) + debug_printf("TLS: a client certificate will be required.\n"); state->verify_requirement = VERIFY_REQUIRED; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE); } else if (verify_check_host(&tls_try_verify_hosts) == OK) { - DEBUG(D_tls) debug_printf("TLS: a client certificate will be requested but not required.\n"); + DEBUG(D_tls) + debug_printf("TLS: a client certificate will be requested but not required.\n"); state->verify_requirement = VERIFY_OPTIONAL; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST); } else { - DEBUG(D_tls) debug_printf("TLS: a client certificate will not be requested.\n"); + DEBUG(D_tls) + debug_printf("TLS: a client certificate will not be requested.\n"); state->verify_requirement = VERIFY_NONE; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE); } @@ -1699,19 +1749,40 @@ if (( state->exp_tls_verify_certificates verify_check_host(&ob->tls_verify_hosts) == OK ) { - DEBUG(D_tls) debug_printf("TLS: server certificate verification required.\n"); - state->verify_requirement = VERIFY_REQUIRED; +#ifdef EXPERIMENTAL_CERTNAMES + if (ob->tls_verify_cert_hostnames) + { + DEBUG(D_tls) + debug_printf("TLS: server cert incl. hostname verification required.\n"); + state->verify_requirement = VERIFY_WITHHOST; + if (!expand_check(ob->tls_verify_cert_hostnames, + US"tls_verify_cert_hostnames", + &state->exp_tls_verify_cert_hostnames)) + return FAIL; + if (state->exp_tls_verify_cert_hostnames) + DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n", + state->exp_tls_verify_cert_hostnames); + } + else +#endif + { + DEBUG(D_tls) + debug_printf("TLS: server certificate verification required.\n"); + state->verify_requirement = VERIFY_REQUIRED; + } gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE); } else if (verify_check_host(&ob->tls_try_verify_hosts) == OK) { - DEBUG(D_tls) debug_printf("TLS: server certificate verification optional.\n"); + DEBUG(D_tls) + debug_printf("TLS: server certificate verification optional.\n"); state->verify_requirement = VERIFY_OPTIONAL; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST); } else { - DEBUG(D_tls) debug_printf("TLS: server certificate verification not required.\n"); + DEBUG(D_tls) + debug_printf("TLS: server certificate verification not required.\n"); state->verify_requirement = VERIFY_NONE; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE); } diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 3000b8fcb..1d6b91470 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -23,7 +23,7 @@ functions from the OpenSSL library. */ #include <openssl/err.h> #include <openssl/rand.h> #ifdef EXPERIMENTAL_OCSP -#include <openssl/ocsp.h> +# include <openssl/ocsp.h> #endif #ifdef EXPERIMENTAL_OCSP @@ -32,7 +32,7 @@ functions from the OpenSSL library. */ #endif #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) -#define EXIM_HAVE_OPENSSL_TLSEXT +# define EXIM_HAVE_OPENSSL_TLSEXT #endif /* Structure for collecting random data for seeding. */ @@ -107,6 +107,10 @@ 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 } tls_ext_ctx_cb; /* should figure out a cleanup of API to handle state preserved per @@ -268,8 +272,7 @@ verify_callback(int state, X509_STORE_CTX *x509ctx, X509 * cert = X509_STORE_CTX_get_current_cert(x509ctx); static uschar txt[256]; -X509_NAME_oneline(X509_get_subject_name(cert), - CS txt, sizeof(txt)); +X509_NAME_oneline(X509_get_subject_name(cert), CS txt, sizeof(txt)); if (state == 0) { @@ -306,8 +309,43 @@ else if (X509_STORE_CTX_get_error_depth(x509ctx) != 0) } else { +#ifdef EXPERIMENTAL_CERTNAMES + uschar * verify_cert_hostnames; +#endif + 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 */ + +# if OPENSSL_VERSION_NUMBER >= 0x010100000L || OPENSSL_VERSION_NUMBER >= 0x010002000L + { + 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)) + break; + if (!name) + { + log_write(0, LOG_MAIN, + "SSL verify error: certificate name mismatch: \"%s\"\n", txt); + return 0; /* reject */ + } + } +# 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); + return 0; /* reject */ + } +# endif +#endif + DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n", *calledp ? "" : " authenticated", txt); if (!*calledp) tlsp->certificate_verified = TRUE; @@ -955,8 +993,8 @@ return i; * Initialize for TLS * *************************************************/ -/* Called from both server and client code, to do preliminary initialization of -the library. +/* Called from both server and client code, to do preliminary initialization +of the library. We allocate and return a context structure. Arguments: host connected host, if client; NULL if server @@ -965,6 +1003,7 @@ Arguments: privatekey private key ocsp_file file of stapling info (server); flag for require ocsp (client) addr address if client; NULL if server (for some randomness) + cbp place to put allocated context Returns: OK/DEFER/FAIL */ @@ -1118,6 +1157,10 @@ else /* client */ # endif #endif +#ifdef EXPERIMENTAL_CERTNAMES +cbinfo->verify_cert_hostnames = NULL; +#endif + /* Set up the RSA callback */ SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback); @@ -1545,6 +1588,7 @@ if (expciphers != NULL) /* 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 ((!ob->tls_verify_hosts && !ob->tls_try_verify_hosts) || (verify_check_host(&ob->tls_verify_hosts) == OK)) { @@ -1552,6 +1596,19 @@ if ((!ob->tls_verify_hosts && !ob->tls_try_verify_hosts) || ob->tls_crl, host, FALSE, verify_callback_client)) != OK) return rc; client_verify_optional = FALSE; + +#ifdef EXPERIMENTAL_CERTNAMES + if (ob->tls_verify_cert_hostnames) + { + if (!expand_check(ob->tls_verify_cert_hostnames, + US"tls_verify_cert_hostnames", + &client_static_cbinfo->verify_cert_hostnames)) + return FAIL; + if (client_static_cbinfo->verify_cert_hostnames) + DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n", + client_static_cbinfo->verify_cert_hostnames); + } +#endif } else if (verify_check_host(&ob->tls_try_verify_hosts) == OK) { diff --git a/src/src/tls.c b/src/src/tls.c index 75c46e9e4..b5ef96595 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -255,6 +255,80 @@ return list; } +#ifdef EXPERIMENTAL_CERTNAMES +/* Compare a domain name with a possibly-wildcarded name. Wildcards +are restricted to a single one, as the first element of patterns +having at least three dot-separated elements. Case-independent. +Return TRUE for a match +*/ +static BOOL +is_name_match(const uschar * name, const uschar * pat) +{ +uschar * cp; +return *pat == '*' /* possible wildcard match */ + ? *++pat == '.' /* starts star, dot */ + && !Ustrchr(++pat, '*') /* has no more stars */ + && Ustrchr(pat, '.') /* and has another dot. */ + && (cp = Ustrchr(name, '.'))/* The name has at least one dot */ + && strcmpic(++cp, pat) == 0 /* and we only compare after it. */ + : !Ustrchr(pat+1, '*') + && strcmpic(name, pat) == 0; +} + +/* Compare a list of names with the dnsname elements +of the Subject Alternate Name, if any, and the +Subject otherwise. + +Arguments: + namelist names to compare + cert certificate + +Returns: + TRUE/FALSE +*/ + +BOOL +tls_is_name_for_cert(uschar * namelist, void * cert) +{ +uschar * altnames = tls_cert_subject_altname(cert, US"dns"); +uschar * subjdn; +uschar * certname; +int cmp_sep = 0; +uschar * cmpname; + +if ((altnames = tls_cert_subject_altname(cert, US"dns"))) + { + int alt_sep = '\n'; + while (cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0)) + { + uschar * an = altnames; + while (certname = string_nextinlist(&an, &alt_sep, NULL, 0)) + if (is_name_match(cmpname, certname)) + return TRUE; + } + } + +else if ((subjdn = tls_cert_subject(cert, NULL))) + { + int sn_sep = ','; + uschar * sn; + + dn_to_list(subjdn); + while (cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0)) + { + uschar * sn = subjdn; + while (certname = string_nextinlist(&sn, &sn_sep, NULL, 0)) + if ( *certname++ == 'C' + && *certname++ == 'N' + && *certname++ == '=' + && is_name_match(cmpname, certname) + ) + return TRUE; + } + } +return FALSE; +} +#endif /* vi: aw ai sw=2 */ diff --git a/src/src/tlscert-gnu.c b/src/src/tlscert-gnu.c index 9b9c83d8b..737637302 100644 --- a/src/src/tlscert-gnu.c +++ b/src/src/tlscert-gnu.c @@ -268,7 +268,7 @@ for(index = 0;; index++) { siz = 0; switch(ret = gnutls_x509_crt_get_subject_alt_name( - (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL)) + (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL)) { case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE: return list; /* no more elements; normal exit */ @@ -286,7 +286,8 @@ for(index = 0;; index++) return g_err("gs1", __FUNCTION__, ret); ele[siz] = '\0'; - if (match != -1 && match != ret) + if ( match != -1 && match != ret /* wrong type of SAN */ + || Ustrlen(ele) != siz) /* contains a NUL */ continue; switch (ret) { diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c index 29095782a..0614b4025 100644 --- a/src/src/tlscert-openssl.c +++ b/src/src/tlscert-openssl.c @@ -237,6 +237,7 @@ uschar sep = '\n'; uschar * tag = US""; uschar * ele; int match = -1; +int len; if (!san) return NULL; @@ -262,19 +263,26 @@ while (sk_GENERAL_NAME_num(san) > 0) case GEN_DNS: tag = US"DNS"; ele = ASN1_STRING_data(namePart->d.dNSName); + len = ASN1_STRING_length(namePart->d.dNSName); break; case GEN_URI: tag = US"URI"; ele = ASN1_STRING_data(namePart->d.uniformResourceIdentifier); + len = ASN1_STRING_length(namePart->d.uniformResourceIdentifier); break; case GEN_EMAIL: tag = US"MAIL"; ele = ASN1_STRING_data(namePart->d.rfc822Name); + len = ASN1_STRING_length(namePart->d.rfc822Name); break; default: continue; /* ignore unrecognised types */ } - list = string_append_listele(list, sep, + if (ele[len]) /* not nul-terminated */ + ele = string_copyn(ele, len); + + if (strnlen(CS ele, len) == len) /* ignore any with embedded nul */ + list = string_append_listele(list, sep, match == -1 ? string_sprintf("%s=%s", tag, ele) : ele); } diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 71a9f2376..c175d2ffe 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -163,6 +163,10 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, tls_tempfail_tryclear) }, { "tls_try_verify_hosts", opt_stringptr, (void *)offsetof(smtp_transport_options_block, tls_try_verify_hosts) }, +#ifdef EXPERIMENTAL_CERTNAMES + { "tls_verify_cert_hostnames", opt_stringptr, + (void *)offsetof(smtp_transport_options_block,tls_verify_cert_hostnames)}, +#endif { "tls_verify_certificates", opt_stringptr, (void *)offsetof(smtp_transport_options_block, tls_verify_certificates) }, { "tls_verify_hosts", opt_stringptr, @@ -245,6 +249,9 @@ smtp_transport_options_block smtp_transport_option_defaults = { TRUE, /* tls_tempfail_tryclear */ NULL, /* tls_verify_hosts */ NULL /* tls_try_verify_hosts */ +# ifdef EXPERIMENTAL_CERTNAMES + ,NULL /* tls_verify_cert_hostnames */ +# endif #endif #ifndef DISABLE_DKIM ,NULL, /* dkim_canon */ diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index c7de0091a..a481943bb 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -55,7 +55,7 @@ typedef struct { BOOL keepalive; BOOL lmtp_ignore_quota; BOOL retry_include_ip_address; - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS uschar *tls_certificate; uschar *tls_crl; uschar *tls_privatekey; @@ -69,18 +69,21 @@ typedef struct { BOOL tls_tempfail_tryclear; uschar *tls_verify_hosts; uschar *tls_try_verify_hosts; - #endif - #ifndef DISABLE_DKIM +# ifdef EXPERIMENTAL_CERTNAMES + uschar *tls_verify_cert_hostnames; +# endif +#endif +#ifndef DISABLE_DKIM uschar *dkim_domain; uschar *dkim_private_key; uschar *dkim_selector; uschar *dkim_canon; uschar *dkim_sign_headers; uschar *dkim_strict; - #endif - #ifdef EXPERIMENTAL_TPDA +#endif +#ifdef EXPERIMENTAL_TPDA uschar *tpda_host_defer_action; - #endif +#endif } smtp_transport_options_block; /* Data for reading the private options. */ |