diff options
author | Matt Caswell <matt@openssl.org> | 2016-01-12 14:52:35 +0000 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2016-03-07 21:39:27 +0000 |
commit | 94777c9c86a2b2ea2726c49d6c8f61078558beba (patch) | |
tree | a0c4cc27b76e5e4044bdb34c21dd1f298af8094d | |
parent | 2f2c9caa727d7d2a5ce4bfb8266e019546ce77df (diff) |
Implement read pipeline support in libssl
Read pipelining is controlled in a slightly different way than with write
pipelining. While reading we are constrained by the number of records that
the peer (and the network) can provide to us in one go. The more records
we can get in one go the more opportunity we have to parallelise the
processing.
There are two parameters that affect this:
* The number of pipelines that we are willing to process in one go. This is
controlled by max_pipelines (as for write pipelining)
* The size of our read buffer. A subsequent commit will provide an API for
adjusting the size of the buffer.
Another requirement for this to work is that "read_ahead" must be set. The
read_ahead parameter will attempt to read as much data into our read buffer
as the network can provide. Without this set, data is read into the read
buffer on demand. Setting the max_pipelines parameter to a value greater
than 1 will automatically also turn read_ahead on.
Finally, the read pipelining as currently implemented will only parallelise
the processing of application data records. This would only make a
difference for renegotiation so is unlikely to have a significant impact.
Reviewed-by: Tim Hudson <tjh@openssl.org>
-rw-r--r-- | ssl/record/rec_layer_d1.c | 4 | ||||
-rw-r--r-- | ssl/record/rec_layer_s3.c | 139 | ||||
-rw-r--r-- | ssl/record/record.h | 5 | ||||
-rw-r--r-- | ssl/record/record_locl.h | 14 | ||||
-rw-r--r-- | ssl/record/ssl3_record.c | 618 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 4 |
6 files changed, 472 insertions, 312 deletions
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c index cd033e008f..86b65854fc 100644 --- a/ssl/record/rec_layer_d1.c +++ b/ssl/record/rec_layer_d1.c @@ -355,7 +355,7 @@ int dtls1_process_buffered_records(SSL *s) if (!dtls1_process_record(s)) return (0); if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds), - SSL3_RECORD_get_seq_num(&s->rlayer.rrec)) < 0) + SSL3_RECORD_get_seq_num(s->rlayer.rrec)) < 0) return -1; } } @@ -464,7 +464,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, * s->s3->rrec.off, - offset into 'data' for next read * s->s3->rrec.length, - number of bytes. */ - rr = &s->rlayer.rrec; + rr = s->rlayer.rrec; /* * We are not handshaking and have no data yet, so process data buffered diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 3a232e5807..1aceed3aa5 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -135,8 +135,8 @@ void RECORD_LAYER_init(RECORD_LAYER *rl, SSL *s) { rl->s = s; - SSL3_RECORD_clear(&rl->rrec); - SSL3_RECORD_clear(&rl->wrec); + SSL3_RECORD_clear(rl->rrec, SSL_MAX_PIPELINES); + SSL3_RECORD_clear(&rl->wrec, 1); } void RECORD_LAYER_clear(RECORD_LAYER *rl) @@ -166,8 +166,8 @@ void RECORD_LAYER_clear(RECORD_LAYER *rl) for(pipes = 0; pipes < rl->numwpipes; pipes++) SSL3_BUFFER_clear(&rl->wbuf[pipes]); rl->numwpipes = 0; - SSL3_RECORD_clear(&rl->rrec); - SSL3_RECORD_clear(&rl->wrec); + SSL3_RECORD_clear(rl->rrec, SSL_MAX_PIPELINES); + SSL3_RECORD_clear(&rl->wrec, 1); RECORD_LAYER_reset_read_sequence(rl); RECORD_LAYER_reset_write_sequence(rl); @@ -182,7 +182,8 @@ void RECORD_LAYER_release(RECORD_LAYER *rl) ssl3_release_read_buffer(rl->s); if (rl->numwpipes > 0) ssl3_release_write_buffer(rl->s); - SSL3_RECORD_release(&rl->rrec); + /* TODO: Check why there is no release of wrec here?? */ + SSL3_RECORD_release(rl->rrec, SSL_MAX_PIPELINES); } int RECORD_LAYER_read_pending(RECORD_LAYER *rl) @@ -224,16 +225,25 @@ void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl) int RECORD_LAYER_setup_comp_buffer(RECORD_LAYER *rl) { - return SSL3_RECORD_setup(&(rl)->rrec); + return SSL3_RECORD_setup((rl)->rrec, SSL_MAX_PIPELINES); } int ssl3_pending(const SSL *s) { + unsigned int i; + int num = 0; + if (s->rlayer.rstate == SSL_ST_READ_BODY) return 0; - return (SSL3_RECORD_get_type(&s->rlayer.rrec) == SSL3_RT_APPLICATION_DATA) - ? SSL3_RECORD_get_length(&s->rlayer.rrec) : 0; + for (i = 0; i < RECORD_LAYER_get_numrpipes(&s->rlayer); i++) { + if (SSL3_RECORD_get_type(&s->rlayer.rrec[i]) + != SSL3_RT_APPLICATION_DATA) + return 0; + num += SSL3_RECORD_get_length(&s->rlayer.rrec[i]); + } + + return num; } const char *SSL_rstate_string_long(const SSL *s) @@ -278,7 +288,7 @@ const char *SSL_rstate_string(const SSL *s) return (str); } -int ssl3_read_n(SSL *s, int n, int max, int extend) +int ssl3_read_n(SSL *s, int n, int max, int extend, int clearold) { /* * If extend == 0, obtain new n-byte packet; if extend == 1, increase @@ -286,6 +296,8 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) * s->s3->rbuf.buf specified by s->packet and s->packet_length. (If * s->rlayer.read_ahead is set, 'max' bytes may be stored in rbuf [plus * s->packet_length bytes if extend == 1].) + * if clearold == 1, move the packet to the start of the buffer; if + * clearold == 0 then leave any old packets where they were */ int i, len, left; size_t align = 0; @@ -362,7 +374,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) * Move any available bytes to front of buffer: 'len' bytes already * pointed to by 'packet', 'left' extra ones at the end */ - if (s->rlayer.packet != pkt) { /* len > 0 */ + if (s->rlayer.packet != pkt && clearold == 1) { /* len > 0 */ memmove(pkt, s->rlayer.packet, len + left); s->rlayer.packet = pkt; rb->offset = len + align; @@ -1071,11 +1083,14 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, int len, int peek) { int al, i, j, ret; - unsigned int n; + unsigned int n, curr_rec, num_recs, read_bytes; SSL3_RECORD *rr; + SSL3_BUFFER *rbuf; void (*cb) (const SSL *ssl, int type2, int val) = NULL; - if (!SSL3_BUFFER_is_initialised(&s->rlayer.rbuf)) { + rbuf = &s->rlayer.rbuf; + + if (!SSL3_BUFFER_is_initialised(rbuf)) { /* Not initialized yet */ if (!ssl3_setup_read_buffer(s)) return (-1); @@ -1132,20 +1147,40 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, s->rwstate = SSL_NOTHING; /*- - * s->s3->rrec.type - is the type of record - * s->s3->rrec.data, - data - * s->s3->rrec.off, - offset into 'data' for next read - * s->s3->rrec.length, - number of bytes. + * For each record 'i' up to |num_recs] + * rr[i].type - is the type of record + * rr[i].data, - data + * rr[i].off, - offset into 'data' for next read + * rr[i].length, - number of bytes. */ - rr = &s->rlayer.rrec; - - /* get new packet if necessary */ - if ((SSL3_RECORD_get_length(rr) == 0) - || (s->rlayer.rstate == SSL_ST_READ_BODY)) { - ret = ssl3_get_record(s); - if (ret <= 0) - return (ret); - } + rr = s->rlayer.rrec; + num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer); + + do { + /* get new records if necessary */ + if (num_recs == 0) { + ret = ssl3_get_record(s); + if (ret <= 0) + return (ret); + num_recs = RECORD_LAYER_get_numrpipes(&s->rlayer); + if (num_recs == 0) { + /* Shouldn't happen */ + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); + goto f_err; + } + } + /* Skip over any records we have already used or are zero in length */ + for (curr_rec = 0; + curr_rec < num_recs && SSL3_RECORD_get_length(&rr[curr_rec]) == 0; + curr_rec++); + if (curr_rec == num_recs) { + RECORD_LAYER_set_numrpipes(&s->rlayer, 0); + num_recs = 0; + curr_rec = 0; + } + } while (num_recs == 0); + rr = &rr[curr_rec]; /* we now have a packet which can be read and processed */ @@ -1200,24 +1235,36 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, if (len <= 0) return (len); - if ((unsigned int)len > SSL3_RECORD_get_length(rr)) - n = SSL3_RECORD_get_length(rr); - else - n = (unsigned int)len; - - memcpy(buf, &(rr->data[rr->off]), n); - if (!peek) { - SSL3_RECORD_add_length(rr, -n); - SSL3_RECORD_add_off(rr, n); - if (SSL3_RECORD_get_length(rr) == 0) { - s->rlayer.rstate = SSL_ST_READ_HEADER; - SSL3_RECORD_set_off(rr, 0); - if (s->mode & SSL_MODE_RELEASE_BUFFERS - && SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) - ssl3_release_read_buffer(s); + read_bytes = 0; + do { + if ((unsigned int)len - read_bytes > SSL3_RECORD_get_length(rr)) + n = SSL3_RECORD_get_length(rr); + else + n = (unsigned int)len - read_bytes; + + memcpy(buf, &(rr->data[rr->off]), n); + buf += n; + if (!peek) { + SSL3_RECORD_add_length(rr, -n); + SSL3_RECORD_add_off(rr, n); + if (SSL3_RECORD_get_length(rr) == 0) { + s->rlayer.rstate = SSL_ST_READ_HEADER; + SSL3_RECORD_set_off(rr, 0); + } } - } - return (n); + if (SSL3_RECORD_get_length(rr) == 0 + || (peek && n == SSL3_RECORD_get_length(rr))) { + curr_rec++; + rr++; + } + read_bytes += n; + } while (type == SSL3_RT_APPLICATION_DATA && curr_rec < num_recs + && read_bytes < (unsigned int)len); + if (!peek && curr_rec == num_recs + && (s->mode & SSL_MODE_RELEASE_BUFFERS) + && SSL3_BUFFER_get_left(rbuf) == 0) + ssl3_release_read_buffer(s); + return read_bytes; } /* @@ -1339,7 +1386,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { - if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) { + if (SSL3_BUFFER_get_left(rbuf) == 0) { /* no read-ahead left? */ BIO *bio; /* @@ -1477,7 +1524,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { - if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) { + if (SSL3_BUFFER_get_left(rbuf) == 0) { /* no read-ahead left? */ BIO *bio; /* @@ -1561,7 +1608,7 @@ void ssl3_record_sequence_update(unsigned char *seq) */ int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl) { - return SSL3_RECORD_is_sslv2_record(&rl->rrec); + return SSL3_RECORD_is_sslv2_record(&rl->rrec[0]); } /* @@ -1569,5 +1616,5 @@ int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl) */ unsigned int RECORD_LAYER_get_rrec_length(RECORD_LAYER *rl) { - return SSL3_RECORD_get_length(&rl->rrec); + return SSL3_RECORD_get_length(&rl->rrec[0]); } diff --git a/ssl/record/record.h b/ssl/record/record.h index 6105dedd44..bf3ffa3cfd 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -253,13 +253,16 @@ typedef struct record_layer_st { /* where we are when reading */ int rstate; + /* How many pipelines can be used to read data */ + unsigned int numrpipes; + /* How many pipelines can be used to write data */ unsigned int numwpipes; /* read IO goes into here */ SSL3_BUFFER rbuf; /* write IO goes into here */ SSL3_BUFFER wbuf[SSL_MAX_PIPELINES]; /* each decoded record goes in here */ - SSL3_RECORD rrec; + SSL3_RECORD rrec[SSL_MAX_PIPELINES]; /* goes out from here */ SSL3_RECORD wrec; diff --git a/ssl/record/record_locl.h b/ssl/record/record_locl.h index f44cda16e5..8239549beb 100644 --- a/ssl/record/record_locl.h +++ b/ssl/record/record_locl.h @@ -120,7 +120,7 @@ #define RECORD_LAYER_get_rbuf(rl) (&(rl)->rbuf) #define RECORD_LAYER_get_wbuf(rl) ((rl)->wbuf) -#define RECORD_LAYER_get_rrec(rl) (&(rl)->rrec) +#define RECORD_LAYER_get_rrec(rl) ((rl)->rrec) #define RECORD_LAYER_get_wrec(rl) (&(rl)->wrec) #define RECORD_LAYER_set_packet(rl, p) ((rl)->packet = (p)) #define RECORD_LAYER_reset_packet_length(rl) ((rl)->packet_length = 0) @@ -128,9 +128,11 @@ #define RECORD_LAYER_set_rstate(rl, st) ((rl)->rstate = (st)) #define RECORD_LAYER_get_read_sequence(rl) ((rl)->read_sequence) #define RECORD_LAYER_get_write_sequence(rl) ((rl)->write_sequence) +#define RECORD_LAYER_get_numrpipes(rl) ((rl)->numrpipes) +#define RECORD_LAYER_set_numrpipes(rl, n) ((rl)->numrpipes = (n)) #define DTLS_RECORD_LAYER_get_r_epoch(rl) ((rl)->d->r_epoch) -__owur int ssl3_read_n(SSL *s, int n, int max, int extend); +__owur int ssl3_read_n(SSL *s, int n, int max, int extend, int clearold); void RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, const unsigned char *ws); DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, @@ -189,13 +191,13 @@ int ssl3_release_write_buffer(SSL *s); #define SSL3_RECORD_is_sslv2_record(r) \ ((r)->rec_version == SSL2_VERSION) -void SSL3_RECORD_clear(SSL3_RECORD *r); -void SSL3_RECORD_release(SSL3_RECORD *r); -int SSL3_RECORD_setup(SSL3_RECORD *r); +void SSL3_RECORD_clear(SSL3_RECORD *r, unsigned int num_recs); +void SSL3_RECORD_release(SSL3_RECORD *r, unsigned int num_recs); +int SSL3_RECORD_setup(SSL3_RECORD *r, unsigned int num_recs); void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num); int ssl3_get_record(SSL *s); __owur int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr); -__owur int ssl3_do_uncompress(SSL *ssl); +__owur int ssl3_do_uncompress(SSL *ssl, SSL3_RECORD *rr); void ssl3_cbc_copy_mac(unsigned char *out, const SSL3_RECORD *rec, unsigned md_size); __owur int ssl3_cbc_remove_padding(SSL3_RECORD *rec, diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index ad19621b11..33122626ec 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -134,27 +134,44 @@ static const unsigned char ssl3_pad_2[48] = { /* * Clear the contents of an SSL3_RECORD but retain any memory allocated */ -void SSL3_RECORD_clear(SSL3_RECORD *r) +void SSL3_RECORD_clear(SSL3_RECORD *r, unsigned int num_recs) { - unsigned char *comp = r->comp; + unsigned char *comp; + unsigned int i; - memset(r, 0, sizeof(*r)); - r->comp = comp; + for (i = 0; i < num_recs; i++) { + comp = r[i].comp; + + memset(&r[i], 0, sizeof(*r)); + r[i].comp = comp; + } } -void SSL3_RECORD_release(SSL3_RECORD *r) +void SSL3_RECORD_release(SSL3_RECORD *r, unsigned int num_recs) { - OPENSSL_free(r->comp); - r->comp = NULL; + unsigned int i; + + for (i = 0; i < num_recs; i++) { + OPENSSL_free(r[i].comp); + r[i].comp = NULL; + } } -int SSL3_RECORD_setup(SSL3_RECORD *r) +int SSL3_RECORD_setup(SSL3_RECORD *r, unsigned int num_recs) { - if (r->comp == NULL) - r->comp = (unsigned char *) - OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH); - if (r->comp == NULL) - return 0; + unsigned int i; + + for (i = 0; i < num_recs; i++) { + if (r[i].comp == NULL) + r[i].comp = (unsigned char *) + OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH); + if (r[i].comp == NULL) { + if (i > 0) + SSL3_RECORD_release(r, i); + return 0; + } + } + return 1; } @@ -163,6 +180,46 @@ void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num) memcpy(r->seq_num, seq_num, SEQ_NUM_SIZE); } + +/* + * Peeks ahead into "read_ahead" data to see if we have a whole record waiting + * for us in the buffer. + */ +static int have_whole_app_data_record_waiting(SSL *s) +{ + SSL3_BUFFER *rbuf; + int left, len; + unsigned char *p; + + rbuf = RECORD_LAYER_get_rbuf(&s->rlayer); + + p = SSL3_BUFFER_get_buf(rbuf); + if (p == NULL) + return 0; + + left = SSL3_BUFFER_get_left(rbuf); + + if (left < SSL3_RT_HEADER_LENGTH) + return 0; + + p += SSL3_BUFFER_get_offset(rbuf); + + /* + * We only check the type and record length, we will sanity check version + * etc later + */ + if (*p != SSL3_RT_APPLICATION_DATA) + return 0; + + p += 3; + n2s(p, len); + + if (left < SSL3_RT_HEADER_LENGTH + len) + return 0; + + return 1; +} + /* * MAX_EMPTY_RECORDS defines the number of consecutive, empty records that * will be processed per call to ssl3_get_record. Without this limit an @@ -173,13 +230,16 @@ void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num) #define SSL2_RT_HEADER_LENGTH 2 /*- - * Call this to get a new input record. + * Call this to get new input records. * It will return <= 0 if more data is needed, normally due to an error * or non-blocking IO. - * When it finishes, one packet has been decoded and can be found in - * ssl->s3->rrec.type - is the type of record - * ssl->s3->rrec.data, - data - * ssl->s3->rrec.length, - number of bytes + * When it finishes, |numrpipes| records have been decoded. For each record 'i': + * rr[i].type - is the type of record + * rr[i].data, - data + * rr[i].length, - number of bytes + * Multiple records will only be returned if the record types are all + * SSL3_RT_APPLICATION_DATA. The number of records returned will always be <= + * |max_pipelines| */ /* used only by ssl3_read_bytes */ int ssl3_get_record(SSL *s) @@ -187,177 +247,205 @@ int ssl3_get_record(SSL *s) int ssl_major, ssl_minor, al; int enc_err, n, i, ret = -1; SSL3_RECORD *rr; + SSL3_BUFFER *rbuf; SSL_SESSION *sess; unsigned char *p; unsigned char md[EVP_MAX_MD_SIZE]; short version; unsigned mac_size; - unsigned empty_record_count = 0; + unsigned empty_record_count = 0, curr_empty = 0; + unsigned int num_recs = 0; + unsigned int max_recs; + unsigned int j; rr = RECORD_LAYER_get_rrec(&s->rlayer); + rbuf = RECORD_LAYER_get_rbuf(&s->rlayer); + max_recs = s->max_pipelines; + if (max_recs == 0) + max_recs = 1; sess = s->session; again: - /* check if we have the header */ - if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) || - (RECORD_LAYER_get_packet_length(&s->rlayer) < SSL3_RT_HEADER_LENGTH)) { - n = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, - SSL3_BUFFER_get_len(&s->rlayer.rbuf), 0); - if (n <= 0) - return (n); /* error or non-blocking */ - RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY); + do { + /* check if we have the header */ + if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) || + (RECORD_LAYER_get_packet_length(&s->rlayer) + < SSL3_RT_HEADER_LENGTH)) { + n = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, + SSL3_BUFFER_get_len(rbuf), 0, num_recs == 0 ? 1 : 0); + if (n <= 0) + return (n); /* error or non-blocking */ + RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY); + + p = RECORD_LAYER_get_packet(&s->rlayer); - p = RECORD_LAYER_get_packet(&s->rlayer); - - /* - * Check whether this is a regular record or an SSLv2 style record. The - * latter is only used in an initial ClientHello for old clients. We - * check s->read_hash and s->enc_read_ctx to ensure this does not apply - * during renegotiation - */ - if (s->first_packet && s->server && !s->read_hash && !s->enc_read_ctx - && (p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO)) { - /* SSLv2 style record */ - rr->type = SSL3_RT_HANDSHAKE; - rr->rec_version = SSL2_VERSION; - - rr->length = ((p[0] & 0x7f) << 8) | p[1]; - - if (rr->length > SSL3_BUFFER_get_len(&s->rlayer.rbuf) - - SSL2_RT_HEADER_LENGTH) { - al = SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG); - goto f_err; - } + /* + * Check whether this is a regular record or an SSLv2 style record. + * The latter is only used in an initial ClientHello for old + * clients. We check s->read_hash and s->enc_read_ctx to ensure this + * does not apply during renegotiation + */ + if (s->first_packet && s->server && !s->read_hash + && !s->enc_read_ctx + && (p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO)) { + /* SSLv2 style record */ + rr[num_recs].type = SSL3_RT_HANDSHAKE; + rr[num_recs].rec_version = SSL2_VERSION; + + rr[num_recs].length = ((p[0] & 0x7f) << 8) | p[1]; + + if (rr[num_recs].length > SSL3_BUFFER_get_len(&rbuf[num_recs]) + - SSL2_RT_HEADER_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG); + goto f_err; + } - if (rr->length < MIN_SSL2_RECORD_LEN) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT); - goto f_err; - } - } else { - /* SSLv3+ style record */ - if (s->msg_callback) - s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s, - s->msg_callback_arg); - - /* Pull apart the header into the SSL3_RECORD */ - rr->type = *(p++); - ssl_major = *(p++); - ssl_minor = *(p++); - version = (ssl_major << 8) | ssl_minor; - rr->rec_version = version; - n2s(p, rr->length); - - /* Lets check version */ - if (!s->first_packet && version != s->version) { - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER); - if ((s->version & 0xFF00) == (version & 0xFF00) - && !s->enc_write_ctx && !s->write_hash) { - if (rr->type == SSL3_RT_ALERT) { + if (rr[num_recs].length < MIN_SSL2_RECORD_LEN) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + } else { + /* SSLv3+ style record */ + if (s->msg_callback) + s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s, + s->msg_callback_arg); + + /* Pull apart the header into the SSL3_RECORD */ + rr[num_recs].type = *(p++); + ssl_major = *(p++); + ssl_minor = *(p++); + version = (ssl_major << 8) | ssl_minor; + rr[num_recs].rec_version = version; + n2s(p, rr[num_recs].length); + + /* Lets check version */ + if (!s->first_packet && version != s->version) { + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER); + if ((s->version & 0xFF00) == (version & 0xFF00) + && !s->enc_write_ctx && !s->write_hash) { + if (rr->type == SSL3_RT_ALERT) { + /* + * The record is using an incorrect version number, + * but what we've got appears to be an alert. We + * haven't read the body yet to check whether its a + * fatal or not - but chances are it is. We probably + * shouldn't send a fatal alert back. We'll just + * end. + */ + goto err; + } /* - * The record is using an incorrect version number, but - * what we've got appears to be an alert. We haven't - * read the body yet to check whether its a fatal or - * not - but chances are it is. We probably shouldn't - * send a fatal alert back. We'll just end. + * Send back error using their minor version number :-) */ - goto err; + s->version = (unsigned short)version; } - /* - * Send back error using their minor version number :-) - */ - s->version = (unsigned short)version; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; } - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - if ((version >> 8) != SSL3_VERSION_MAJOR) { - if (s->first_packet) { - /* Go back to start of packet, look at the five bytes - * that we have. */ - p = RECORD_LAYER_get_packet(&s->rlayer); - if (strncmp((char *)p, "GET ", 4) == 0 || - strncmp((char *)p, "POST ", 5) == 0 || - strncmp((char *)p, "HEAD ", 5) == 0 || - strncmp((char *)p, "PUT ", 4) == 0) { - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_HTTP_REQUEST); - goto err; - } else if (strncmp((char *)p, "CONNE", 5) == 0) { - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_HTTPS_PROXY_REQUEST); - goto err; + if ((version >> 8) != SSL3_VERSION_MAJOR) { + if (s->first_packet) { + /* Go back to start of packet, look at the five bytes + * that we have. */ + p = RECORD_LAYER_get_packet(&s->rlayer); + if (strncmp((char *)p, "GET ", 4) == 0 || + strncmp((char *)p, "POST ", 5) == 0 || + strncmp((char *)p, "HEAD ", 5) == 0 || + strncmp((char *)p, "PUT ", 4) == 0) { + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_HTTP_REQUEST); + goto err; + } else if (strncmp((char *)p, "CONNE", 5) == 0) { + SSLerr(SSL_F_SSL3_GET_RECORD, + SSL_R_HTTPS_PROXY_REQUEST); + goto err; + } } + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER); + goto err; } - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER); - goto err; - } - if (rr->length > - SSL3_BUFFER_get_len(&s->rlayer.rbuf) - - SSL3_RT_HEADER_LENGTH) { - al = SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG); - goto f_err; + if (rr[num_recs].length > + SSL3_BUFFER_get_len(rbuf) - SSL3_RT_HEADER_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG); + goto f_err; + } } + + /* now s->rlayer.rstate == SSL_ST_READ_BODY */ } - /* now s->rlayer.rstate == SSL_ST_READ_BODY */ - } + /* + * s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data. + * Calculate how much more data we need to read for the rest of the + * record + */ + if (rr[num_recs].rec_version == SSL2_VERSION) { + i = rr[num_recs].length + SSL2_RT_HEADER_LENGTH + - SSL3_RT_HEADER_LENGTH; + } else { + i = rr[num_recs].length; + } + if (i > 0) { + /* now s->packet_length == SSL3_RT_HEADER_LENGTH */ - /* - * s->rlayer.rstate == SSL_ST_READ_BODY, get and decode the data. - * Calculate how much more data we need to read for the rest of the record - */ - if (rr->rec_version == SSL2_VERSION) { - i = rr->length + SSL2_RT_HEADER_LENGTH - SSL3_RT_HEADER_LENGTH; - } else { - i = rr->length; - } - if (i > 0) { - /* now s->packet_length == SSL3_RT_HEADER_LENGTH */ + n = ssl3_read_n(s, i, i, 1, 0); + if (n <= 0) + return (n); /* error or non-blocking io */ + } - n = ssl3_read_n(s, i, i, 1); - if (n <= 0) - return (n); /* error or non-blocking io */ - } + /* set state for later operations */ + RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER); - /* set state for later operations */ - RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER); + /* + * At this point, s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length, + * or s->packet_length == SSL2_RT_HEADER_LENGTH + rr->length + * and we have that many bytes in s->packet + */ + if(rr[num_recs].rec_version == SSL2_VERSION) { + rr[num_recs].input = + &(RECORD_LAYER_get_packet(&s->rlayer)[SSL2_RT_HEADER_LENGTH]); + } else { + rr[num_recs].input = + &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]); + } - /* - * At this point, s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length, - * or s->packet_length == SSL2_RT_HEADER_LENGTH + rr->length - * and we have that many bytes in s->packet - */ - if(rr->rec_version == SSL2_VERSION) { - rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[SSL2_RT_HEADER_LENGTH]); - } else { - rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]); - } + /* + * ok, we can now read from 's->packet' data into 'rr' rr->input points + * at rr->length bytes, which need to be copied into rr->data by either + * the decryption or by the decompression When the data is 'copied' into + * the rr->data buffer, rr->input will be pointed at the new buffer + */ - /* - * ok, we can now read from 's->packet' data into 'rr' rr->input points - * at rr->length bytes, which need to be copied into rr->data by either - * the decryption or by the decompression When the data is 'copied' into - * the rr->data buffer, rr->input will be pointed at the new buffer - */ + /* + * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length + * bytes of encrypted compressed stuff. + */ - /* - * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length - * bytes of encrypted compressed stuff. - */ + /* check is not needed I believe */ + if (rr[num_recs].length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); + goto f_err; + } + + /* decrypt in place in 'rr->input' */ + rr[num_recs].data = rr[num_recs].input; + rr[num_recs].orig_len = rr[num_recs].length; + num_recs++; + + /* we have pulled in a full packet so zero things */ + RECORD_LAYER_reset_packet_length(&s->rlayer); + } while (num_recs < max_recs && rr->type == SSL3_RT_APPLICATION_DATA + && SSL_USE_EXPLICIT_IV(s) + && s->enc_read_ctx != NULL + && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_read_ctx)) + & EVP_CIPH_FLAG_PIPELINE) + && have_whole_app_data_record_waiting(s)); - /* check is not needed I believe */ - if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { - al = SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); - goto f_err; - } - /* decrypt in place in 'rr->input' */ - rr->data = rr->input; - rr->orig_len = rr->length; /* * If in encrypt-then-mac mode calculate mac from encrypted record. All * the details below are public so no timing details can leak. @@ -366,23 +454,25 @@ int ssl3_get_record(SSL *s) unsigned char *mac; mac_size = EVP_MD_CTX_size(s->read_hash); OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE); - if (rr->length < mac_size) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT); - goto f_err; - } - rr->length -= mac_size; - mac = rr->data + rr->length; - i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ ); - if (i < 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) { - al = SSL_AD_BAD_RECORD_MAC; - SSLerr(SSL_F_SSL3_GET_RECORD, - SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); - goto f_err; + for (j = 0; j < num_recs; j++) { + if (rr[j].length < mac_size) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + rr[j].length -= mac_size; + mac = rr[j].data + rr[j].length; + i = s->method->ssl3_enc->mac(s, &rr[j], md, 0 /* not send */ ); + if (i < 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) { + al = SSL_AD_BAD_RECORD_MAC; + SSLerr(SSL_F_SSL3_GET_RECORD, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + goto f_err; + } } } < |