Don't crash when processing a zero-length, TLS >= 1.1 record.
[openssl.git] / ssl / t1_enc.c
index 3a349920d9cd2144e73472f43b98f46fc59c74cf..aaa4a5ef280296a6ef51a39167983563203fb6b6 100644 (file)
 
 #include <stdio.h>
 #include "ssl_locl.h"
+#ifndef OPENSSL_NO_COMP
 #include <openssl/comp.h>
+#endif
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 #include <openssl/md5.h>
 #endif
 
 /* seed1 through seed5 are virtually concatenated */
-static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
+static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
                        int sec_len,
                        const void *seed1, int seed1_len,
                        const void *seed2, int seed2_len,
@@ -155,60 +157,84 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
                        const void *seed5, int seed5_len,
                        unsigned char *out, int olen)
        {
-       int chunk,n;
+       int chunk;
        unsigned int j;
        HMAC_CTX ctx;
        HMAC_CTX ctx_tmp;
        unsigned char A1[EVP_MAX_MD_SIZE];
        unsigned int A1_len;
+       int ret = 0;
        
        chunk=EVP_MD_size(md);
+       OPENSSL_assert(chunk >= 0);
 
        HMAC_CTX_init(&ctx);
        HMAC_CTX_init(&ctx_tmp);
-       HMAC_Init_ex(&ctx,sec,sec_len,md, NULL);
-       HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL);
-       if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len);
-       if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len);
-       if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len);
-       if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len);
-       if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len);
-       HMAC_Final(&ctx,A1,&A1_len);
-
-       n=0;
+       if (!HMAC_Init_ex(&ctx,sec,sec_len,md, NULL))
+               goto err;
+       if (!HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL))
+               goto err;
+       if (seed1 != NULL && !HMAC_Update(&ctx,seed1,seed1_len))
+               goto err;
+       if (seed2 != NULL && !HMAC_Update(&ctx,seed2,seed2_len))
+               goto err;
+       if (seed3 != NULL && !HMAC_Update(&ctx,seed3,seed3_len))
+               goto err;
+       if (seed4 != NULL && !HMAC_Update(&ctx,seed4,seed4_len))
+               goto err;
+       if (seed5 != NULL && !HMAC_Update(&ctx,seed5,seed5_len))
+               goto err;
+       if (!HMAC_Final(&ctx,A1,&A1_len))
+               goto err;
+
        for (;;)
                {
-               HMAC_Init_ex(&ctx,NULL,0,NULL,NULL); /* re-init */
-               HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL); /* re-init */
-               HMAC_Update(&ctx,A1,A1_len);
-               HMAC_Update(&ctx_tmp,A1,A1_len);
-               if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len);
-               if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len);
-               if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len);
-               if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len);
-               if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len);
+               if (!HMAC_Init_ex(&ctx,NULL,0,NULL,NULL)) /* re-init */
+                       goto err;
+               if (!HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL)) /* re-init */
+                       goto err;
+               if (!HMAC_Update(&ctx,A1,A1_len))
+                       goto err;
+               if (!HMAC_Update(&ctx_tmp,A1,A1_len))
+                       goto err;
+               if (seed1 != NULL && !HMAC_Update(&ctx,seed1,seed1_len))
+                       goto err;
+               if (seed2 != NULL && !HMAC_Update(&ctx,seed2,seed2_len))
+                       goto err;
+               if (seed3 != NULL && !HMAC_Update(&ctx,seed3,seed3_len))
+                       goto err;
+               if (seed4 != NULL && !HMAC_Update(&ctx,seed4,seed4_len))
+                       goto err;
+               if (seed5 != NULL && !HMAC_Update(&ctx,seed5,seed5_len))
+                       goto err;
 
                if (olen > chunk)
                        {
-                       HMAC_Final(&ctx,out,&j);
+                       if (!HMAC_Final(&ctx,out,&j))
+                               goto err;
                        out+=j;
                        olen-=j;
-                       HMAC_Final(&ctx_tmp,A1,&A1_len); /* calc the next A1 value */
+                       if (!HMAC_Final(&ctx_tmp,A1,&A1_len)) /* calc the next A1 value */
+                               goto err;
                        }
                else    /* last one */
                        {
-                       HMAC_Final(&ctx,A1,&A1_len);
+                       if (!HMAC_Final(&ctx,A1,&A1_len))
+                               goto err;
                        memcpy(out,A1,olen);
                        break;
                        }
                }
