From 44c04a2e063715abdf2db095827261456fada74a Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 8 Feb 2017 09:15:22 +0000 Subject: [PATCH] Provide a function to send a KeyUpdate message This implements the server side KeyUpdate sending capability as well. Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/2609) --- include/openssl/ssl.h | 18 +++++++++++++++++- include/openssl/ssl3.h | 1 + ssl/ssl_err.c | 5 +++++ ssl/ssl_lib.c | 41 +++++++++++++++++++++++++++++++--------- ssl/ssl_locl.h | 2 ++ ssl/statem/statem_lib.c | 13 +++++++++++++ ssl/statem/statem_locl.h | 1 + ssl/statem/statem_srvr.c | 19 ++++++++++++++----- util/libssl.num | 1 + 9 files changed, 86 insertions(+), 15 deletions(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 89b4514cfb..88d7736d32 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -825,6 +825,14 @@ DEFINE_STACK_OF(SSL_COMP) # define SSL_CTX_set_app_data(ctx,arg) (SSL_CTX_set_ex_data(ctx,0,(char *)arg)) DEPRECATEDIN_1_1_0(void SSL_set_debug(SSL *s, int debug)) +/* TLSv1.3 KeyUpdate message types */ +typedef enum { + /* -1 used so that this is an invalid value for the on-the-wire protocol */ + SSL_KEY_UPDATE_NONE = -1, + /* Values as defined for the on-the-wire protocol */ + SSL_KEY_UPDATE_NOT_REQUESTED = 0, + SSL_KEY_UPDATE_REQUESTED = 1 +} SSL_KEY_UPDATE; /* * The valid handshake states (one for each type message sent and one for each @@ -882,7 +890,9 @@ typedef enum { TLS_ST_SW_CERT_VRFY, TLS_ST_CR_HELLO_REQ, TLS_ST_SW_HELLO_RETRY_REQUEST, - TLS_ST_CR_HELLO_RETRY_REQUEST + TLS_ST_CR_HELLO_RETRY_REQUEST, + TLS_ST_SW_KEY_UPDATE, + TLS_ST_CW_KEY_UPDATE } OSSL_HANDSHAKE_STATE; /* @@ -1650,6 +1660,7 @@ __owur STACK_OF(SSL_CIPHER) *SSL_get_client_ciphers(const SSL *s); __owur STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s); __owur int SSL_do_handshake(SSL *s); +int SSL_key_update(SSL *s, SSL_KEY_UPDATE updatetype); int SSL_renegotiate(SSL *s); int SSL_renegotiate_abbreviated(SSL *s); __owur int SSL_renegotiate_pending(SSL *s); @@ -2195,6 +2206,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_GET_SERVER_CERT_INDEX 322 # define SSL_F_SSL_GET_SIGN_PKEY 183 # define SSL_F_SSL_INIT_WBIO_BUFFER 184 +# define SSL_F_SSL_KEY_UPDATE 515 # define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185 # define SSL_F_SSL_LOG_MASTER_SECRET 498 # define SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE 499 @@ -2210,6 +2222,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_PEEK_EX 432 # define SSL_F_SSL_READ 223 # define SSL_F_SSL_READ_EX 434 +# define SSL_F_SSL_RENEGOTIATE 516 # define SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT 320 # define SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT 321 # define SSL_F_SSL_SESSION_DUP 348 @@ -2305,6 +2318,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_FINISHED 359 # define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST 373 # define SSL_F_TLS_CONSTRUCT_HELLO_RETRY_REQUEST 510 +# define SSL_F_TLS_CONSTRUCT_KEY_UPDATE 517 # define SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET 428 # define SSL_F_TLS_CONSTRUCT_NEXT_PROTO 426 # define SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE 490 @@ -2472,6 +2486,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_INVALID_COMPRESSION_ALGORITHM 341 # define SSL_R_INVALID_CONFIGURATION_NAME 113 # define SSL_R_INVALID_CT_VALIDATION_TYPE 212 +# define SSL_R_INVALID_KEY_UPDATE_TYPE 120 # define SSL_R_INVALID_NULL_CMD_NAME 385 # define SSL_R_INVALID_SEQUENCE_NUMBER 402 # define SSL_R_INVALID_SERVERINFO_DATA 388 @@ -2578,6 +2593,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303 # define SSL_R_SSL_SESSION_ID_TOO_LONG 408 # define SSL_R_SSL_SESSION_VERSION_MISMATCH 210 +# define SSL_R_STILL_IN_INIT 121 # define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 # define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 # define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index f2f62b4f1a..5948dfbf77 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -287,6 +287,7 @@ extern "C" { # define SSL3_MT_CLIENT_KEY_EXCHANGE 16 # define SSL3_MT_FINISHED 20 # define SSL3_MT_CERTIFICATE_STATUS 22 +# define SSL3_MT_KEY_UPDATE 24 # ifndef OPENSSL_NO_NEXTPROTONEG # define SSL3_MT_NEXT_PROTO 67 # endif diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index cea604072a..2d9efbb06a 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -179,6 +179,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_SSL_GET_SERVER_CERT_INDEX), "ssl_get_server_cert_index"}, {ERR_FUNC(SSL_F_SSL_GET_SIGN_PKEY), "ssl_get_sign_pkey"}, {ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "ssl_init_wbio_buffer"}, + {ERR_FUNC(SSL_F_SSL_KEY_UPDATE), "SSL_key_update"}, {ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE), "SSL_load_client_CA_file"}, {ERR_FUNC(SSL_F_SSL_LOG_MASTER_SECRET), "ssl_log_master_secret"}, {ERR_FUNC(SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE), @@ -201,6 +202,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_SSL_PEEK_EX), "SSL_peek_ex"}, {ERR_FUNC(SSL_F_SSL_READ), "SSL_read"}, {ERR_FUNC(SSL_F_SSL_READ_EX), "SSL_read_ex"}, + {ERR_FUNC(SSL_F_SSL_RENEGOTIATE), "SSL_renegotiate"}, {ERR_FUNC(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT), "ssl_scan_clienthello_tlsext"}, {ERR_FUNC(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT), @@ -333,6 +335,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { "tls_construct_hello_request"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_HELLO_RETRY_REQUEST), "tls_construct_hello_retry_request"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_KEY_UPDATE), "tls_construct_key_update"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET), "tls_construct_new_session_ticket"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEXT_PROTO), "tls_construct_next_proto"}, @@ -568,6 +571,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = { "invalid configuration name"}, {ERR_REASON(SSL_R_INVALID_CT_VALIDATION_TYPE), "invalid ct validation type"}, + {ERR_REASON(SSL_R_INVALID_KEY_UPDATE_TYPE), "invalid key update type"}, {ERR_REASON(SSL_R_INVALID_NULL_CMD_NAME), "invalid null cmd name"}, {ERR_REASON(SSL_R_INVALID_SEQUENCE_NUMBER), "invalid sequence number"}, {ERR_REASON(SSL_R_INVALID_SERVERINFO_DATA), "invalid serverinfo data"}, @@ -715,6 +719,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = { {ERR_REASON(SSL_R_SSL_SESSION_ID_TOO_LONG), "ssl session id too long"}, {ERR_REASON(SSL_R_SSL_SESSION_VERSION_MISMATCH), "ssl session version mismatch"}, + {ERR_REASON(SSL_R_STILL_IN_INIT), "still in init"}, {ERR_REASON(SSL_R_TLSV1_ALERT_ACCESS_DENIED), "tlsv1 alert access denied"}, {ERR_REASON(SSL_R_TLSV1_ALERT_DECODE_ERROR), "tlsv1 alert decode error"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 1642215ce4..0ca04bd96e 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -471,6 +471,8 @@ int SSL_clear(SSL *s) clear_ciphers(s); s->first_packet = 0; + s->key_update = SSL_KEY_UPDATE_NONE; + /* Reset DANE verification result state */ s->dane.mdpth = -1; s->dane.pdpth = -1; @@ -639,6 +641,8 @@ SSL *SSL_new(SSL_CTX *ctx) s->method = ctx->method; + s->key_update = SSL_KEY_UPDATE_NONE; + if (!s->method->ssl_new(s)) goto err; @@ -1714,14 +1718,37 @@ int SSL_shutdown(SSL *s) } } +int SSL_key_update(SSL *s, SSL_KEY_UPDATE updatetype) +{ + if (!SSL_IS_TLS13(s)) { + SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_WRONG_SSL_VERSION); + return 0; + } + + if (updatetype != SSL_KEY_UPDATE_NOT_REQUESTED + && updatetype != SSL_KEY_UPDATE_REQUESTED) { + SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_INVALID_KEY_UPDATE_TYPE); + return 0; + } + + if (!SSL_is_init_finished(s)) { + SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_STILL_IN_INIT); + return 0; + } + + ossl_statem_set_in_init(s, 1); + + s->key_update = updatetype; + + return 1; +} + int SSL_renegotiate(SSL *s) { - /* - * TODO(TLS1.3): Return an error for now. Perhaps we should do a KeyUpdate - * instead when we support that? - */ - if (SSL_IS_TLS13(s)) + if (SSL_IS_TLS13(s)) { + SSLerr(SSL_F_SSL_RENEGOTIATE, SSL_R_WRONG_SSL_VERSION); return 0; + } if (s->renegotiate == 0) s->renegotiate = 1; @@ -1733,10 +1760,6 @@ int SSL_renegotiate(SSL *s) int SSL_renegotiate_abbreviated(SSL *s) { - /* - * TODO(TLS1.3): Return an error for now. Perhaps we should do a KeyUpdate - * instead when we support that? - */ if (SSL_IS_TLS13(s)) return 0; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 6f838778a6..8a3f573bf9 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1172,6 +1172,8 @@ struct ssl_st { * (i.e. not just sending a HelloRequest) */ int renegotiate; + /* If sending a KeyUpdate is pending */ + SSL_KEY_UPDATE key_update; # ifndef OPENSSL_NO_SRP /* ctx for SRP authentication */ SRP_CTX srp_ctx; diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index ed07266c01..fa7387a5ad 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -495,6 +495,19 @@ int tls_construct_finished(SSL *s, WPACKET *pkt) return 0; } +int tls_construct_key_update(SSL *s, WPACKET *pkt) +{ + if (!WPACKET_put_bytes_u8(pkt, s->key_update)) { + SSLerr(SSL_F_TLS_CONSTRUCT_KEY_UPDATE, ERR_R_INTERNAL_ERROR); + goto err; + } + + return 1; + err: + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + return 0; +} + #ifndef OPENSSL_NO_NEXTPROTONEG /* * ssl3_take_mac calculates the Finished MAC for the handshakes messages seen diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index fa13a26126..96ddac2cb6 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -111,6 +111,7 @@ __owur int tls_construct_change_cipher_spec(SSL *s, WPACKET *pkt); __owur int dtls_construct_change_cipher_spec(SSL *s, WPACKET *pkt); __owur int tls_construct_finished(SSL *s, WPACKET *pkt); +__owur int tls_construct_key_update(SSL *s, WPACKET *pkt); __owur WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs); __owur WORK_STATE dtls_wait_for_dry(SSL *s); diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 2330bde360..4cdd6c9492 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -393,11 +393,6 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s) { OSSL_STATEM *st = &s->statem; - /* - * TODO(TLS1.3): This is still based on the TLSv1.2 state machine. Over time - * we will update this to look more like real TLSv1.3 - */ - /* * No case for TLS_ST_BEFORE, because at that stage we have not negotiated * TLSv1.3 yet, so that is handled by ossl_statem_server_write_transition() @@ -408,6 +403,13 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s) /* Shouldn't happen */ return WRITE_TRAN_ERROR; + case TLS_ST_OK: + if (s->key_update != SSL_KEY_UPDATE_NONE) { + st->hand_state = TLS_ST_SW_KEY_UPDATE; + return WRITE_TRAN_CONTINUE; + } + return WRITE_TRAN_ERROR; + case TLS_ST_SR_CLNT_HELLO: if (s->hello_retry_request) st->hand_state = TLS_ST_SW_HELLO_RETRY_REQUEST; @@ -459,6 +461,7 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s) st->hand_state = TLS_ST_SW_SESSION_TICKET; return WRITE_TRAN_CONTINUE; + case TLS_ST_SW_KEY_UPDATE: case TLS_ST_SW_SESSION_TICKET: st->hand_state = TLS_ST_OK; ossl_statem_set_in_init(s, 0); @@ -822,6 +825,7 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) } break; + case TLS_ST_SW_KEY_UPDATE: case TLS_ST_SW_SESSION_TICKET: if (SSL_IS_TLS13(s) && statem_flush(s) != 1) return WORK_MORE_A; @@ -923,6 +927,11 @@ int ossl_statem_server_construct_message(SSL *s, WPACKET *pkt, *confunc = tls_construct_hello_retry_request; *mt = SSL3_MT_HELLO_RETRY_REQUEST; break; + + case TLS_ST_SW_KEY_UPDATE: + *confunc = tls_construct_key_update; + *mt = SSL3_MT_KEY_UPDATE; + break; } return 1; diff --git a/util/libssl.num b/util/libssl.num index 199c17a214..d137c93e3d 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -413,3 +413,4 @@ SSL_COMP_get0_name 413 1_1_0d EXIST::FUNCTION: SSL_CTX_set_keylog_callback 414 1_1_1 EXIST::FUNCTION: SSL_CTX_get_keylog_callback 415 1_1_1 EXIST::FUNCTION: SSL_get_peer_signature_type_nid 416 1_1_1 EXIST::FUNCTION: +SSL_key_update 417 1_1_1 EXIST::FUNCTION: -- 2.39.5