From 0d9824c1712b6cacd9b0ecfba26fb66ae4badfb4 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 8 Nov 2016 23:20:31 +0000 Subject: [PATCH] Implement tls13_change_cipher_state() Reviewed-by: Rich Salz --- include/openssl/ssl.h | 1 + include/openssl/ssl3.h | 2 + ssl/ssl_err.c | 1 + ssl/ssl_lib.c | 3 +- ssl/ssl_locl.h | 1 + ssl/tls13_enc.c | 156 ++++++++++++++++++++++++++++++++++++++++ test/tls13secretstest.c | 8 +++ 7 files changed, 170 insertions(+), 2 deletions(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 1f9aaf855e..5064e65cf5 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2242,6 +2242,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_WRITE_EX 433 # define SSL_F_STATE_MACHINE 353 # define SSL_F_TLS12_CHECK_PEER_SIGALG 333 +# define SSL_F_TLS13_CHANGE_CIPHER_STATE 435 # define SSL_F_TLS1_CHANGE_CIPHER_STATE 209 # define SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS 341 # define SSL_F_TLS1_ENC 401 diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index aca1922306..321a8dde31 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -296,6 +296,8 @@ extern "C" { # define SSL3_CC_WRITE 0x02 # define SSL3_CC_CLIENT 0x10 # define SSL3_CC_SERVER 0x20 +# define SSL3_CC_HANDSHAKE 0x40 +# define SSL3_CC_APPLICATION 0x80 # define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE) # define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ) # define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ) diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 235a53ccc8..b7ba8a5202 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -238,6 +238,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_SSL_WRITE_EX), "SSL_write_ex"}, {ERR_FUNC(SSL_F_STATE_MACHINE), "state_machine"}, {ERR_FUNC(SSL_F_TLS12_CHECK_PEER_SIGALG), "tls12_check_peer_sigalg"}, + {ERR_FUNC(SSL_F_TLS13_CHANGE_CIPHER_STATE), "tls13_change_cipher_state"}, {ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "tls1_change_cipher_state"}, {ERR_FUNC(SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS), "tls1_check_duplicate_extensions"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 5f2c941b79..4d41b17fa0 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -3828,8 +3828,7 @@ EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md) void ssl_clear_hash_ctx(EVP_MD_CTX **hash) { - if (*hash) - EVP_MD_CTX_free(*hash); + EVP_MD_CTX_free(*hash); *hash = NULL; } diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 41382bafc0..527b2b40e2 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -2003,6 +2003,7 @@ __owur size_t tls1_final_finish_mac(SSL *s, const char *str, size_t slen, __owur int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, size_t len, size_t *secret_size); +__owur int tls13_change_cipher_state(SSL *s, int which); __owur int tls13_derive_secret(SSL *s, const unsigned char *insecret, const unsigned char *label, size_t labellen, unsigned char *secret); 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; +} diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c index 6b6c9bc946..ceafd3d824 100644 --- a/test/tls13secretstest.c +++ b/test/tls13secretstest.c @@ -162,6 +162,14 @@ const EVP_MD *ssl_handshake_md(SSL *s) return EVP_sha256(); } +void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl) +{ +} + +void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl) +{ +} + /* End of mocked out code */ static int test_secret(SSL *s, unsigned char *prk, -- 2.34.1