+       ret = 1;
+err:
        HMAC_CTX_cleanup(&ctx);
        HMAC_CTX_cleanup(&ctx_tmp);
        OPENSSL_cleanse(A1,sizeof(A1));
+       return ret;
        }
 
 /* seed1 through seed5 are virtually concatenated */
-static void tls1_PRF(long digest_mask,
+static int tls1_PRF(long digest_mask,
                     const void *seed1, int seed1_len,
                     const void *seed2, int seed2_len,
                     const void *seed3, int seed3_len,
@@ -222,6 +248,7 @@ static void tls1_PRF(long digest_mask,
        const unsigned char *S1;
        long m;
        const EVP_MD *md;
+       int ret = 0;
 
        /* Count number of digests and partition sec evenly */
        count=0;
@@ -236,11 +263,12 @@ static void tls1_PRF(long digest_mask,
                        if (!md) {
                                SSLerr(SSL_F_TLS1_PRF,
                                SSL_R_UNSUPPORTED_DIGEST_TYPE);
-                               return;                         
+                               goto err;                               
                        }
-                       tls1_P_hash(md ,S1,len+(slen&1),
-                                   seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
-                                   out2,olen);
+                       if (!tls1_P_hash(md ,S1,len+(slen&1),
+                                       seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
+                                       out2,olen))
+                               goto err;
                        S1+=len;
                        for (i=0; i<olen; i++)
                        {
@@ -248,12 +276,15 @@ static void tls1_PRF(long digest_mask,
                        }
                }
        }
-
+       ret = 1;
+err:
+       return ret;
 }
-static void tls1_generate_key_block(SSL *s, unsigned char *km,
+static int tls1_generate_key_block(SSL *s, unsigned char *km,
             unsigned char *tmp, int num)
        {
-       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+       int ret;
+       ret = tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
                 TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
                 s->s3->server_random,SSL3_RANDOM_SIZE,
                 s->s3->client_random,SSL3_RANDOM_SIZE,
@@ -271,18 +302,19 @@ static void tls1_generate_key_block(SSL *s, unsigned char *km,
                 }
         printf("\n");  }
 #endif    /* KSSL_DEBUG */
+       return ret;
        }
 
 int tls1_change_cipher_state(SSL *s, int which)
        {
        static const unsigned char empty[]="";
-       unsigned char *p,*key_block,*mac_secret;
+       unsigned char *p,*mac_secret;
        unsigned char *exp_label;
        unsigned char tmp1[EVP_MAX_KEY_LENGTH];
        unsigned char tmp2[EVP_MAX_KEY_LENGTH];
        unsigned char iv1[EVP_MAX_IV_LENGTH*2];
        unsigned char iv2[EVP_MAX_IV_LENGTH*2];
-       unsigned char *ms,*key,*iv,*er1,*er2;
+       unsigned char *ms,*key,*iv;
        int client_write;
        EVP_CIPHER_CTX *dd;
        const EVP_CIPHER *c;
@@ -304,7 +336,6 @@ int tls1_change_cipher_state(SSL *s, int which)
 #ifndef OPENSSL_NO_COMP
        comp=s->s3->tmp.new_compression;
 #endif
-       key_block=s->s3->tmp.key_block;
 
 #ifdef KSSL_DEBUG
        printf("tls1_change_cipher_state(which= %d) w/\n", which);
@@ -319,7 +350,7 @@ int tls1_change_cipher_state(SSL *s, int which)
        {
         int i;
         for (i=0; i<s->s3->tmp.key_block_length; i++)
-               printf("%02x", key_block[i]);  printf("\n");
+               printf("%02x", s->s3->tmp.key_block[i]);  printf("\n");
         }
 #endif /* KSSL_DEBUG */
 
@@ -415,8 +446,6 @@ int tls1_change_cipher_state(SSL *s, int which)
                       cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
        /* Was j=(exp)?5:EVP_CIPHER_key_length(c); */
        k=EVP_CIPHER_iv_length(c);
-       er1= &(s->s3->client_random[0]);
-       er2= &(s->s3->server_random[0]);
        if (    (which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
                (which == SSL3_CHANGE_CIPHER_SERVER_READ))
                {
@@ -458,22 +487,24 @@ printf("which = %04X\nmac key=",which);
                /* In here I set both the read and write key/iv to the
                 * same value since only the correct one will be used :-).
                 */
-               tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
-                        exp_label,exp_label_len,
-                        s->s3->client_random,SSL3_RANDOM_SIZE,
-                        s->s3->server_random,SSL3_RANDOM_SIZE,
-                        NULL,0,NULL,0,
-                        key,j,tmp1,tmp2,EVP_CIPHER_key_length(c));
+               if (!tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+                               exp_label,exp_label_len,
+                               s->s3->client_random,SSL3_RANDOM_SIZE,
+                               s->s3->server_random,SSL3_RANDOM_SIZE,
+                               NULL,0,NULL,0,
+                               key,j,tmp1,tmp2,EVP_CIPHER_key_length(c)))
+                       goto err2;
                key=tmp1;
 
                if (k > 0)
                        {
-                       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
-                                TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE,
-                                s->s3->client_random,SSL3_RANDOM_SIZE,
-                                s->s3->server_random,SSL3_RANDOM_SIZE,
-                                NULL,0,NULL,0,
-                                empty,0,iv1,iv2,k*2);
+                       if (!tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+                                       TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE,
+                                       s->s3->client_random,SSL3_RANDOM_SIZE,
+                                       s->s3->server_random,SSL3_RANDOM_SIZE,
+                                       NULL,0,NULL,0,
+                                       empty,0,iv1,iv2,k*2))
+                               goto err2;
                        if (client_write)
                                iv=iv1;
                        else
@@ -515,12 +546,13 @@ err2:
 
 int tls1_setup_key_block(SSL *s)
        {
-       unsigned char *p1,*p2;
+       unsigned char *p1,*p2=NULL;
        const EVP_CIPHER *c;
        const EVP_MD *hash;
        int num;
        SSL_COMP *comp;
        int mac_type= NID_undef,mac_secret_size=0;
+       int ret=0;
 
 #ifdef KSSL_DEBUG
        printf ("tls1_setup_key_block()\n");
@@ -545,13 +577,19 @@ int tls1_setup_key_block(SSL *s)
        ssl3_cleanup_key_block(s);
 
        if ((p1=(unsigned char *)OPENSSL_malloc(num)) == NULL)
+               {
+               SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE);
                goto err;
-       if ((p2=(unsigned char *)OPENSSL_malloc(num)) == NULL)
-               goto err;
+               }
 
        s->s3->tmp.key_block_length=num;
        s->s3->tmp.key_block=p1;
 
+       if ((p2=(unsigned char *)OPENSSL_malloc(num)) == NULL)
+               {
+               SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE);
+               goto err;
+               }
 
 #ifdef TLS_DEBUG
 printf("client random\n");
@@ -561,9 +599,8 @@ printf("server random\n");
 printf("pre-master\n");
 { int z; for (z=0; z<s->session->master_key_length; z++) printf("%02X%c",s->session->master_key[z],((z+1)%16)?' ':'\n'); }
 #endif
-       tls1_generate_key_block(s,p1,p2,num);
-       OPENSSL_cleanse(p2,num);
-       OPENSSL_free(p2);
+       if (!tls1_generate_key_block(s,p1,p2,num))
+               goto err;
 #ifdef TLS_DEBUG
 printf("\nkey block\n");
 { int z; for (z=0; z<num; z++) printf("%02X%c",p1[z],((z+1)%16)?' ':'\n'); }
@@ -588,24 +625,41 @@ printf("\nkey block\n");
                        }
                }
                
