Simplify fragmented HelloRequest state.

With server-side renegotiation gone, handshake_fragment's only purpose
in life is to handle a fragmented HelloRequest (we probably do need to
support those if some server does 1/n-1 record-splitting on handshake
records). The logic to route the data into
ssl3_read_bytes(SSL3_RT_HANDSHAKE) never happens, and the contents are
always a HelloRequest prefix.

This also trims a tiny bit of per-connection state.

Change-Id: Ia1b0dda5b7e79d817c28da1478640977891ebc97
Reviewed-on: https://boringssl-review.googlesource.com/6641
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2015-11-26 01:39:53 -05:00 committed by Adam Langley
parent ef5dfd2980
commit 8fd5c23218
2 changed files with 25 additions and 55 deletions

View File

@ -3949,10 +3949,9 @@ typedef struct ssl3_state_st {
SSL3_RECORD rrec; /* each decoded record goes in here */ SSL3_RECORD rrec; /* each decoded record goes in here */
/* storage for Handshake protocol data received but not yet processed by /* hello_request_len is the number of bytes of HelloRequest received, possibly
* ssl3_read_bytes: */ * split over multiple records. */
uint8_t handshake_fragment[4]; uint8_t hello_request_len;
unsigned int handshake_fragment_len;
/* partial write - check the numbers match */ /* partial write - check the numbers match */
unsigned int wnum; /* number of bytes sent so far */ unsigned int wnum; /* number of bytes sent so far */

View File

@ -317,11 +317,10 @@ static int do_ssl3_write(SSL *s, int type, const uint8_t *buf, unsigned len) {
/* ssl3_expect_change_cipher_spec informs the record layer that a /* ssl3_expect_change_cipher_spec informs the record layer that a
* ChangeCipherSpec record is required at this point. If a Handshake record is * ChangeCipherSpec record is required at this point. If a Handshake record is
* received before ChangeCipherSpec, the connection will fail. Moreover, if * received before ChangeCipherSpec, the connection will fail. If there is an
* there are unprocessed handshake bytes, the handshake will also fail and the * unprocessed handshake message, it returns zero. Otherwise, it returns one. */
* function returns zero. Otherwise, the function returns one. */
int ssl3_expect_change_cipher_spec(SSL *s) { int ssl3_expect_change_cipher_spec(SSL *s) {
if (s->s3->handshake_fragment_len > 0 || s->s3->tmp.reuse_message) { if (s->s3->tmp.reuse_message) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNPROCESSED_HANDSHAKE_DATA); OPENSSL_PUT_ERROR(SSL, SSL_R_UNPROCESSED_HANDSHAKE_DATA);
return 0; return 0;
} }
@ -393,29 +392,6 @@ int ssl3_read_bytes(SSL *s, int type, uint8_t *buf, int len, int peek) {
return -1; return -1;
} }
if (type == SSL3_RT_HANDSHAKE && s->s3->handshake_fragment_len > 0) {
/* (partially) satisfy request from storage */
uint8_t *src = s->s3->handshake_fragment;
uint8_t *dst = buf;
unsigned int k;
/* peek == 0 */
n = 0;
while (len > 0 && s->s3->handshake_fragment_len > 0) {
*dst++ = *src++;
len--;
s->s3->handshake_fragment_len--;
n++;
}
/* move any remaining fragment bytes: */
for (k = 0; k < s->s3->handshake_fragment_len; k++) {
s->s3->handshake_fragment[k] = *src++;
}
return n;
}
/* Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
/* This may require multiple iterations. False Start will cause /* This may require multiple iterations. False Start will cause
* |s->handshake_func| to signal success one step early, but the handshake * |s->handshake_func| to signal success one step early, but the handshake
* must be completely finished before other modes are accepted. * must be completely finished before other modes are accepted.
@ -532,33 +508,28 @@ start:
goto f_err; goto f_err;
} }
/* HelloRequests may be fragmented across multiple records. */ /* This must be a HelloRequest, possibly fragmented over multiple records.
const size_t size = sizeof(s->s3->handshake_fragment); * Consume data from the handshake protocol until it is complete. */
const size_t avail = size - s->s3->handshake_fragment_len; static const uint8_t kHelloRequest[] = {SSL3_MT_HELLO_REQUEST, 0, 0, 0};
const size_t todo = (rr->length < avail) ? rr->length : avail; while (s->s3->hello_request_len < sizeof(kHelloRequest)) {
memcpy(s->s3->handshake_fragment + s->s3->handshake_fragment_len, if (rr->length == 0) {
&rr->data[rr->off], todo); /* Get a new record. */
rr->off += todo; goto start;
rr->length -= todo; }
s->s3->handshake_fragment_len += todo; if (rr->data[rr->off] != kHelloRequest[s->s3->hello_request_len]) {
if (s->s3->handshake_fragment_len < size) { al = SSL_AD_DECODE_ERROR;
goto start; /* fragment was too small */ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST);
goto f_err;
}
rr->off++;
rr->length--;
s->s3->hello_request_len++;
} }
s->s3->hello_request_len = 0;
/* Parse out and consume a HelloRequest. */
if (s->s3->handshake_fragment[0] != SSL3_MT_HELLO_REQUEST ||
s->s3->handshake_fragment[1] != 0 ||
s->s3->handshake_fragment[2] != 0 ||
s->s3->handshake_fragment[3] != 0) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST);
goto f_err;
}
s->s3->handshake_fragment_len = 0;
if (s->msg_callback) { if (s->msg_callback) {
s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, kHelloRequest,
s->s3->handshake_fragment, 4, s, s->msg_callback_arg); sizeof(kHelloRequest), s, s->msg_callback_arg);
} }
if (!SSL_is_init_finished(s) || !s->s3->initial_handshake_complete) { if (!SSL_is_init_finished(s) || !s->s3->initial_handshake_complete) {