Hi, This patch is for CVE-2016-8610. See http://seclists.org/oss-sec/2016/q4/224 .
- Don't allow too many consecutive warning alerts up to MAX_WARN_ALERT_COUNT OpenSSL seems not to fix this issue on branch 1.0.1. Then I refer to these 2 commits on branch 1.0.2. - Don't allow too many consecutive warning alerts https://github.com/openssl/openssl/commit/22646a075e75991b4e8f5d67171e45a6aead5b48 - Add missing error string for SSL_R_TOO_MANY_WARN_ALERTS https://github.com/openssl/openssl/commit/f1f97699cb5e01f1b7e37f4c92df1a9bce6772f5 With this patch, I could build LibreSSL portable and confirmed all regressions were passed. But, I could not test by POC or exploit code since it is not opened. This patch is created by command `cvs diff -Nau`. ok ? Index: lib/libssl/d1_pkt.c =================================================================== RCS file: /cvs/src/lib/libssl/d1_pkt.c,v retrieving revision 1.48 diff -u -p -a -u -r1.48 d1_pkt.c --- lib/libssl/d1_pkt.c 11 Sep 2015 18:08:21 -0000 1.48 +++ lib/libssl/d1_pkt.c 26 Oct 2016 09:35:28 -0000 @@ -722,6 +722,13 @@ start: goto start; } + /* + * Reset the count of consecutive warning alerts if we've got a non-empty + * record that isn't an alert. + */ + if (rr->type != SSL3_RT_ALERT && rr->length != 0) + s->cert->alert_count = 0; + /* we now have a packet which can be read and processed */ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, @@ -932,15 +939,21 @@ start: cb(s, SSL_CB_READ_ALERT, j); } - if (alert_level == 1) /* warning */ - { + if (alert_level == SSL3_AL_WARNING) { s->s3->warn_alert = alert_descr; + + s->cert->alert_count++; + if (s->cert->alert_count == MAX_WARN_ALERT_COUNT) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS); + goto f_err; + } + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { s->shutdown |= SSL_RECEIVED_SHUTDOWN; return (0); } - } else if (alert_level == 2) /* fatal */ - { + } else if (alert_level == SSL3_AL_FATAL) { s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); Index: lib/libssl/s3_pkt.c =================================================================== RCS file: /cvs/src/lib/libssl/s3_pkt.c,v retrieving revision 1.58 diff -u -p -a -u -r1.58 s3_pkt.c --- lib/libssl/s3_pkt.c 10 Jul 2016 23:07:34 -0000 1.58 +++ lib/libssl/s3_pkt.c 26 Oct 2016 09:35:29 -0000 @@ -914,6 +914,13 @@ start: return (ret); } + /* + * Reset the count of consecutive warning alerts if we've got a non-empty + * record that isn't an alert. + */ + if (rr->type != SSL3_RT_ALERT && rr->length != 0) + s->cert->alert_count = 0; + /* we now have a packet which can be read and processed */ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, @@ -1103,9 +1110,17 @@ start: cb(s, SSL_CB_READ_ALERT, j); } - if (alert_level == 1) { + if (alert_level == SSL3_AL_WARNING) { /* warning */ s->s3->warn_alert = alert_descr; + + s->cert->alert_count++; + if (s->cert->alert_count == MAX_WARN_ALERT_COUNT) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS); + goto f_err; + } + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { s->shutdown |= SSL_RECEIVED_SHUTDOWN; return (0); @@ -1125,7 +1140,7 @@ start: SSL_R_NO_RENEGOTIATION); goto f_err; } - } else if (alert_level == 2) { + } else if (alert_level == SSL3_AL_FATAL) { /* fatal */ s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; Index: lib/libssl/ssl.h =================================================================== RCS file: /cvs/src/lib/libssl/ssl.h,v retrieving revision 1.96 diff -u -p -a -u -r1.96 ssl.h --- lib/libssl/ssl.h 25 Oct 2015 16:07:04 -0000 1.96 +++ lib/libssl/ssl.h 26 Oct 2016 09:35:30 -0000 @@ -2329,6 +2329,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157 #define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233 #define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234 +#define SSL_R_TOO_MANY_WARN_ALERTS 409 #define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 235 #define SSL_R_UNABLE_TO_DECODE_DH_CERTS 236 #define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 313 Index: lib/libssl/ssl_err.c =================================================================== RCS file: /cvs/src/lib/libssl/ssl_err.c,v retrieving revision 1.29 diff -u -p -a -u -r1.29 ssl_err.c --- lib/libssl/ssl_err.c 22 Feb 2015 15:54:27 -0000 1.29 +++ lib/libssl/ssl_err.c 26 Oct 2016 09:35:30 -0000 @@ -549,6 +549,7 @@ static ERR_STRING_DATA SSL_str_reasons[] {ERR_REASON(SSL_R_TLS_HEARTBEAT_PENDING) , "heartbeat request already pending"}, {ERR_REASON(SSL_R_TLS_ILLEGAL_EXPORTER_LABEL), "tls illegal exporter label"}, {ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST), "tls invalid ecpointformat list"}, + {ERR_REASON(SSL_R_TOO_MANY_WARN_ALERTS), "too many warn alerts"}, {ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST), "tls peer did not respond with certificate list"}, {ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG), "tls rsa encrypted value length is wrong"}, {ERR_REASON(SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER), "tried to use unsupported cipher"}, Index: lib/libssl/ssl_locl.h =================================================================== RCS file: /cvs/src/lib/libssl/ssl_locl.h,v retrieving revision 1.130 diff -u -p -a -u -r1.130 ssl_locl.h --- lib/libssl/ssl_locl.h 19 Oct 2016 16:38:40 -0000 1.130 +++ lib/libssl/ssl_locl.h 26 Oct 2016 09:35:31 -0000 @@ -425,6 +425,8 @@ typedef struct cert_pkey_st { const EVP_MD *digest; } CERT_PKEY; +#define MAX_WARN_ALERT_COUNT 5 + typedef struct cert_st { /* Current active set */ CERT_PKEY *key; /* ALWAYS points to an element of the pkeys array @@ -448,6 +450,9 @@ typedef struct cert_st { CERT_PKEY pkeys[SSL_PKEY_NUM]; int references; /* >1 only if SSL_copy_session_id is used */ + + /* Count of the number of consecutive warning alerts received */ + unsigned int alert_count; } CERT;