Thursday, April 30, 2020

Re: mail/alpine vs GMail vs TLSv1.3

On 2020/04/30 16:43, Theo Buehler wrote:
> procter reported to me yesterday that the last time that he could use
> his GMail account with alpine was before the Hobart hackathon, i.e.,
> before the TLSv1.3 client was enabled.
>
> There are two problems:
>
> First, if you establish a TLSv1.3 connection to imap.gmail.com:993
> without SNI, it answers with a self-signed cert containing
>
> subject=/OU=No SNI provided; please fix your client./CN=invalid2.invalid
> issuer=/OU=No SNI provided; please fix your client./CN=invalid2.invalid
>
> Unless you turn off certificate validation in the alpine config, the
> connection will fail. The SNI hunk is taken from alpine 2.22 [1].

Yep we've seen that one with a few ports already :-)

> Second, our TLSv1.3 stack tends to want more retries. alpine already
> retries reads, but doesn't do it for writes. We verified that SSL_write
> returns SSL_ERROR_WANT_WRITE. I did essentially the same thing we did
> (and shortly after undid) for wget.
>
>
> procter verified that the combination of these two fixes allows him to
> use alpine with GMail imap and smtp again.
>
> I'm both surprised and a bit worried that it took so long for somebody
> to report this.

I'm not entirely surprised, console-based mail clients are often run
directly on mail servers which tend to not get updated all that often.

> An alternative would be to update to alpine 2.22, but I suspect that the
> SSL_write issue is still present there, so the patch below would seem to
> be the safer option.
>
> [1]: https://repo.or.cz/alpine.git/blob/99948a254e2c2352547b962cbd1c23738e7af6b3:/imap/src/osdep/unix/ssl_unix.c#l446

OK.

> Index: Makefile
> ===================================================================
> RCS file: /var/cvs/ports/mail/alpine/Makefile,v
> retrieving revision 1.46
> diff -u -p -r1.46 Makefile
> --- Makefile 20 Mar 2020 16:44:24 -0000 1.46
> +++ Makefile 29 Apr 2020 13:29:40 -0000
> @@ -28,7 +28,7 @@ PKGNAME-mailutil= mailutil-uw-${V}
> PKGNAME-pico= pico-${PICO_V}
> PKGNAME-pilot= pilot-${PILOT_V}
>
> -REVISION= 3
> +REVISION= 4
> REVISION-pico= 20
> REVISION-pilot= 20
>
> Index: patches/patch-imap_src_osdep_unix_ssl_unix_c
> ===================================================================
> RCS file: patches/patch-imap_src_osdep_unix_ssl_unix_c
> diff -N patches/patch-imap_src_osdep_unix_ssl_unix_c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ patches/patch-imap_src_osdep_unix_ssl_unix_c 30 Apr 2020 10:49:20 -0000
> @@ -0,0 +1,57 @@
> +$OpenBSD$
> +
> +Workarounds for GMail:
> +* imap.gmail.com requires SNI for TLSv1.3 clients
> +* retry the writes if we're told to do so.
> +
> +Index: imap/src/osdep/unix/ssl_unix.c
> +--- imap/src/osdep/unix/ssl_unix.c.orig
> ++++ imap/src/osdep/unix/ssl_unix.c
> +@@ -266,6 +266,7 @@ static char *ssl_start_work (SSLSTREAM *stream,char *h
> + {
> + BIO *bio;
> + X509 *cert;
> ++ int ssl_err;
> + unsigned long sl,tl;
> + char *s,*t,*err,tmp[MAILTMPLEN], buf[256];
> + sslcertificatequery_t scq =
> +@@ -313,12 +314,22 @@ static char *ssl_start_work (SSLSTREAM *stream,char *h
> + /* create connection */
> + if (!(stream->con = (SSL *) SSL_new (stream->context)))
> + return "SSL connection failed";
> ++ if (host && !SSL_set_tlsext_host_name(stream->con, host)) {
> ++ return "Server Name Identification (SNI) failed";
> ++ }
> + bio = BIO_new_socket (stream->tcpstream->tcpsi,BIO_NOCLOSE);
> + SSL_set_bio (stream->con,bio,bio);
> + SSL_set_connect_state (stream->con);
> + if (SSL_in_init (stream->con)) SSL_total_renegotiations (stream->con);
> + /* now negotiate SSL */
> +- if (SSL_write (stream->con,"",0) < 0)
> ++ do {
> ++ ssl_err = SSL_write (stream->con,"",0);
> ++ } while ((ssl_err == -1 &&
> ++ SSL_get_error(stream->con, ssl_err) == SSL_ERROR_SYSCALL && errno == EINTR) ||
> ++ (ssl_err < 0 &&
> ++ (SSL_get_error(stream->con, ssl_err) == SSL_ERROR_WANT_READ ||
> ++ SSL_get_error(stream->con, ssl_err) == SSL_ERROR_WANT_WRITE)));
> ++ if (ssl_err < 0)
> + return ssl_last_error ? ssl_last_error : "SSL negotiation failed";
> + /* need to validate host names? */
> + if (!(flags & NET_NOVALIDATECERT) &&
> +@@ -626,7 +637,14 @@ long ssl_sout (SSLSTREAM *stream,char *string,unsigned
> + /* until request satisfied */
> + for (i = 0; size > 0; string += i,size -= i)
> + /* write as much as we can */
> +- if ((i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size))) < 0) {
> ++ do {
> ++ i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size));
> ++ } while ((i == -1 &&
> ++ SSL_get_error(stream->con, i) == SSL_ERROR_SYSCALL && errno == EINTR) ||
> ++ (i < 0 &&
> ++ (SSL_get_error(stream->con, i) == SSL_ERROR_WANT_READ ||
> ++ SSL_get_error(stream->con, i) == SSL_ERROR_WANT_WRITE)));
> ++ if (i < 0) {
> + if (tcpdebug) {
> + char tmp[MAILTMPLEN];
> + sprintf (tmp,"SSL data write I/O error %d SSL error %d",
>

No comments:

Post a Comment