Back-port TLS AEAD framework [from HEAD].
authorAndy Polyakov <appro@openssl.org>
Thu, 21 Jul 2011 19:22:57 +0000 (19:22 +0000)
committerAndy Polyakov <appro@openssl.org>
Thu, 21 Jul 2011 19:22:57 +0000 (19:22 +0000)
crypto/evp/evp.h
ssl/ssl_ciph.c
ssl/t1_enc.c

index b672d01964df0ec536d38898a7764656d7067b68..fb651b7ea5b972c1a62b0cac16cd04e47ad88d71 100644 (file)
@@ -361,6 +361,7 @@ struct evp_cipher_st
  * as finalisation.
  */
 #define        EVP_CIPH_FLAG_CUSTOM_CIPHER     0x100000
+#define                EVP_CIPH_FLAG_AEAD_CIPHER       0x200000
 
 /* ctrl() values */
 
@@ -383,6 +384,14 @@ struct evp_cipher_st
 #define                EVP_CTRL_CCM_SET_TAG            EVP_CTRL_GCM_SET_TAG
 #define                EVP_CTRL_CCM_SET_L              0x14
 #define                EVP_CTRL_CCM_SET_MSGLEN         0x15
+/* AEAD cipher deduces payload length and returns number of bytes
+ * required to store MAC and eventual padding. Subsequent call to
+ * EVP_Cipher even appends/verifies MAC.
+ */
+#define                EVP_CTRL_AEAD_TLS1_AAD          0x16
+/* Used by composite AEAD ciphers, no-op in GCM, CCM... */
+#define                EVP_CTRL_AEAD_SET_MAC_KEY       0x17
+
 
 typedef struct evp_cipher_info_st
        {
index 87a9f68ce9d7b68906588ab5f61cb2ef892b91c8..b0542d1b4a90ecb4b68e21406185ee5ad2399ad6 100644 (file)
@@ -583,8 +583,29 @@ int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
                if (mac_secret_size!=NULL) *mac_secret_size = ssl_mac_secret_size[i];
        }       
 
