| Index: openssl/ssl/t1_enc.c
|
| diff --git a/openssl/ssl/t1_enc.c b/openssl/ssl/t1_enc.c
|
| index 809ad2ee1e53ff3a3a9d824aa448a7b25475d4c3..87b70218653e21553d9f3ba967744b46b96c51ac 100644
|
| --- a/openssl/ssl/t1_enc.c
|
| +++ b/openssl/ssl/t1_enc.c
|
| @@ -316,56 +316,92 @@ static int tls1_generate_key_block(SSL *s, unsigned char *km,
|
| return ret;
|
| }
|
|
|
| -int tls1_change_cipher_state(SSL *s, int which)
|
| +/* tls1_aead_ctx_init allocates |*aead_ctx|, if needed and returns 1. It
|
| + * returns 0 on malloc error. */
|
| +static int tls1_aead_ctx_init(SSL_AEAD_CTX **aead_ctx)
|
| {
|
| - static const unsigned char empty[]="";
|
| - 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;
|
| - int client_write;
|
| - EVP_CIPHER_CTX *dd;
|
| - const EVP_CIPHER *c;
|
| -#ifndef OPENSSL_NO_COMP
|
| - const SSL_COMP *comp;
|
| -#endif
|
| - const EVP_MD *m;
|
| - int mac_type;
|
| - int *mac_secret_size;
|
| + if (*aead_ctx != NULL)
|
| + EVP_AEAD_CTX_cleanup(&(*aead_ctx)->ctx);
|
| + else
|
| + {
|
| + *aead_ctx = (SSL_AEAD_CTX*) OPENSSL_malloc(sizeof(SSL_AEAD_CTX));
|
| + if (*aead_ctx == NULL)
|
| + {
|
| + SSLerr(SSL_F_TLS1_AEAD_CTX_INIT, ERR_R_MALLOC_FAILURE);
|
| + return 0;
|
| + }
|
| + }
|
| +
|
| + return 1;
|
| + }
|
| +
|
| +static int tls1_change_cipher_state_aead(SSL *s, char is_read,
|
| + const unsigned char *key, unsigned key_len,
|
| + const unsigned char *iv, unsigned iv_len)
|
| + {
|
| + const EVP_AEAD *aead = s->s3->tmp.new_aead;
|
| + SSL_AEAD_CTX *aead_ctx;
|
| +
|
| + if (is_read)
|
| + {
|
| + if (!tls1_aead_ctx_init(&s->aead_read_ctx))
|
| + return 0;
|
| + aead_ctx = s->aead_read_ctx;
|
| + }
|
| + else
|
| + {
|
| + if (!tls1_aead_ctx_init(&s->aead_write_ctx))
|
| + return 0;
|
| + aead_ctx = s->aead_write_ctx;
|
| + }
|
| +
|
| + if (!EVP_AEAD_CTX_init(&aead_ctx->ctx, aead, key, key_len,
|
| + EVP_AEAD_DEFAULT_TAG_LENGTH, NULL /* engine */))
|
| + return 0;
|
| + if (iv_len > sizeof(aead_ctx->fixed_nonce))
|
| + {
|
| + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE_AEAD, ERR_R_INTERNAL_ERROR);
|
| + return 0;
|
| + }
|
| + memcpy(aead_ctx->fixed_nonce, iv, iv_len);
|
| + aead_ctx->fixed_nonce_len = iv_len;
|
| + aead_ctx->variable_nonce_len = 8; /* always the case, currently. */
|
| + aead_ctx->variable_nonce_included_in_record =
|
| + (s->s3->tmp.new_cipher->algorithm2 & SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD) != 0;
|
| + if (aead_ctx->variable_nonce_len + aead_ctx->fixed_nonce_len != EVP_AEAD_nonce_length(aead))
|
| + {
|
| + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE_AEAD, ERR_R_INTERNAL_ERROR);
|
| + return 0;
|
| + }
|
| + aead_ctx->tag_len = EVP_AEAD_max_overhead(aead);
|
| +
|
| + return 1;
|
| + }
|
| +
|
| +/* tls1_change_cipher_state_cipher performs the work needed to switch cipher
|
| + * states when using EVP_CIPHER. The argument |is_read| is true iff this
|
| + * function is being called due to reading, as opposed to writing, a
|
| + * ChangeCipherSpec message. In order to support export ciphersuites,
|
| + * use_client_keys indicates whether the key material provided is in the
|
| + * "client write" direction. */
|
| +static int tls1_change_cipher_state_cipher(
|
| + SSL *s, char is_read, char use_client_keys,
|
| + const unsigned char *mac_secret, unsigned mac_secret_len,
|
| + const unsigned char *key, unsigned key_len,
|
| + const unsigned char *iv, unsigned iv_len)
|
| + {
|
| + const EVP_CIPHER *cipher = s->s3->tmp.new_sym_enc;
|
| + const char is_export = SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) != 0;
|
| + EVP_CIPHER_CTX *cipher_ctx;
|
| EVP_MD_CTX *mac_ctx;
|
| - EVP_PKEY *mac_key;
|
| - int is_export,n,i,j,k,exp_label_len,cl;
|
| - int reuse_dd = 0;
|
| + char is_aead_cipher;
|
|
|
| - is_export=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
|
| - c=s->s3->tmp.new_sym_enc;
|
| - m=s->s3->tmp.new_hash;
|
| - mac_type = s->s3->tmp.new_mac_pkey_type;
|
| -#ifndef OPENSSL_NO_COMP
|
| - comp=s->s3->tmp.new_compression;
|
| -#endif
|
| + unsigned char export_tmp1[EVP_MAX_KEY_LENGTH];
|
| + unsigned char export_tmp2[EVP_MAX_KEY_LENGTH];
|
| + unsigned char export_iv1[EVP_MAX_IV_LENGTH * 2];
|
| + unsigned char export_iv2[EVP_MAX_IV_LENGTH * 2];
|
|
|
| -#ifdef KSSL_DEBUG
|
| - printf("tls1_change_cipher_state(which= %d) w/\n", which);
|
| - printf("\talg= %ld/%ld, comp= %p\n",
|
| - s->s3->tmp.new_cipher->algorithm_mkey,
|
| - s->s3->tmp.new_cipher->algorithm_auth,
|
| - comp);
|
| - printf("\tevp_cipher == %p ==? &d_cbc_ede_cipher3\n", c);
|
| - printf("\tevp_cipher: nid, blksz= %d, %d, keylen=%d, ivlen=%d\n",
|
| - c->nid,c->block_size,c->key_len,c->iv_len);
|
| - printf("\tkey_block: len= %d, data= ", s->s3->tmp.key_block_length);
|
| - {
|
| - int i;
|
| - for (i=0; i<s->s3->tmp.key_block_length; i++)
|
| - printf("%02x", s->s3->tmp.key_block[i]); printf("\n");
|
| - }
|
| -#endif /* KSSL_DEBUG */
|
| -
|
| - if (which & SSL3_CC_READ)
|
| + if (is_read)
|
| {
|
| if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
|
| s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM;
|
| @@ -373,217 +409,287 @@ int tls1_change_cipher_state(SSL *s, int which)
|
| s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM;
|
|
|
| if (s->enc_read_ctx != NULL)
|
| - reuse_dd = 1;
|
| + EVP_CIPHER_CTX_cleanup(s->enc_read_ctx);
|
| 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;
|
| - mac_ctx=ssl_replace_hash(&s->read_hash,NULL);
|
| -#ifndef OPENSSL_NO_COMP
|
| - if (s->expand != NULL)
|
| - {
|
| - COMP_CTX_free(s->expand);
|
| - s->expand=NULL;
|
| - }
|
| - if (comp != NULL)
|
| - {
|
| - s->expand=COMP_CTX_new(comp->method);
|
| - if (s->expand == NULL)
|
| - {
|
| - SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR);
|
| - goto err2;
|
| - }
|
| - if (s->s3->rrec.comp == NULL)
|
| - s->s3->rrec.comp=(unsigned char *)
|
| - OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH);
|
| - if (s->s3->rrec.comp == NULL)
|
| - goto err;
|
| - }
|
| -#endif
|
| - /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
|
| - if (s->version != DTLS1_VERSION)
|
| - memset(&(s->s3->read_sequence[0]),0,8);
|
| - mac_secret= &(s->s3->read_mac_secret[0]);
|
| - mac_secret_size=&(s->s3->read_mac_secret_size);
|
| +
|
| + cipher_ctx = s->enc_read_ctx;
|
| + mac_ctx = ssl_replace_hash(&s->read_hash, NULL);
|
| +
|
| + memcpy(s->s3->read_mac_secret, mac_secret, mac_secret_len);
|
| + s->s3->read_mac_secret_size = mac_secret_len;
|
| }
|
| else
|
| {
|
| if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
|
| s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
|
| - else
|
| + else
|
| s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM;
|
| +
|
| if (s->enc_write_ctx != NULL)
|
| - reuse_dd = 1;
|
| + EVP_CIPHER_CTX_cleanup(s->enc_write_ctx);
|
| 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;
|
| - mac_ctx = ssl_replace_hash(&s->write_hash,NULL);
|
| -#ifndef OPENSSL_NO_COMP
|
| - if (s->compress != NULL)
|
| - {
|
| - COMP_CTX_free(s->compress);
|
| - s->compress=NULL;
|
| - }
|
| - if (comp != NULL)
|
| - {
|
| - s->compress=COMP_CTX_new(comp->method);
|
| - if (s->compress == NULL)
|
| - {
|
| - SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR);
|
| - goto err2;
|
| - }
|
| - }
|
| -#endif
|
| - /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
|
| - if (s->version != DTLS1_VERSION)
|
| - memset(&(s->s3->write_sequence[0]),0,8);
|
| - mac_secret= &(s->s3->write_mac_secret[0]);
|
| - mac_secret_size = &(s->s3->write_mac_secret_size);
|
| - }
|
| -
|
| - if (reuse_dd)
|
| - EVP_CIPHER_CTX_cleanup(dd);
|
|
|
| - p=s->s3->tmp.key_block;
|
| - i=*mac_secret_size=s->s3->tmp.new_mac_secret_size;
|
| + cipher_ctx = s->enc_write_ctx;
|
| + mac_ctx = ssl_replace_hash(&s->write_hash, NULL);
|
|
|
| - cl=EVP_CIPHER_key_length(c);
|
| - j=is_export ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
|
| - cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
|
| - /* Was j=(exp)?5:EVP_CIPHER_key_length(c); */
|
| - /* If GCM mode only part of IV comes from PRF */
|
| - if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
|
| - k = EVP_GCM_TLS_FIXED_IV_LEN;
|
| - else
|
| - k=EVP_CIPHER_iv_length(c);
|
| - if ( (which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
|
| - (which == SSL3_CHANGE_CIPHER_SERVER_READ))
|
| - {
|
| - ms= &(p[ 0]); n=i+i;
|
| - key= &(p[ n]); n+=j+j;
|
| - iv= &(p[ n]); n+=k+k;
|
| - exp_label=(unsigned char *)TLS_MD_CLIENT_WRITE_KEY_CONST;
|
| - exp_label_len=TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE;
|
| - client_write=1;
|
| - }
|
| - else
|
| - {
|
| - n=i;
|
| - ms= &(p[ n]); n+=i+j;
|
| - key= &(p[ n]); n+=j+k;
|
| - iv= &(p[ n]); n+=k;
|
| - exp_label=(unsigned char *)TLS_MD_SERVER_WRITE_KEY_CONST;
|
| - exp_label_len=TLS_MD_SERVER_WRITE_KEY_CONST_SIZE;
|
| - client_write=0;
|
| + memcpy(s->s3->write_mac_secret, mac_secret, mac_secret_len);
|
| + s->s3->write_mac_secret_size = mac_secret_len;
|
| }
|
|
|
| - if (n > s->s3->tmp.key_block_length)
|
| - {
|
| - SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,ERR_R_INTERNAL_ERROR);
|
| - goto err2;
|
| - }
|
| -
|
| - memcpy(mac_secret,ms,i);
|
| -
|
| - 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'); }
|
| -#endif
|
| if (is_export)
|
| {
|
| /* In here I set both the read and write key/iv to the
|
| * same value since only the correct one will be used :-).
|
| */
|
| + const unsigned char *label;
|
| + unsigned label_len;
|
| +
|
| + if (use_client_keys)
|
| + {
|
| + label = (const unsigned char*) TLS_MD_CLIENT_WRITE_KEY_CONST;
|
| + label_len = TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE;
|
| + }
|
| + else
|
| + {
|
| + label = (const unsigned char*) TLS_MD_SERVER_WRITE_KEY_CONST;
|
| + label_len = TLS_MD_SERVER_WRITE_KEY_CONST_SIZE;
|
| + }
|
| +
|
| if (!tls1_PRF(ssl_get_algorithm2(s),
|
| - 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;
|
| + label, label_len,
|
| + s->s3->client_random, SSL3_RANDOM_SIZE,
|
| + s->s3->server_random, SSL3_RANDOM_SIZE,
|
| + NULL, 0, NULL, 0,
|
| + key /* secret */, key_len /* secret length */,
|
| + export_tmp1 /* output */,
|
| + export_tmp2 /* scratch space */,
|
| + EVP_CIPHER_key_length(s->s3->tmp.new_sym_enc) /* output length */))
|
| + return 0;
|
| + key = export_tmp1;
|
|
|
| - if (k > 0)
|
| + if (iv_len > 0)
|
| {
|
| + static const unsigned char empty[] = "";
|
| +
|
| if (!tls1_PRF(ssl_get_algorithm2(s),
|
| - 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;
|
| + 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 /* secret */ ,0 /* secret length */,
|
| + export_iv1 /* output */,
|
| + export_iv2 /* scratch space */,
|
| + iv_len * 2 /* output length */))
|
| + return 0;
|
| +
|
| + if (use_client_keys)
|
| + iv = export_iv1;
|
| else
|
| - iv= &(iv1[k]);
|
| + iv = &export_iv1[iv_len];
|
| }
|
| }
|
|
|
| - s->session->key_arg_length=0;
|
| -#ifdef KSSL_DEBUG
|
| - {
|
| - int i;
|
| - printf("EVP_CipherInit_ex(dd,c,key=,iv=,which)\n");
|
| - printf("\tkey= "); for (i=0; i<c->key_len; i++) printf("%02x", key[i]);
|
| - printf("\n");
|
| - printf("\t iv= "); for (i=0; i<c->iv_len; i++) printf("%02x", iv[i]);
|
| - printf("\n");
|
| - }
|
| -#endif /* KSSL_DEBUG */
|
| + /* is_aead_cipher indicates whether the EVP_CIPHER implements an AEAD
|
| + * interface. This is different from the newer EVP_AEAD interface. */
|
| + is_aead_cipher = (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) != 0;
|
|
|
| - if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
|
| + if (!is_aead_cipher)
|
| {
|
| - EVP_CipherInit_ex(dd,c,NULL,key,NULL,(which & SSL3_CC_WRITE));
|
| - EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GCM_SET_IV_FIXED, k, iv);
|
| + EVP_PKEY *mac_key =
|
| + EVP_PKEY_new_mac_key(s->s3->tmp.new_mac_pkey_type,
|
| + NULL, mac_secret, mac_secret_len);
|
| + if (!mac_key)
|
| + return 0;
|
| + EVP_DigestSignInit(mac_ctx, NULL, s->s3->tmp.new_hash, NULL, mac_key);
|
| + EVP_PKEY_free(mac_key);
|
| }
|
| - else
|
| - EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE));
|
| +
|
| + if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE)
|
| + {
|
| + EVP_CipherInit_ex(cipher_ctx, cipher, NULL /* engine */, key,
|
| + NULL /* iv */, !is_read);
|
| + EVP_CIPHER_CTX_ctrl(cipher_ctx, EVP_CTRL_GCM_SET_IV_FIXED, iv_len, (void*) iv);
|
| + }
|
| + else
|
| + EVP_CipherInit_ex(cipher_ctx, cipher, NULL /* engine */, key, iv, !is_read);
|
|
|
| /* 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'); }
|
| -printf("\niv=");
|
| -{ int z; for (z=0; z<k; z++) printf("%02X%c",iv[z],((z+1)%16)?' ':'\n'); }
|
| -printf("\n");
|
| -#endif
|
| -
|
| - OPENSSL_cleanse(tmp1,sizeof(tmp1));
|
| - OPENSSL_cleanse(tmp2,sizeof(tmp1));
|
| - OPENSSL_cleanse(iv1,sizeof(iv1));
|
| - OPENSSL_cleanse(iv2,sizeof(iv2));
|
| - return(1);
|
| + if (is_aead_cipher && mac_secret_len > 0)
|
| + EVP_CIPHER_CTX_ctrl(cipher_ctx, EVP_CTRL_AEAD_SET_MAC_KEY,
|
| + mac_secret_len, (void*) mac_secret);
|
| +
|
| + if (is_export)
|
| + {
|
| + OPENSSL_cleanse(export_tmp1, sizeof(export_tmp1));
|
| + OPENSSL_cleanse(export_tmp2, sizeof(export_tmp1));
|
| + OPENSSL_cleanse(export_iv1, sizeof(export_iv1));
|
| + OPENSSL_cleanse(export_iv2, sizeof(export_iv2));
|
| + }
|
| +
|
| + return 1;
|
| +
|
| +err:
|
| + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE_CIPHER, ERR_R_MALLOC_FAILURE);
|
| + return 0;
|
| + }
|
| +
|
| +int tls1_change_cipher_state(SSL *s, int which)
|
| + {
|
| + /* is_read is true if we have just read a ChangeCipherSpec message -
|
| + * i.e. we need to update the read cipherspec. Otherwise we have just
|
| + * written one. */
|
| + const char is_read = (which & SSL3_CC_READ) != 0;
|
| + /* use_client_keys is true if we wish to use the keys for the "client
|
| + * write" direction. This is the case if we're a client sending a
|
| + * ChangeCipherSpec, or a server reading a client's ChangeCipherSpec. */
|
| + const char use_client_keys = which == SSL3_CHANGE_CIPHER_CLIENT_WRITE ||
|
| + which == SSL3_CHANGE_CIPHER_SERVER_READ;
|
| + const unsigned char *client_write_mac_secret, *server_write_mac_secret, *mac_secret;
|
| + const unsigned char *client_write_key, *server_write_key, *key;
|
| + const unsigned char *client_write_iv, *server_write_iv, *iv;
|
| + const EVP_CIPHER *cipher = s->s3->tmp.new_sym_enc;
|
| + const EVP_AEAD *aead = s->s3->tmp.new_aead;
|
| + unsigned key_len, iv_len, mac_secret_len;
|
| + const unsigned char *key_data;
|
| + const char is_export = SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) != 0;
|
| +
|
| + /* Update compression contexts. */
|
| +#ifndef OPENSSL_NO_COMP
|
| + const SSL_COMP *comp = s->s3->tmp.new_compression;
|
| +
|
| + if (is_read)
|
| + {
|
| + if (s->expand != NULL)
|
| + {
|
| + COMP_CTX_free(s->expand);
|
| + s->expand = NULL;
|
| + }
|
| + if (comp != NULL)
|
| + {
|
| + s->expand=COMP_CTX_new(comp->method);
|
| + if (s->expand == NULL)
|
| + {
|
| + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR);
|
| + return 0;
|
| + }
|
| + if (s->s3->rrec.comp == NULL)
|
| + s->s3->rrec.comp =
|
| + (unsigned char *)OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH);
|
| + if (s->s3->rrec.comp == NULL)
|
| + goto err;
|
| + }
|
| + }
|
| + else
|
| + {
|
| + if (s->compress != NULL)
|
| + {
|
| + COMP_CTX_free(s->compress);
|
| + s->compress = NULL;
|
| + }
|
| + if (comp != NULL)
|
| + {
|
| + s->compress = COMP_CTX_new(comp->method);
|
| + if (s->compress == NULL)
|
| + {
|
| + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR);
|
| + return 0;
|
| + }
|
| + }
|
| + }
|
| +#endif /* OPENSSL_NO_COMP */
|
| +
|
| + /* Reset sequence number to zero. */
|
| + memset(is_read ? s->s3->read_sequence : s->s3->write_sequence, 0, 8);
|
| +
|
| + /* key_arg is used for SSLv2. We don't need it for TLS. */
|
| + s->session->key_arg_length = 0;
|
| +
|
| + mac_secret_len = s->s3->tmp.new_mac_secret_size;
|
| +
|
| + if (aead != NULL)
|
| + {
|
| + key_len = EVP_AEAD_key_length(aead);
|
| + iv_len = SSL_CIPHER_AEAD_FIXED_NONCE_LEN(s->s3->tmp.new_cipher);
|
| + }
|
| + else
|
| + {
|
| + key_len = EVP_CIPHER_key_length(cipher);
|
| + if (is_export && key_len > SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher))
|
| + key_len = SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher);
|
| +
|
| + if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE)
|
| + iv_len = EVP_GCM_TLS_FIXED_IV_LEN;
|
| + else
|
| + iv_len = EVP_CIPHER_iv_length(cipher);
|
| + }
|
| +
|
| + key_data = s->s3->tmp.key_block;
|
| + client_write_mac_secret = key_data; key_data += mac_secret_len;
|
| + server_write_mac_secret = key_data; key_data += mac_secret_len;
|
| + client_write_key = key_data; key_data += key_len;
|
| + server_write_key = key_data; key_data += key_len;
|
| + client_write_iv = key_data; key_data += iv_len;
|
| + server_write_iv = key_data; key_data += iv_len;
|
| +
|
| + if (use_client_keys)
|
| + {
|
| + mac_secret = client_write_mac_secret;
|
| + key = client_write_key;
|
| + iv = client_write_iv;
|
| + }
|
| + else
|
| + {
|
| + mac_secret = server_write_mac_secret;
|
| + key = server_write_key;
|
| + iv = server_write_iv;
|
| + }
|
| +
|
| + if (key_data - s->s3->tmp.key_block != s->s3->tmp.key_block_length)
|
| + {
|
| + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,ERR_R_INTERNAL_ERROR);
|
| + return 0;
|
| + }
|
| +
|
| + if (aead != NULL)
|
| + {
|
| + if (!tls1_change_cipher_state_aead(s, is_read,
|
| + key, key_len, iv, iv_len))
|
| + return 0;
|
| + }
|
| + else
|
| + {
|
| + if (!tls1_change_cipher_state_cipher(s, is_read, use_client_keys,
|
| + mac_secret, mac_secret_len,
|
| + key, key_len,
|
| + iv, iv_len))
|
| + return 0;
|
| + }
|
| +
|
| + return 1;
|
| err:
|
| - SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE,ERR_R_MALLOC_FAILURE);
|
| -err2:
|
| - return(0);
|
| + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE);
|
| + return 0;
|
| }
|
|
|
| int tls1_setup_key_block(SSL *s)
|
| {
|
| unsigned char *p1,*p2=NULL;
|
| - const EVP_CIPHER *c;
|
| - const EVP_MD *hash;
|
| + const EVP_CIPHER *c = NULL;
|
| + const EVP_MD *hash = NULL;
|
| + const EVP_AEAD *aead = NULL;
|
| int num;
|
| SSL_COMP *comp;
|
| int mac_type= NID_undef,mac_secret_size=0;
|
| int ret=0;
|
| + unsigned key_len, iv_len;
|
|
|
| #ifdef KSSL_DEBUG
|
| printf ("tls1_setup_key_block()\n");
|
| @@ -592,17 +698,36 @@ int tls1_setup_key_block(SSL *s)
|
| if (s->s3->tmp.key_block_length != 0)
|
| return(1);
|
|
|
| - if (!ssl_cipher_get_evp(s->session,&c,&hash,&mac_type,&mac_secret_size,&comp))
|
| + if (!ssl_cipher_get_comp(s->session, &comp))
|
| + goto cipher_unavailable_err;
|
| +
|
| + if (s->session->cipher &&
|
| + (s->session->cipher->algorithm2 & SSL_CIPHER_ALGORITHM2_AEAD))
|
| + {
|
| + if (!ssl_cipher_get_evp_aead(s->session, &aead))
|
| + goto cipher_unavailable_err;
|
| + key_len = EVP_AEAD_key_length(aead);
|
| + iv_len = SSL_CIPHER_AEAD_FIXED_NONCE_LEN(s->session->cipher);
|
| + }
|
| + else
|
| {
|
| - SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
|
| - return(0);
|
| + if (!ssl_cipher_get_evp(s->session,&c,&hash,&mac_type,&mac_secret_size))
|
| + goto cipher_unavailable_err;
|
| + key_len = EVP_CIPHER_key_length(c);
|
| +
|
| + if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
|
| + iv_len = EVP_GCM_TLS_FIXED_IV_LEN;
|
| + else
|
| + iv_len = EVP_CIPHER_iv_length(c);
|
| }
|
|
|
| + s->s3->tmp.new_aead=aead;
|
| s->s3->tmp.new_sym_enc=c;
|
| s->s3->tmp.new_hash=hash;
|
| s->s3->tmp.new_mac_pkey_type = mac_type;
|
| s->s3->tmp.new_mac_secret_size = mac_secret_size;
|
| - num=EVP_CIPHER_key_length(c)+mac_secret_size+EVP_CIPHER_iv_length(c);
|
| +
|
| + num=key_len+mac_secret_size+iv_len;
|
| num*=2;
|
|
|
| ssl3_cleanup_key_block(s);
|
| @@ -665,6 +790,10 @@ err:
|
| OPENSSL_free(p2);
|
| }
|
| return(ret);
|
| +
|
| +cipher_unavailable_err:
|
| + SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
|
| + return 0;
|
| }
|
|
|
| /* tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
|
| @@ -683,6 +812,134 @@ int tls1_enc(SSL *s, int send)
|
| unsigned long l;
|
| int bs,i,j,k,pad=0,ret,mac_size=0;
|
| const EVP_CIPHER *enc;
|
| + const SSL_AEAD_CTX *aead;
|
| +
|
| + if (send)
|
| + rec = &s->s3->wrec;
|
| + else
|
| + rec = &s->s3->rrec;
|
| +
|
| + if (send)
|
| + aead = s->aead_write_ctx;
|
| + else
|
| + aead = s->aead_read_ctx;
|
| +
|
| + if (aead)
|
| + {
|
| + unsigned char ad[13], *seq, *in, *out, nonce[16];
|
| + unsigned nonce_used;
|
| + ssize_t n;
|
| +
|
| + 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(ad, dtlsseq, 8);
|
| + }
|
| + else
|
| + {
|
| + memcpy(ad, seq, 8);
|
| + for (i=7; i>=0; i--) /* increment */
|
| + {
|
| + ++seq[i];
|
| + if (seq[i] != 0)
|
| + break;
|
| + }
|
| + }
|
| +
|
| + ad[8] = rec->type;
|
| + ad[9] = (unsigned char)(s->version>>8);
|
| + ad[10] = (unsigned char)(s->version);
|
| +
|
| + if (aead->fixed_nonce_len + aead->variable_nonce_len > sizeof(nonce) ||
|
| + aead->variable_nonce_len > 8)
|
| + return -1; /* internal error - should never happen. */
|
| +
|
| + memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
|
| + nonce_used = aead->fixed_nonce_len;
|
| +
|
| + if (send)
|
| + {
|
| + size_t len = rec->length;
|
| + size_t eivlen = 0;
|
| + in = rec->input;
|
| + out = rec->data;
|
| +
|
| + /* When sending we use the sequence number as the
|
| + * variable part of the nonce. */
|
| + if (aead->variable_nonce_len > 8)
|
| + return -1;
|
| + memcpy(nonce + nonce_used, ad, aead->variable_nonce_len);
|
| + nonce_used += aead->variable_nonce_len;
|
| +
|
| + /* in do_ssl3_write, rec->input is moved forward by
|
| + * variable_nonce_len in order to leave space for the
|
| + * variable nonce. Thus we can copy the sequence number
|
| + * bytes into place without overwriting any of the
|
| + * plaintext. */
|
| + if (aead->variable_nonce_included_in_record)
|
| + {
|
| + memcpy(out, ad, aead->variable_nonce_len);
|
| + len -= aead->variable_nonce_len;
|
| + eivlen = aead->variable_nonce_len;
|
| + }
|
| +
|
| + ad[11] = len >> 8;
|
| + ad[12] = len & 0xff;
|
| +
|
| + n = EVP_AEAD_CTX_seal(&aead->ctx,
|
| + out + eivlen, len + aead->tag_len,
|
| + nonce, nonce_used,
|
| + in + eivlen, len,
|
| + ad, sizeof(ad));
|
| + if (n >= 0 && aead->variable_nonce_included_in_record)
|
| + n += aead->variable_nonce_len;
|
| + }
|
| + else
|
| + {
|
| + /* receive */
|
| + size_t len = rec->length;
|
| +
|
| + if (rec->data != rec->input)
|
| + return -1; /* internal error - should never happen. */
|
| + out = in = rec->input;
|
| +
|
| + if (len < aead->variable_nonce_len)
|
| + return 0;
|
| + memcpy(nonce + nonce_used,
|
| + aead->variable_nonce_included_in_record ? in : ad,
|
| + aead->variable_nonce_len);
|
| + nonce_used += aead->variable_nonce_len;
|
| +
|
| + if (aead->variable_nonce_included_in_record)
|
| + {
|
| + in += aead->variable_nonce_len;
|
| + len -= aead->variable_nonce_len;
|
| + out += aead->variable_nonce_len;
|
| + }
|
| +
|
| + if (len < aead->tag_len)
|
| + return 0;
|
| + len -= aead->tag_len;
|
| +
|
| + ad[11] = len >> 8;
|
| + ad[12] = len & 0xff;
|
| +
|
| + n = EVP_AEAD_CTX_open(&aead->ctx, out, len, nonce, nonce_used,
|
| + in, len + aead->tag_len, ad, sizeof(ad));
|
| +
|
| + rec->data = rec->input = out;
|
| + }
|
| +
|
| + if (n == -1)
|
| + return -1;
|
| + rec->length = n;
|
| + return 1;
|
| + }
|
|
|
| if (send)
|
| {
|
|
|