diff options
author | Matt Caswell <matt@openssl.org> | 2016-11-08 23:20:31 +0000 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2016-11-23 15:31:21 +0000 |
commit | 0d9824c1712b6cacd9b0ecfba26fb66ae4badfb4 (patch) | |
tree | 1a85d63a7527e480783cb6ce46cf69a5b63c6099 /ssl/tls13_enc.c | |
parent | 9362c93ebc5b14bf18e82cdebf380ccc52f3d92f (diff) |
Implement tls13_change_cipher_state()
Reviewed-by: Rich Salz <rsalz@openssl.org>
Diffstat (limited to 'ssl/tls13_enc.c')
-rw-r--r-- | ssl/tls13_enc.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 39a61f4461..04dba3b23e 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -214,4 +214,160 @@ int tls13_generate_master_secret(SSL *s, unsigned char *out, return tls13_generate_secret(s, prev, NULL, 0, out); } +const unsigned char client_handshake_traffic[] = + "client handshake traffic secret"; +const unsigned char client_application_traffic[] = + "client application traffic secret"; +const unsigned char server_handshake_traffic[] = + "server handshake traffic secret"; +const unsigned char server_application_traffic[] = + "server application traffic secret"; +int tls13_change_cipher_state(SSL *s, int which) +{ + unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char secret[EVP_MAX_MD_SIZE]; + unsigned char *insecret; + EVP_CIPHER_CTX *ciph_ctx; + const EVP_CIPHER *ciph = s->s3->tmp.new_sym_enc;; + size_t ivlen, keylen; + const unsigned char *label; + size_t labellen; + + if (which & SSL3_CC_READ) { + if (s->enc_read_ctx != NULL) { + EVP_CIPHER_CTX_reset(s->enc_read_ctx); + } else { + s->enc_read_ctx = EVP_CIPHER_CTX_new(); + if (s->enc_read_ctx == NULL) { + SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE); + goto err; + } + } + ciph_ctx = s->enc_read_ctx; + + RECORD_LAYER_reset_read_sequence(&s->rlayer); + } else { + if (s->enc_write_ctx != NULL) { + EVP_CIPHER_CTX_reset(s->enc_write_ctx); + } else { + s->enc_write_ctx = EVP_CIPHER_CTX_new(); + if (s->enc_write_ctx == NULL) { + SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE); + goto err; + } + } + ciph_ctx = s->enc_write_ctx; + + RECORD_LAYER_reset_write_sequence(&s->rlayer); + } + + if (((which & SSL3_CC_CLIENT) && (which & SSL3_CC_WRITE)) + || ((which & SSL3_CC_SERVER) && (which & SSL3_CC_READ))) { + if (which & SSL3_CC_HANDSHAKE) { + insecret = s->handshake_secret; + label = client_handshake_traffic; + labellen = sizeof(client_handshake_traffic) - 1; + } else { + insecret = s->session->master_key; + label = client_application_traffic; + labellen = sizeof(client_application_traffic) - 1; + } + } else { + if (which & SSL3_CC_HANDSHAKE) { + insecret = s->handshake_secret; + label = server_handshake_traffic; + labellen = sizeof(server_handshake_traffic) - 1; + } else { + insecret = s->session->master_key; + label = server_application_traffic; + labellen = sizeof(server_application_traffic) - 1; + } + } + + if (!tls13_derive_secret(s, insecret, label, labellen, secret)) { + SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* TODO(size_t): convert me */ + keylen = EVP_CIPHER_key_length(ciph); + + if (EVP_CIPHER_mode(ciph) == EVP_CIPH_GCM_MODE) + ivlen = EVP_GCM_TLS_FIXED_IV_LEN; + else if (EVP_CIPHER_mode(ciph) == EVP_CIPH_CCM_MODE) + ivlen = EVP_CCM_TLS_FIXED_IV_LEN; + else + ivlen = EVP_CIPHER_iv_length(ciph); + + if (!tls13_derive_key(s, secret, key, keylen) + || !tls13_derive_iv(s, secret, iv, ivlen)) { + SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (EVP_CIPHER_mode(ciph) == EVP_CIPH_GCM_MODE) { + if (!EVP_CipherInit_ex(ciph_ctx, ciph, NULL, key, NULL, + (which & SSL3_CC_WRITE)) + || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_GCM_SET_IV_FIXED, + (int)ivlen, iv)) { + SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_EVP_LIB); + goto err; + } + } else if (EVP_CIPHER_mode(ciph) == EVP_CIPH_CCM_MODE) { + int taglen; + if (s->s3->tmp.new_cipher->algorithm_enc + & (SSL_AES128CCM8 | SSL_AES256CCM8)) + taglen = 8; + else + taglen = 16; + if (!EVP_CipherInit_ex(ciph_ctx, ciph, NULL, NULL, NULL, + (which & SSL3_CC_WRITE)) + || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, + NULL) + || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG, taglen, + NULL) + || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_CCM_SET_IV_FIXED, + (int)ivlen, iv) + || !EVP_CipherInit_ex(ciph_ctx, NULL, NULL, key, NULL, -1)) { + SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_EVP_LIB); + goto err; + } + } else { + if (!EVP_CipherInit_ex(ciph_ctx, ciph, NULL, key, iv, + (which & SSL3_CC_WRITE))) { + SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_EVP_LIB); + goto err; + } + } + +#ifdef OPENSSL_SSL_TRACE_CRYPTO + if (s->msg_callback) { + int wh = which & SSL3_CC_WRITE ? TLS1_RT_CRYPTO_WRITE : 0; + + if (ciph->key_len) + s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_KEY, + key, ciph->key_len, s, s->msg_callback_arg); + if (ivlen) { + if (EVP_CIPHER_mode(ciph) == EVP_CIPH_GCM_MODE) + wh |= TLS1_RT_CRYPTO_FIXED_IV; + else + wh |= TLS1_RT_CRYPTO_IV; + s->msg_callback(2, s->version, wh, iv, ivlen, s, + s->msg_callback_arg); + } + } +#endif + + OPENSSL_cleanse(secret, sizeof(secret)); + OPENSSL_cleanse(key, sizeof(key)); + OPENSSL_cleanse(iv, sizeof(iv)); + return 1; + + err: + OPENSSL_cleanse(secret, sizeof(secret)); + OPENSSL_cleanse(key, sizeof(key)); + OPENSSL_cleanse(iv, sizeof(iv)); + return 0; +} |