summaryrefslogtreecommitdiffstats
path: root/ssl/record
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2015-09-22 11:12:50 +0100
committerMatt Caswell <matt@openssl.org>2016-03-07 21:39:27 +0000
commitd102d9df8625cb6f75c537b7f2a696bb5f305ff2 (patch)
tree905ded5ae4a3c44de312bf87f5d7b91b949b0eb5 /ssl/record
parent98ee75439d7e844de6c063a4be5bd09b3cc9db53 (diff)
Implement write pipeline support in libssl
Use the new pipeline cipher capability to encrypt multiple records being written out all in one go. Two new SSL/SSL_CTX parameters can be used to control how this works: max_pipelines and split_send_fragment. max_pipelines defines the maximum number of pipelines that can ever be used in one go for a single connection. It must always be less than or equal to SSL_MAX_PIPELINES (currently defined to be 32). By default only one pipeline will be used (i.e. normal non-parallel operation). split_send_fragment defines how data is split up into pipelines. The number of pipelines used will be determined by the amount of data provided to the SSL_write call divided by split_send_fragment. For example if split_send_fragment is set to 2000 and max_pipelines is 4 then: SSL_write called with 0-2000 bytes == 1 pipeline used SSL_write called with 2001-4000 bytes == 2 pipelines used SSL_write called with 4001-6000 bytes == 3 pipelines used SSL_write_called with 6001+ bytes == 4 pipelines used split_send_fragment must always be less than or equal to max_send_fragment. By default it is set to be equal to max_send_fragment. This will mean that the same number of records will always be created as would have been created in the non-parallel case, although the data will be apportioned differently. In the parallel case data will be spread equally between the pipelines. Reviewed-by: Tim Hudson <tjh@openssl.org>
Diffstat (limited to 'ssl/record')
-rw-r--r--ssl/record/rec_layer_d1.c8
-rw-r--r--ssl/record/rec_layer_s3.c329
-rw-r--r--ssl/record/record.h17
-rw-r--r--ssl/record/record_locl.h6
-rw-r--r--ssl/record/ssl3_buffer.c47
-rw-r--r--ssl/record/ssl3_record.c229
6 files changed, 401 insertions, 235 deletions
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index a1b0e9e7db..cd033e008f 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -1039,7 +1039,7 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
SSL3_BUFFER *wb;
SSL_SESSION *sess;
- wb = &s->rlayer.wbuf;
+ wb = &s->rlayer.wbuf[0];
/*
* first check if there is a SSL3_BUFFER still being written out. This
@@ -1128,7 +1128,7 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
/* first we compress */
if (s->compress != NULL) {
- if (!ssl3_do_compress(s)) {
+ if (!ssl3_do_compress(s, wr)) {
SSLerr(SSL_F_DO_DTLS1_WRITE, SSL_R_COMPRESSION_FAILURE);
goto err;
}
@@ -1145,7 +1145,7 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
*/
if (mac_size != 0) {
- if (s->method->ssl3_enc->mac(s,
+ if (s->method->ssl3_enc->mac(s, wr,
&(p[SSL3_RECORD_get_length(wr) + eivlen]), 1) < 0)
goto err;
SSL3_RECORD_add_length(wr, mac_size);
@@ -1158,7 +1158,7 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
if (eivlen)
SSL3_RECORD_add_length(wr, eivlen);
- if (s->method->ssl3_enc->enc(s, 1) < 1)
+ if (s->method->ssl3_enc->enc(s, wr, 1, 1) < 1)
goto err;
/* record length after mac and block padding */
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index 6a4f92f9ba..3a232e5807 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -141,6 +141,8 @@ void RECORD_LAYER_init(RECORD_LAYER *rl, SSL *s)
void RECORD_LAYER_clear(RECORD_LAYER *rl)
{
+ unsigned int pipes;
+
rl->rstate = SSL_ST_READ_HEADER;
/* Do I need to clear read_ahead? As far as I can tell read_ahead did not
@@ -161,7 +163,9 @@ void RECORD_LAYER_clear(RECORD_LAYER *rl)
rl->wpend_buf = NULL;
SSL3_BUFFER_clear(&rl->rbuf);
- SSL3_BUFFER_clear(&rl->wbuf);
+ 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);
@@ -176,7 +180,7 @@ void RECORD_LAYER_release(RECORD_LAYER *rl)
{
if (SSL3_BUFFER_is_initialised(&rl->rbuf))
ssl3_release_read_buffer(rl->s);
- if (SSL3_BUFFER_is_initialised(&rl->wbuf))
+ if (rl->numwpipes > 0)
ssl3_release_write_buffer(rl->s);
SSL3_RECORD_release(&rl->rrec);
}
@@ -188,7 +192,8 @@ int RECORD_LAYER_read_pending(RECORD_LAYER *rl)
int RECORD_LAYER_write_pending(RECORD_LAYER *rl)
{
- return SSL3_BUFFER_get_left(&rl->wbuf) != 0;
+ return (rl->numwpipes > 0)
+ && SSL3_BUFFER_get_left(&rl->wbuf[rl->numwpipes-1]) != 0;
}
int RECORD_LAYER_set_data(RECORD_LAYER *rl, const unsigned char *buf, int len)
@@ -433,10 +438,10 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
int tot;
unsigned int n, nw;
#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
- unsigned int max_send_fragment;
+ unsigned int max_send_fragment, split_send_fragment, maxpipes;
unsigned int u_len = (unsigned int)len;
#endif
- SSL3_BUFFER *wb = &s->rlayer.wbuf;
+ SSL3_BUFFER *wb = &s->rlayer.wbuf[0];
int i;
if (len < 0) {
@@ -622,13 +627,70 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
}
n = (len - tot);
+
+ split_send_fragment = s->split_send_fragment;
+ /*
+ * If max_pipelines is 0 then this means "undefined" and we default to
+ * 1 pipeline. Similaraly if the cipher does not support pipelined
+ * processing then we also only use 1 pipeline, or if we're not using
+ * explicit IVs
+ */
+ maxpipes = s->max_pipelines;
+ if (maxpipes > SSL_MAX_PIPELINES) {
+ /*
+ * We should have prevented this when we set max_pipelines so we
+ * shouldn't get here
+ */
+ SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ if (maxpipes == 0
+ || s->enc_write_ctx == NULL
+ || !(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx))
+ & EVP_CIPH_FLAG_PIPELINE)
+ || !SSL_USE_EXPLICIT_IV(s))
+ maxpipes = 1;
+ if (s->max_send_fragment == 0 || split_send_fragment > s->max_send_fragment
+ || split_send_fragment == 0) {
+ /*
+ * We should have prevented this when we set the split and max send
+ * fragments so we shouldn't get here
+ */
+ SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
for (;;) {
- if (n > s->max_send_fragment)
- nw = s->max_send_fragment;
+ unsigned int pipelens[SSL_MAX_PIPELINES], tmppipelen, remain;
+ unsigned int numpipes, j;
+
+ if (n == 0)
+ numpipes = 1;
else
- nw = n;
+ numpipes = ((n - 1) / split_send_fragment) + 1;
+ if (numpipes > maxpipes)
+ numpipes = maxpipes;
+
+ if (n / numpipes >= s->max_send_fragment) {
+ /*
+ * We have enough data to completely fill all available
+ * pipelines
+ */
+ for (j = 0; j < numpipes; j++) {
+ pipelens[j] = s->max_send_fragment;
+ }
+ } else {
+ /* We can partially fill all available pipelines */
+ tmppipelen = n / numpipes;
+ remain = n % numpipes;
+ for (j = 0; j < numpipes; j++) {
+ pipelens[j] = tmppipelen;
+ if (j < remain)
+ pipelens[j]++;
+ }
+ }
- i = do_ssl3_write(s, type, &(buf[tot]), nw, 0);
+ i = do_ssl3_write(s, type, &(buf[tot]), pipelens, numpipes, 0);
if (i <= 0) {
/* XXX should we ssl3_release_write_buffer if i<0? */
s->rlayer.wnum = tot;
@@ -657,23 +719,28 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
}
int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
- unsigned int len, int create_empty_fragment)
+ unsigned int *pipelens, unsigned int numpipes,
+ int create_empty_fragment)
{
- unsigned char *p, *plen;
+ unsigned char *outbuf[SSL_MAX_PIPELINES], *plen[SSL_MAX_PIPELINES];
+ SSL3_RECORD wr[SSL_MAX_PIPELINES];
int i, mac_size, clear = 0;
int prefix_len = 0;
int eivlen;
size_t align = 0;
- SSL3_RECORD *wr;
- SSL3_BUFFER *wb = &s->rlayer.wbuf;
+ SSL3_BUFFER *wb;
SSL_SESSION *sess;
+ unsigned int totlen = 0;
+ unsigned int j;
+ for (j = 0; j < numpipes; j++)
+ totlen += pipelens[j];
/*
* first check if there is a SSL3_BUFFER still being written out. This
* will happen with non blocking IO
*/
- if (SSL3_BUFFER_get_left(wb) != 0)
- return (ssl3_write_pending(s, type, buf, len));
+ if (RECORD_LAYER_write_pending(&s->rlayer))
+ return (ssl3_write_pending(s, type, buf, totlen));
/* If we have an alert to send, lets send it */
if (s->s3->alert_dispatch) {
@@ -683,14 +750,13 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
/* if it went, fall through and send more stuff */
}
- if (!SSL3_BUFFER_is_initialised(wb))
- if (!ssl3_setup_write_buffer(s))
+ if (s->rlayer.numwpipes < numpipes)
+ if (!ssl3_setup_write_buffer(s, numpipes))
return -1;
- if (len == 0 && !create_empty_fragment)
+ if (totlen == 0 && !create_empty_fragment)
return 0;
- wr = &s->rlayer.wrec;
sess = s->session;
if ((sess == NULL) ||
@@ -720,7 +786,9 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
* 'prefix_len' bytes are sent out later together with the actual
* payload)
*/
- prefix_len = do_ssl3_write(s, type, buf, 0, 1);
+ unsigned int tmppipelen = 0;
+
+ prefix_len = do_ssl3_write(s, type, buf, &tmppipelen, 1, 1);
if (prefix_len <= 0)
goto err;
@@ -737,6 +805,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
}
if (create_empty_fragment) {
+ wb = &s->rlayer.wbuf[0];
#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
/*
* extra fragment would be couple of cipher blocks, which would be
@@ -746,38 +815,24 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
align = (size_t)SSL3_BUFFER_get_buf(wb) + 2 * SSL3_RT_HEADER_LENGTH;
align = (0-align) & (SSL3_ALIGN_PAYLOAD - 1);
#endif
- p = SSL3_BUFFER_get_buf(wb) + align;
+ outbuf[0] = SSL3_BUFFER_get_buf(wb) + align;
SSL3_BUFFER_set_offset(wb, align);
} else if (prefix_len) {
- p = SSL3_BUFFER_get_buf(wb) + SSL3_BUFFER_get_offset(wb) + prefix_len;
+ wb = &s->rlayer.wbuf[0];
+ outbuf[0] = SSL3_BUFFER_get_buf(wb) + SSL3_BUFFER_get_offset(wb)
+ + prefix_len;
} else {
+ for (j=0; j < numpipes; j++) {
+ wb = &s->rlayer.wbuf[j];
#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
- align = (size_t)SSL3_BUFFER_get_buf(wb) + SSL3_RT_HEADER_LENGTH;
- align = (0-align) & (SSL3_ALIGN_PAYLOAD - 1);
+ align = (size_t)SSL3_BUFFER_get_buf(wb) + SSL3_RT_HEADER_LENGTH;
+ align = (-align) & (SSL3_ALIGN_PAYLOAD - 1);
#endif
- p = SSL3_BUFFER_get_buf(wb) + align;
- SSL3_BUFFER_set_offset(wb, align);
+ outbuf[j] = SSL3_BUFFER_get_buf(wb) + align;
+ SSL3_BUFFER_set_offset(wb, align);
+ }
}
- /* write the header */
-
- *(p++) = type & 0xff;
- SSL3_RECORD_set_type(wr, type);
-
- *(p++) = (s->version >> 8);
- /*
- * Some servers hang if iniatial client hello is larger than 256 bytes
- * and record version number > TLS 1.0
- */
- if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO
- && !s->renegotiate && TLS1_get_version(s) > TLS1_VERSION)
- *(p++) = 0x1;
- else
- *(p++) = s->version & 0xff;
-
- /* field where we are to write out packet length */
- plen = p;
- p += 2;
/* Explicit IV length, block ciphers appropriate version flag */
if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s)) {
int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
@@ -796,94 +851,132 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
} else
eivlen = 0;
- /* lets setup the record stuff. */
- SSL3_RECORD_set_data(wr, p + eivlen);
- SSL3_RECORD_set_length(wr, (int)len);
- SSL3_RECORD_set_input(wr, (unsigned char *)buf);
+ totlen = 0;
+ /* Clear our SSL3_RECORD structures */
+ memset(wr, 0, sizeof wr);
+ for (j=0; j < numpipes; j++) {
+ /* write the header */
+ *(outbuf[j]++) = type & 0xff;
+ SSL3_RECORD_set_type(&wr[j], type);
- /*
- * we now 'read' from wr->input, wr->length bytes into wr->data
- */
+ *(outbuf[j]++) = (s->version >> 8);
+ /*
+ * Some servers hang if iniatial client hello is larger than 256 bytes
+ * and record version number > TLS 1.0
+ */
+ if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO
+ && !s->renegotiate && TLS1_get_version(s) > TLS1_VERSION)
+ *(outbuf[j]++) = 0x1;
+ else
+ *(outbuf[j]++) = s->version & 0xff;
- /* first we compress */
- if (s->compress != NULL) {
- if (!ssl3_do_compress(s)) {
- SSLerr(SSL_F_DO_SSL3_WRITE, SSL_R_COMPRESSION_FAILURE);
- goto err;
- }
- } else {
- memcpy(wr->data, wr->input, wr->length);
- SSL3_RECORD_reset_input(wr);
- }
+ /* field where we are to write out packet length */
+ plen[j] = outbuf[j];
+ outbuf[j] += 2;
- /*
- * we should still have the output to wr->data and the input from
- * wr->input. Length should be wr->length. wr->data still points in the
- * wb->buf
- */
+ /* lets setup the record stuff. */
+ SSL3_RECORD_set_data(&wr[j], outbuf[j] + eivlen);
+ SSL3_RECORD_set_length(&wr[j], (int)pipelens[j]);
+ SSL3_RECORD_set_input(&wr[j], (unsigned char *)&buf[totlen]);
+ totlen += pipelens[j];
- if (!SSL_USE_ETM(s) && mac_size != 0) {
- if (s->method->ssl3_enc->mac(s, &(p[wr->length + eivlen]), 1) < 0)
- goto err;
- SSL3_RECORD_add_length(wr, mac_size);
- }
+ /*
+ * we now 'read' from wr->input, wr->length bytes into wr->data
+ */
- SSL3_RECORD_set_data(wr, p);
- SSL3_RECORD_reset_input(wr);
+ /* first we compress */
+ if (s->compress != NULL) {
+ if (!ssl3_do_compress(s, &wr[j])) {
+ SSLerr(SSL_F_DO_SSL3_WRITE, SSL_R_COMPRESSION_FAILURE);
+ goto err;
+ }
+ } else {
+ memcpy(wr[j].data, wr[j].input, wr[j].length);
+ SSL3_RECORD_reset_input(&wr[j]);
+ }
- if (eivlen) {
/*
- * if (RAND_pseudo_bytes(p, eivlen) <= 0) goto err;
+ * we should still have the output to wr->data and the input from
+ * wr->input. Length should be wr->length. wr->data still points in the
+ * wb->buf
*/
- SSL3_RECORD_add_length(wr, eivlen);
- }
- if (s->method->ssl3_enc->enc(s, 1) < 1)
- goto err;
+ if (!SSL_USE_ETM(s) && mac_size != 0) {
+ if (s->method->ssl3_enc->mac(s, &wr[j],
+ &(outbuf[j][wr[j].length + eivlen]), 1) < 0)
+ goto err;
+ SSL3_RECORD_add_length(&wr[j], mac_size);
+ }
- if (SSL_USE_ETM(s) && mac_size != 0) {
- if (s->method->ssl3_enc->mac(s, p + wr->length, 1) < 0)
- goto err;
- SSL3_RECORD_add_length(wr, mac_size);
+
+ SSL3_RECORD_set_data(&wr[j], outbuf[j]);
+ SSL3_RECORD_reset_input(&wr[j]);
+
+ if (eivlen) {
+ /*
+ * if (RAND_pseudo_bytes(p, eivlen) <= 0) goto err;
+ */
+ SSL3_RECORD_add_length(&wr[j], eivlen);
+ }
}
- /* record length after mac and block padding */
- s2n(SSL3_RECORD_get_length(wr), plen);
+ if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1)
+ goto err;
- if (s->msg_callback)
- s->msg_callback(1, 0, SSL3_RT_HEADER, plen - 5, 5, s,
- s->msg_callback_arg);
+ for (j=0; j < numpipes; j++) {
+ if (SSL_USE_ETM(s) && mac_size != 0) {
+ if (s->method->ssl3_enc->mac(s, &wr[j],
+ outbuf[j] + wr[j].length, 1) < 0)
+ goto err;
+ SSL3_RECORD_add_length(&wr[j], mac_size);
+ }
- /*
- * we should now have wr->data pointing to the encrypted data, which is
- * wr->length long
- */
- SSL3_RECORD_set_type(wr, type); /* not needed but helps for debugging */
- SSL3_RECORD_add_length(wr, SSL3_RT_HEADER_LENGTH);
+ /* record length after mac and block padding */
+ s2n(SSL3_RECORD_get_length(&wr[j]), plen[j]);
+
+ if (s->msg_callback)
+ s->msg_callback(1, 0, SSL3_RT_HEADER, plen[j] - 5, 5, s,
+ s->msg_callback_arg);
- if (create_empty_fragment) {
/*
- * we are in a recursive call; just return the length, don't write
- * out anything here
+ * we should now have wr->data pointing to the encrypted data, which is
+ * wr->length long
*/
- return SSL3_RECORD_get_length(wr);
+ SSL3_RECORD_set_type(&wr[j], type); /* not needed but helps for debugging */
+ SSL3_RECORD_add_length(&wr[j], SSL3_RT_HEADER_LENGTH);
+
+ if (create_empty_fragment) {
+ /*
+ * we are in a recursive call; just return the length, don't write
+ * out anything here
+ */
+ if (j > 0) {
+ /* We should never be pipelining an empty fragment!! */
+ SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ return SSL3_RECORD_get_length(wr);
+ }
+
+ /* now let's set up wb */
+ SSL3_BUFFER_set_left(&s->rlayer.wbuf[j],
+ prefix_len + SSL3_RECORD_get_length(&wr[j]));
}
- /* now let's set up wb */
- SSL3_BUFFER_set_left(wb, prefix_len + SSL3_RECORD_get_length(wr));
+
/*
* memorize arguments so that ssl3_write_pending can detect bad write
* retries later
*/
- s->rlayer.wpend_tot = len;
+ s->rlayer.wpend_tot = totlen;
s->rlayer.wpend_buf = buf;
s->rlayer.wpend_type = type;
- s->rlayer.wpend_ret = len;
+ s->rlayer.wpend_ret = totlen;
/* we now just need to write the buffer */
- return ssl3_write_pending(s, type, buf, len);
+ return ssl3_write_pending(s, type, buf, totlen);
err:
return -1;
}
@@ -893,7 +986,8 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
unsigned int len)
{
int i;
- SSL3_BUFFER *wb = &s->rlayer.wbuf;
+ SSL3_BUFFER *wb = s->rlayer.wbuf;
+ unsigned int currbuf = 0;
/* XXXX */
if ((s->rlayer.wpend_tot > (int)len)
@@ -905,19 +999,28 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
}
for (;;) {
+ /* Loop until we find a buffer we haven't written out yet */
+ if (SSL3_BUFFER_get_left(&wb[currbuf]) == 0
+ && currbuf < s->rlayer.numwpipes - 1) {
+ currbuf++;
+ continue;
+ }
clear_sys_error();
if (s->wbio != NULL) {
s->rwstate = SSL_WRITING;
i = BIO_write(s->wbio,
- (char *)&(SSL3_BUFFER_get_buf(wb)[SSL3_BUFFER_get_offset(wb)]),
- (unsigned int)SSL3_BUFFER_get_left(wb));
+ (char *)&(SSL3_BUFFER_get_buf(&wb[currbuf])[
+ SSL3_BUFFER_get_offset(&wb[currbuf])]),
+ (unsigned int)SSL3_BUFFER_get_left(&wb[currbuf]));
} else {
SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET);
i = -1;
}
- if (i == SSL3_BUFFER_get_left(wb)) {
- SSL3_BUFFER_set_left(wb, 0);
- SSL3_BUFFER_add_offset(wb, i);
+ if (i == SSL3_BUFFER_get_left(&wb[currbuf])) {
+ SSL3_BUFFER_set_left(&wb[currbuf], 0);
+ SSL3_BUFFER_add_offset(&wb[currbuf], i);
+ if (currbuf + 1 < s->rlayer.numwpipes)
+ continue;
s->rwstate = SSL_NOTHING;
return (s->rlayer.wpend_ret);
} else if (i <= 0) {
@@ -926,12 +1029,12 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
* For DTLS, just drop it. That's kind of the whole point in
* using a datagram service
*/
- SSL3_BUFFER_set_left(wb, 0);
+ SSL3_BUFFER_set_left(&wb[currbuf], 0);
}
return (i);
}
- SSL3_BUFFER_add_offset(wb, i);
- SSL3_BUFFER_add_left(wb, -i);
+ SSL3_BUFFER_add_offset(&wb[currbuf], i);
+ SSL3_BUFFER_add_left(&wb[currbuf], -i);
}
}
diff --git a/ssl/record/record.h b/ssl/record/record.h
index a3b50dcfcf..6105dedd44 100644
--- a/ssl/record/record.h
+++ b/ssl/record/record.h
@@ -252,10 +252,12 @@ typedef struct record_layer_st {
int read_ahead;
/* where we are when reading */
int rstate;
+
+ unsigned int numwpipes;
/* read IO goes into here */
SSL3_BUFFER rbuf;
/* write IO goes into here */
- SSL3_BUFFER wbuf;
+ SSL3_BUFFER wbuf[SSL_MAX_PIPELINES];
/* each decoded record goes in here */
SSL3_RECORD rrec;
/* goes out from here */
@@ -326,16 +328,19 @@ unsigned int RECORD_LAYER_get_rrec_length(RECORD_LAYER *rl);
__owur int ssl3_pending(const SSL *s);
__owur int ssl3_write_bytes(SSL *s, int type, const void *buf, int len);
__owur int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
- unsigned int len, int create_empty_fragment);
+ unsigned int *pipelens, unsigned int numpipes,
+ int create_empty_fragment);
__owur int ssl3_read_bytes(SSL *s, int type, int *recvd_type,
unsigned char *buf, int len, int peek);
__owur int ssl3_setup_buffers(SSL *s);
-__owur int ssl3_enc(SSL *s, int send_data);
-__owur int n_ssl3_mac(SSL *ssl, unsigned char *md, int send_data);
+__owur int ssl3_enc(SSL *s, SSL3_RECORD *inrecs, unsigned int numpipes,
+ int send);
+__owur int n_ssl3_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int send);
__owur int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
unsigned int len);
-__owur int tls1_enc(SSL *s, int snd);
-__owur int tls1_mac(SSL *ssl, unsigned char *md, int snd);
+__owur int tls1_enc(SSL *s, SSL3_RECORD *recs, unsigned int numpipes,
+ int send);
+__owur int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int send);
int DTLS_RECORD_LAYER_new(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_free(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
diff --git a/ssl/record/record_locl.h b/ssl/record/record_locl.h
index 333d3c947d..f44cda16e5 100644
--- a/ssl/record/record_locl.h
+++ b/ssl/record/record_locl.h
@@ -119,7 +119,7 @@
/* Functions/macros provided by the RECORD_LAYER component */
#define RECORD_LAYER_get_rbuf(rl) (&(rl)->rbuf)
-#define RECORD_LAYER_get_wbuf(rl) (&(rl)->wbuf)
+#define RECORD_LAYER_get_wbuf(rl) ((rl)->wbuf)
#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))
@@ -165,7 +165,7 @@ void SSL3_BUFFER_clear(SSL3_BUFFER *b);
void SSL3_BUFFER_set_data(SSL3_BUFFER *b, const unsigned char *d, int n);
void SSL3_BUFFER_release(SSL3_BUFFER *b);
__owur int ssl3_setup_read_buffer(SSL *s);
-__owur int ssl3_setup_write_buffer(SSL *s);
+__owur int ssl3_setup_write_buffer(SSL *s, unsigned int numwpipes);
int ssl3_release_read_buffer(SSL *s);
int ssl3_release_write_buffer(SSL *s);
@@ -194,7 +194,7 @@ void SSL3_RECORD_release(SSL3_RECORD *r);
int SSL3_RECORD_setup(SSL3_RECORD *r);
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);
+__owur int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr);
__owur int ssl3_do_uncompress(SSL *ssl);
void ssl3_cbc_copy_mac(unsigned char *out,
const SSL3_RECORD *rec, unsigned md_size);
diff --git a/ssl/record/ssl3_buffer.c b/ssl/record/ssl3_buffer.c
index 3c03499f59..576533c31e 100644
--- a/ssl/record/ssl3_buffer.c
+++ b/ssl/record/ssl3_buffer.c
@@ -176,13 +176,15 @@ int ssl3_setup_read_buffer(SSL *s)
return 0;
}
-int ssl3_setup_write_buffer(SSL *s)
+int ssl3_setup_write_buffer(SSL *s, unsigned int numwpipes)
{
unsigned char *p;
size_t len, align = 0, headerlen;
SSL3_BUFFER *wb;
+ unsigned int currpipe;
+
+ s->rlayer.numwpipes = numwpipes;
- wb = RECORD_LAYER_get_wbuf(&s->rlayer);
if (SSL_IS_DTLS(s))
headerlen = DTLS1_RT_HEADER_LENGTH + 1;
@@ -193,20 +195,25 @@ int ssl3_setup_write_buffer(SSL *s)
align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1);
#endif
- if (wb->buf == NULL) {
- len = s->max_send_fragment
- + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + headerlen + align;
+ len = s->max_send_fragment
+ + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + headerlen + align;
#ifndef OPENSSL_NO_COMP
- if (ssl_allow_compression(s))
- len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+ if (ssl_allow_compression(s))
+ len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
#endif
- if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS))
- len += headerlen + align + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
+ if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS))
+ len += headerlen + align + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
- if ((p = OPENSSL_malloc(len)) == NULL)
- goto err;
- wb->buf = p;
- wb->len = len;
+ wb = RECORD_LAYER_get_wbuf(&s->rlayer);
+ for (currpipe = 0; currpipe < numwpipes; currpipe++) {
+ if (wb[currpipe].buf == NULL) {
+ if ((p = OPENSSL_malloc(len)) == NULL) {
+ s->rlayer.numwpipes = currpipe;
+ goto err;
+ }
+ wb[currpipe].buf = p;
+ wb[currpipe].len = len;
+ }
}
return 1;
@@ -220,7 +227,7 @@ int ssl3_setup_buffers(SSL *s)
{
if (!ssl3_setup_read_buffer(s))
return 0;
- if (!ssl3_setup_write_buffer(s))
+ if (!ssl3_setup_write_buffer(s, 1))
return 0;
return 1;
}
@@ -228,11 +235,17 @@ int ssl3_setup_buffers(SSL *s)
int ssl3_release_write_buffer(SSL *s)
{
SSL3_BUFFER *wb;
+ unsigned int pipes;
- wb = RECORD_LAYER_get_wbuf(&s->rlayer);
+ pipes = s->rlayer.numwpipes;
+ while (pipes > 0) {
+ wb = &RECORD_LAYER_get_wbuf(&s->rlayer)[pipes - 1];
- OPENSSL_free(wb->buf);
- wb->buf = NULL;
+ OPENSSL_free(wb->buf);
+ wb->buf = NULL;
+ pipes--;
+ }
+ s->rlayer.numwpipes = 0;
return 1;
}
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 7f89cc0a1c..ad19621b11 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -373,7 +373,7 @@ int ssl3_get_record(SSL *s)
}
rr->length -= mac_size;
mac = rr->data + rr->length;
- i = s->method->ssl3_enc->mac(s, md, 0 /* not send */ );
+ 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,
@@ -382,7 +382,7 @@ int ssl3_get_record(SSL *s)
}
}
- enc_err = s->method->ssl3_enc->enc(s, 0);
+ enc_err = s->method->ssl3_enc->enc(s, rr, 1, 0);
/*-
* enc_err is:
* 0: (in non-constant time) if the record is publically invalid.
@@ -449,7 +449,7 @@ int ssl3_get_record(SSL *s)
mac = &rr->data[rr->length];
}
- i = s->method->ssl3_enc->mac(s, md, 0 /* not send */ );
+ i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */ );
if (i < 0 || mac == NULL
|| CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
enc_err = -1;
@@ -542,13 +542,11 @@ int ssl3_do_uncompress(SSL *ssl)
return (1);
}
-int ssl3_do_compress(SSL *ssl)
+int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr)
{
#ifndef OPENSSL_NO_COMP
int i;
- SSL3_RECORD *wr;
- wr = RECORD_LAYER_get_wrec(&ssl->rlayer);
i = COMP_compress_block(ssl->compress, wr->data,
SSL3_RT_MAX_COMPRESSED_LENGTH,
wr->input, (int)wr->length);
@@ -572,7 +570,7 @@ int ssl3_do_compress(SSL *ssl)
* -1: if the record's padding is invalid or, if sending, an internal error
* occurred.
*/
-int ssl3_enc(SSL *s, int send)
+int ssl3_enc(SSL *s, SSL3_RECORD *inrecs, unsigned int numpipes, int send)
{
SSL3_RECORD *rec;
EVP_CIPHER_CTX *ds;
@@ -580,16 +578,15 @@ int ssl3_enc(SSL *s, int send)
int bs, i, mac_size = 0;
const EVP_CIPHER *enc;
+ rec = inrecs;
if (send) {
ds = s->enc_write_ctx;
- rec = RECORD_LAYER_get_wrec(&s->rlayer);
if (s->enc_write_ctx == NULL)
enc = NULL;
else
enc = EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
} else {
ds = s->enc_read_ctx;
- rec = RECORD_LAYER_get_rrec(&s->rlayer);
if (s->enc_read_ctx == NULL)
enc = NULL;
else
@@ -646,13 +643,14 @@ int ssl3_enc(SSL *s, int send)
* -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
* an internal error occurred.
*/
-int tls1_enc(SSL *s, int send)
+int tls1_enc(SSL *s, SSL3_RECORD *recs, unsigned int numpipes, int send)
{
- SSL3_RECORD *rec;
EVP_CIPHER_CTX *ds;
- unsigned long l;
+ size_t reclen[SSL_MAX_PIPELINES];
+ unsigned char buf[SSL_MAX_PIPELINES][EVP_AEAD_TLS1_AAD_LEN];
int bs, i, j, k, pad = 0, ret, mac_size = 0;
const EVP_CIPHER *enc;
+ unsigned int ctr;
if (send) {
if (EVP_MD_CTX_md(s->write_hash)) {
@@ -660,7 +658,6 @@ int tls1_enc(SSL *s, int send)
OPENSSL_assert(n >= 0);
}
ds = s->enc_write_ctx;
- rec = RECORD_LAYER_get_wrec(&s->rlayer);
if (s->enc_write_ctx == NULL)
enc = NULL;
else {
@@ -673,14 +670,19 @@ int tls1_enc(SSL *s, int send)
else
ivlen = 0;
if (ivlen > 1) {
- if (rec->data != rec->input)
- /*
- * we can't write into the input stream: Can this ever
- * happen?? (steve)
- */
- fprintf(stderr, "tls1_enc(): rec->data != rec->input\n");
- else if (RAND_bytes(rec->input, ivlen) <= 0)
- return -1;
+ for (ctr = 0; ctr < numpipes; ctr++) {
+ if (recs[ctr].data != recs[ctr].input) {
+ /*
+ * we can't write into the input stream: Can this ever
+ * happen?? (steve)
+ */
+ SSLerr(SSL_F_TLS1_ENC, ERR_R_INTERNAL_ERROR);
+ return -1;
+ } else if (RAND_bytes(recs[ctr].input, ivlen) <= 0) {
+ SSLerr(SSL_F_TLS1_ENC, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ }
}
}
} else {
@@ -689,7 +691,6 @@ int tls1_enc(SSL *s, int send)
OPENSSL_assert(n >= 0);
}
ds = s->enc_read_ctx;
- rec = RECORD_LAYER_get_rrec(&s->rlayer);
if (s->enc_read_ctx == NULL)
enc = NULL;
else
@@ -697,97 +698,146 @@ int tls1_enc(SSL *s, int send)
}
if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) {
- memmove(rec->data, rec->input, rec->length);
- rec->input = rec->data;
+ for (ctr = 0; ctr < numpipes; ctr++) {
+ memmove(recs[ctr].data, recs[ctr].input, recs[ctr].length);
+ recs[ctr].input = recs[ctr].data;
+ }
ret = 1;
} else {
- l = rec->length;
- bs = EVP_CIPHER_CTX_block_size(ds);
+ bs = EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(ds));
+
+ if (numpipes > 1) {
+ if(!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ds))
+ & EVP_CIPH_FLAG_PIPELINE)) {
+ /*
+ * We shouldn't have been called with pipeline data if the
+ * cipher doesn't support pipelining
+ */
+ SSLerr(SSL_F_TLS1_ENC, SSL_R_PIPELINE_FAILURE);
+ return -1;
+ }
+ }
+ for (ctr = 0; ctr < numpipes; ctr++) {
+ reclen[ctr] = recs[ctr].length;
+
+ if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ds))
+ & EVP_CIPH_FLAG_AEAD_CIPHER) {
+ unsigned char *seq;
+
+