Move the SCT List extension parser into libssl.
[openssl.git] / ssl / s3_pkt.c
index ee103cd..b9e45c7 100644 (file)
 #include <openssl/buffer.h>
 #include <openssl/rand.h>
 
+#ifndef  EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0
+#endif
+
+#if    defined(OPENSSL_SMALL_FOOTPRINT) || \
+       !(      defined(AES_ASM) &&     ( \
+               defined(__x86_64)       || defined(__x86_64__)  || \
+               defined(_M_AMD64)       || defined(_M_X64)      || \
+               defined(__INTEL__)      ) \
+       )
+# undef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0
+#endif
+
 static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                         unsigned int len, int create_empty_fragment);
 static int ssl3_get_record(SSL *s);
@@ -180,7 +194,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
        /* For DTLS/UDP reads should not span multiple packets
         * because the read operation returns the whole packet
         * at once (as long as it fits into the buffer). */
-       if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+       if (SSL_IS_DTLS(s))
                {
                if (left > 0 && n > left)
                        n = left;
@@ -247,7 +261,8 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
                if (i <= 0)
                        {
                        rb->left = left;
-                       if (s->mode & SSL_MODE_RELEASE_BUFFERS)
+                       if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
+                               !SSL_IS_DTLS(s))
                                if (len+left == 0)
                                        ssl3_release_read_buffer(s);
                        return(i);
@@ -256,7 +271,7 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
                /* reads should *never* span multiple packets for DTLS because
                 * the underlying transport protocol is message oriented as opposed
                 * to byte oriented as in the TLS case. */
-               if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+               if (SSL_IS_DTLS(s))
                        {
                        if (n > left)
                                n = left; /* makes the while condition false */
@@ -271,6 +286,12 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
        return(n);
        }
 
+/* MAX_EMPTY_RECORDS defines the number of consecutive, empty records that will
+ * be processed per call to ssl3_get_record. Without this limit an attacker
+ * could send empty records at a faster rate than we can process and cause
+ * ssl3_get_record to loop forever. */
+#define MAX_EMPTY_RECORDS 32
+
 /* Call this to get a new input record.
  * It will return <= 0 if more data is needed, normally due to an error
  * or non-blocking IO.
@@ -289,11 +310,9 @@ static int ssl3_get_record(SSL *s)
        unsigned char *p;
        unsigned char md[EVP_MAX_MD_SIZE];
        short version;
-       int mac_size;
-       int clear=0;
+       unsigned mac_size;
        size_t extra;
-       int decryption_failed_or_bad_record_mac = 0;
-       unsigned char *mac = NULL;
+       unsigned empty_record_count = 0;
 
        rr= &(s->s3->rrec);
        sess=s->session;
@@ -320,6 +339,8 @@ again:
                s->rstate=SSL_ST_READ_BODY;
 
                p=s->packet;
+               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++);
@@ -337,7 +358,7 @@ fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
                        if (version != s->version)
                                {
                                SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
-                                if ((s->version & 0xFF00) == (version & 0xFF00))
+                                if ((s->version & 0xFF00) == (version & 0xFF00) && !s->enc_write_ctx && !s->write_hash)
                                        /* Send back error using their minor version number :-) */
                                        s->version = (unsigned short)version;
                                al=SSL_AD_PROTOCOL_VERSION;
@@ -400,19 +421,42 @@ fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
 
        /* 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.
+        */
+       if (SSL_USE_ETM(s) && s->read_hash)
+               {
+               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,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;
+                       }
+               }
 
        enc_err = s->method->ssl3_enc->enc(s,0);
-       if (enc_err <= 0)
+       /* enc_err is:
+        *    0: (in non-constant time) if the record is publically invalid.
+        *    1: if the padding is valid
+        *    -1: if the padding is invalid */
+       if (enc_err == 0)
                {
-               if (enc_err == 0)
-                       /* SSLerr() and ssl3_send_alert() have been called */
-                       goto err;
-
-               /* Otherwise enc_err == -1, which indicates bad padding
-                * (rec->length has not been changed in this case).
-                * To minimize information leaked via timing, we will perform
-                * the MAC computation anyway. */
-               decryption_failed_or_bad_record_mac = 1;
+               al=SSL_AD_DECRYPTION_FAILED;
+               SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
+               goto f_err;
                }
 
 #ifdef TLS_DEBUG
