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",
> 

Reply via email to