| From 6d65fc2d2bd6d6f4a5de364ff2cf7ec2da8f5037 Mon Sep 17 00:00:00 2001 |
| From: Adam Langley <[email protected]> |
| Date: Thu, 31 Oct 2013 13:22:54 -0400 |
| |
| This patch removes support for empty records (which is almost |
| universally disabled via SSL_OP_ALL) and adds optional support for 1/n-1 |
| record splitting. |
| |
| The latter is not enabled by default, since it's not typically used on |
| servers, but it should be enabled in web browsers since there are known |
| attacks in that case (see BEAST). |
| |
| (Of course, this is a poor workaround for using TLS 1.2 and an AEAD |
| cipher suite). |
| --- |
| apps/s_client.c | 16 +++++--- |
| ssl/d1_pkt.c | 50 ++++--------------------- |
| ssl/s3_enc.c | 17 ++++----- |
| ssl/s3_pkt.c | 112 +++++++++++++++++++++++++++++++------------------------- |
| ssl/ssl.h | 19 +++++++--- |
| ssl/ssl3.h | 4 +- |
| ssl/ssl_locl.h | 2 - |
| ssl/t1_enc.c | 10 ++--- |
| 8 files changed, 109 insertions(+), 121 deletions(-) |
| |
| diff --git a/apps/s_client.c b/apps/s_client.c |
| index cb1efcd..0c70580 100644 |
| --- a/apps/s_client.c |
| +++ b/apps/s_client.c |
| @@ -363,6 +363,7 @@ static void sc_usage(void) |
| # endif |
| #endif |
| BIO_printf(bio_err," -cutthrough - enable 1-RTT full-handshake for strong ciphers\n"); |
| + BIO_printf(bio_err," -no_record_splitting - disable 1/n-1 record splitting in CBC mode\n"); |
| BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); |
| #ifndef OPENSSL_NO_SRTP |
| BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); |
| @@ -579,7 +580,7 @@ int MAIN(int argc, char **argv) |
| EVP_PKEY *key = NULL; |
| char *CApath=NULL,*CAfile=NULL,*cipher=NULL; |
| int reconnect=0,badop=0,verify=SSL_VERIFY_NONE,bugs=0; |
| - int cutthrough=0; |
| + int cutthrough=0, no_record_splitting=0; |
| int crlf=0; |
| int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending; |
| SSL_CTX *ctx=NULL; |
| @@ -594,6 +595,7 @@ int MAIN(int argc, char **argv) |
| char *inrand=NULL; |
| int mbuf_len=0; |
| struct timeval timeout, *timeoutp; |
| + int ssl_mode; |
| #ifndef OPENSSL_NO_ENGINE |
| char *engine_id=NULL; |
| char *ssl_client_engine_id=NULL; |
| @@ -894,6 +896,8 @@ int MAIN(int argc, char **argv) |
| #endif |
| else if (strcmp(*argv,"-cutthrough") == 0) |
| cutthrough=1; |
| + else if (strcmp(*argv,"-no_record_splitting") == 0) |
| + no_record_splitting=1; |
| else if (strcmp(*argv,"-serverpref") == 0) |
| off|=SSL_OP_CIPHER_SERVER_PREFERENCE; |
| else if (strcmp(*argv,"-legacy_renegotiation") == 0) |
| @@ -1183,14 +1187,16 @@ bad: |
| } |
| #endif |
| |
| - /* Enable handshake cutthrough for client connections using |
| - * strong ciphers. */ |
| + ssl_mode = SSL_CTX_get_mode(ctx); |
| + if (!no_record_splitting) |
| + ssl_mode |= SSL_MODE_CBC_RECORD_SPLITTING; |
| if (cutthrough) |
| { |
| - int ssl_mode = SSL_CTX_get_mode(ctx); |
| + /* Enable handshake cutthrough for client connections using |
| + * strong ciphers. */ |
| ssl_mode |= SSL_MODE_HANDSHAKE_CUTTHROUGH; |
| - SSL_CTX_set_mode(ctx, ssl_mode); |
| } |
| + SSL_CTX_set_mode(ctx, ssl_mode); |
| |
| if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); |
| if (cipher != NULL) |
| diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c |
| index 0bf87be..cb0f8f0 100644 |
| --- a/ssl/d1_pkt.c |
| +++ b/ssl/d1_pkt.c |
| @@ -179,6 +179,8 @@ static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, |
| static int dtls1_buffer_record(SSL *s, record_pqueue *q, |
| unsigned char *priority); |
| static int dtls1_process_record(SSL *s); |
| +static int do_dtls1_write(SSL *s, int type, const unsigned char *buf, |
| + unsigned int len); |
| |
| /* copy buffered record into SSL structure */ |
| static int |
| @@ -1456,11 +1458,12 @@ int dtls1_write_bytes(SSL *s, int type, const void *buf, int len) |
| |
| OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); |
| s->rwstate=SSL_NOTHING; |
| - i=do_dtls1_write(s, type, buf, len, 0); |
| + i=do_dtls1_write(s, type, buf, len); |
| return i; |
| } |
| |
| -int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment) |
| +static int do_dtls1_write(SSL *s, int type, const unsigned char *buf, |
| + unsigned int len) |
| { |
| unsigned char *p,*pseq; |
| int i,mac_size,clear=0; |
| @@ -1487,7 +1490,7 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, |
| /* if it went, fall through and send more stuff */ |
| } |
| |
| - if (len == 0 && !create_empty_fragment) |
| + if (len == 0) |
| return 0; |
| |
| wr= &(s->s3->wrec); |
| @@ -1508,37 +1511,6 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, |
| goto err; |
| } |
| |
| - /* DTLS implements explicit IV, so no need for empty fragments */ |
| -#if 0 |
| - /* 'create_empty_fragment' is true only when this function calls itself */ |
| - if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done |
| - && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) |
| - { |
| - /* countermeasure against known-IV weakness in CBC ciphersuites |
| - * (see http://www.openssl.org/~bodo/tls-cbc.txt) |
| - */ |
| - |
| - if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA) |
| - { |
| - /* recursive function call with 'create_empty_fragment' set; |
| - * this prepares and buffers the data for an empty fragment |
| - * (these 'prefix_len' bytes are sent out later |
| - * together with the actual payload) */ |
| - prefix_len = s->method->do_ssl_write(s, type, buf, 0, 1); |
| - if (prefix_len <= 0) |
| - goto err; |
| - |
| - if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE) |
| - { |
| - /* insufficient space */ |
| - SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR); |
| - goto err; |
| - } |
| - } |
| - |
| - s->s3->empty_fragment_done = 1; |
| - } |
| -#endif |
| p = wb->buf + prefix_len; |
| |
| /* write the header */ |
| @@ -1644,14 +1616,6 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, |
| |
| ssl3_record_sequence_update(&(s->s3->write_sequence[0])); |
| |
| - if (create_empty_fragment) |
| - { |
| - /* we are in a recursive call; |
| - * just return the length, don't write out anything here |
| - */ |
| - return wr->length; |
| - } |
| - |
| /* now let's set up wb */ |
| wb->left = prefix_len + wr->length; |
| wb->offset = 0; |
| @@ -1748,7 +1712,7 @@ int dtls1_dispatch_alert(SSL *s) |
| } |
| #endif |
| |
| - i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0); |
| + i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf)); |
| if (i <= 0) |
| { |
| s->s3->alert_dispatch=1; |
| diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c |
| index 191b86b..6358e1b 100644 |
| --- a/ssl/s3_enc.c |
| +++ b/ssl/s3_enc.c |
| @@ -434,27 +434,26 @@ int ssl3_setup_key_block(SSL *s) |
| |
| ret = ssl3_generate_key_block(s,p,num); |
| |
| - if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) |
| + /* enable vulnerability countermeasure for CBC ciphers with |
| + * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt) */ |
| + if ((s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0) |
| { |
| - /* enable vulnerability countermeasure for CBC ciphers with |
| - * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt) |
| - */ |
| - s->s3->need_empty_fragments = 1; |
| + s->s3->need_record_splitting = 1; |
| |
| if (s->session->cipher != NULL) |
| { |
| if (s->session->cipher->algorithm_enc == SSL_eNULL) |
| - s->s3->need_empty_fragments = 0; |
| - |
| + s->s3->need_record_splitting = 0; |
| + |
| #ifndef OPENSSL_NO_RC4 |
| if (s->session->cipher->algorithm_enc == SSL_RC4) |
| - s->s3->need_empty_fragments = 0; |
| + s->s3->need_record_splitting = 0; |
| #endif |
| } |
| } |
| |
| return ret; |
| - |
| + |
| err: |
| SSLerr(SSL_F_SSL3_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE); |
| return(0); |
| diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c |
| index 04b474d..d690493 100644 |
| --- a/ssl/s3_pkt.c |
| +++ b/ssl/s3_pkt.c |
| @@ -118,7 +118,7 @@ |
| #include <openssl/rand.h> |
| |
| static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
| - unsigned int len, int create_empty_fragment); |
| + unsigned int len, char fragment, char is_fragment); |
| static int ssl3_get_record(SSL *s); |
| |
| int ssl3_read_n(SSL *s, int n, int max, int extend) |
| @@ -618,12 +618,34 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) |
| n=(len-tot); |
| for (;;) |
| { |
| - if (n > s->max_send_fragment) |
| - nw=s->max_send_fragment; |
| + /* max contains the maximum number of bytes that we can put |
| + * into a record. */ |
| + unsigned max = s->max_send_fragment; |
| + /* fragment is true if do_ssl3_write should send the first byte |
| + * in its own record in order to randomise a CBC IV. */ |
| + int fragment = 0; |
| + |
| + if (n > 1 && |
| + s->s3->need_record_splitting && |
| + type == SSL3_RT_APPLICATION_DATA && |
| + !s->s3->record_split_done) |
| + { |
| + fragment = 1; |
| + /* The first byte will be in its own record, so we |
| + * can write an extra byte. */ |
| + max++; |
| + /* record_split_done records that the splitting has |
| + * been done in case we hit an SSL_WANT_WRITE condition. |
| + * In that case, we don't need to do the split again. */ |
| + s->s3->record_split_done = 1; |
| + } |
| + |
| + if (n > max) |
| + nw=max; |
| else |
| nw=n; |
| |
| - i=do_ssl3_write(s, type, &(buf[tot]), nw, 0); |
| + i=do_ssl3_write(s, type, &(buf[tot]), nw, fragment, 0); |
| if (i <= 0) |
| { |
| s->s3->wnum=tot; |
| @@ -634,10 +656,10 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) |
| (type == SSL3_RT_APPLICATION_DATA && |
| (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) |
| { |
| - /* next chunk of data should get another prepended empty fragment |
| - * in ciphersuites with known-IV weakness: */ |
| - s->s3->empty_fragment_done = 0; |
| - |
| + /* next chunk of data should get another prepended, |
| + * one-byte fragment in ciphersuites with known-IV |
| + * weakness. */ |
| + s->s3->record_split_done = 0; |
| return tot+i; |
| } |
| |
| @@ -646,11 +668,16 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) |
| } |
| } |
| |
| +/* do_ssl3_write writes an SSL record of the given type. If |fragment| is 1 |
| + * then it splits the record into a one byte record and a record with the rest |
| + * of the data in order to randomise a CBC IV. If |is_fragment| is true then |
| + * this call resulted from do_ssl3_write calling itself in order to create that |
| + * one byte fragment. */ |
| static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
| - unsigned int len, int create_empty_fragment) |
| + unsigned int len, char fragment, char is_fragment) |
| { |
| unsigned char *p,*plen; |
| - int i,mac_size,clear=0; |
| + int i,mac_size; |
| int prefix_len=0; |
| int eivlen; |
| long align=0; |
| @@ -676,7 +703,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
| /* if it went, fall through and send more stuff */ |
| } |
| |
| - if (len == 0 && !create_empty_fragment) |
| + if (len == 0) |
| return 0; |
| |
| wr= &(s->s3->wrec); |
| @@ -686,11 +713,6 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
| (s->enc_write_ctx == NULL) || |
| (EVP_MD_CTX_md(s->write_hash) == NULL)) |
| { |
| -#if 1 |
| - clear=s->enc_write_ctx?0:1; /* must be AEAD cipher */ |
| -#else |
| - clear=1; |
| -#endif |
| mac_size=0; |
| } |
| else |
| @@ -700,42 +722,33 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
| goto err; |
| } |
| |
| - /* 'create_empty_fragment' is true only when this function calls itself */ |
| - if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done) |
| + if (fragment) |
| { |
| /* countermeasure against known-IV weakness in CBC ciphersuites |
| * (see http://www.openssl.org/~bodo/tls-cbc.txt) */ |
| + prefix_len = do_ssl3_write(s, type, buf, 1 /* length */, |
| + 0 /* fragment */, |
| + 1 /* is_fragment */); |
| + if (prefix_len <= 0) |
| + goto err; |
| |
| - if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA) |
| + if (prefix_len > (SSL3_RT_HEADER_LENGTH + |
| + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) |
| { |
| - /* recursive function call with 'create_empty_fragment' set; |
| - * this prepares and buffers the data for an empty fragment |
| - * (these 'prefix_len' bytes are sent out later |
| - * together with the actual payload) */ |
| - prefix_len = do_ssl3_write(s, type, buf, 0, 1); |
| - if (prefix_len <= 0) |
| - goto err; |
| - |
| - if (prefix_len > |
| - (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) |
| - { |
| - /* insufficient space */ |
| - SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR); |
| - goto err; |
| - } |
| + /* insufficient space */ |
| + SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR); |
| + goto err; |
| } |
| - |
| - s->s3->empty_fragment_done = 1; |
| } |
| |
| - if (create_empty_fragment) |
| + if (is_fragment) |
| { |
| #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 |
| - /* extra fragment would be couple of cipher blocks, |
| - * which would be multiple of SSL3_ALIGN_PAYLOAD, so |
| - * if we want to align the real payload, then we can |
| - * just pretent we simply have two headers. */ |
| - align = (long)wb->buf + 2*SSL3_RT_HEADER_LENGTH; |
| + /* The extra fragment would be couple of cipher blocks, and |
| + * that will be a multiple of SSL3_ALIGN_PAYLOAD. So, if we |
| + * want to align the real payload, we can just pretend that we |
| + * have two headers and a byte. */ |
| + align = (long)wb->buf + 2*SSL3_RT_HEADER_LENGTH + 1; |
| align = (-align)&(SSL3_ALIGN_PAYLOAD-1); |
| #endif |
| p = wb->buf + align; |
| @@ -772,7 +785,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
| *(p++)=s->version&0xff; |
| |
| /* field where we are to write out packet length */ |
| - plen=p; |
| + plen=p; |
| p+=2; |
| /* Explicit IV length, block ciphers and TLS version 1.1 or later */ |
| if (s->enc_write_ctx && s->version >= TLS1_1_VERSION) |
| @@ -800,8 +813,8 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
| |
| /* lets setup the record stuff. */ |
| wr->data=p + eivlen; |
| - wr->length=(int)len; |
| - wr->input=(unsigned char *)buf; |
| + wr->length=(int)(len - (fragment != 0)); |
| + wr->input=(unsigned char *)buf + (fragment != 0); |
| |
| /* we now 'read' from wr->input, wr->length bytes into |
| * wr->data */ |
| @@ -854,11 +867,10 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, |
| wr->type=type; /* not needed but helps for debugging */ |
| wr->length+=SSL3_RT_HEADER_LENGTH; |
| |
| - if (create_empty_fragment) |
| + if (is_fragment) |
| { |
| - /* we are in a recursive call; |
| - * just return the length, don't write out anything here |
| - */ |
| + /* we are in a recursive call; just return the length, don't |
| + * write out anything. */ |
| return wr->length; |
| } |
| |
| @@ -1514,7 +1526,7 @@ int ssl3_dispatch_alert(SSL *s) |
| void (*cb)(const SSL *ssl,int type,int val)=NULL; |
| |
| s->s3->alert_dispatch=0; |
| - i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0); |
| + i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0, 0); |
| if (i <= 0) |
| { |
| s->s3->alert_dispatch=1; |
| diff --git a/ssl/ssl.h b/ssl/ssl.h |
| index b289bc2..8564484 100644 |
| --- a/ssl/ssl.h |
| +++ b/ssl/ssl.h |
| @@ -580,11 +580,15 @@ struct ssl_session_st |
| #define SSL_OP_TLS_D5_BUG 0x00000100L |
| #define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L |
| |
| -/* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added |
| - * in OpenSSL 0.9.6d. Usually (depending on the application protocol) |
| - * the workaround is not needed. Unfortunately some broken SSL/TLS |
| - * implementations cannot handle it at all, which is why we include |
| - * it in SSL_OP_ALL. */ |
| +/* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS is vestigial. Previously it disabled the |
| + * insertion of empty records in CBC mode, but the empty records were commonly |
| + * misinterpreted as EOF by other TLS stacks and so this was disabled by |
| + * SSL_OP_ALL. |
| + * |
| + * This has been replaced by 1/n-1 record splitting, which is enabled by |
| + * SSL_MODE_CBC_RECORD_SPLITTING in SSL_set_mode. This involves sending a |
| + * one-byte record rather than an empty record and has much better |
| + * compatibility. */ |
| #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800L /* added in 0.9.6e */ |
| |
| /* SSL_OP_ALL: various bug workarounds that should be rather harmless. |
| @@ -668,6 +672,11 @@ struct ssl_session_st |
| * and Finished. This mode enables full-handshakes to 'complete' in |
| * one RTT. */ |
| #define SSL_MODE_HANDSHAKE_CUTTHROUGH 0x00000080L |
| +/* When set, TLS 1.0 and SSLv3, multi-byte, CBC records will be split in two: |
| + * the first record will contain a single byte and the second will contain the |
| + * rest of the bytes. This effectively randomises the IV and prevents BEAST |
| + * attacks. */ |
| +#define SSL_MODE_CBC_RECORD_SPLITTING 0x00000100L |
| |
| /* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, |
| * they cannot be used to clear bits. */ |
| diff --git a/ssl/ssl3.h b/ssl/ssl3.h |
| index 6a5cdbe..65f58a7 100644 |
| --- a/ssl/ssl3.h |
| +++ b/ssl/ssl3.h |
| @@ -418,8 +418,8 @@ typedef struct ssl3_state_st |
| unsigned char client_random[SSL3_RANDOM_SIZE]; |
| |
| /* flags for countermeasure against known-IV weakness */ |
| - int need_empty_fragments; |
| - int empty_fragment_done; |
| + int need_record_splitting; |
| + int record_split_done; |
| |
| /* The value of 'extra' when the buffers were initialized */ |
| int init_extra; |
| diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h |
| index b83d8cd..dac33e2 100644 |
| --- a/ssl/ssl_locl.h |
| +++ b/ssl/ssl_locl.h |
| @@ -1091,8 +1091,6 @@ int dtls1_shutdown(SSL *s); |
| |
| long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok); |
| int dtls1_get_record(SSL *s); |
| -int do_dtls1_write(SSL *s, int type, const unsigned char *buf, |
| - unsigned int len, int create_empty_fragement); |
| int dtls1_dispatch_alert(SSL *s); |
| int dtls1_enc(SSL *s, int snd); |
| |
| diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c |
| index 15800af..b2686f4 100644 |
| --- a/ssl/t1_enc.c |
| +++ b/ssl/t1_enc.c |
| @@ -762,22 +762,22 @@ printf("\nkey block\n"); |
| { int z; for (z=0; z<num; z++) printf("%02X%c",p1[z],((z+1)%16)?' ':'\n'); } |
| #endif |
| |
| - if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
| - && s->method->version <= TLS1_VERSION) |
| + if (s->method->version <= TLS1_VERSION && |
| + (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0) |
| { |
| /* enable vulnerability countermeasure for CBC ciphers with |
| * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt) |
| */ |
| - s->s3->need_empty_fragments = 1; |
| + s->s3->need_record_splitting = 1; |
| |
| if (s->session->cipher != NULL) |
| { |
| if (s->session->cipher->algorithm_enc == SSL_eNULL) |
| - s->s3->need_empty_fragments = 0; |
| + s->s3->need_record_splitting = 0; |
| |
| #ifndef OPENSSL_NO_RC4 |
| if (s->session->cipher->algorithm_enc == SSL_RC4) |
| - s->s3->need_empty_fragments = 0; |
| + s->s3->need_record_splitting = 0; |
| #endif |
| } |
| } |
| -- |
| 1.8.4.1 |
| |