Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
deps: cherry-pick akamai/openssl/commit/bf4b08ecfbb7a26ca4b0b9ecaee3b…
…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.
  • Loading branch information
tatsuhiro-t authored and jasnell committed Jun 23, 2020
commit 7540e94b1048431b5c88585dcf9b2b4049602151
2 changes: 2 additions & 0 deletions deps/openssl/openssl/ssl/ssl_local.h
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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