-       return(1);
+       ret = 1;
 err:
-       SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE);
-       return(0);
+       if (p2)
+               {
+               OPENSSL_cleanse(p2,num);
+               OPENSSL_free(p2);
+               }
+       return(ret);
        }
 
+/* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
+ *
+ * Returns:
+ *   0: (in non-constant time) if the record is publically invalid (i.e. too
+ *       short etc).
+ *   1: if the record's padding is valid / the encryption was successful.
+ *   -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
+ *       an internal error occured.
+ */
 int tls1_enc(SSL *s, int send)
        {
        SSL3_RECORD *rec;
        EVP_CIPHER_CTX *ds;
        unsigned long l;
-       int bs,i,ii,j,k,n=0;
+       int bs,i,j,k,pad=0,ret,mac_size=0;
+       int n;
        const EVP_CIPHER *enc;
 
        if (send)
                {
                if (EVP_MD_CTX_md(s->write_hash))
+                       {
                        n=EVP_MD_CTX_size(s->write_hash);
+                       OPENSSL_assert(n >= 0);
+                       }
                ds=s->enc_write_ctx;
                rec= &(s->s3->wrec);
                if (s->enc_write_ctx == NULL)
@@ -616,7 +670,10 @@ int tls1_enc(SSL *s, int send)
        else
                {
                if (EVP_MD_CTX_md(s->read_hash))
+                       {
                        n=EVP_MD_CTX_size(s->read_hash);
+                       OPENSSL_assert(n >= 0);
+                       }
                ds=s->enc_read_ctx;
                rec= &(s->s3->rrec);
                if (s->enc_read_ctx == NULL)
@@ -629,11 +686,11 @@ int tls1_enc(SSL *s, int send)
        printf("tls1_enc(%d)\n", send);
 #endif    /* KSSL_DEBUG */
 
-       if ((s->session == NULL) || (ds == NULL) ||
-               (enc == NULL))
+       if ((s->session == NULL) || (ds == NULL) || (enc == NULL))
                {
                memmove(rec->data,rec->input,rec->length);
                rec->input=rec->data;
+               ret = 1;
                }
        else
                {
@@ -661,13 +718,13 @@ int tls1_enc(SSL *s, int send)
 
 #ifdef KSSL_DEBUG
                {
-                unsigned long ui;
+               unsigned long ui;
                printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
-                        ds,rec->data,rec->input,l);
+                       ds,rec->data,rec->input,l);
                printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
-                        ds->buf_len, ds->cipher->key_len,
-                        DES_KEY_SZ, DES_SCHEDULE_SZ,
-                        ds->cipher->iv_len);
+                       ds->buf_len, ds->cipher->key_len,
+                       DES_KEY_SZ, DES_SCHEDULE_SZ,
+                       ds->cipher->iv_len);
                printf("\t\tIV: ");
                for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
                printf("\n");
@@ -691,57 +748,24 @@ int tls1_enc(SSL *s, int send)
 
 #ifdef KSSL_DEBUG
                {
-                unsigned long i;
-                printf("\trec->data=");
+               unsigned long i;
+               printf("\trec->data=");
                for (i=0; i<l; i++)
-                        printf(" %02x", rec->data[i]);  printf("\n");
-                }
+                       printf(" %02x", rec->data[i]);  printf("\n");
+               }
 #endif /* KSSL_DEBUG */
 
