diff options
author | Daiki Ueno <ueno@gnu.org> | 2021-02-10 19:17:03 +0000 |
---|---|---|
committer | Daiki Ueno <ueno@gnu.org> | 2021-02-10 19:17:03 +0000 |
commit | 6a1028ca5c0dd106e34155d7e195f8895cff0a5a (patch) | |
tree | b20b452511338d6f4a7b46cd8a76ce495ac4b61e | |
parent | d8cb3f2e88b45edf0ba5b9e2a17d3cd7a31ff723 (diff) | |
parent | 37e54a05221e076ba905d2d53fc7d885dc9e9ebc (diff) | |
download | gnutls-6a1028ca5c0dd106e34155d7e195f8895cff0a5a.tar.gz |
Merge branch 'wip/dueno/hrr-resumption' into 'master'
handshake: TLS 1.3: don't generate session ID in resumption mode
See merge request gnutls/gnutls!1381
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | .gitlab-ci.yml | 1 | ||||
-rw-r--r-- | lib/constate.c | 4 | ||||
-rw-r--r-- | lib/db.c | 2 | ||||
-rw-r--r-- | lib/dtls.h | 4 | ||||
-rw-r--r-- | lib/ext/pre_shared_key.c | 4 | ||||
-rw-r--r-- | lib/ext/session_ticket.c | 4 | ||||
-rw-r--r-- | lib/gnutls_int.h | 9 | ||||
-rw-r--r-- | lib/handshake-tls13.c | 6 | ||||
-rw-r--r-- | lib/handshake.c | 114 | ||||
-rw-r--r-- | lib/kx.c | 2 | ||||
-rw-r--r-- | lib/record.c | 2 | ||||
-rw-r--r-- | lib/session.c | 2 | ||||
-rw-r--r-- | lib/sslv2_compat.c | 4 | ||||
-rw-r--r-- | lib/state.c | 17 | ||||
-rw-r--r-- | lib/state.h | 4 | ||||
-rw-r--r-- | lib/tls13/session_ticket.c | 2 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/resume-with-previous-stek.c | 2 | ||||
-rw-r--r-- | tests/resume-with-stek-expiration.c | 2 | ||||
-rw-r--r-- | tests/tls13/hello_retry_request_resume.c | 318 |
21 files changed, 407 insertions, 99 deletions
diff --git a/.gitignore b/.gitignore index b721fee238..f473a6fd04 100644 --- a/.gitignore +++ b/.gitignore @@ -857,6 +857,7 @@ tests/tls13/change_cipher_spec tests/tls13/cookie tests/tls13/hello_random_value tests/tls13/hello_retry_request +tests/tls13/hello_retry_request_resume tests/tls13/key_limits tests/tls13/key_share tests/tls13/key_update diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 22edca6ada..72d08de7d7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -329,7 +329,6 @@ fedora-FIPS140-2/build: - ./bootstrap - dash ./configure --disable-gcc-warnings --cache-file $CCACHE_FILE --disable-non-suiteb-curves --enable-fips140-mode --disable-doc --disable-full-test-suite --disable-guile - make -j$BUILDJOBS - - make -j$CHECKJOBS check - mkdir -p lib/.libs/fipscheck - | for i in lib/.libs/libgnutls.so*; do diff --git a/lib/constate.c b/lib/constate.c index 3717522d38..fc56a7569a 100644 --- a/lib/constate.c +++ b/lib/constate.c @@ -814,7 +814,7 @@ int _gnutls_read_connection_state_init(gnutls_session_t session) /* Update internals from CipherSuite selected. * If we are resuming just copy the connection session */ - if (session->internals.resumed != RESUME_FALSE && + if (session->internals.resumed && session->security_parameters.entity == GNUTLS_CLIENT) _gnutls_set_resumed_parameters(session); @@ -850,7 +850,7 @@ int _gnutls_write_connection_state_init(gnutls_session_t session) /* Update internals from CipherSuite selected. * If we are resuming just copy the connection session */ - if (session->internals.resumed != RESUME_FALSE && + if (session->internals.resumed && session->security_parameters.entity == GNUTLS_SERVER) _gnutls_set_resumed_parameters(session); @@ -272,7 +272,7 @@ int _gnutls_server_register_current_session(gnutls_session_t session) key.data = session->security_parameters.session_id; key.size = session->security_parameters.session_id_size; - if (session->internals.resumable == RESUME_FALSE) { + if (!session->internals.resumable) { gnutls_assert(); return GNUTLS_E_INVALID_SESSION; } diff --git a/lib/dtls.h b/lib/dtls.h index 88fba4f3d1..7d9fb40094 100644 --- a/lib/dtls.h +++ b/lib/dtls.h @@ -68,9 +68,9 @@ int _dtls_wait_and_retransmit(gnutls_session_t session); inline static int _dtls_is_async(gnutls_session_t session) { if ((session->security_parameters.entity == GNUTLS_SERVER - && session->internals.resumed == RESUME_FALSE) + && !session->internals.resumed) || (session->security_parameters.entity == GNUTLS_CLIENT - && session->internals.resumed == RESUME_TRUE)) + && session->internals.resumed)) return 1; else return 0; diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index b5a86b7db1..a042c6488e 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -696,7 +696,7 @@ static int server_recv_params(gnutls_session_t session, } } - session->internals.resumed = RESUME_TRUE; + session->internals.resumed = true; _gnutls_handshake_log("EXT[%p]: selected resumption PSK identity (%d)\n", session, psk_index); } @@ -819,7 +819,7 @@ static int _gnutls_psk_recv_params(gnutls_session_t session, for (i=0;i<sizeof(session->key.binders)/sizeof(session->key.binders[0]);i++) { if (session->key.binders[i].prf != NULL && session->key.binders[i].idx == selected_identity) { if (session->key.binders[i].resumption) { - session->internals.resumed = RESUME_TRUE; + session->internals.resumed = true; _gnutls_handshake_log("EXT[%p]: selected PSK-resumption mode\n", session); } else { _gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session); diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c index 8f22462fae..5877f8fa12 100644 --- a/lib/ext/session_ticket.c +++ b/lib/ext/session_ticket.c @@ -370,7 +370,7 @@ unpack_session(gnutls_session_t session, const gnutls_datum_t *state) if (ret < 0) return gnutls_assert_val(ret); - session->internals.resumed = RESUME_TRUE; + session->internals.resumed = true; return 0; } @@ -656,7 +656,7 @@ int _gnutls_send_new_session_ticket(gnutls_session_t session, int again) /* Under TLS1.2 with session tickets, the session ID is used for different * purposes than the TLS1.0 session ID. Ensure that there is an internally * set value which the server will see on the original and resumed sessions */ - if (session->internals.resumed != RESUME_TRUE) { + if (!session->internals.resumed) { ret = _gnutls_generate_session_id(session->security_parameters. session_id, &session->security_parameters. diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index b9134dcbdd..5eb47b4bdf 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -361,9 +361,6 @@ verify(GNUTLS_EXTENSION_MAX_VALUE - GNUTLS_EXTENSION_MAX >= 16); typedef enum { CIPHER_STREAM, CIPHER_BLOCK, CIPHER_AEAD } cipher_type_t; -#define RESUME_TRUE 1 -#define RESUME_FALSE 0 - /* Record Protocol */ typedef enum content_type_t { GNUTLS_CHANGE_CIPHER_SPEC = 20, GNUTLS_ALERT, @@ -1086,7 +1083,7 @@ typedef struct { gnutls_buffer_st handshake_hash_buffer; /* used to keep the last received handshake * message */ - bool resumable; /* TRUE or FALSE - if we can resume that session */ + bool resumable; /* if we can resume that session */ send_ticket_state_t ticket_state; /* used by gnutls_session_ticket_send() */ bye_state_t bye_state; /* used by gnutls_bye() */ @@ -1100,7 +1097,7 @@ typedef struct { * no interruption has happened. */ - bool invalid_connection; /* true or FALSE - if this session is valid */ + bool invalid_connection; /* if this session is valid */ bool may_not_read; /* if it's 0 then we can read/write, otherwise it's forbidden to read/write */ @@ -1135,7 +1132,7 @@ typedef struct { uint16_t dh_prime_bits; /* srp_prime_bits */ /* resumed session */ - bool resumed; /* RESUME_TRUE or FALSE - if we are resuming a session */ + bool resumed; /* if we are resuming a session */ /* server side: non-zero if resumption was requested by client * client side: non-zero if we set resumption parameters */ diff --git a/lib/handshake-tls13.c b/lib/handshake-tls13.c index ea236c803c..7dd42becf1 100644 --- a/lib/handshake-tls13.c +++ b/lib/handshake-tls13.c @@ -210,7 +210,7 @@ int _gnutls13_handshake_client(gnutls_session_t session) SAVE_TRANSCRIPT; - if (session->internals.resumed != RESUME_FALSE) + if (session->internals.resumed) _gnutls_set_resumed_parameters(session); return 0; @@ -325,7 +325,7 @@ static int generate_hs_traffic_keys(gnutls_session_t session) if ((session->security_parameters.entity == GNUTLS_CLIENT && (!(session->internals.hsk_flags & HSK_KEY_SHARE_RECEIVED) || (!(session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK) && - session->internals.resumed != RESUME_FALSE))) || + session->internals.resumed))) || (session->security_parameters.entity == GNUTLS_SERVER && !(session->internals.hsk_flags & HSK_KEY_SHARE_SENT))) { @@ -506,7 +506,7 @@ int _gnutls13_handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE109: - if (session->internals.resumed != RESUME_FALSE) + if (session->internals.resumed) _gnutls_set_resumed_parameters(session); if (session->internals.hsk_flags & HSK_EARLY_START_USED) { diff --git a/lib/handshake.c b/lib/handshake.c index 52bb20bfe2..6c894eb68a 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -61,9 +61,6 @@ #include <valgrind/memcheck.h> #endif -#define TRUE 1 -#define FALSE 0 - static int check_if_null_comp_present(gnutls_session_t session, uint8_t * data, int datalen); static int handshake_client(gnutls_session_t session); @@ -532,7 +529,7 @@ _gnutls_user_hello_func(gnutls_session_t session, * server, and that includes switching version which we have already * negotiated; note that this doesn't apply when resuming as the version * negotiation is already complete. */ - if (session->internals.resumed != RESUME_TRUE) { + if (!session->internals.resumed) { new_max = _gnutls_version_max(session); old_vers = get_version(session); @@ -580,7 +577,7 @@ static int set_auth_types(gnutls_session_t session) /* Under TLS1.3 this returns a KX which matches the negotiated * groups from the key shares; if we are resuming then the KX seen * here doesn't match the original session. */ - if (session->internals.resumed == RESUME_FALSE) + if (!session->internals.resumed) kx = gnutls_kx_get(session); else kx = GNUTLS_KX_UNKNOWN; @@ -592,7 +589,7 @@ static int set_auth_types(gnutls_session_t session) if (kx != GNUTLS_KX_UNKNOWN) { session->security_parameters.server_auth_type = _gnutls_map_kx_get_cred(kx, 1); session->security_parameters.client_auth_type = _gnutls_map_kx_get_cred(kx, 0); - } else if (unlikely(session->internals.resumed == RESUME_FALSE)) { + } else if (unlikely(!session->internals.resumed)) { /* Here we can only arrive if something we received * prevented the session from completing. */ return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); @@ -740,7 +737,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, if (ret < 0) return gnutls_assert_val(ret); - session->internals.resumed = RESUME_TRUE; + session->internals.resumed = true; return _gnutls_user_hello_func(session, major, minor); } else { @@ -751,7 +748,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, if (ret < 0) return gnutls_assert_val(ret); - session->internals.resumed = RESUME_FALSE; + session->internals.resumed = false; } } else { /* TLS1.3 */ /* we echo client's session ID - length was checked previously */ @@ -792,7 +789,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, } /* resumed by session_ticket extension */ - if (!vers->tls13_sem && session->internals.resumed != RESUME_FALSE) { + if (!vers->tls13_sem && session->internals.resumed) { session->internals.resumed_security_parameters. max_record_recv_size = session->security_parameters.max_record_recv_size; @@ -930,10 +927,10 @@ int _gnutls_send_finished(gnutls_session_t session, int again) return ret; } - if ((session->internals.resumed == RESUME_FALSE + if ((!session->internals.resumed && session->security_parameters.entity == GNUTLS_CLIENT) - || (session->internals.resumed != RESUME_FALSE + || (session->internals.resumed && session->security_parameters.entity == GNUTLS_SERVER)) { /* if we are a client not resuming - or we are a server resuming */ @@ -1034,9 +1031,9 @@ int _gnutls_recv_finished(gnutls_session_t session) goto cleanup; } - if ((session->internals.resumed != RESUME_FALSE + if ((session->internals.resumed && session->security_parameters.entity == GNUTLS_CLIENT) - || (session->internals.resumed == RESUME_FALSE + || (!session->internals.resumed && session->security_parameters.entity == GNUTLS_SERVER)) { /* if we are a client resuming - or we are a server not resuming */ _gnutls_handshake_log @@ -1845,13 +1842,13 @@ client_check_if_resuming(gnutls_session_t session, goto no_resume; } - session->internals.resumed = RESUME_TRUE; /* we are resuming */ + session->internals.resumed = true; /* we are resuming */ return 0; } else { no_resume: /* keep the new session id */ - session->internals.resumed = RESUME_FALSE; /* we are not resuming */ + session->internals.resumed = false; /* we are not resuming */ return -1; } } @@ -2097,17 +2094,19 @@ static int send_client_hello(gnutls_session_t session, int again) const version_entry_st *hver, *min_ver, *max_ver; uint8_t tver[2]; gnutls_buffer_st extdata; - int rehandshake = 0; + bool rehandshake = false; + bool resuming = false; unsigned add_sr_scsv = 0; + uint8_t *session_id = + session->internals.resumed_security_parameters.session_id; uint8_t session_id_len = - session->internals.resumed_security_parameters.session_id_size; - + session->internals.resumed_security_parameters.session_id_size; if (again == 0) { /* note that rehandshake is different than resuming */ if (session->internals.initial_negotiation_completed) - rehandshake = 1; + rehandshake = true; ret = _gnutls_buffer_init_handshake_mbuffer(&extdata); if (ret < 0) @@ -2124,6 +2123,8 @@ static int send_client_hello(gnutls_session_t session, int again) hver = _gnutls_legacy_version_max(session); } else { /* we are resuming a session */ + resuming = true; + hver = session->internals.resumed_security_parameters. pversion; @@ -2211,11 +2212,8 @@ static int send_client_hello(gnutls_session_t session, int again) goto cleanup; } - uint8_t *resumed_session_id = session->internals.resumed_security_parameters.session_id; #ifdef TLS13_APPENDIX_D4 - if (max_ver->tls13_sem && - session->security_parameters.session_id_size == 0) { - + if (max_ver->tls13_sem && !resuming) { /* Under TLS1.3 we generate a random session ID to make * the TLS1.3 session look like a resumed TLS1.2 session */ ret = _gnutls_generate_session_id(session->security_parameters. @@ -2226,7 +2224,7 @@ static int send_client_hello(gnutls_session_t session, int again) gnutls_assert(); goto cleanup; } - resumed_session_id = session->security_parameters.session_id; + session_id = session->security_parameters.session_id; session_id_len = session->security_parameters.session_id_size; } #endif @@ -2234,7 +2232,7 @@ static int send_client_hello(gnutls_session_t session, int again) /* Copy the Session ID - if any */ ret = _gnutls_buffer_append_data_prefix(&extdata, 8, - resumed_session_id, + session_id, session_id_len); if (ret < 0) { gnutls_assert(); @@ -2393,7 +2391,7 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) goto fail; } - if (!vers->tls13_sem && session->internals.resumed != RESUME_FALSE) + if (!vers->tls13_sem && session->internals.resumed) etype = GNUTLS_EXT_MANDATORY; else etype = GNUTLS_EXT_ANY; @@ -3002,7 +3000,7 @@ static int handshake_client(gnutls_session_t session) FALLTHROUGH; case STATE6: /* RECV CERTIFICATE */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_recv_server_certificate(session); STATE = STATE6; IMED_RET("recv server certificate", ret, 1); @@ -3010,7 +3008,7 @@ static int handshake_client(gnutls_session_t session) case STATE7: #ifdef ENABLE_OCSP /* RECV CERTIFICATE STATUS */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_recv_server_certificate_status (session); @@ -3027,7 +3025,7 @@ static int handshake_client(gnutls_session_t session) FALLTHROUGH; case STATE9: /* receive the server key exchange */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_recv_server_kx_message(session); STATE = STATE9; IMED_RET("recv server kx message", ret, 1); @@ -3036,7 +3034,7 @@ static int handshake_client(gnutls_session_t session) /* receive the server certificate request - if any */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_recv_server_crt_request(session); STATE = STATE10; IMED_RET("recv server certificate request message", ret, @@ -3044,7 +3042,7 @@ static int handshake_client(gnutls_session_t session) FALLTHROUGH; case STATE11: /* receive the server hello done */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_SERVER_HELLO_DONE, @@ -3064,7 +3062,7 @@ static int handshake_client(gnutls_session_t session) case STATE13: /* send our certificate - if any and if requested */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_send_client_certificate(session, AGAIN @@ -3073,7 +3071,7 @@ static int handshake_client(gnutls_session_t session) IMED_RET("send client certificate", ret, 0); FALLTHROUGH; case STATE14: - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_send_client_kx_message(session, AGAIN(STATE14)); @@ -3082,7 +3080,7 @@ static int handshake_client(gnutls_session_t session) FALLTHROUGH; case STATE15: /* send client certificate verify */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_send_client_certificate_verify(session, AGAIN @@ -3092,8 +3090,8 @@ static int handshake_client(gnutls_session_t session) FALLTHROUGH; case STATE16: STATE = STATE16; - if (session->internals.resumed == RESUME_FALSE) { - ret = send_handshake_final(session, TRUE); + if (!session->internals.resumed) { + ret = send_handshake_final(session, true); IMED_RET("send handshake final 2", ret, 1); } else { ret = _gnutls_recv_new_session_ticket(session); @@ -3103,7 +3101,7 @@ static int handshake_client(gnutls_session_t session) FALLTHROUGH; case STATE17: STATE = STATE17; - if (session->internals.resumed == RESUME_FALSE && (session->internals.flags & GNUTLS_ENABLE_FALSE_START) && can_send_false_start(session)) { + if (!session->internals.resumed && (session->internals.flags & GNUTLS_ENABLE_FALSE_START) && can_send_false_start(session)) { session->internals.hsk_flags |= HSK_FALSE_START_USED; session->internals.recv_state = RECV_STATE_FALSE_START; /* complete this phase of the handshake. We @@ -3118,22 +3116,22 @@ static int handshake_client(gnutls_session_t session) case STATE18: STATE = STATE18; - if (session->internals.resumed == RESUME_FALSE) { + if (!session->internals.resumed) { ret = _gnutls_recv_new_session_ticket(session); IMED_RET("recv handshake new session ticket", ret, 1); } else { - ret = recv_handshake_final(session, TRUE); + ret = recv_handshake_final(session, true); IMED_RET("recv handshake final", ret, 1); } FALLTHROUGH; case STATE19: STATE = STATE19; - if (session->internals.resumed == RESUME_FALSE) { - ret = recv_handshake_final(session, FALSE); + if (!session->internals.resumed) { + ret = recv_handshake_final(session, false); IMED_RET("recv handshake final 2", ret, 1); } else { - ret = send_handshake_final(session, FALSE); + ret = send_handshake_final(session, false); IMED_RET("send handshake final", ret, 1); } @@ -3245,7 +3243,7 @@ static int send_handshake_final(gnutls_session_t session, int init) } /* Initialize the connection session (start encryption) - in case of client */ - if (init == TRUE) { + if (init) { ret = _gnutls_connection_state_init(session); if (ret < 0) { gnutls_assert(); @@ -3330,7 +3328,7 @@ static int recv_handshake_final(gnutls_session_t session, int init) session->internals.dtls.hsk_read_seq++; /* Initialize the connection session (start encryption) - in case of server */ - if (init == TRUE) { + if (init) { ret = _gnutls_connection_state_init(session); if (ret < 0) { gnutls_assert(); @@ -3438,7 +3436,7 @@ static int handshake_server(gnutls_session_t session) case STATE5: /* NOTE: these should not be send if we are resuming */ - if (session->internals.resumed == RESUME_FALSE) + if (!session->internals.resumed) ret = _gnutls_send_server_certificate(session, AGAIN(STATE5)); @@ -3447,7 +3445,7 @@ static int handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE6: #ifdef ENABLE_OCSP - if (session->internals.resumed == RESUME_FALSE) + if (!session->internals.resumed) ret = _gnutls_send_server_certificate_status(session, AGAIN @@ -3458,7 +3456,7 @@ static int handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE7: /* send server key exchange (A) */ - if (session->internals.resumed == RESUME_FALSE) + if (!session->internals.resumed) ret = _gnutls_send_server_kx_message(session, AGAIN(STATE7)); @@ -3467,7 +3465,7 @@ static int handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE8: /* Send certificate request - if requested to */ - if (session->internals.resumed == RESUME_FALSE) + if (!session->internals.resumed) ret = _gnutls_send_server_crt_request(session, AGAIN(STATE8)); @@ -3476,7 +3474,7 @@ static int handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE9: /* send the server hello done */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_send_empty_handshake(session, GNUTLS_HANDSHAKE_SERVER_HELLO_DONE, @@ -3494,7 +3492,7 @@ static int handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE11: /* receive the client certificate message */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_recv_client_certificate(session); STATE = STATE11; IMED_RET("recv client certificate", ret, 1); @@ -3507,14 +3505,14 @@ static int handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE13: /* receive the client key exchange message */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_recv_client_kx_message(session); STATE = STATE13; IMED_RET("recv client kx", ret, 1); FALLTHROUGH; case STATE14: /* receive the client certificate verify message */ - if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + if (!session->internals.resumed) /* if we are not resuming */ ret = _gnutls_recv_client_certificate_verify_message (session); @@ -3523,11 +3521,11 @@ static int handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE15: STATE = STATE15; - if (session->internals.resumed == RESUME_FALSE) { /* if we are not resuming */ - ret = recv_handshake_final(session, TRUE); + if (!session->internals.resumed) { /* if we are not resuming */ + ret = recv_handshake_final(session, true); IMED_RET("recv handshake final", ret, 1); } else { - ret = send_handshake_final(session, TRUE); + ret = send_handshake_final(session, true); IMED_RET("send handshake final 2", ret, 1); } FALLTHROUGH; @@ -3540,8 +3538,8 @@ static int handshake_server(gnutls_session_t session) FALLTHROUGH; case STATE17: STATE = STATE17; - if (session->internals.resumed == RESUME_FALSE) { /* if we are not resuming */ - ret = send_handshake_final(session, FALSE); + if (!session->internals.resumed) { /* if we are not resuming */ + ret = send_handshake_final(session, false); IMED_RET("send handshake final", ret, 1); if (session->security_parameters.entity == @@ -3552,7 +3550,7 @@ static int handshake_server(gnutls_session_t session) (session); } } else { - ret = recv_handshake_final(session, FALSE); + ret = recv_handshake_final(session, false); IMED_RET("recv handshake final 2", ret, 1); } @@ -54,7 +54,7 @@ static int generate_normal_master(gnutls_session_t session, int _gnutls_generate_master(gnutls_session_t session, int keep_premaster) { - if (session->internals.resumed == RESUME_FALSE) + if (!session->internals.resumed) return generate_normal_master(session, &session->key.key, keep_premaster); else if (session->internals.premaster_set) { diff --git a/lib/record.c b/lib/record.c index 8b0d2bc60e..cd9df80520 100644 --- a/lib/record.c +++ b/lib/record.c @@ -341,7 +341,7 @@ int gnutls_bye(gnutls_session_t session, gnutls_close_request_t how) inline static void session_unresumable(gnutls_session_t session) { - session->internals.resumable = RESUME_FALSE; + session->internals.resumable = false; } /* returns 0 if session is valid diff --git a/lib/session.c b/lib/session.c index b9a23e8d02..bdaf572b0e 100644 --- a/lib/session.c +++ b/lib/session.c @@ -166,7 +166,7 @@ gnutls_session_get_data2(gnutls_session_t session, gnutls_datum_t *data) } } - if (session->internals.resumable == RESUME_FALSE) + if (!session->internals.resumable) return GNUTLS_E_INVALID_SESSION; ret = _gnutls_session_pack(session, data); diff --git a/lib/sslv2_compat.c b/lib/sslv2_compat.c index 4dd62d01c1..c4a0143b92 100644 --- a/lib/sslv2_compat.c +++ b/lib/sslv2_compat.c @@ -238,7 +238,7 @@ _gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); - session->internals.resumed = RESUME_TRUE; + session->internals.resumed = true; return 0; } else { ret = _gnutls_generate_session_id( @@ -247,7 +247,7 @@ _gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data, if (ret < 0) return gnutls_assert_val(ret); - session->internals.resumed = RESUME_FALSE; + session->internals.resumed = false; } return sret; diff --git a/lib/state.c b/lib/state.c index fcf6183fa4..9f306faf70 100644 --- a/lib/state.c +++ b/lib/state.c @@ -419,7 +419,7 @@ static void handshake_internal_state_clear1(gnutls_session_t session) session->internals.last_handshake_in = -1; session->internals.last_handshake_out = -1; - session->internals.resumable = RESUME_TRUE; + session->internals.resumable = true; session->internals.handshake_suspicious_loops = 0; session->internals.dtls.hsk_read_seq = 0; @@ -640,13 +640,6 @@ int gnutls_init(gnutls_session_t * session, unsigned int flags) return 0; } -/* returns RESUME_FALSE or RESUME_TRUE. - */ -int _gnutls_session_is_resumable(gnutls_session_t session) -{ - return session->internals.resumable; -} - /** * gnutls_deinit: @@ -988,9 +981,9 @@ int gnutls_session_is_resumed(gnutls_session_t session) { if (session->security_parameters.entity == GNUTLS_CLIENT) { const version_entry_st *ver = get_version(session); - if (ver && ver->tls13_sem && - session->internals.resumed != RESUME_FALSE) - return 1; + if (ver && ver->tls13_sem) { + return session->internals.resumed; + } if (session->security_parameters.session_id_size > 0 && session->security_parameters.session_id_size == @@ -1004,7 +997,7 @@ int gnutls_session_is_resumed(gnutls_session_t session) session_id_size) == 0) return 1; } else { - if (session->internals.resumed != RESUME_FALSE) + if (session->internals.resumed) return 1; } diff --git a/lib/state.h b/lib/state.h index 819df21ec6..ff945b0690 100644 --- a/lib/state.h +++ b/lib/state.h @@ -99,12 +99,8 @@ static inline int _gnutls_dh_get_min_prime_bits(gnutls_session_t session) void _gnutls_handshake_internal_state_clear(gnutls_session_t); -int _gnutls_session_is_resumable(gnutls_session_t session); - int _gnutls_session_is_psk(gnutls_session_t session); -int _gnutls_openpgp_send_fingerprint(gnutls_session_t session); - void reset_binders(gnutls_session_t session); inline static int diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c index 072a56d9c1..3f64d8c32e 100644 --- a/lib/tls13/session_ticket.c +++ b/lib/tls13/session_ticket.c @@ -201,7 +201,7 @@ generate_session_ticket(gnutls_session_t session, tls13_ticket_st *ticket) tls13_ticket_st ticket_data; gnutls_gettime(&now); - if (session->internals.resumed != RESUME_FALSE) { + if (session->internals.resumed) { /* If we are resuming ensure that we don't extend the lifetime * of the ticket past the original session expiration time */ if (now.tv_sec >= session->security_parameters.timestamp + session->internals.expire_time) diff --git a/tests/Makefile.am b/tests/Makefile.am index 35d06db8fc..8f7972a7d5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -118,6 +118,8 @@ ctests = tls13/supported_versions tls13/tls12-no-tls13-exts \ ctests += tls13/hello_retry_request +ctests += tls13/hello_retry_request_resume + ctests += tls13/psk-ext ctests += tls13/key_update diff --git a/tests/resume-with-previous-stek.c b/tests/resume-with-previous-stek.c index 05c1c90868..3bbba8f896 100644 --- a/tests/resume-with-previous-stek.c +++ b/tests/resume-with-previous-stek.c @@ -227,11 +227,13 @@ static void run(const char *name, const char *prio, int resume[], int rounds) if (child) { /* We are the parent */ + close(sockets[1]); server(sockets[0], rounds, prio); waitpid(child, &status, 0); check_wait_status(status); } else { /* We are the child */ + close(sockets[0]); client(sockets[1], resume, rounds, prio); exit(0); } diff --git a/tests/resume-with-stek-expiration.c b/tests/resume-with-stek-expiration.c index 80445d64d0..de0f07012b 100644 --- a/tests/resume-with-stek-expiration.c +++ b/tests/resume-with-stek-expiration.c @@ -297,11 +297,13 @@ static void run(const char *name, const char *prio, int resumption_should_succee if (child) { /* We are the parent */ + close(sockets[1]); server(sockets[0], resumption_should_succeed, rounds, prio); waitpid(child, &status, 0); check_wait_status(status); } else { /* We are the child */ + close(sockets[0]); client(sockets[1], resumption_should_succeed, rounds, prio); exit(0); } diff --git a/tests/tls13/hello_retry_request_resume.c b/tests/tls13/hello_retry_request_resume.c new file mode 100644 index 0000000000..6672bc7a9c --- /dev/null +++ b/tests/tls13/hello_retry_request_resume.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2017-2020 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos, Daiki Ueno + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +#if defined(_WIN32) + +int main() +{ + exit(77); +} + +#else + +#include <string.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <gnutls/gnutls.h> +#include <signal.h> +#include <assert.h> + +#include "../lib/handshake-defs.h" +#include "cert-common.h" +#include "utils.h" + +/* This program tests whether the certificate seen in Post Handshake Auth + * is found in a resumed session under TLS 1.3. + */ + +static void server_log_func(int level, const char *str) +{ + fprintf(stderr, "server|<%d>| %s", level, str); +} + +static void client_log_func(int level, const char *str) +{ + fprintf(stderr, "client|<%d>| %s", level, str); +} + +static int ticket_callback(gnutls_session_t session, unsigned int htype, + unsigned post, unsigned int incoming, const gnutls_datum_t *msg) +{ + gnutls_datum *d; + int ret; + + assert(htype == GNUTLS_HANDSHAKE_NEW_SESSION_TICKET); + + d = gnutls_session_get_ptr(session); + + if (post == GNUTLS_HOOK_POST) { + if (d->data) + gnutls_free(d->data); + ret = gnutls_session_get_data2(session, d); + assert(ret >= 0); + assert(d->size > 4); + + return 0; + } + + return 0; +} + +static void client(int fd) +{ + int ret; + gnutls_session_t session; + unsigned try = 0; + gnutls_datum_t session_data = {NULL, 0}; + gnutls_certificate_credentials_t x509_cred; + + global_init(); + + if (debug) { + gnutls_global_set_log_function(client_log_func); + gnutls_global_set_log_level(7); + } + + assert(gnutls_certificate_allocate_credentials(&x509_cred)>=0); + + retry: + /* Initialize TLS session + */ + assert(gnutls_init(&session, GNUTLS_CLIENT)>=0); + + gnutls_handshake_set_timeout(session, 20 * 1000); + + ret = gnutls_priority_set_direct(session, "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1:+GROUP-X25519", NULL); + if (ret < 0) + fail("cannot set TLS 1.3 priorities\n"); + + + if (try == 0) { + gnutls_session_set_ptr(session, &session_data); + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, + GNUTLS_HOOK_BOTH, + ticket_callback); + } else { + assert(gnutls_session_set_data(session, session_data.data, session_data.size) >= 0); + } + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + gnutls_transport_set_int(session, fd); + + /* Perform the TLS handshake + */ + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret != 0) + fail("handshake failed: %s\n", gnutls_strerror(ret)); + + do { + ret = gnutls_bye(session, GNUTLS_SHUT_RDWR); + } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + + if (ret != 0) { + fail("error in recv: %s\n", gnutls_strerror(ret)); + } + + gnutls_deinit(session); + + if (try == 0) { + try++; + goto retry; + } + + gnutls_free(session_data.data); + close(fd); + gnutls_certificate_free_credentials(x509_cred); + + gnutls_global_deinit(); +} + +#define HANDSHAKE_SESSION_ID_POS 34 + +static int client_hello_callback(gnutls_session_t session, unsigned int htype, + unsigned post, unsigned int incoming, + const gnutls_datum_t *msg) +{ + gnutls_datum *d; + + assert(post == GNUTLS_HOOK_POST); + assert(msg->size >= HANDSHAKE_SESSION_ID_POS + 1); + + d = gnutls_session_get_ptr(session); + d->size = msg->data[HANDSHAKE_SESSION_ID_POS]; + d->data = gnutls_malloc(d->size); + memcpy(d->data, &msg->data[HANDSHAKE_SESSION_ID_POS], d->size); + + return 0; +} + +static void server(int fd) +{ + int ret; + gnutls_session_t session; + unsigned try = 0; + gnutls_certificate_credentials_t x509_cred; + gnutls_datum_t skey; + gnutls_datum_t session_id = {NULL, 0}; + gnutls_datum_t retry_session_id = {NULL, 0}; + + /* this must be called once in the program + */ + global_init(); + + assert(gnutls_session_ticket_key_generate(&skey)>=0); + + if (debug) { + gnutls_global_set_log_function(server_log_func); + gnutls_global_set_log_level(4711); + } + + gnutls_certificate_allocate_credentials(&x509_cred); + gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert, + &server_key, + GNUTLS_X509_FMT_PEM); + + retry: + assert(gnutls_init(&session, GNUTLS_SERVER)>=0); + + assert(gnutls_session_ticket_enable_server(session, &skey) >= 0); + gnutls_handshake_set_timeout(session, 20 * 1000); + + /* server only supports x25519, client advertises secp256r1 */ + assert(gnutls_priority_set_direct(session, "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-X25519", NULL)>=0); + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + gnutls_transport_set_int(session, fd); + + if (try == 0) { + gnutls_session_set_ptr(session, &session_id); + } else { + gnutls_session_set_ptr(session, &retry_session_id); + } + + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_CLIENT_HELLO, + GNUTLS_HOOK_POST, + client_hello_callback); + + do { + ret = gnutls_handshake(session); + } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret != 0) + fail("handshake failed: %s\n", gnutls_strerror(ret)); + + if (try > 0) { + assert(gnutls_session_is_resumed(session) != 0); + + /* Check that the same (non-empty) session ID is used in both + * initial and resumption handshakes. This assumes + * TLS13_APPENDIX_D4 is set to 1 in lib/handshake-defs.h. Once + * it's turned off, both session IDs should be empty. */ + if (session_id.size == 0 || + session_id.size != retry_session_id.size || + memcmp(session_id.data, retry_session_id.data, session_id.size)) { + fail("session ids are different after resumption: %u, %u\n", + session_id.size, retry_session_id.size); + } + } + + do { + ret = gnutls_bye(session, GNUTLS_SHUT_RDWR); + } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + gnutls_deinit(session); + + if (try == 0) { + try++; + goto retry; + } + + gnutls_free(skey.data); + close(fd); + gnutls_certificate_free_credentials(x509_cred); + gnutls_free(session_id.data); + gnutls_free(retry_session_id.data); + + gnutls_global_deinit(); + + if (debug) + success("server: client/server hello were verified\n"); +} + +static void ch_handler(int sig) +{ + int status = 0; + wait(&status); + check_wait_status(status); + return; +} + +void doit(void) +{ + int fd[2]; + int ret; + pid_t child; + + signal(SIGCHLD, ch_handler); + signal(SIGPIPE, SIG_IGN); + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); + if (ret < 0) { + perror("socketpair"); + exit(1); + } + + child = fork(); + if (child < 0) { + perror("fork"); + fail("fork"); + exit(1); + } + + if (child) { + /* parent */ + close(fd[1]); + server(fd[0]); + kill(child, SIGTERM); + } else { + close(fd[0]); + client(fd[1]); + exit(0); + } + +} +#endif /* _WIN32 */ |