@@ -422,58 +466,64 @@ printf("\n");
 #endif
 
        /* r->length is now the compressed data plus mac */
-       if (    (sess == NULL) ||
-               (s->enc_read_ctx == NULL) ||
-               (EVP_MD_CTX_md(s->read_hash) == NULL))
-               clear=1;
-
-       if (!clear)
+       if ((sess != NULL) &&
+           (s->enc_read_ctx != NULL) &&
+           (EVP_MD_CTX_md(s->read_hash) != NULL) && !SSL_USE_ETM(s))
                {
-               /* !clear => s->read_hash != NULL => mac_size != -1 */
+               /* s->read_hash != NULL => mac_size != -1 */
+               unsigned char *mac = NULL;
+               unsigned char mac_tmp[EVP_MAX_MD_SIZE];
                mac_size=EVP_MD_CTX_size(s->read_hash);
-               OPENSSL_assert(mac_size >= 0);
+               OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
 
-               if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
+               /* orig_len is the length of the record before any padding was
+                * removed. This is public information, as is the MAC in use,
+                * therefore we can safely process the record in a different
+                * amount of time if it's too short to possibly contain a MAC.
+                */
+               if (rr->orig_len < mac_size ||
+                   /* CBC records must have a padding length byte too. */
+                   (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+                    rr->orig_len < mac_size+1))
                        {
-#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */
-                       al=SSL_AD_RECORD_OVERFLOW;
-                       SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
+                       al=SSL_AD_DECODE_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
                        goto f_err;
-#else
-                       decryption_failed_or_bad_record_mac = 1;
-#endif                 
                        }
-               /* check the MAC for rr->input (it's in mac_size bytes at the tail) */
-               if (rr->length >= (unsigned int)mac_size)
+
+               if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
                        {
+                       /* We update the length so that the TLS header bytes
+                        * can be constructed correctly but we need to extract
+                        * the MAC in constant time from within the record,
+                        * without leaking the contents of the padding bytes.
+                        * */
+                       mac = mac_tmp;
+                       ssl3_cbc_copy_mac(mac_tmp, rr, mac_size);
                        rr->length -= mac_size;
-                       mac = &rr->data[rr->length];
                        }
                else
                        {
-                       /* record (minus padding) is too short to contain a MAC */
-#if 0 /* OK only for stream ciphers */
-                       al=SSL_AD_DECODE_ERROR;
-                       SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
-                       goto f_err;
-#else
-                       decryption_failed_or_bad_record_mac = 1;
-                       rr->length = 0;
-#endif
-                       }
-               i=s->method->ssl3_enc->mac(s,md,0);
-               if (i < 0 || mac == NULL || memcmp(md, mac, (size_t)mac_size) != 0)
-                       {
-                       decryption_failed_or_bad_record_mac = 1;
+                       /* In this case there's no padding, so |rec->orig_len|
+                        * equals |rec->length| and we checked that there's
+                        * enough bytes for |mac_size| above. */
+                       rr->length -= mac_size;
+                       mac = &rr->data[rr->length];
                        }
+
+               i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
+               if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
+                       enc_err = -1;
+               if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
+                       enc_err = -1;
                }
 
-       if (decryption_failed_or_bad_record_mac)
+       if (enc_err < 0)
                {
                /* A separate 'decryption_failed' alert was introduced with TLS 1.0,
                 * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
                 * failure is directly visible from the ciphertext anyway,
-                * we should not reveal which kind of error occured -- this
+                * we should not reveal which kind of error occurred -- this
                 * might become visible to an attacker (e.g. via a logfile) */
                al=SSL_AD_BAD_RECORD_MAC;
                SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
@@ -517,7 +567,17 @@ printf("\n");
        s->packet_length=0;
 
        /* just read a 0 length packet */
-       if (rr->length == 0) goto again;
+       if (rr->length == 0)
+               {
+               empty_record_count++;
+               if (empty_record_count > MAX_EMPTY_RECORDS)
+                       {
+                       al=SSL_AD_UNEXPECTED_MESSAGE;
+                       SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_TOO_MANY_EMPTY_FRAGMENTS);
+                       goto f_err;
+                       }
+               goto again;
+               }
 
 #if 0
 fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, rr->length);
