diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 8d23a72d300eb..a46b7563d9ca2 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1213,6 +1213,7 @@ void SSL_free(SSL *s) #ifndef OPENSSL_NO_QUIC OPENSSL_free(s->ext.quic_transport_params); OPENSSL_free(s->ext.peer_quic_transport_params); + BUF_MEM_free(s->quic_buf); while (s->quic_input_data_head != NULL) { QUIC_DATA *qd; diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index fa61ec838c10c..04f67ce939de9 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1084,9 +1084,8 @@ typedef struct cert_pkey_st CERT_PKEY; struct quic_data_st { struct quic_data_st *next; OSSL_ENCRYPTION_LEVEL level; - size_t offset; + size_t start; /* offset into quic_buf->data */ size_t length; - /* char data[]; should be here but C90 VLAs not allowed here */ }; typedef struct quic_data_st QUIC_DATA; int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level); @@ -1408,8 +1407,10 @@ struct ssl_st { #ifndef OPENSSL_NO_QUIC OSSL_ENCRYPTION_LEVEL quic_read_level; OSSL_ENCRYPTION_LEVEL quic_write_level; + BUF_MEM *quic_buf; /* buffer incoming handshake messages */ QUIC_DATA *quic_input_data_head; QUIC_DATA *quic_input_data_tail; + size_t quic_next_record_start; const SSL_QUIC_METHOD *quic_method; #endif /* diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c index 339414ded0218..2427342633a76 100644 --- a/ssl/ssl_quic.c +++ b/ssl/ssl_quic.c @@ -91,8 +91,7 @@ OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl) int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, const uint8_t *data, size_t len) { - size_t l; - uint8_t mt; + size_t l, offset; if (!SSL_IS_QUIC(ssl)) { SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); @@ -106,42 +105,46 @@ 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; - - /* 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; - } + if (ssl->quic_buf == NULL) { + BUF_MEM *buf; + if ((buf = BUF_MEM_new()) == NULL) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR); + return 0; } - - if (len < SSL3_HM_HEADER_LENGTH) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH); + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR); + BUF_MEM_free(buf); return 0; } + ssl->quic_buf = buf; + /* We preallocated storage, but there's still no *data*. */ + ssl->quic_buf->length = 0; + buf = NULL; + } + + offset = ssl->quic_buf->length; + if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) { + SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR); + return 0; + } + memcpy(ssl->quic_buf->data + offset, data, len); + + /* Split on handshake message boundaries */ + while (ssl->quic_buf->length > ssl->quic_next_record_start + + SSL3_HM_HEADER_LENGTH) { + QUIC_DATA *qd; + const uint8_t *p; + /* TLS Handshake message header has 1-byte type and 3-byte length */ - mt = *data; - p = data + 1; + p = (const uint8_t *)ssl->quic_buf->data + + ssl->quic_next_record_start + 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); - return 0; - } + /* Don't allocate a QUIC_DATA if we don't have a full record */ + if (l > ssl->quic_buf->length - ssl->quic_next_record_start) + break; - qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l); + qd = OPENSSL_zalloc(sizeof(*qd)); if (qd == NULL) { SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR); return 0; @@ -149,21 +152,15 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, qd->next = NULL; qd->length = l; + qd->start = ssl->quic_next_record_start; qd->level = level; - /* partial data received? */ - if (l > len) - l = len; - qd->offset = l; - memcpy((void*)(qd + 1), data, l); if (ssl->quic_input_data_tail != NULL) ssl->quic_input_data_tail->next = qd; else ssl->quic_input_data_head = qd; ssl->quic_input_data_tail = qd; - - data += l; - len -= l; + ssl->quic_next_record_start += l; } return 1; diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c index a2ba29337c049..2843938ce2ef4 100644 --- a/ssl/statem/statem_quic.c +++ b/ssl/statem/statem_quic.c @@ -17,7 +17,7 @@ int quic_get_message(SSL *s, int *mt, size_t *len) QUIC_DATA *qd = s->quic_input_data_head; uint8_t *p; - if (qd == NULL || (qd->length - qd->offset) != 0) { + if (qd == NULL) { s->rwstate = SSL_READING; *mt = *len = 0; return 0; @@ -46,7 +46,7 @@ int quic_get_message(SSL *s, int *mt, size_t *len) } /* Copy buffered data */ - memcpy(s->init_buf->data, (void*)(qd + 1), qd->length); + memcpy(s->init_buf->data, s->quic_buf->data + qd->start, qd->length); s->init_buf->length = qd->length; s->quic_input_data_head = qd->next; if (s->quic_input_data_head == NULL) @@ -67,6 +67,14 @@ int quic_get_message(SSL *s, int *mt, size_t *len) *len = 0; return 0; } + /* No KeyUpdate in QUIC */ + if (*mt == SSL3_MT_KEY_UPDATE) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_QUIC_GET_MESSAGE, + SSL_R_UNEXPECTED_MESSAGE); + *len = 0; + return 0; + } + /* * If receiving Finished, record MAC of prior handshake messages for