On 2016-09-12 17:00:28 [+0200], Kurt Roeckx wrote: > > But this problem existed before 1.1.0 support (this patch). > > What do you recommend here? The builtin usage > > (X509_VERIFY_PARAM_set_hostflags()) looks simple. The alternative > > X509_check_host() is 1.0.2+ and since it can not be applied to stable I > > don't see the point. I would add this for 1.1.0 and keep the current > > validation for < 1.1.0. > > We don't want to upload this to Debian stable in any case. But if > it's only doing the right thing with 1.1.0 that works for me.
So I've been looking at this again. The patch attached should do what you asked for. It is so untested that EA is already using it… Ehm. One thing: The callback that uw-imap invokes scq(err_str_cpy, "hostname", cert_subj) expects to pass the hostname of the connection. I have no idea how to obtain it at that point. I could also drop that callback, set SSL_VERIFY_NONE instead and then check the connection after the handshake via SSL_get_verify_result(). It is enough exercise I think. And I haven't got any response from upstream. So I leave it to someone that can test it and is using it. So far it seems only alpine does [0]. [0] http://sources.debian.net/src/alpine/2.20%2Bdfsg1-2/web/src/alpined.d/alpined.c/?hl=10831#L10831 > Kurt Sebastian
>From b45c2495fffd431a4eee359c24a0b292c87bc33c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior <sebast...@breakpoint.cc> Date: Wed, 2 Nov 2016 22:21:42 +0000 Subject: [PATCH] uw-imap: use openssl host validation Signed-off-by: Sebastian Andrzej Siewior <sebast...@breakpoint.cc> --- src/osdep/unix/ssl_unix.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/osdep/unix/ssl_unix.c b/src/osdep/unix/ssl_unix.c index 836e9fa..eddf420 100644 --- a/src/osdep/unix/ssl_unix.c +++ b/src/osdep/unix/ssl_unix.c @@ -205,6 +205,40 @@ static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) static char *ssl_last_error = NIL; static char *ssl_last_host = NIL; +#if OPENSSL_VERSION_NUMBER >= 0x10100000 + +static int cert_verify(int preverify, X509_STORE_CTX* x509_ctx) +{ + sslcertificatequery_t scq; + X509* cert; + char cert_subj[250]; + int err; + char err_str_cpy[50]; + const char *err_str; + + if (preverify == 1) + return 1; + + scq = mail_parameters(NIL, GET_SSLCERTIFICATEQUERY, NIL); + if (!scq) + return 0; + + cert = X509_STORE_CTX_get_current_cert(x509_ctx); + if (!cert) + return 0; + err = X509_STORE_CTX_get_error(x509_ctx); + err_str = X509_verify_cert_error_string(err); + err_str_cpy[sizeof(err_str_cpy) - 1] = '\0'; + strncpy(err_str_cpy, err_str, sizeof(err_str_cpy) - 1); + + X509_NAME_oneline(X509_get_subject_name(cert), cert_subj, sizeof(cert_subj)); + + if (scq(err_str_cpy, "hostname", cert_subj) == 0) + return 0; + return 1; +} +#endif + static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags) { BIO *bio; @@ -226,10 +260,12 @@ static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags) return "SSL context failed"; SSL_CTX_set_options (stream->context,0); /* disable certificate validation? */ +#if OPENSSL_VERSION_NUMBER < 0x10100000 if (flags & NET_NOVALIDATECERT) SSL_CTX_set_verify (stream->context,SSL_VERIFY_NONE,NIL); else SSL_CTX_set_verify (stream->context,SSL_VERIFY_PEER,ssl_open_verify); /* set default paths to CAs... */ +#endif SSL_CTX_set_default_verify_paths (stream->context); /* ...unless a non-standard path desired */ if (s = (char *) mail_parameters (NIL,GET_SSLCAPATH,NIL)) @@ -259,6 +295,20 @@ static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags) /* create connection */ if (!(stream->con = (SSL *) SSL_new (stream->context))) return "SSL connection failed"; +#if OPENSSL_VERSION_NUMBER >= 0x10100000 + SSL_set_tlsext_host_name(stream->con, host); + if (!(flags & NET_NOVALIDATECERT)) { + X509_VERIFY_PARAM *param; + + param = SSL_get0_param(stream->con); + X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + X509_VERIFY_PARAM_set1_host(param, host, 0); + + SSL_set_verify(stream->con, SSL_VERIFY_PEER, cert_verify); + } else { + SSL_set_verify(stream->con, SSL_VERIFY_NONE, 0); + } +#endif bio = BIO_new_socket (stream->tcpstream->tcpsi,BIO_NOCLOSE); SSL_set_bio (stream->con,bio,bio); SSL_set_connect_state (stream->con); @@ -267,6 +317,7 @@ static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags) if (SSL_write (stream->con,"",0) < 0) return ssl_last_error ? ssl_last_error : "SSL negotiation failed"; /* need to validate host names? */ +#if OPENSSL_VERSION_NUMBER < 0x10100000 if (!(flags & NET_NOVALIDATECERT)) { cert_subj[0] = '\0'; @@ -281,6 +332,7 @@ static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags) sprintf (tmp,"*%.128s: %.255s",err,cert ? cert_subj : "???"); return ssl_last_error = cpystr (tmp); } +#endif return NIL; } @@ -319,6 +371,7 @@ static int ssl_open_verify (int ok,X509_STORE_CTX *ctx) * Returns: NIL if validated, else string of error message */ +#if OPENSSL_VERSION_NUMBER < 0x10100000 static char *ssl_validate_cert (X509 *cert,char *host, char *cert_subj) { int i,n; @@ -348,6 +401,7 @@ static char *ssl_validate_cert (X509 *cert,char *host, char *cert_subj) else ret = "Unable to locate common name in certificate"; return ret; } +#endif /* Case-independent wildcard pattern match * Accepts: base string -- 2.10.2