Skip to content

Commit 0bbcd60

Browse files
kaduktmshort
authored andcommitted
Buffer all provided quic data
Make all data supplied via SSL_provide_quic_data() pass through an internal buffer, so that we can handle data supplied with arbitrary framing and only parse complete TLS records onto the list of QUIC_DATA managed by quic_input_data_head/quic_input_data_tail. This lets us remove the concept of "incomplete" QUIC_DATA structures, and the 'offset' field needed to support them. However, we've already moved the provided data onto the buffer by the time we can check for KeyUpdate messages, so defer that check to quic_get_message() (where it is adjacent to the preexisting ChangeCipherSpec check). To avoid extra memory copies, we also make the QUIC_DATA structures just store offsets into the consolidated buffer instead of having copies of the TLS handshake messages themselves.
1 parent 93f2e10 commit 0bbcd60

File tree

4 files changed

+50
-43
lines changed

4 files changed

+50
-43
lines changed

ssl/ssl_lib.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,7 @@ void SSL_free(SSL *s)
12131213
#ifndef OPENSSL_NO_QUIC
12141214
OPENSSL_free(s->ext.quic_transport_params);
12151215
OPENSSL_free(s->ext.peer_quic_transport_params);
1216+
BUF_MEM_free(s->quic_buf);
12161217
while (s->quic_input_data_head != NULL) {
12171218
QUIC_DATA *qd;
12181219

ssl/ssl_local.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,9 +1084,8 @@ typedef struct cert_pkey_st CERT_PKEY;
10841084
struct quic_data_st {
10851085
struct quic_data_st *next;
10861086
OSSL_ENCRYPTION_LEVEL level;
1087-
size_t offset;
1087+
size_t start; /* offset into quic_buf->data */
10881088
size_t length;
1089-
/* char data[]; should be here but C90 VLAs not allowed here */
10901089
};
10911090
typedef struct quic_data_st QUIC_DATA;
10921091
int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level);
@@ -1408,8 +1407,10 @@ struct ssl_st {
14081407
#ifndef OPENSSL_NO_QUIC
14091408
OSSL_ENCRYPTION_LEVEL quic_read_level;
14101409
OSSL_ENCRYPTION_LEVEL quic_write_level;
1410+
BUF_MEM *quic_buf; /* buffer incoming handshake messages */
14111411
QUIC_DATA *quic_input_data_head;
14121412
QUIC_DATA *quic_input_data_tail;
1413+
size_t quic_next_record_start;
14131414
const SSL_QUIC_METHOD *quic_method;
14141415
#endif
14151416
/*

ssl/ssl_quic.c

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl)
9191
int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
9292
const uint8_t *data, size_t len)
9393
{
94-
size_t l;
95-
uint8_t mt;
94+
size_t l, offset;
9695

9796
if (!SSL_IS_QUIC(ssl)) {
9897
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
@@ -106,64 +105,62 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
106105
return 0;
107106
}
108107

109-
/* Split on handshake message boundaries, if necessary */
110-
while (len > 0) {
111-
QUIC_DATA *qd;
112-
const uint8_t *p;
113-
114-
/* Check for an incomplete block */
115-
qd = ssl->quic_input_data_tail;
116-
if (qd != NULL) {
117-
l = qd->length - qd->offset;
118-
if (l != 0) {
119-
/* we still need to copy `l` bytes into the last data block */
120-
if (l > len)
121-
l = len;
122-
memcpy((char*)(qd+1) + qd->offset, data, l);
123-
qd->offset += l;
124-
len -= l;
125-
data += l;
126-
continue;
127-
}
108+
if (ssl->quic_buf == NULL) {
109+
BUF_MEM *buf;
110+
if ((buf = BUF_MEM_new()) == NULL) {
111+
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR);
112+
return 0;
128113
}
129-
130-
if (len < SSL3_HM_HEADER_LENGTH) {
131-
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH);
114+
if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
115+
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR);
116+
BUF_MEM_free(buf);
132117
return 0;
133118
}
119+
ssl->quic_buf = buf;
120+
/* We preallocated storage, but there's still no *data*. */
121+
ssl->quic_buf->length = 0;
122+
buf = NULL;
123+
}
124+
125+
offset = ssl->quic_buf->length;
126+
if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) {
127+
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR);
128+
return 0;
129+
}
130+
memcpy(ssl->quic_buf->data + offset, data, len);
131+
132+
/* Split on handshake message boundaries */
133+
while (ssl->quic_buf->length > ssl->quic_next_record_start
134+
+ SSL3_HM_HEADER_LENGTH) {
135+
QUIC_DATA *qd;
136+
const uint8_t *p;
137+
134138
/* TLS Handshake message header has 1-byte type and 3-byte length */
135-
mt = *data;
136-
p = data + 1;
139+
p = (const uint8_t *)ssl->quic_buf->data
140+
+ ssl->quic_next_record_start + 1;
137141
n2l3(p, l);
138142
l += SSL3_HM_HEADER_LENGTH;
139-
if (mt == SSL3_MT_KEY_UPDATE) {
140-
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_UNEXPECTED_MESSAGE);
141-
return 0;
142-
}
143+
/* Don't allocate a QUIC_DATA if we don't have a full record */
144+
if (l > ssl->quic_buf->length - ssl->quic_next_record_start)
145+
break;
143146

144-
qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l);
147+
qd = OPENSSL_zalloc(sizeof(*qd));
145148
if (qd == NULL) {
146149
SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_INTERNAL_ERROR);
147150
return 0;
148151
}
149152

150153
qd->next = NULL;
151154
qd->length = l;
155+
qd->start = ssl->quic_next_record_start;
152156
qd->level = level;
153-
/* partial data received? */
154-
if (l > len)
155-
l = len;
156-
qd->offset = l;
157157

158-
memcpy((void*)(qd + 1), data, l);
159158
if (ssl->quic_input_data_tail != NULL)
160159
ssl->quic_input_data_tail->next = qd;
161160
else
162161
ssl->quic_input_data_head = qd;
163162
ssl->quic_input_data_tail = qd;
164-
165-
data += l;
166-
len -= l;
163+
ssl->quic_next_record_start += l;
167164
}
168165

169166
return 1;

ssl/statem/statem_quic.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
1717
QUIC_DATA *qd = s->quic_input_data_head;
1818
uint8_t *p;
1919

20-
if (qd == NULL || (qd->length - qd->offset) != 0) {
20+
if (qd == NULL) {
2121
s->rwstate = SSL_READING;
2222
*mt = *len = 0;
2323
return 0;
@@ -46,7 +46,7 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
4646
}
4747

4848
/* Copy buffered data */
49-
memcpy(s->init_buf->data, (void*)(qd + 1), qd->length);
49+
memcpy(s->init_buf->data, s->quic_buf->data + qd->start, qd->length);
5050
s->init_buf->length = qd->length;
5151
s->quic_input_data_head = qd->next;
5252
if (s->quic_input_data_head == NULL)
@@ -67,6 +67,14 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
6767
*len = 0;
6868
return 0;
6969
}
70+
/* No KeyUpdate in QUIC */
71+
if (*mt == SSL3_MT_KEY_UPDATE) {
72+
SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_QUIC_GET_MESSAGE,
73+
SSL_R_UNEXPECTED_MESSAGE);
74+
*len = 0;
75+
return 0;
76+
}
77+
7078

7179
/*
7280
* If receiving Finished, record MAC of prior handshake messages for

0 commit comments

Comments
 (0)