-       if ((*enc != NULL) && (*md != NULL) && (!mac_pkey_type||*mac_pkey_type != NID_undef))
+       if ((*enc != NULL) &&
+           (*md != NULL || (EVP_CIPHER_flags(*enc)&EVP_CIPH_FLAG_AEAD_CIPHER)) &&
+           (!mac_pkey_type||*mac_pkey_type != NID_undef))
+               {
+               const EVP_CIPHER *evp;
+
+               if      (s->ssl_version >= TLS1_VERSION &&
+                        c->algorithm_enc == SSL_RC4 &&
+                        c->algorithm_mac == SSL_MD5 &&
+                        (evp=EVP_get_cipherbyname("RC4-HMAC-MD5")))
+                       *enc = evp, *md = NULL;
+               else if (s->ssl_version >= TLS1_VERSION &&
+                        c->algorithm_enc == SSL_AES128 &&
+                        c->algorithm_mac == SSL_SHA1 &&
+                        (evp=EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA1")))
+                       *enc = evp, *md = NULL;
+               else if (s->ssl_version >= TLS1_VERSION &&
+                        c->algorithm_enc == SSL_AES256 &&
+                        c->algorithm_mac == SSL_SHA1 &&
+                        (evp=EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA1")))
+                       *enc = evp, *md = NULL;
                return(1);
+               }
        else
                return(0);
        }
index d180bfc95c4ba094f84223b1af8864cdd17c1a99..1c14637072ebf13b16e8ee56287f09f182a2342a 100644 (file)
@@ -369,7 +369,7 @@ int tls1_change_cipher_state(SSL *s, int which)
                {
                if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
                        s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM;
-                       else
+               else
                        s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM;
 
                if (s->enc_read_ctx != NULL)
@@ -485,10 +485,14 @@ int tls1_change_cipher_state(SSL *s, int which)
                }
 
        memcpy(mac_secret,ms,i);
-       mac_key = EVP_PKEY_new_mac_key(mac_type, NULL,
-                       mac_secret,*mac_secret_size);
-       EVP_DigestSignInit(mac_ctx,NULL,m,NULL,mac_key);
-       EVP_PKEY_free(mac_key);
+
+       if (!(EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER))
+               {
+               mac_key = EVP_PKEY_new_mac_key(mac_type, NULL,
+                               mac_secret,*mac_secret_size);
+               EVP_DigestSignInit(mac_ctx,NULL,m,NULL,mac_key);
+               EVP_PKEY_free(mac_key);
+               }
 #ifdef TLS_DEBUG
 printf("which = %04X\nmac key=",which);
 { int z; for (z=0; z<i; z++) printf("%02X%c",ms[z],((z+1)%16)?' ':'\n'); }
@@ -536,6 +540,12 @@ printf("which = %04X\nmac key=",which);
 #endif /* KSSL_DEBUG */
 
        EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE));
+
+       /* Needed for "composite" AEADs, such as RC4-HMAC-MD5 */
+       if ((EVP_CIPHER_flags(c)&EVP_CIPH_FLAG_AEAD_CIPHER) && *mac_secret_size)
+               EVP_CIPHER_CTX_ctrl(dd,EVP_CTRL_AEAD_SET_MAC_KEY,
+                               *mac_secret_size,mac_secret);
+
 #ifdef TLS_DEBUG
 printf("which = %04X\nkey=",which);
 { int z; for (z=0; z<EVP_CIPHER_key_length(c); z++) printf("%02X%c",key[z],((z+1)%16)?' ':'\n'); }
@@ -652,14 +662,14 @@ 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,ii,j,k,pad=0;
        const EVP_CIPHER *enc;
 
        if (send)
                {
                if (EVP_MD_CTX_md(s->write_hash))
                        {
-                       n=EVP_MD_CTX_size(s->write_hash);
+                       int n=EVP_MD_CTX_size(s->write_hash);
                        OPENSSL_assert(n >= 0);
                        }
                ds=s->enc_write_ctx;
@@ -679,12 +689,12 @@ int tls1_enc(SSL *s, int send)
                        if (ivlen > 1)
                                {
                                if ( rec->data != rec->input)
-                               /* we can't write into the input stream:
-                                * Can this ever happen?? (steve)
-                                */
-                               fprintf(stderr,
-                                       "%s:%d: rec->data != rec->input\n",
-                                       __FILE__, __LINE__);
+                                       /* we can't write into the input stream:
+                                        * Can this ever happen?? (steve)
+                                        */
+                                       fprintf(stderr,
+                                               "%s:%d: rec->data != rec->input\n",
+                                               __FILE__, __LINE__);
                                else if (RAND_bytes(rec->input, ivlen) <= 0)
                                        return -1;
                                }
@@ -694,7 +704,7 @@ int tls1_enc(SSL *s, int send)
                {
                if (EVP_MD_CTX_md(s->read_hash))
                        {
-                       n=EVP_MD_CTX_size(s->read_hash);
+                       int n=EVP_MD_CTX_size(s->read_hash);
                        OPENSSL_assert(n >= 0);
                        }
                ds=s->enc_read_ctx;
@@ -720,7 +730,43 @@ int tls1_enc(SSL *s, int send)
                l=rec->length;
                bs=EVP_CIPHER_block_size(ds->cipher);
 
-               if ((bs != 1) && send)
+               if (EVP_CIPHER_flags(ds->cipher)&EVP_CIPH_FLAG_AEAD_CIPHER)
+                       {
+                       unsigned char buf[13],*seq;
+
+                       seq = send?s->s3->write_sequence:s->s3->read_sequence;
+
+                       if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+                               {
+                               unsigned char dtlsseq[9],*p=dtlsseq;
+
+                               s2n(send?s->d1->w_epoch:s->d1->r_epoch,p);
+                               memcpy(p,&seq[2],6);
+                               memcpy(buf,dtlsseq,8);
+                               }
+                       else
+                               {
+                               memcpy(buf,seq,8);
+                               for (i=7; i>=0; i--)    /* increment */
+                                       {
+                                       ++seq[i];
+                                       if (seq[i] != 0) break; 
+                                       }
+                               }
+
+                       buf[8]=rec->type;
+                       buf[9]=(unsigned char)(s->version>>8);
+                       buf[10]=(unsigned char)(s->version);
+                       buf[11]=rec->length>>8;
+                       buf[12]=rec->length&0xff;
+                       pad=EVP_CIPHER_CTX_ctrl(ds,EVP_CTRL_AEAD_TLS1_AAD,13,buf);
+                       if (send)
+                               {
+                               l+=pad;
+                               rec->length+=pad;
+                               }
+                       }
+               else if ((bs != 1) && send)
                        {
                        i=bs-((int)l%bs);
 
@@ -769,7 +815,8 @@ int tls1_enc(SSL *s, int send)
                                }
                        }
                
-               EVP_Cipher(ds,rec->data,rec->input,l);
+               if (!EVP_Cipher(ds,rec->data,rec->input,l))
+                       return -1;      /* AEAD can fail to verify MAC */
 
 #ifdef KSSL_DEBUG
                {
@@ -828,6 +875,8 @@ int tls1_enc(SSL *s, int send)
                                rec->length -= bs;
                                }
                        }
+               if (pad && !send)
+                       rec->length -= pad;
                }
        return(1);
        }