ustream-openssl: clear error stack before SSL_read/SSL_write openwrt-19.07
authorJo-Philipp Wich <jo@mein.io>
Fri, 13 Mar 2020 09:37:06 +0000 (10:37 +0100)
committerJo-Philipp Wich <jo@mein.io>
Wed, 6 May 2020 17:44:09 +0000 (19:44 +0200)
The OpenSSL library uses a global error queue per thread which needs to
be cleared prior to calling I/O functions in order to get reliable error
results.

Failure to do so will lead to stray errors reported by SSL_get_error()
when an unrelated connection within the same thread encountered a TLS
error since the last SSL_read() or SSL_write() on the current connection.

This issue was frequently triggered by Google Chrome which usually
initiates simultaneous TLS connections (presumably for protocol support
probing) and subsequently closes most of them with a "certificate unknown"
TLS error, causing the next SSL_get_error() to report an SSL library error
instead of the expected SSL_WANT_READ or SSL_WANT_WRITE error states.

Solve this issue by invoking ERR_clear_error() prior to invoking SSL_read()
or SSL_write() to ensure that the subsequent SSL_get_error() returns
current valid results.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
(cherry picked from commit 5e1bc3429cbf9c3be4db65ef5dbf21ea99cf5b95)

ustream-openssl.c

index 1469473..fa99e67 100644 (file)
@@ -256,6 +256,8 @@ __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us)
        void *ssl = us->ssl;
        int r;
 
+       ERR_clear_error();
+
        if (us->server)
                r = SSL_accept(ssl);
        else
@@ -277,7 +279,11 @@ __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us)
 __hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int len)
 {
        void *ssl = us->ssl;
-       int ret = SSL_write(ssl, buf, len);
+       int ret;
+
+       ERR_clear_error();
+
+       ret = SSL_write(ssl, buf, len);
 
        if (ret < 0) {
                int err = SSL_get_error(ssl, ret);
@@ -293,7 +299,11 @@ __hidden int __ustream_ssl_write(struct ustream_ssl *us, const char *buf, int le
 
 __hidden int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len)
 {
-       int ret = SSL_read(us->ssl, buf, len);
+       int ret;
+
+       ERR_clear_error();
+
+       ret = SSL_read(us->ssl, buf, len);
 
        if (ret < 0) {
                ret = SSL_get_error(us->ssl, ret);