PR: 2457
[openssl.git] / ssl / s3_enc.c
index b4c6f0f19bcdd55cc6e9a8b891543627a85357f0..58386e1ba03cac59d74b1e75c9d84888c51b0a54 100644 (file)
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -155,10 +155,8 @@ static unsigned char ssl3_pad_2[48]={
        0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,
        0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,
        0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c };
-
-static int ssl3_handshake_mac(SSL *s, EVP_MD_CTX *in_ctx,
+static int ssl3_handshake_mac(SSL *s, int md_nid,
        const char *sender, int len, unsigned char *p);
-
 static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num)
        {
        EVP_MD_CTX m5;
@@ -216,7 +214,7 @@ static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num)
 
 int ssl3_change_cipher_state(SSL *s, int which)
        {
-       unsigned char *p,*key_block,*mac_secret;
+       unsigned char *p,*mac_secret;
        unsigned char exp_key[EVP_MAX_KEY_LENGTH];
        unsigned char exp_iv[EVP_MAX_IV_LENGTH];
        unsigned char *ms,*key,*iv,*er1,*er2;
@@ -233,13 +231,14 @@ int ssl3_change_cipher_state(SSL *s, int which)
        is_exp=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
        c=s->s3->tmp.new_sym_enc;
        m=s->s3->tmp.new_hash;
+       /* m == NULL will lead to a crash later */
+       OPENSSL_assert(m);
 #ifndef OPENSSL_NO_COMP
        if (s->s3->tmp.new_compression == NULL)
                comp=NULL;
        else
                comp=s->s3->tmp.new_compression->method;
 #endif
-       key_block=s->s3->tmp.key_block;
 
        if (which & SSL3_CC_READ)
                {
@@ -247,8 +246,12 @@ int ssl3_change_cipher_state(SSL *s, int which)
                        reuse_dd = 1;
                else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
                        goto err;
+               else
+                       /* make sure it's intialized in case we exit later with an error */
+                       EVP_CIPHER_CTX_init(s->enc_read_ctx);
                dd= s->enc_read_ctx;
-               s->read_hash=m;
+
+               ssl_replace_hash(&s->read_hash,m);
 #ifndef OPENSSL_NO_COMP
                /* COMPRESS */
                if (s->expand != NULL)
@@ -280,8 +283,11 @@ int ssl3_change_cipher_state(SSL *s, int which)
                        reuse_dd = 1;
                else if ((s->enc_write_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
                        goto err;
+               else
+                       /* make sure it's intialized in case we exit later with an error */
+                       EVP_CIPHER_CTX_init(s->enc_write_ctx);
                dd= s->enc_write_ctx;
-               s->write_hash=m;
+               ssl_replace_hash(&s->write_hash,m);
 #ifndef OPENSSL_NO_COMP
                /* COMPRESS */
                if (s->compress != NULL)
@@ -305,10 +311,11 @@ int ssl3_change_cipher_state(SSL *s, int which)
 
        if (reuse_dd)
                EVP_CIPHER_CTX_cleanup(dd);
-       EVP_CIPHER_CTX_init(dd);
 
        p=s->s3->tmp.key_block;
        i=EVP_MD_size(m);
+       if (i < 0)
+               goto err2;
        cl=EVP_CIPHER_key_length(c);
        j=is_exp ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
                 cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
@@ -389,7 +396,7 @@ int ssl3_setup_key_block(SSL *s)
        if (s->s3->tmp.key_block_length != 0)
                return(1);
 
-       if (!ssl_cipher_get_evp(s->session,&c,&hash,&comp))
+       if (!ssl_cipher_get_evp(s->session,&c,&hash,NULL,NULL,&comp))
                {
                SSLerr(SSL_F_SSL3_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
                return(0);
@@ -403,7 +410,11 @@ int ssl3_setup_key_block(SSL *s)
        s->s3->tmp.new_compression=comp;
 #endif
 
-       num=EVP_CIPHER_key_length(c)+EVP_MD_size(hash)+EVP_CIPHER_iv_length(c);
+       num=EVP_MD_size(hash);
+       if (num < 0)
+               return 0;
+
+       num=EVP_CIPHER_key_length(c)+num+EVP_CIPHER_iv_length(c);
        num*=2;
 
        ssl3_cleanup_key_block(s);
@@ -425,11 +436,11 @@ int ssl3_setup_key_block(SSL *s)
 
                if (s->session->cipher != NULL)
                        {
-                       if ((s->session->cipher->algorithms & SSL_ENC_MASK) == SSL_eNULL)
+                       if (s->session->cipher->algorithm_enc == SSL_eNULL)
                                s->s3->need_empty_fragments = 0;
                        
 #ifndef OPENSSL_NO_RC4
-                       if ((s->session->cipher->algorithms & SSL_ENC_MASK) == SSL_RC4)
+                       if (s->session->cipher->algorithm_enc == SSL_RC4)
                                s->s3->need_empty_fragments = 0;
 #endif
                        }
@@ -539,47 +550,131 @@ int ssl3_enc(SSL *s, int send)
 
 void ssl3_init_finished_mac(SSL *s)
        {
-       EVP_DigestInit_ex(&(s->s3->finish_dgst1),s->ctx->md5, NULL);
-       EVP_DigestInit_ex(&(s->s3->finish_dgst2),s->ctx->sha1, NULL);
+       if (s->s3->handshake_buffer) BIO_free(s->s3->handshake_buffer);
+       if (s->s3->handshake_dgst) ssl3_free_digest_list(s);
+    s->s3->handshake_buffer=BIO_new(BIO_s_mem());      
+       (void)BIO_set_close(s->s3->handshake_buffer,BIO_CLOSE);
        }
 
+void ssl3_free_digest_list(SSL *s) 
+       {
+       int i;
+       if (!s->s3->handshake_dgst) return;
+       for (i=0;i<SSL_MAX_DIGEST;i++) 
+               {
+               if (s->s3->handshake_dgst[i])
+                       EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]);
+               }
+       OPENSSL_free(s->s3->handshake_dgst);
+       s->s3->handshake_dgst=NULL;
+       }       
+               
+
+
 void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
        {
-       EVP_DigestUpdate(&(s->s3->finish_dgst1),buf,len);
-       EVP_DigestUpdate(&(s->s3->finish_dgst2),buf,len);
+       if (s->s3->handshake_buffer) 
+               {
+               BIO_write (s->s3->handshake_buffer,(void *)buf,len);
+               } 
+       else 
+               {
+               int i;
+               for (i=0;i< SSL_MAX_DIGEST;i++) 
+                       {
+                       if (s->s3->handshake_dgst[i]!= NULL)
+                       EVP_DigestUpdate(s->s3->handshake_dgst[i],buf,len);
+                       }
+               }       
        }
 
-int ssl3_cert_verify_mac(SSL *s, EVP_MD_CTX *ctx, unsigned char *p)
+int ssl3_digest_cached_records(SSL *s)
        {
-       return(ssl3_handshake_mac(s,ctx,NULL,0,p));
+       int i;
+       long mask;
+       const EVP_MD *md;
+       long hdatalen;
+       void *hdata;
+
+       /* Allocate handshake_dgst array */
+       ssl3_free_digest_list(s);
+       s->s3->handshake_dgst = OPENSSL_malloc(SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *));
+       memset(s->s3->handshake_dgst,0,SSL_MAX_DIGEST *sizeof(EVP_MD_CTX *));
+       hdatalen = BIO_get_mem_data(s->s3->handshake_buffer,&hdata);
+       if (hdatalen <= 0)
+               {
+               SSLerr(SSL_F_SSL3_DIGEST_CACHED_RECORDS, SSL_R_BAD_HANDSHAKE_LENGTH);
+               return 0;
+               }
+
+       /* Loop through bitso of algorithm2 field and create MD_CTX-es */
+       for (i=0;ssl_get_handshake_digest(i,&mask,&md); i++) 
+               {
+               if ((mask & s->s3->tmp.new_cipher->algorithm2) && md) 
+                       {
+                       s->s3->handshake_dgst[i]=EVP_MD_CTX_create();
+                       EVP_DigestInit_ex(s->s3->handshake_dgst[i],md,NULL);
+                       EVP_DigestUpdate(s->s3->handshake_dgst[i],hdata,hdatalen);
+                       } 
+               else 
+                       {       
+                       s->s3->handshake_dgst[i]=NULL;
+                       }
+               }
+       /* Free handshake_buffer BIO */
+       BIO_free(s->s3->handshake_buffer);
+       s->s3->handshake_buffer = NULL;
+
+       return 1;
        }
 
-int ssl3_final_finish_mac(SSL *s, EVP_MD_CTX *ctx1, EVP_MD_CTX *ctx2,
+int ssl3_cert_verify_mac(SSL *s, int md_nid, unsigned char *p)
+       {
+       return(ssl3_handshake_mac(s,md_nid,NULL,0,p));
+       }
+int ssl3_final_finish_mac(SSL *s, 
             const char *sender, int len, unsigned char *p)
        {
        int ret;
-
-       ret=ssl3_handshake_mac(s,ctx1,sender,len,p);
+       ret=ssl3_handshake_mac(s,NID_md5,sender,len,p);
        p+=ret;
-       ret+=ssl3_handshake_mac(s,ctx2,sender,len,p);
+       ret+=ssl3_handshake_mac(s,NID_sha1,sender,len,p);
        return(ret);
        }
-
-static int ssl3_handshake_mac(SSL *s, EVP_MD_CTX *in_ctx,
+static int ssl3_handshake_mac(SSL *s, int md_nid,
             const char *sender, int len, unsigned char *p)
        {
        unsigned int ret;
        int npad,n;
        unsigned int i;
        unsigned char md_buf[EVP_MAX_MD_SIZE];
-       EVP_MD_CTX ctx;
+       EVP_MD_CTX ctx,*d=NULL;
 
-       EVP_MD_CTX_init(&ctx);
-       EVP_MD_CTX_copy_ex(&ctx,in_ctx);
+       if (s->s3->handshake_buffer) 
+               if (!ssl3_digest_cached_records(s))
+                       return 0;
 
+       /* Search for digest of specified type in the handshake_dgst
+        * array*/
+       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) 
+                       {
+                       d=s->s3->handshake_dgst[i];
+                       break;
+                       }
+               }
+       if (!d) {
+               SSLerr(SSL_F_SSL3_HANDSHAKE_MAC,SSL_R_NO_REQUIRED_DIGEST);
+               return 0;
+       }       
+       EVP_MD_CTX_init(&ctx);
+       EVP_MD_CTX_copy_ex(&ctx,d);
        n=EVP_MD_CTX_size(&ctx);
-       npad=(48/n)*n;
+       if (n < 0)
+               return 0;
 
+       npad=(48/n)*n;
        if (sender != NULL)
                EVP_DigestUpdate(&ctx,sender,len);
        EVP_DigestUpdate(&ctx,s->session->master_key,
@@ -599,15 +694,16 @@ static int ssl3_handshake_mac(SSL *s, EVP_MD_CTX *in_ctx,
        return((int)ret);
        }
 
-int ssl3_mac(SSL *ssl, unsigned char *md, int send)
+int n_ssl3_mac(SSL *ssl, unsigned char *md, int send)
        {
        SSL3_RECORD *rec;
        unsigned char *mac_sec,*seq;
        EVP_MD_CTX md_ctx;
-       const EVP_MD *hash;
+       const EVP_MD_CTX *hash;
        unsigned char *p,rec_char;
        unsigned int md_size;
        int npad;
+       int t;
 
        if (send)
                {
@@ -624,13 +720,16 @@ int ssl3_mac(SSL *ssl, unsigned char *md, int send)
                hash=ssl->read_hash;
                }
 
-       md_size=EVP_MD_size(hash);
+       t=EVP_MD_CTX_size(hash);
+       if (t < 0)
+               return -1;
+       md_size=t;
        npad=(48/md_size)*md_size;
 
        /* Chop the digest off the end :-) */
        EVP_MD_CTX_init(&md_ctx);
 
-       EVP_DigestInit_ex(  &md_ctx,hash, NULL);
+       EVP_MD_CTX_copy_ex( &md_ctx,hash);
        EVP_DigestUpdate(&md_ctx,mac_sec,md_size);
        EVP_DigestUpdate(&md_ctx,ssl3_pad_1,npad);
        EVP_DigestUpdate(&md_ctx,seq,8);
@@ -642,7 +741,7 @@ int ssl3_mac(SSL *ssl, unsigned char *md, int send)
        EVP_DigestUpdate(&md_ctx,rec->input,rec->length);
        EVP_DigestFinal_ex( &md_ctx,md,NULL);
 
-       EVP_DigestInit_ex(  &md_ctx,hash, NULL);
+       EVP_MD_CTX_copy_ex( &md_ctx,hash);
        EVP_DigestUpdate(&md_ctx,mac_sec,md_size);
        EVP_DigestUpdate(&md_ctx,ssl3_pad_2,npad);
        EVP_DigestUpdate(&md_ctx,md,md_size);