@@ -575,7 +635,12 @@ int ssl3_do_compress(SSL *ssl)
 int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
        {
        const unsigned char *buf=buf_;
-       unsigned int tot,n,nw;
+       int tot;
+       unsigned int n,nw;
+#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+       unsigned int max_send_fragment;
+#endif
+       SSL3_BUFFER *wb=&(s->s3->wbuf);
        int i;
 
        s->rwstate=SSL_NOTHING;
@@ -593,6 +658,164 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
                        }
                }
 
+       /* first check if there is a SSL3_BUFFER still being written
+        * out.  This will happen with non blocking IO */
+       if (wb->left != 0)
+               {
+               i = ssl3_write_pending(s,type,&buf[tot],s->s3->wpend_tot);
+               if (i<=0)
+                       {
+                       /* XXX should we ssl3_release_write_buffer if i<0? */
+                       s->s3->wnum=tot;
+                       return i;
+                       }
+               tot += i;       /* this might be last fragment */
+               }
+
+#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+       /*
+        * Depending on platform multi-block can deliver several *times*
+        * better performance. Downside is that it has to allocate
+        * jumbo buffer to accomodate up to 8 records, but the
+        * compromise is considered worthy.
+        */
+       if (type==SSL3_RT_APPLICATION_DATA &&
+           len >= 4*(max_send_fragment=s->max_send_fragment) &&
+           s->compress==NULL && s->msg_callback==NULL &&
+           !SSL_USE_ETM(s) && SSL_USE_EXPLICIT_IV(s) &&
+           EVP_CIPHER_flags(s->enc_write_ctx->cipher)&EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)
+               {
+               unsigned char aad[13];
+               EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param;
+               int packlen;
+
+               /* minimize address aliasing conflicts */
+               if ((max_send_fragment&0xffff) == 0)
+                       max_send_fragment -= 512;
+
+               if (tot==0 || wb->buf==NULL)    /* allocate jumbo buffer */
+                       {
+                       ssl3_release_write_buffer(s);
+
+                       packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+                                       EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE,
+                                       max_send_fragment,NULL);
+
+                       if (len>=8*max_send_fragment)   packlen *= 8;
+                       else                            packlen *= 4;
+
+                       wb->buf=OPENSSL_malloc(packlen);
+                       wb->len=packlen;
+                       }
+               else if (tot==len)              /* done? */
+                       {
+                       OPENSSL_free(wb->buf);  /* free jumbo buffer */
+                       wb->buf = NULL;
+                       return tot;
+                       }
+
+               n=(len-tot);
+               for (;;)
+                       {
+                       if (n < 4*max_send_fragment)
+                               {
+                               OPENSSL_free(wb->buf);  /* free jumbo buffer */
+                               wb->buf = NULL;
+                               break;
+                               }
+
+                       if (s->s3->alert_dispatch)
+                               {
+                               i=s->method->ssl_dispatch_alert(s);
+                               if (i <= 0)
+                                       {
+                                       s->s3->wnum=tot;
+                                       return i;
+                                       }
+                               }
+
+                       if (n >= 8*max_send_fragment)
+                               nw = max_send_fragment*(mb_param.interleave=8);
+                       else
+                               nw = max_send_fragment*(mb_param.interleave=4);
+
+                       memcpy(aad,s->s3->write_sequence,8);
+                       aad[8]=type;
+                       aad[9]=(unsigned char)(s->version>>8);
+                       aad[10]=(unsigned char)(s->version);
+                       aad[11]=0;
+                       aad[12]=0;
+                       mb_param.out = NULL;
+                       mb_param.inp = aad;
+                       mb_param.len = nw;
+
+                       packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+                                       EVP_CTRL_TLS1_1_MULTIBLOCK_AAD,
+                                       sizeof(mb_param),&mb_param);
+
+                       if (packlen<=0 || packlen>wb->len)      /* never happens */
+                               {
+                               OPENSSL_free(wb->buf);  /* free jumbo buffer */
+                               wb->buf = NULL;
+                               break;
+                               }
+
+                       mb_param.out = wb->buf;
+                       mb_param.inp = &buf[tot];
+                       mb_param.len = nw;
+
+                       if (EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+                                       EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT,
+                                       sizeof(mb_param),&mb_param)<=0)
+                               return -1;
+
+                       s->s3->write_sequence[7] += mb_param.interleave;
+                       if (s->s3->write_sequence[7] < mb_param.interleave)
+                               {
+                               int j=6;
+                               while (j>=0 && (++s->s3->write_sequence[j--])==0) ;
+                               }
+
+                       wb->offset = 0;
+                       wb->left = packlen;
+
+                       s->s3->wpend_tot = nw;
+                       s->s3->wpend_buf = &buf[tot];
+                       s->s3->wpend_type= type;
+                       s->s3->wpend_ret = nw;
+
+                       i = ssl3_write_pending(s,type,&buf[tot],nw);
+                       if (i<=0)
+                               {
+                               if (i<0)
+                                       {
+                                       OPENSSL_free(wb->buf);
+                                       wb->buf = NULL;
+                                       }
+                               s->s3->wnum=tot;
+                               return i;
+                               }
+                       if (i==(int)n)
+                               {
+                               OPENSSL_free(wb->buf);  /* free jumbo buffer */
+                               wb->buf = NULL;
+                               return tot+i;
+                               }
+                       n-=i;
+                       tot+=i;
+                       }
+               }
+       else
+#endif
+       if (tot==len)           /* done? */
+               {
+               if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
+                       !SSL_IS_DTLS(s))
+                       ssl3_release_write_buffer(s);
+
+               return tot;
+               }
+
        n=(len-tot);
        for (;;)
                {
@@ -604,6 +827,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
                i=do_ssl3_write(s, type, &(buf[tot]), nw, 0);
                if (i <= 0)
                        {
+                       /* XXX should we ssl3_release_write_buffer if i<0? */
                        s->s3->wnum=tot;
                        return i;
                        }
@@ -615,7 +839,11 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
                        /* next chunk of data should get another prepended empty fragment
                         * in ciphersuites with known-IV weakness: */
                        s->s3->empty_fragment_done = 0;
-                       
+
+                       if ((i==(int)n) && s->mode & SSL_MODE_RELEASE_BUFFERS &&
+                               !SSL_IS_DTLS(s))
+                               ssl3_release_write_buffer(s);
+
                        return tot+i;
                        }
 
