Re: mail/alpine vs GMail vs TLSv1.3
On Thu, Apr 30 2020, 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]. > > > 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. > > 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. Rationale makes sense and changes look good. ok jca@ Regarding the comment, is it only gmail that tells us to retry writes? (If not, please tweak the comment.) > [1]: > https://repo.or.cz/alpine.git/blob/99948a254e2c2352547b962cbd1c23738e7af6b3:/imap/src/osdep/unix/ssl_unix.c#l446 > > 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 - 1.46 > +++ Makefile 29 Apr 2020 13:29:40 - > @@ -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 - > +++ patches/patch-imap_src_osdep_unix_ssl_unix_c 30 Apr 2020 10:49:20 > - > @@ -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 || > ++ SS
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 - 1.46 > +++ Makefile 29 Apr 2020 13:29:40 - > @@ -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 - > +++ patches/patch-imap_src_osdep_unix_ssl_unix_c 30 Apr 2020 10:49:20 > - > @@ -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) ==
mail/alpine vs GMail vs TLSv1.3
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]. 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. 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 Index: Makefile === RCS file: /var/cvs/ports/mail/alpine/Makefile,v retrieving revision 1.46 diff -u -p -r1.46 Makefile --- Makefile20 Mar 2020 16:44:24 - 1.46 +++ Makefile29 Apr 2020 13:29:40 - @@ -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 - +++ patches/patch-imap_src_osdep_unix_ssl_unix_c30 Apr 2020 10:49:20 - @@ -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",