Skip to content

Commit

Permalink
deps: cherry-pick akamai/openssl/commit/bf4b08ecfbb7a26ca4b0b9ecaee3b…
Browse files Browse the repository at this point in the history
…31d18d7bda9

Original Commit Message:

  Fix out-of-bounds read when TLS msg is split up into multiple chunks

  Previously, SSL_provide_quic_data tried to handle this kind of
  situation, but it failed when the length of input data is less than
  SSL3_HM_HEADER_LENGTH.  If that happens, the code might get wrong
  message length by reading value from out-of-bounds region.

PR-URL: #34033
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
  • Loading branch information
tatsuhiro-t authored and jasnell committed Jun 24, 2020
1 parent c3d85b7 commit ec7ad1d
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 30 deletions.
2 changes: 2 additions & 0 deletions deps/openssl/openssl/ssl/ssl_local.h
Expand Up @@ -1410,6 +1410,8 @@ struct ssl_st {
OSSL_ENCRYPTION_LEVEL quic_write_level;
QUIC_DATA *quic_input_data_head;
QUIC_DATA *quic_input_data_tail;
uint8_t quic_msg_hd[SSL3_HM_HEADER_LENGTH];
size_t quic_msg_hd_offset;
const SSL_QUIC_METHOD *quic_method;
#endif
/*
Expand Down
104 changes: 74 additions & 30 deletions deps/openssl/openssl/ssl/ssl_quic.c
Expand Up @@ -93,6 +93,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
{
size_t l;
uint8_t mt;
QUIC_DATA *qd;

if (!SSL_IS_QUIC(ssl)) {
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
Expand All @@ -106,35 +107,65 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
return 0;
}

/* Split on handshake message boundaries, if necessary */
while (len > 0) {
QUIC_DATA *qd;
const uint8_t *p;
if (len == 0) {
return 1;
}

/* Check for an incomplete block */
qd = ssl->quic_input_data_tail;
if (qd != NULL) {
l = qd->length - qd->offset;
if (l != 0) {
/* we still need to copy `l` bytes into the last data block */
if (l > len)
l = len;
memcpy((char*)(qd+1) + qd->offset, data, l);
qd->offset += l;
len -= l;
data += l;
continue;
}
/* Check for an incomplete block */
qd = ssl->quic_input_data_tail;
if (qd != NULL) {
l = qd->length - qd->offset;
if (l != 0) {
/* we still need to copy `l` bytes into the last data block */
if (l > len)
l = len;
memcpy((char *)(qd + 1) + qd->offset, data, l);
qd->offset += l;
len -= l;
data += l;
}
}

if (len < SSL3_HM_HEADER_LENGTH) {
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH);
return 0;
/* Split the QUIC messages up, if necessary */
while (len > 0) {
const uint8_t *p;
uint8_t *dst;

if (ssl->quic_msg_hd_offset != 0) {
/* If we have already buffered premature message header,
try to add new data to it to form complete message
header. */
size_t nread =
SSL3_HM_HEADER_LENGTH - ssl->quic_msg_hd_offset;

if (len < nread)
nread = len;
memcpy(ssl->quic_msg_hd + ssl->quic_msg_hd_offset, data, nread);
ssl->quic_msg_hd_offset += nread;

if (ssl->quic_msg_hd_offset < SSL3_HM_HEADER_LENGTH) {
/* We still have premature message header. */
break;
}
data += nread;
len -= nread;
/* TLS Handshake message header has 1-byte type and 3-byte length */
mt = *ssl->quic_msg_hd;
p = ssl->quic_msg_hd + 1;
n2l3(p, l);
} else if (len < SSL3_HM_HEADER_LENGTH) {
/* We don't get complete message header. Just buffer the
received data and wait for the next data to arrive. */
memcpy(ssl->quic_msg_hd, data, len);
ssl->quic_msg_hd_offset += len;
break;
} else {
/* We have complete message header in data. */
/* TLS Handshake message header has 1-byte type and 3-byte length */
mt = *data;
p = data + 1;
n2l3(p, l);
}
/* TLS Handshake message header has 1-byte type and 3-byte length */
mt = *data;
p = data + 1;
n2l3(p, l);
l += SSL3_HM_HEADER_LENGTH;
if (mt == SSL3_MT_KEY_UPDATE) {
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_UNEXPECTED_MESSAGE);
Expand All @@ -150,12 +181,23 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
qd->next = NULL;
qd->length = l;
qd->level = level;
/* partial data received? */
if (l > len)
l = len;
qd->offset = l;

memcpy((void*)(qd + 1), data, l);
dst = (uint8_t *)(qd + 1);
if (ssl->quic_msg_hd_offset) {
memcpy(dst, ssl->quic_msg_hd, ssl->quic_msg_hd_offset);
dst += ssl->quic_msg_hd_offset;
l -= SSL3_HM_HEADER_LENGTH;
if (l > len)
l = len;
qd->offset = SSL3_HM_HEADER_LENGTH + l;
memcpy(dst, data, l);
} else {
/* partial data received? */
if (l > len)
l = len;
qd->offset = l;
memcpy(dst, data, l);
}
if (ssl->quic_input_data_tail != NULL)
ssl->quic_input_data_tail->next = qd;
else
Expand All @@ -164,6 +206,8 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,

data += l;
len -= l;

ssl->quic_msg_hd_offset = 0;
}

return 1;
Expand Down

0 comments on commit ec7ad1d

Please sign in to comment.