@@ -663,10 +891,14 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        if (    (sess == NULL) ||
                (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;
-
-       if (clear)
+#endif
                mac_size=0;
+               }
        else
                {
                mac_size=EVP_MD_CTX_size(s->write_hash);
@@ -674,6 +906,55 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                        goto err;
                }
 
+#if 0 && !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
+       if (type==SSL3_RT_APPLICATION_DATA && s->compress==NULL &&
+           !SSL_USE_ETM(s) && SSL_USE_EXPLICIT_IV(s) && /*!SSL_IS_DTLS(s) &&*/
+           EVP_CIPHER_flags(s->enc_write_ctx->cipher)&EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)
+               do {
+               unsigned char aad[13];
+               EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param = {NULL,aad,sizeof(aad),0};
+               int packlen;
+
+               memcpy(aad,s->s3->write_sequence,8);
+               aad[8]=type;
+               aad[9]=(unsigned char)(s->version>>8);
+               aad[10]=(unsigned char)(s->version);
+               aad[11]=(unsigned char)(len>>8);
+               aad[12]=(unsigned char)len;
+               packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+                               EVP_CTRL_TLS1_1_MULTIBLOCK_AAD,
+                               sizeof(mb_param),&mb_param);
+
+               if (packlen==0 || packlen > wb->len) break;
+
+               mb_param.out = wb->buf;
+               mb_param.inp = buf;
+               mb_param.len = len;
+               EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
+                               EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT,
+                               sizeof(mb_param),&mb_param);
+
+               s->s3->write_sequence[7] += mb_param.interleave;
+               if (s->s3->write_sequence[7] < mb_param.interleave)
+                       {
+                       int j=6;
+                       while (j>=0 && (++s->s3->write_sequence[j--])==0) ;
+                       }
+
+               wb->offset=0;
+               wb->left = packlen;
+
+               /* memorize arguments so that ssl3_write_pending can detect bad write retries later */
+               s->s3->wpend_tot=len;
+               s->s3->wpend_buf=buf;
+               s->s3->wpend_type=type;
+               s->s3->wpend_ret=len;
+
+               /* we now just need to write the buffer */
+               return ssl3_write_pending(s,type,buf,len);
+               } while (0);
+#endif
+
        /* 'create_empty_fragment' is true only when this function calls itself */
        if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
                {
@@ -735,17 +1016,33 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        wr->type=type;
 
        *(p++)=(s->version>>8);
-       *(p++)=s->version&0xff;
+       /* Some servers hang if iniatial client hello is larger than 256
+        * bytes and record version number > TLS 1.0
+        */
+       if (s->state == SSL3_ST_CW_CLNT_HELLO_B
+                               && !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 and TLS version 1.1 or later */
-       if (s->enc_write_ctx && s->version >= TLS1_1_VERSION
-               && EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE)
+       /* Explicit IV length, block ciphers appropriate version flag */
+       if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s))
                {
-               eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
-               if (eivlen <= 1)
+               int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx);
+               if (mode == EVP_CIPH_CBC_MODE)
+                       {
+                       eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
+                       if (eivlen <= 1)
+                               eivlen = 0;
+                       }
+               /* Need explicit part of IV for GCM mode */
+               else if (mode == EVP_CIPH_GCM_MODE)
+                       eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+               else
                        eivlen = 0;
                }
        else 