+               ret = 1;
+               if (EVP_MD_CTX_md(s->read_hash) != NULL)
+                       mac_size = EVP_MD_CTX_size(s->read_hash);
                if ((bs != 1) && !send)
-                       {
-                       ii=i=rec->data[l-1]; /* padding_length */
-                       i++;
-                       /* NB: if compression is in operation the first packet
-                        * may not be of even length so the padding bug check
-                        * cannot be performed. This bug workaround has been
-                        * around since SSLeay so hopefully it is either fixed
-                        * now or no buggy implementation supports compression 
-                        * [steve]
-                        */
-                       if ( (s->options&SSL_OP_TLS_BLOCK_PADDING_BUG)
-                               && !s->expand)
-                               {
-                               /* First packet is even in size, so check */
-                               if ((memcmp(s->s3->read_sequence,
-                                       "\0\0\0\0\0\0\0\0",8) == 0) && !(ii & 1))
-                                       s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG;
-                               if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
-                                       i--;
-                               }
-                       /* TLS 1.0 does not bound the number of padding bytes by the block size.
-                        * All of them must have value 'padding_length'. */
-                       if (i > (int)rec->length)
-                               {
-                               /* Incorrect padding. SSLerr() and ssl3_alert are done
-                                * by caller: we don't want to reveal whether this is
-                                * a decryption error or a MAC verification failure
-                                * (see http://www.openssl.org/~bodo/tls-cbc.txt) */
-                               return -1;
-                               }
-                       for (j=(int)(l-i); j<(int)l; j++)
-                               {
-                               if (rec->data[j] != ii)
-                                       {
-                                       /* Incorrect padding */
-                                       return -1;
-                                       }
-                               }
-                       rec->length-=i;
-                       }
+                       ret = tls1_cbc_remove_padding(s, rec, bs, mac_size);
+               if (pad && !send)
+                       rec->length -= pad;
                }
