diff --git a/ChangeLog.d/tls12-handshake-length-read-bounds.txt b/ChangeLog.d/tls12-handshake-length-read-bounds.txt new file mode 100644 index 0000000000..f9e14e209b --- /dev/null +++ b/ChangeLog.d/tls12-handshake-length-read-bounds.txt @@ -0,0 +1,6 @@ +Bugfix + * Fix a one-byte buffer over-read when parsing a TLS 1.2 ClientHello or + CertificateRequest. The length checks preceding the ciphersuite-list + length (server side) and the certificate-authorities length (client + side) reserved one byte too few, so a truncated message could cause the + two-byte length field to be read one byte past the end of the message. diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c index 8799287a09..b3341770ea 100644 --- a/library/ssl_tls12_client.c +++ b/library/ssl_tls12_client.c @@ -2279,6 +2279,16 @@ static int ssl_parse_certificate_request(mbedtls_ssl_context *ssl) n += 2 + sig_alg_len; + /* The signature-algorithms check above leaves room for only one of the two + * distinguished-name length bytes, so make sure both are in the message + * before reading them. */ + if (ssl->in_hslen < mbedtls_ssl_hs_hdr_len(ssl) + 3 + n) { + MBEDTLS_SSL_DEBUG_MSG(1, ("bad certificate request message")); + mbedtls_ssl_send_alert_message(ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR); + return MBEDTLS_ERR_SSL_DECODE_ERROR; + } + /* certificate_authorities */ dn_len = MBEDTLS_GET_UINT16_BE(buf, mbedtls_ssl_hs_hdr_len(ssl) + 1 + n); diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index 2a825e07b1..85d7a8c625 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -1074,6 +1074,16 @@ static int ssl_parse_client_hello(mbedtls_ssl_context *ssl) #endif /* MBEDTLS_SSL_PROTO_DTLS */ ciph_offset = 35 + sess_len; + /* The two-byte ciphersuite list length field must be within the message. + * The DTLS branch above reserves it via the cookie length check; the + * session id length check does not, so guard the read here. */ + if (ciph_offset + 2 > msg_len) { + MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message")); + mbedtls_ssl_send_alert_message(ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR); + return MBEDTLS_ERR_SSL_DECODE_ERROR; + } + ciph_len = MBEDTLS_GET_UINT16_BE(buf, ciph_offset); if (ciph_len < 2 ||