@@ -778,7 +1075,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
         * from wr->input.  Length should be wr->length.
         * wr->data still points in the wb->buf */
 
-       if (mac_size != 0)
+       if (!SSL_USE_ETM(s) && mac_size != 0)
                {
                if (s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0)
                        goto err;
@@ -798,9 +1095,19 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        /* ssl3_enc can only have an error on read */
        s->method->ssl3_enc->enc(s,1);
 
+       if (SSL_USE_ETM(s) && mac_size != 0)
+               {
+               if (s->method->ssl3_enc->mac(s,p + wr->length,1) < 0)
+                       goto err;
+               wr->length+=mac_size;
+               }
+
        /* record length after mac and block padding */
        s2n(wr->length,plen);
 
+       if (s->msg_callback)
+               s->msg_callback(1, 0, SSL3_RT_HEADER, plen - 5, 5, s, s->msg_callback_arg);
+
        /* we should now have
         * wr->data pointing to the encrypted data, which is
         * wr->length long */
@@ -866,8 +1173,6 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
                        {
                        wb->left=0;
                        wb->offset+=i;
-                       if (s->mode & SSL_MODE_RELEASE_BUFFERS)
-                               ssl3_release_write_buffer(s);
                        s->rwstate=SSL_NOTHING;
                        return(s->s3->wpend_ret);
                        }
@@ -1060,6 +1365,19 @@ start:
                        dest = s->s3->alert_fragment;
                        dest_len = &s->s3->alert_fragment_len;
                        }
+#ifndef OPENSSL_NO_HEARTBEATS
+               else if (rr->type == TLS1_RT_HEARTBEAT)
+                       {
+                       tls1_process_heartbeat(s);
+
+                       /* Exit and notify application to read again */
+                       rr->length = 0;
+                       s->rwstate=SSL_READING;
+                       BIO_clear_retry_flags(SSL_get_rbio(s));
+                       BIO_set_retry_read(SSL_get_rbio(s));
+                       return(-1);
+                       }
+#endif
 
                if (dest_maxlen > 0)
                        {
@@ -1420,8 +1738,14 @@ int ssl3_do_change_cipher_spec(SSL *s)
                slen=s->method->ssl3_enc->client_finished_label_len;
                }
 
-       s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
+       i = s->method->ssl3_enc->final_finish_mac(s,
                sender,slen,s->s3->tmp.peer_finish_md);
+       if (i == 0)
+               {
+               SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
+               return 0;
+               }
+       s->s3->tmp.peer_finish_md_len = i;
 
        return(1);
        }