-       return(1);
+       return ret;
        }
+
 int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out)
        {
        unsigned int ret;
@@ -749,7 +773,9 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out)
        int i;
 
        if (s->s3->handshake_buffer) 
-               ssl3_digest_cached_records(s);
+               if (!ssl3_digest_cached_records(s))
+                       return 0;
+
        for (i=0;i<SSL_MAX_DIGEST;i++) 
                {
                  if (s->s3->handshake_dgst[i]&&EVP_MD_CTX_type(s->s3->handshake_dgst[i])==md_nid) 
@@ -784,17 +810,18 @@ int tls1_final_finish_mac(SSL *s,
 
        q=buf;
 
-       EVP_MD_CTX_init(&ctx);
-
        if (s->s3->handshake_buffer) 
-               ssl3_digest_cached_records(s);
+               if (!ssl3_digest_cached_records(s))
+                       return 0;
+
+       EVP_MD_CTX_init(&ctx);
 
        for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++)
                {
                if (mask & s->s3->tmp.new_cipher->algorithm2)
                        {
-                       unsigned int hashsize = EVP_MD_size(md);
-                       if (hashsize (sizeof buf - (size_t)(q-buf)))
+                       int hashsize = EVP_MD_size(md);
+                       if (hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf)))
                                {
                                /* internal error: 'buf' is too small for this cipersuite! */
                                err = 1;
@@ -803,17 +830,18 @@ int tls1_final_finish_mac(SSL *s,
                                {
                                EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]);
                                EVP_DigestFinal_ex(&ctx,q,&i);
-                               if (i != hashsize) /* can't really happen */
+                               if (i != (unsigned int)hashsize) /* can't really happen */
                                        err = 1;
                                q+=i;
                                }
                        }
                }
                
-       tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
-                str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0,
-                s->session->master_key,s->session->master_key_length,
-                out,buf2,sizeof buf2);
+       if (!tls1_PRF(s->s3->tmp.new_cipher->algorithm2,
+                       str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0,
+                       s->session->master_key,s->session->master_key_length,
+                       out,buf2,sizeof buf2))
+               err = 1;
        EVP_MD_CTX_cleanup(&ctx);
 
        if (err)
