summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/openssl/ssl.h15
-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
-rw-r--r--ssl/s3_msg.c4
-rw-r--r--ssl/ssl_err.c2
-rw-r--r--ssl/ssl_lib.c29
-rw-r--r--ssl/ssl_locl.h25
11 files changed, 471 insertions, 240 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index e827214209..43d59a623b 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -181,6 +181,9 @@ extern "C" {
# define SSL_MAX_KEY_ARG_LENGTH 8
# define SSL_MAX_MASTER_KEY_LENGTH 48
+/* The maximum number of encrypt/decrypt pipelines we can support */
+# define SSL_MAX_PIPELINES 32
+
/* text strings for the ciphers */
/* These are used to specify which ciphers to use and not to use */
@@ -1233,6 +1236,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
# define SSL_CTRL_GET_EXTMS_SUPPORT 122
# define SSL_CTRL_SET_MIN_PROTO_VERSION 123
# define SSL_CTRL_SET_MAX_PROTO_VERSION 124
+# define SSL_CTRL_SET_SPLIT_SEND_FRAGMENT 125
+# define SSL_CTRL_SET_MAX_PIPELINES 126
# define SSL_CERT_SET_FIRST 1
# define SSL_CERT_SET_NEXT 2
# define SSL_CERT_SET_SERVER 3
@@ -1794,6 +1799,14 @@ __owur int SSL_get_ex_data_X509_STORE_CTX_idx(void);
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
# define SSL_set_max_send_fragment(ssl,m) \
SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL)
+# define SSL_CTX_set_split_send_fragment(ctx,m) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SPLIT_SEND_FRAGMENT,m,NULL)
+# define SSL_set_split_send_fragment(ssl,m) \
+ SSL_ctrl(ssl,SSL_CTRL_SET_SPLIT_SEND_FRAGMENT,m,NULL)
+# define SSL_CTX_set_max_pipelines(ctx,m) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_PIPELINES,m,NULL)
+# define SSL_set_max_pipelines(ssl,m) \
+ SSL_ctrl(ssl,SSL_CTRL_SET_MAX_PIPELINES,m,NULL)
/* NB: the keylength is only applicable when is_export is true */
# ifndef OPENSSL_NO_DH
@@ -2193,6 +2206,7 @@ void ERR_load_SSL_strings(void);
# define SSL_F_TLS1_CHANGE_CIPHER_STATE 209
# define SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS 341
# define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274
+# define SSL_F_TLS1_ENC 401
# define SSL_F_TLS1_EXPORT_KEYING_MATERIAL 314
# define SSL_F_TLS1_GET_CURVELIST 338
# define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT 275
@@ -2412,6 +2426,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199
# define SSL_R_PEM_NAME_BAD_PREFIX 391
# define SSL_R_PEM_NAME_TOO_SHORT 392
+# define SSL_R_PIPELINE_FAILURE 406
# define SSL_R_PRE_MAC_LENGTH_TOO_LONG 205
# define SSL_R_PROTOCOL_IS_SHUTDOWN 207
# define SSL_R_PSK_IDENTITY_NOT_FOUND 223
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