@@ -825,36 +853,31 @@ int tls1_final_finish_mac(SSL *s,
 int tls1_mac(SSL *ssl, unsigned char *md, int send)
        {
        SSL3_RECORD *rec;
-       unsigned char *mac_sec,*seq;
+       unsigned char *seq;
        EVP_MD_CTX *hash;
        size_t md_size;
        int i;
        EVP_MD_CTX hmac, *mac_ctx;
-       unsigned char buf[5]; 
+       unsigned char header[13];
        int stream_mac = (send?(ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM):(ssl->mac_flags&SSL_MAC_FLAG_READ_MAC_STREAM));
+       int t;
 
        if (send)
                {
                rec= &(ssl->s3->wrec);
-               mac_sec= &(ssl->s3->write_mac_secret[0]);
                seq= &(ssl->s3->write_sequence[0]);
                hash=ssl->write_hash;
                }
        else
                {
                rec= &(ssl->s3->rrec);
-               mac_sec= &(ssl->s3->read_mac_secret[0]);
                seq= &(ssl->s3->read_sequence[0]);
                hash=ssl->read_hash;
                }
 
-       md_size=EVP_MD_CTX_size(hash);
-
-       buf[0]=rec->type;
-       buf[1]=(unsigned char)(ssl->version>>8);
-       buf[2]=(unsigned char)(ssl->version);
-       buf[3]=rec->length>>8;
-       buf[4]=rec->length&0xff;
+       t=EVP_MD_CTX_size(hash);
+       OPENSSL_assert(t >= 0);
+       md_size=t;
 
        /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
        if (stream_mac) 
@@ -867,22 +890,51 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send)
                        mac_ctx = &hmac;
                }
 
-       if (ssl->version == DTLS1_VERSION)
+       if (ssl->version == DTLS1_VERSION || ssl->version == DTLS1_BAD_VER)
                {
                unsigned char dtlsseq[8],*p=dtlsseq;
 
                s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p);
                memcpy (p,&seq[2],6);
 
-               EVP_DigestSignUpdate(mac_ctx,dtlsseq,8);
+               memcpy(header, dtlsseq, 8);
                }
        else
-               EVP_DigestSignUpdate(mac_ctx,seq,8);
+               memcpy(header, seq, 8);
+
+       header[8]=rec->type;
+       header[9]=(unsigned char)(ssl->version>>8);
+       header[10]=(unsigned char)(ssl->version);
+       header[11]=(rec->length)>>8;
+       header[12]=(rec->length)&0xff;
 
-       EVP_DigestSignUpdate(mac_ctx,buf,5);
-       EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length);
-       EVP_DigestSignFinal(mac_ctx,md,&md_size);
-       if (!stream_mac) EVP_MD_CTX_cleanup(&hmac);
+       if (!send &&
+           EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
+           ssl3_cbc_record_digest_supported(mac_ctx))
+               {
+               /* This is a CBC-encrypted record. We must avoid leaking any
+                * timing-side channel information about how many blocks of
+                * data we are hashing because that gives an attacker a
+                * timing-oracle. */
+               ssl3_cbc_digest_record(
+                       mac_ctx,
+                       md, &md_size,
+                       header, rec->input,
+                       rec->length + md_size, rec->orig_len,
+                       ssl->s3->read_mac_secret,
+                       ssl->s3->read_mac_secret_size,
+                       0 /* not SSLv3 */);
+               }
+       else
+               {
+               EVP_DigestSignUpdate(mac_ctx,header,sizeof(header));
+               EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length);
+               t=EVP_DigestSignFinal(mac_ctx,md,&md_size);
+               OPENSSL_assert(t > 0);
+               }
+               
+       if (!stream_mac)
+               EVP_MD_CTX_cleanup(&hmac);
 #ifdef TLS_DEBUG
 printf("sec=");
 {unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",mac_sec[z]); printf("\n"); }
@@ -894,7 +946,7 @@ printf("rec=");
 {unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
 #endif
 
-       if (ssl->version != DTLS1_VERSION)
+       if (ssl->version != DTLS1_VERSION && ssl->version != DTLS1_BAD_VER)
                {
                for (i=7; i>=0; i--)
                        {