From 3e4416072542029a95feac9382014935854f5096 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 11 Apr 2019 11:23:26 +0200 Subject: prf: centrally define "exporter" label in handshake.h Signed-off-by: Daiki Ueno --- lib/handshake-defs.h | 2 +- lib/prf.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/handshake-defs.h b/lib/handshake-defs.h index d322febc90..0b89cca608 100644 --- a/lib/handshake-defs.h +++ b/lib/handshake-defs.h @@ -34,7 +34,7 @@ #define APPLICATION_TRAFFIC_UPDATE "traffic upd" #define EXPORTER_MASTER_LABEL "exp master" #define RMS_MASTER_LABEL "res master" -#define EXPORTER_LABEL "exp master" +#define EXPORTER_LABEL "exporter" #define RESUMPTION_LABEL "resumption" #define HRR_RANDOM \ diff --git a/lib/prf.c b/lib/prf.c index dd66327e3d..19e25cfa8d 100644 --- a/lib/prf.c +++ b/lib/prf.c @@ -27,13 +27,12 @@ #include "gnutls_int.h" #include "errors.h" +#include "handshake.h" #include "secrets.h" #include #include #include -#define EXPORTER_LABEL "exporter" - /** * gnutls_prf_raw: * @session: is a #gnutls_session_t type. -- cgit v1.2.1 From 7137b3d492a83ffc5b89fa1ec426626e789b0868 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 11 Apr 2019 12:10:00 +0200 Subject: tests/tls13/prf: check if the exported material matches on server Signed-off-by: Daiki Ueno --- tests/tls13/prf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/tls13/prf.c b/tests/tls13/prf.c index 6cc96580dd..a8a529bcb8 100644 --- a/tests/tls13/prf.c +++ b/tests/tls13/prf.c @@ -314,6 +314,8 @@ static void server(int fd) gnutls_protocol_get_name (gnutls_protocol_get_version(session))); + check_prfs(session); + /* do not wait for the peer to close the connection. */ gnutls_bye(session, GNUTLS_SHUT_WR); -- cgit v1.2.1 From 163c32a8d6b107eca08bf404ee076b0d240bf942 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 11 Apr 2019 12:00:46 +0200 Subject: handshake: move early secrets calculation to pre_shared_key TLS 1.3 Early Secret and the derived keys are calculated upon a PSK being selected, thus the code fits better in ext/pre_shared_key.c. Signed-off-by: Daiki Ueno --- lib/ext/pre_shared_key.c | 70 ++++++++++++++++++++- lib/ext/pre_shared_key.h | 2 + lib/handshake.c | 159 +++++++++++------------------------------------ lib/state.c | 2 +- 4 files changed, 109 insertions(+), 124 deletions(-) diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index 771092fa9c..42f728286b 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -24,6 +24,7 @@ #include "gnutls_int.h" #include "auth/psk.h" #include "handshake.h" +#include "kx.h" #include "secrets.h" #include "tls13/anti_replay.h" #include "tls13/psk_ext_parser.h" @@ -188,6 +189,58 @@ error: return ret; } +static int +generate_early_secrets(gnutls_session_t session, + const mac_entry_st *prf) +{ + int ret; + + ret = _tls13_derive_secret2(prf, EARLY_TRAFFIC_LABEL, sizeof(EARLY_TRAFFIC_LABEL)-1, + session->internals.handshake_hash_buffer.data, + session->internals.handshake_hash_buffer_client_hello_len, + session->key.proto.tls13.temp_secret, + session->key.proto.tls13.e_ckey); + if (ret < 0) + return gnutls_assert_val(ret); + + _gnutls_nss_keylog_write(session, "CLIENT_EARLY_TRAFFIC_SECRET", + session->key.proto.tls13.e_ckey, + prf->output_size); + + return 0; +} + +/* Calculate TLS 1.3 Early Secret and the derived secrets from the + * selected PSK. */ +int +_gnutls_generate_early_secrets_for_psk(gnutls_session_t session) +{ + const uint8_t *psk; + size_t psk_size; + const mac_entry_st *prf; + int ret; + + psk = session->key.binders[0].psk.data; + psk_size = session->key.binders[0].psk.size; + prf = session->key.binders[0].prf; + + if (unlikely(psk_size == 0)) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ret = _tls13_init_secret2(prf, psk, psk_size, + session->key.proto.tls13.temp_secret); + if (ret < 0) + return gnutls_assert_val(ret); + + session->key.proto.tls13.temp_secret_size = prf->output_size; + + ret = generate_early_secrets(session, session->key.binders[0].prf); + if (ret < 0) + return gnutls_assert_val(ret); + + return 0; +} + static int client_send_params(gnutls_session_t session, gnutls_buffer_t extdata, @@ -651,6 +704,12 @@ static int server_recv_params(gnutls_session_t session, session->key.binders[0].prf = prf; session->key.binders[0].resumption = resuming; + ret = _gnutls_generate_early_secrets_for_psk(session); + if (ret < 0) { + gnutls_assert(); + goto fail; + } + return 0; fail: @@ -742,6 +801,7 @@ static int _gnutls_psk_recv_params(gnutls_session_t session, unsigned i; gnutls_psk_server_credentials_t pskcred; const version_entry_st *vers = get_version(session); + int ret; if (!vers || !vers->tls13_sem) return 0; @@ -759,9 +819,15 @@ static int _gnutls_psk_recv_params(gnutls_session_t session, _gnutls_handshake_log("EXT[%p]: selected PSK mode\n", session); } - /* ensure that selected binder is set on (our) index zero */ - if (i != 0) + /* different PSK is selected, than the one we calculated early secrets */ + if (i != 0) { + /* ensure that selected binder is set on (our) index zero */ swap_binders(session); + + ret = _gnutls_generate_early_secrets_for_psk(session); + if (ret < 0) + return gnutls_assert_val(ret); + } session->internals.hsk_flags |= HSK_PSK_SELECTED; } } diff --git a/lib/ext/pre_shared_key.h b/lib/ext/pre_shared_key.h index 4ad7b240f3..71116e5d10 100644 --- a/lib/ext/pre_shared_key.h +++ b/lib/ext/pre_shared_key.h @@ -18,4 +18,6 @@ unsigned _gnutls_have_psk_credentials(const gnutls_psk_client_credentials_t cred return 0; } +int _gnutls_generate_early_secrets_for_psk(gnutls_session_t session); + #endif diff --git a/lib/handshake.c b/lib/handshake.c index 45bf99a6f7..1e6164cabe 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -45,6 +45,7 @@ #include "constate.h" #include #include +#include #include #include #include @@ -826,6 +827,14 @@ read_client_hello(gnutls_session_t session, uint8_t * data, return ret; } + /* Calculate TLS 1.3 Early Secret */ + if (session->security_parameters.pversion->tls13_sem && + !(session->internals.hsk_flags & HSK_PSK_SELECTED)) { + ret = _tls13_init_secret(session, NULL, 0); + if (ret < 0) + return gnutls_assert_val(ret); + } + ret = set_auth_types(session); if (ret < 0) { gnutls_assert(); @@ -1265,7 +1274,7 @@ _gnutls_send_handshake2(gnutls_session_t session, mbuffer_st * bufel, /* Here we keep the handshake messages in order to hash them... */ - if (!IS_ASYNC(type, vers)) + if (!IS_ASYNC(type, vers)) { if ((ret = handshake_hash_add_sent(session, type, data, datasize)) < 0) { @@ -1273,6 +1282,19 @@ _gnutls_send_handshake2(gnutls_session_t session, mbuffer_st * bufel, _mbuffer_xfree(&bufel); return ret; } + /* If we are sending a PSK, generate early secrets here. + * This cannot be done in pre_shared_key.c, because it + * relies on transcript hash of a Client Hello. */ + if (type == GNUTLS_HANDSHAKE_CLIENT_HELLO && + session->key.binders[0].prf != NULL) { + ret = _gnutls_generate_early_secrets_for_psk(session); + if (ret < 0) { + gnutls_assert(); + _mbuffer_xfree(&bufel); + return ret; + } + } + } ret = _gnutls_call_hook_func(session, type, GNUTLS_HOOK_PRE, 0, _mbuffer_get_udata_ptr(bufel), _mbuffer_get_udata_size(bufel)); @@ -1807,26 +1829,6 @@ no_resume: } -static int generate_early_traffic_secret(gnutls_session_t session, - const mac_entry_st *prf) -{ - int ret; - - ret = _tls13_derive_secret2(prf, EARLY_TRAFFIC_LABEL, sizeof(EARLY_TRAFFIC_LABEL)-1, - session->internals.handshake_hash_buffer.data, - session->internals.handshake_hash_buffer_client_hello_len, - session->key.proto.tls13.temp_secret, - session->key.proto.tls13.e_ckey); - if (ret < 0) - return gnutls_assert_val(ret); - - _gnutls_nss_keylog_write(session, "CLIENT_EARLY_TRAFFIC_SECRET", - session->key.proto.tls13.e_ckey, - prf->output_size); - - return 0; -} - /* This function reads and parses the server hello handshake message. * This function also restores resumed parameters if we are resuming a * session. @@ -1840,12 +1842,10 @@ read_server_hello(gnutls_session_t session, uint8_t *cs_pos, *comp_pos, *srandom_pos; uint8_t major, minor; int pos = 0; - int ret = 0; + int ret; int len = datalen; unsigned ext_parse_flag = 0; const version_entry_st *vers, *saved_vers; - const uint8_t *psk = NULL; - size_t psk_size = 0; if (datalen < GNUTLS_RANDOM_SIZE+2) { gnutls_assert(); @@ -1925,6 +1925,13 @@ read_server_hello(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); + /* reset keys and binders if we are not using TLS 1.3 */ + if (!vers->tls13_sem) { + gnutls_memset(&session->key.proto.tls13, 0, + sizeof(session->key.proto.tls13)); + reset_binders(session); + } + /* check if we are resuming and set the appropriate * values; */ @@ -2016,31 +2023,17 @@ read_server_hello(gnutls_session_t session, /* Calculate TLS 1.3 Early Secret */ if (vers->tls13_sem && - !(session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT)) { - if (session->internals.hsk_flags & HSK_PSK_SELECTED) { - psk = session->key.binders[0].psk.data; - psk_size = session->key.binders[0].psk.size; - - if (psk_size == 0) - return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); - } - - ret = _tls13_init_secret(session, psk, psk_size); - if (ret < 0) { - gnutls_assert(); - return ret; - } + !(session->internals.hsk_flags & HSK_PSK_SELECTED)) { + ret = _tls13_init_secret(session, NULL, 0); + if (ret < 0) + return gnutls_assert_val(ret); } ret = set_auth_types(session); - if (ret < 0) { - gnutls_assert(); - goto cleanup; - } - -cleanup: + if (ret < 0) + return gnutls_assert_val(ret); - return ret; + return 0; } /* This function copies the appropriate compression methods, to a locally allocated buffer @@ -2064,56 +2057,6 @@ append_null_comp(gnutls_session_t session, return ret; } -/* Calculate TLS 1.3 Early Secret and client_early_traffic_secret, - * assuming that the PSK we offer will be accepted by the server */ -static int -generate_early_traffic_secret_from_ticket(gnutls_session_t session) -{ - int ret = 0; - const uint8_t *psk; - size_t psk_size; - const mac_entry_st *prf; - - if (!(session->internals.hsk_flags & HSK_TLS13_TICKET_SENT)) { - ret = GNUTLS_E_INVALID_REQUEST; - gnutls_assert(); - goto cleanup; - } - - psk = session->key.binders[0].psk.data; - psk_size = session->key.binders[0].psk.size; - prf = session->key.binders[0].prf; - - if (psk_size == 0) { - ret = GNUTLS_E_INVALID_REQUEST; - gnutls_assert(); - goto cleanup; - } - - ret = _tls13_init_secret2(prf, psk, psk_size, - session->key.proto.tls13.temp_secret); - if (ret < 0) { - gnutls_assert(); - goto cleanup; - } - session->key.proto.tls13.temp_secret_size = prf->output_size; - - ret = generate_early_traffic_secret(session, prf); - if (ret < 0) { - gnutls_assert(); - goto cleanup; - } - - return ret; - - cleanup: - /* If any of the above calculation fails, we are not going to - * send early data. */ - session->internals.hsk_flags &= ~HSK_EARLY_DATA_IN_FLIGHT; - - return ret; -} - /* This function sends the client hello handshake message. */ static int send_client_hello(gnutls_session_t session, int again) @@ -2349,9 +2292,6 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) const version_entry_st *vers; uint8_t vbytes[2]; unsigned extflag = 0; - const uint8_t *psk = NULL; - size_t psk_size = 0; - const mac_entry_st *prf = session->security_parameters.prf; gnutls_ext_parse_type_t etype; _gnutls_buffer_init(&buf); @@ -2362,25 +2302,6 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (vers->tls13_sem) { - /* TLS 1.3 Early Secret */ - if (session->internals.hsk_flags & HSK_PSK_SELECTED) { - psk = session->key.binders[0].psk.data; - psk_size = session->key.binders[0].psk.size; - prf = session->key.binders[0].prf; - } - - ret = _tls13_init_secret(session, psk, psk_size); - if (ret < 0) { - gnutls_assert(); - goto fail; - } - - ret = generate_early_traffic_secret(session, prf); - if (ret < 0) { - gnutls_assert(); - goto fail; - } - vbytes[0] = 0x03; /* TLS1.2 */ vbytes[1] = 0x03; extflag |= GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; @@ -2971,10 +2892,6 @@ static int handshake_client(gnutls_session_t session) ret = send_client_hello(session, AGAIN(STATE1)); STATE = STATE1; IMED_RET("send hello", ret, 1); - if (session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT) { - ret = generate_early_traffic_secret_from_ticket(session); - IMED_RET_FATAL("generate early traffic keys from ticket", ret, 0); - } FALLTHROUGH; case STATE2: if (IS_DTLS(session)) { diff --git a/lib/state.c b/lib/state.c index fe40bd980a..97461e6722 100644 --- a/lib/state.c +++ b/lib/state.c @@ -345,7 +345,7 @@ static void deinit_keys(gnutls_session_t session) gnutls_pk_params_release(&session->key.kshare.ecdh_params); gnutls_pk_params_release(&session->key.kshare.dh_params); - if (!vers->tls13_sem) { + if (!vers->tls13_sem && session->key.binders[0].prf == NULL) { gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params); gnutls_pk_params_release(&session->key.proto.tls12.dh.params); zrelease_temp_mpi_key(&session->key.proto.tls12.ecdh.x); -- cgit v1.2.1 From 0e579649a6e9ab690f0a3f6f8a0b7abd3f715881 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 11 Apr 2019 12:07:00 +0200 Subject: handshake: generate early exporter secret Signed-off-by: Daiki Ueno --- lib/ext/pre_shared_key.c | 12 ++++++++++++ lib/gnutls_int.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index 42f728286b..436a426a87 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -207,6 +207,18 @@ generate_early_secrets(gnutls_session_t session, session->key.proto.tls13.e_ckey, prf->output_size); + ret = _tls13_derive_secret2(prf, EARLY_EXPORTER_MASTER_LABEL, sizeof(EARLY_EXPORTER_MASTER_LABEL)-1, + session->internals.handshake_hash_buffer.data, + session->internals.handshake_hash_buffer_client_hello_len, + session->key.proto.tls13.temp_secret, + session->key.proto.tls13.ap_expkey); + if (ret < 0) + return gnutls_assert_val(ret); + + _gnutls_nss_keylog_write(session, "EARLY_EXPORTER_SECRET", + session->key.proto.tls13.ap_expkey, + prf->output_size); + return 0; } diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 72d6c066b6..53ca32b19c 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -537,7 +537,7 @@ struct gnutls_key_st { uint8_t hs_skey[MAX_HASH_SIZE]; /* server_hs_traffic_secret */ uint8_t ap_ckey[MAX_HASH_SIZE]; /* client_ap_traffic_secret */ uint8_t ap_skey[MAX_HASH_SIZE]; /* server_ap_traffic_secret */ - uint8_t ap_expkey[MAX_HASH_SIZE]; /* exporter_master_secret */ + uint8_t ap_expkey[MAX_HASH_SIZE]; /* {early_,}exporter_master_secret */ uint8_t ap_rms[MAX_HASH_SIZE]; /* resumption_master_secret */ } tls13; /* tls1.3 */ -- cgit v1.2.1 From 89c975cc25d4e7c5040a3f657b732dd1704bfb2b Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 11 Apr 2019 12:11:00 +0200 Subject: prf: add function to retrieve early keying material This adds a new function gnutls_prf_early, which shall be called in a handshake hook waiting for GNUTLS_HANDSHAKE_CLIENT_HELLO. The test needs to be run in a datefudge wrapper as the early secrets depend on the current time (through PSK). Signed-off-by: Daiki Ueno --- .gitignore | 1 + NEWS | 4 +- devel/libgnutls-latest-x86_64.abi | 1 + devel/symbols.last | 1 + doc/Makefile.am | 2 + doc/manpages/Makefile.am | 1 + lib/includes/gnutls/gnutls.h.in | 4 + lib/libgnutls.map | 1 + lib/prf.c | 116 +++++++--- tests/Makefile.am | 4 +- tests/tls13/prf-early.c | 464 ++++++++++++++++++++++++++++++++++++++ tests/tls13/prf-early.sh | 29 +++ 12 files changed, 599 insertions(+), 29 deletions(-) create mode 100644 tests/tls13/prf-early.c create mode 100755 tests/tls13/prf-early.sh diff --git a/.gitignore b/.gitignore index 6716e4c728..0e33b02d40 100644 --- a/.gitignore +++ b/.gitignore @@ -830,6 +830,7 @@ tests/tls13/post-handshake-with-cert-ticket tests/tls13/post-handshake-with-psk tests/tls13/post-handshake-without-cert tests/tls13/prf +tests/tls13/prf-early tests/tls13/psk-dumbfw tests/tls13/psk-ext tests/tls13/supported_versions diff --git a/NEWS b/NEWS index 0be3696576..0ada7c1a31 100644 --- a/NEWS +++ b/NEWS @@ -9,8 +9,10 @@ See the end for copying conditions. ** libgnutls: Added support for AES-XTS cipher (#354) +** libgnutls: Added new function to retrieve early keying material (#329) + ** API and ABI modifications: -No changes since last version. +gnutls_prf_early: Added * Version 3.6.7 (released 2019-03-27) diff --git a/devel/libgnutls-latest-x86_64.abi b/devel/libgnutls-latest-x86_64.abi index 9e23e0221c..c4659d954b 100644 --- a/devel/libgnutls-latest-x86_64.abi +++ b/devel/libgnutls-latest-x86_64.abi @@ -587,6 +587,7 @@ + diff --git a/devel/symbols.last b/devel/symbols.last index e5f0e01c69..d9dedea09c 100644 --- a/devel/symbols.last +++ b/devel/symbols.last @@ -553,6 +553,7 @@ gnutls_pkcs8_info@GNUTLS_3_4 gnutls_pkcs_schema_get_name@GNUTLS_3_4 gnutls_pkcs_schema_get_oid@GNUTLS_3_4 gnutls_prf@GNUTLS_3_4 +gnutls_prf_early@GNUTLS_3_6_6 gnutls_prf_raw@GNUTLS_3_4 gnutls_prf_rfc5705@GNUTLS_3_4 gnutls_priority_certificate_type_list2@GNUTLS_3_6_4 diff --git a/doc/Makefile.am b/doc/Makefile.am index 19982f5ad8..c60d0e46dd 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1547,6 +1547,8 @@ FUNCS += functions/gnutls_pk_to_sign FUNCS += functions/gnutls_pk_to_sign.short FUNCS += functions/gnutls_prf FUNCS += functions/gnutls_prf.short +FUNCS += functions/gnutls_prf_early +FUNCS += functions/gnutls_prf_early.short FUNCS += functions/gnutls_prf_raw FUNCS += functions/gnutls_prf_raw.short FUNCS += functions/gnutls_prf_rfc5705 diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am index 0aab479df2..bbf4220c09 100644 --- a/doc/manpages/Makefile.am +++ b/doc/manpages/Makefile.am @@ -575,6 +575,7 @@ APIMANS += gnutls_pk_get_oid.3 APIMANS += gnutls_pk_list.3 APIMANS += gnutls_pk_to_sign.3 APIMANS += gnutls_prf.3 +APIMANS += gnutls_prf_early.3 APIMANS += gnutls_prf_raw.3 APIMANS += gnutls_prf_rfc5705.3 APIMANS += gnutls_priority_certificate_type_list.3 diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 7fc96aaea1..0801203128 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1471,6 +1471,10 @@ int gnutls_prf_rfc5705(gnutls_session_t session, size_t label_size, const char *label, size_t context_size, const char *context, size_t outsize, char *out); +int gnutls_prf_early(gnutls_session_t session, + size_t label_size, const char *label, + size_t context_size, const char *context, + size_t outsize, char *out); int gnutls_prf_raw(gnutls_session_t session, size_t label_size, const char *label, diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 19c9f535f9..d10e22b20e 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1271,6 +1271,7 @@ GNUTLS_3_6_6 gnutls_certificate_set_rawpk_key_file; gnutls_pcert_import_rawpk; gnutls_pcert_import_rawpk_raw; + gnutls_prf_early; } GNUTLS_3_6_5; GNUTLS_FIPS140_3_4 { diff --git a/lib/prf.c b/lib/prf.c index 19e25cfa8d..6708b00db2 100644 --- a/lib/prf.c +++ b/lib/prf.c @@ -89,6 +89,36 @@ gnutls_prf_raw(gnutls_session_t session, return ret; } +static int +_tls13_derive_exporter(const mac_entry_st *prf, + gnutls_session_t session, + size_t label_size, const char *label, + size_t context_size, const char *context, + size_t outsize, char *out, + bool early) +{ + uint8_t secret[MAX_HASH_SIZE]; + uint8_t digest[MAX_HASH_SIZE]; + unsigned digest_size = prf->output_size; + int ret; + + ret = _tls13_derive_secret2(prf, label, label_size, NULL, 0, + session->key.proto.tls13.ap_expkey, + secret); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = gnutls_hash_fast((gnutls_digest_algorithm_t)prf->id, + context, context_size, digest); + if (ret < 0) + return gnutls_assert_val(ret); + + return _tls13_expand_secret2(prf, + EXPORTER_LABEL, sizeof(EXPORTER_LABEL)-1, + digest, digest_size, + secret, outsize, out); +} + /** * gnutls_prf_rfc5705: * @session: is a #gnutls_session_t type. @@ -99,8 +129,8 @@ gnutls_prf_raw(gnutls_session_t session, * @outsize: size of pre-allocated output buffer to hold the output. * @out: pre-allocated buffer to hold the generated data. * - * Exports keyring material from TLS/DTLS session to an application, - * as specified in RFC5705. + * Exports keying material from TLS/DTLS session to an application, as + * specified in RFC5705. * * In the TLS versions prior to 1.3, it applies the TLS * Pseudo-Random-Function (PRF) on the master secret and the provided @@ -136,30 +166,12 @@ gnutls_prf_rfc5705(gnutls_session_t session, int ret; if (vers && vers->tls13_sem) { - uint8_t secret[MAX_HASH_SIZE]; - uint8_t digest[MAX_HASH_SIZE]; - unsigned digest_size = session->security_parameters.prf->output_size; - - /* exporter_master_secret might not be set, when - * handshake is in progress */ - if (session->internals.handshake_in_progress) { - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; - } - - ret = _tls13_derive_secret(session, label, label_size, NULL, 0, - session->key.proto.tls13.ap_expkey, secret); - if (ret < 0) - return gnutls_assert_val(ret); - - ret = gnutls_hash_fast((gnutls_digest_algorithm_t)session->security_parameters.prf->id, - context, context_size, digest); - if (ret < 0) - return gnutls_assert_val(ret); - - ret = _tls13_expand_secret(session, EXPORTER_LABEL, sizeof(EXPORTER_LABEL)-1, - digest, digest_size, - secret, outsize, out); + ret = _tls13_derive_exporter(session->security_parameters.prf, + session, + label_size, label, + context_size, context, + outsize, out, + 0); } else { char *pctx = NULL; @@ -189,6 +201,58 @@ gnutls_prf_rfc5705(gnutls_session_t session, return ret; } +/** + * gnutls_prf_early: + * @session: is a #gnutls_session_t type. + * @label_size: length of the @label variable. + * @label: label used in PRF computation, typically a short string. + * @context_size: length of the @extra variable. + * @context: optional extra data to seed the PRF with. + * @outsize: size of pre-allocated output buffer to hold the output. + * @out: pre-allocated buffer to hold the generated data. + * + * This function is similar to gnutls_prf_rfc5705(), but only works in + * TLS 1.3 or later to export early keying material. + * + * Note that the keying material is only available after the + * ClientHello message is processed and before the application traffic + * keys are established. Therefore this function shall be called in a + * handshake hook function for %GNUTLS_HANDSHAKE_CLIENT_HELLO. + * + * The @label variable usually contains a string denoting the purpose + * for the generated data. + * + * The @context variable can be used to add more data to the seed, after + * the random variables. It can be used to make sure the + * generated output is strongly connected to some additional data + * (e.g., a string used in user authentication). + * + * The output is placed in @out, which must be pre-allocated. + * + * Note that, to provide the RFC5705 context, the @context variable + * must be non-null. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + * + * Since: 3.6.6 + **/ +int +gnutls_prf_early(gnutls_session_t session, + size_t label_size, const char *label, + size_t context_size, const char *context, + size_t outsize, char *out) +{ + if (session->internals.initial_negotiation_completed || + session->key.binders[0].prf == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + return _tls13_derive_exporter(session->key.binders[0].prf, session, + label_size, label, + context_size, context, + outsize, out, + 1); +} + /** * gnutls_prf: * @session: is a #gnutls_session_t type. diff --git a/tests/Makefile.am b/tests/Makefile.am index 96e10bfc5b..3917967988 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -104,7 +104,7 @@ noinst_LTLIBRARIES = libutils.la libutils_la_SOURCES = utils.h utils.c seccomp.c utils-adv.c libutils_la_LIBADD = ../lib/libgnutls.la -indirect_tests = +indirect_tests = tls13/prf-early ctests = tls13/supported_versions tls13/tls12-no-tls13-exts \ tls13/post-handshake-with-cert tls13/post-handshake-without-cert \ tls13/cookie tls13/key_share tls13/prf tls13/post-handshake-with-cert-ticket \ @@ -458,7 +458,7 @@ tls13_post_handshake_with_cert_pkcs11_LDADD = $(LDADD) $(LIBDL) endif endif -dist_check_SCRIPTS = rfc2253-escape-test rsa-md5-collision/rsa-md5-collision.sh systemkey.sh +dist_check_SCRIPTS = rfc2253-escape-test rsa-md5-collision/rsa-md5-collision.sh systemkey.sh tls13/prf-early.sh if !WINDOWS diff --git a/tests/tls13/prf-early.c b/tests/tls13/prf-early.c new file mode 100644 index 0000000000..758f78efe7 --- /dev/null +++ b/tests/tls13/prf-early.c @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2015-2019 Red Hat, Inc. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#if !defined(__linux__) || !defined(__GNUC__) + +int main(int argc, char **argv) +{ + exit(77); +} + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cert-common.h" +#include "utils.h" +#include "virt-time.h" + +static void terminate(void); + +#define SESSIONS 2 +#define MAX_BUF 5*1024 +#define MSG "Hello TLS" + +/* This program tests whether the gnutls_prf() works as + * expected. + */ + +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); +} + +/* These are global */ +static pid_t child; + +static const +gnutls_datum_t hrnd = {(void*)"\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32}; +static const +gnutls_datum_t hsrnd = {(void*)"\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32}; + +static int gnutls_rnd_works; + +int __attribute__ ((visibility ("protected"))) +gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len) +{ + gnutls_rnd_works = 1; + + memset(data, 0xff, len); + + /* Flip the first byte to avoid infinite loop in the RSA + * blinding code of Nettle */ + if (len > 0) + memset(data, 0x0, 1); + return 0; +} + +static gnutls_datum_t session_ticket_key = { NULL, 0 }; + +static void dump(const char *name, const uint8_t *data, unsigned data_size) +{ + unsigned i; + + fprintf(stderr, "%s", name); + for (i=0;i 0) { + gnutls_session_set_data(session, session_data.data, + session_data.size); + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_CLIENT_HELLO, + GNUTLS_HOOK_POST, + handshake_callback); + } + + /* Perform the TLS handshake + */ + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret < 0) { + fail("client: Handshake failed: %s\n", strerror(ret)); + exit(1); + } else { + if (debug) + success("client: Handshake was completed\n"); + } + + if (debug) + success("client: TLS version is: %s\n", + gnutls_protocol_get_name + (gnutls_protocol_get_version(session))); + + ret = gnutls_cipher_get(session); + if (ret != GNUTLS_CIPHER_AES_256_GCM) { + fprintf(stderr, "negotiated unexpected cipher: %s\n", gnutls_cipher_get_name(ret)); + exit(1); + } + + ret = gnutls_mac_get(session); + if (ret != GNUTLS_MAC_AEAD) { + fprintf(stderr, "negotiated unexpected mac: %s\n", gnutls_mac_get_name(ret)); + exit(1); + } + + if (t == 0) { + /* get the session data size */ + ret = + gnutls_session_get_data2(session, + &session_data); + if (ret < 0) + fail("Getting resume data failed\n"); + + if (handshake_callback_called != 0) + fail("client: handshake callback is called\n"); + } else { + if (handshake_callback_called != t) + fail("client: handshake callback is not called\n"); + } + + gnutls_record_send(session, MSG, strlen(MSG)); + + do { + ret = gnutls_record_recv(session, buffer, MAX_BUF); + } while (ret == GNUTLS_E_AGAIN); + if (ret == 0) { + if (debug) + success + ("client: Peer has closed the TLS connection\n"); + } else if (ret < 0) { + fail("client: Error: %s\n", gnutls_strerror(ret)); + } + + if (debug) { + printf("- Received %d bytes: ", ret); + for (ii = 0; ii < ret; ii++) { + fputc(buffer[ii], stdout); + } + fputs("\n", stdout); + } + + gnutls_bye(session, GNUTLS_SHUT_WR); + + close(sds[t]); + + gnutls_deinit(session); + } + + gnutls_free(session_data.data); + gnutls_certificate_free_credentials(clientx509cred); + + gnutls_global_deinit(); +} + +static void terminate(void) +{ + int status = 0; + + kill(child, SIGTERM); + wait(&status); + exit(1); +} + +static void server(int sds[]) +{ + int ret; + gnutls_session_t session; + gnutls_certificate_credentials_t serverx509cred; + int t; + char buffer[MAX_BUF + 1]; + + /* this must be called once in the program + */ + global_init(); + + virt_time_init(); + + if (debug) { + gnutls_global_set_log_function(server_log_func); + gnutls_global_set_log_level(4711); + } + + gnutls_certificate_allocate_credentials(&serverx509cred); + + gnutls_session_ticket_key_generate(&session_ticket_key); + + for (t = 0; t < SESSIONS; t++) { + gnutls_init(&session, GNUTLS_SERVER); + + gnutls_session_ticket_enable_server(session, + &session_ticket_key); + + /* avoid calling all the priority functions, since the defaults + * are adequate. + */ + ret = gnutls_priority_set_direct(session, + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-KX-ALL:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA384:-GROUP-ALL:+GROUP-SECP256R1", NULL); + if (ret < 0) { + fail("server: priority set failed (%s)\n\n", + gnutls_strerror(ret)); + terminate(); + } + + gnutls_certificate_set_x509_key_mem(serverx509cred, + &server_cert, &server_key, + GNUTLS_X509_FMT_PEM); + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, + serverx509cred); + + gnutls_handshake_set_random(session, &hsrnd); + gnutls_transport_set_int(session, sds[t]); + + if (t > 0) { + if (!gnutls_rnd_works) { + fprintf(stderr, "gnutls_rnd() could not be overridden, skipping prf checks see #584\n"); + exit(77); + } else { + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_CLIENT_HELLO, + GNUTLS_HOOK_POST, + handshake_callback); + } + } + + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + if (ret < 0) { + close(sds[t]); + gnutls_deinit(session); + fail("server: Handshake has failed (%s)\n\n", + gnutls_strerror(ret)); + terminate(); + } + if (debug) + success("server: Handshake was completed\n"); + + if (debug) + success("server: TLS version is: %s\n", + gnutls_protocol_get_name + (gnutls_protocol_get_version(session))); + + if (t == 0) { + if (handshake_callback_called != 0) + fail("server: handshake callback is called\n"); + } else { + if (handshake_callback_called != t) + fail("server: handshake callback is not called\n"); + } + + for (;;) { + memset(buffer, 0, MAX_BUF + 1); + ret = gnutls_record_recv(session, buffer, MAX_BUF); + + if (ret == 0) { + if (debug) + success + ("server: Peer has closed the GnuTLS connection\n"); + break; + } else if (ret < 0) { + kill(child, SIGTERM); + fail("server: Received corrupted data(%d). Closing...\n", ret); + break; + } else if (ret > 0) { + /* echo data back to the client + */ + gnutls_record_send(session, buffer, + strlen(buffer)); + } + } + + /* do not wait for the peer to close the connection. + */ + gnutls_bye(session, GNUTLS_SHUT_WR); + + close(sds[t]); + gnutls_deinit(session); + } + + gnutls_certificate_free_credentials(serverx509cred); + + gnutls_free(session_ticket_key.data); + session_ticket_key.data = NULL; + + gnutls_global_deinit(); + + if (debug) + success("server: finished\n"); +} + +void doit(void) +{ + int client_sds[SESSIONS], server_sds[SESSIONS]; + int i; + int ret; + + signal(SIGPIPE, SIG_IGN); + + for (i = 0; i < SESSIONS; i++) { + int sockets[2]; + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); + if (ret == -1) { + perror("socketpair"); + fail("socketpair failed\n"); + return; + } + + server_sds[i] = sockets[0]; + client_sds[i] = sockets[1]; + } + + child = fork(); + if (child < 0) { + perror("fork"); + fail("fork"); + exit(1); + } + + if (child) { + int status = 0; + /* parent */ + + for (i = 0; i < SESSIONS; i++) + close(client_sds[i]); + server(server_sds); + wait(&status); + check_wait_status(status); + } else { + for (i = 0; i < SESSIONS; i++) + close(server_sds[i]); + client(client_sds); + exit(0); + } +} + +#endif /* _WIN32 */ diff --git a/tests/tls13/prf-early.sh b/tests/tls13/prf-early.sh new file mode 100755 index 0000000000..5b5ff0c33b --- /dev/null +++ b/tests/tls13/prf-early.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# Copyright (C) 2019 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 +# + +srcdir="${srcdir:-.}" +builddir="${builddir:-.}" + +. "${srcdir}/scripts/common.sh" + +check_for_datefudge + +datefudge 2019-04-12 "${builddir}/tls13/prf-early" "$@" +exit $? -- cgit v1.2.1 From 96a5dd4fa8e9c7b1d45fe934ec7829d494dbd372 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 11 Apr 2019 14:35:32 +0200 Subject: serv, cli: add --keymatexport option This adds --keymatexport and --keymatexportsize options to both gnutls-serv and gnutls-cli. Those would be useful for testing interoperability with other implementations. Signed-off-by: Daiki Ueno --- src/cli-args.def | 14 +++++++++++++ src/cli.c | 5 +++++ src/common.c | 37 +++++++++++++++++++++++++++++++++ src/common.h | 1 + src/serv-args.def | 14 +++++++++++++ src/serv.c | 7 +++++++ tests/scripts/common.sh | 4 ++-- tests/suite/testcompat-tls13-openssl.sh | 22 ++++++++++++++++++++ 8 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/cli-args.def b/src/cli-args.def index 518a97466e..621de61f3c 100644 --- a/src/cli-args.def +++ b/src/cli-args.def @@ -423,6 +423,20 @@ flag = { doc = ""; }; +flag = { + name = keymatexport; + arg-type = string; + descrip = "Label used for exporting keying material"; + doc = ""; +}; + +flag = { + name = keymatexportsize; + arg-type = number; + descrip = "Size of the exported keying material"; + doc = ""; +}; + doc-section = { ds-type = 'SEE ALSO'; // or anything else ds-format = 'texi'; // or texi or mdoc format diff --git a/src/cli.c b/src/cli.c index a770c74bcc..691eb98c54 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1659,6 +1659,11 @@ int do_handshake(socket_st * socket) if (ret == 0) { /* print some information */ print_info(socket->session, verbose, HAVE_OPT(X509CERTFILE)?P_WAIT_FOR_CERT:0); + if (HAVE_OPT(KEYMATEXPORT)) + print_key_material(socket->session, + OPT_ARG(KEYMATEXPORT), + HAVE_OPT(KEYMATEXPORTSIZE) ? + OPT_VALUE_KEYMATEXPORTSIZE : 20); socket->secure = 1; } else { gnutls_alert_send_appropriate(socket->session, ret); diff --git a/src/common.c b/src/common.c index 28452fd589..664513c9ad 100644 --- a/src/common.c +++ b/src/common.c @@ -876,6 +876,43 @@ void print_list(const char *priorities, int verbose) } } +void +print_key_material(gnutls_session_t session, const char *label, size_t size) +{ + gnutls_datum_t bin = { NULL, 0 }, hex = { NULL, 0 }; + int ret; + + bin.data = gnutls_malloc(size); + if (!bin.data) { + fprintf(stderr, "Error in gnutls_malloc: %s\n", + gnutls_strerror(GNUTLS_E_MEMORY_ERROR)); + goto out; + } + + bin.size = size; + + ret = gnutls_prf_rfc5705(session, strlen(label), label, + 0, NULL, size, (char *)bin.data); + if (ret < 0) { + fprintf(stderr, "Error in gnutls_prf_rfc5705: %s\n", + gnutls_strerror(ret)); + goto out; + } + + ret = gnutls_hex_encode2(&bin, &hex); + if (ret < 0) { + fprintf(stderr, "Error in hex encoding: %s\n", + gnutls_strerror(ret)); + goto out; + } + log_msg(stdout, "- Key material: %s\n", hex.data); + fflush(stdout); + + out: + gnutls_free(bin.data); + gnutls_free(hex.data); +} + int check_command(gnutls_session_t session, const char *str, unsigned no_cli_cert) { size_t len = strnlen(str, 128); diff --git a/src/common.h b/src/common.h index 588ee82bf1..91b9ed04f2 100644 --- a/src/common.h +++ b/src/common.h @@ -61,6 +61,7 @@ extern const char str_unknown[]; #define P_WAIT_FOR_CERT (1<<1) int print_info(gnutls_session_t state, int verbose, int flags); void print_cert_info(gnutls_session_t, int flag, int print_cert); +void print_key_material(gnutls_session_t, const char *label, size_t size); int log_msg(FILE *file, const char *message, ...) __attribute__((format(printf, 2, 3))); void log_set(FILE *file); diff --git a/src/serv-args.def b/src/serv-args.def index ac056f37dc..4be3d9f298 100644 --- a/src/serv-args.def +++ b/src/serv-args.def @@ -318,6 +318,20 @@ flag = { doc = "This will override the default options in /etc/gnutls/pkcs11.conf"; }; +flag = { + name = keymatexport; + arg-type = string; + descrip = "Label used for exporting keying material"; + doc = ""; +}; + +flag = { + name = keymatexportsize; + arg-type = number; + descrip = "Size of the exported keying material"; + doc = ""; +}; + doc-section = { ds-type = 'SEE ALSO'; // or anything else ds-format = 'texi'; // or texi or mdoc format diff --git a/src/serv.c b/src/serv.c index bc490ee7da..0866bff903 100644 --- a/src/serv.c +++ b/src/serv.c @@ -1331,6 +1331,13 @@ static void retry_handshake(listener_item *j) #endif print_info(j->tls_session, verbose, verbose); + + if (HAVE_OPT(KEYMATEXPORT)) + print_key_material(j->tls_session, + OPT_ARG(KEYMATEXPORT), + HAVE_OPT(KEYMATEXPORTSIZE) ? + OPT_VALUE_KEYMATEXPORTSIZE : + 20); } j->close_ok = 1; diff --git a/tests/scripts/common.sh b/tests/scripts/common.sh index 1cce09d04e..a714bcd608 100644 --- a/tests/scripts/common.sh +++ b/tests/scripts/common.sh @@ -158,7 +158,7 @@ launch_server() { shift wait_for_free_port ${PORT} - ${SERV} ${DEBUG} -p "${PORT}" $* >/dev/null & + ${SERV} ${DEBUG} -p "${PORT}" $* >${LOGFILE-/dev/null} & } launch_pkcs11_server() { @@ -177,7 +177,7 @@ launch_bare_server() { shift wait_for_free_port ${PORT} - ${SERV} $* >/dev/null & + ${SERV} $* >${LOGFILE-/dev/null} & } wait_server() { diff --git a/tests/suite/testcompat-tls13-openssl.sh b/tests/suite/testcompat-tls13-openssl.sh index 27ca3826e3..6d17941b8e 100755 --- a/tests/suite/testcompat-tls13-openssl.sh +++ b/tests/suite/testcompat-tls13-openssl.sh @@ -264,6 +264,28 @@ run_client_suite() { kill ${PID} wait + # Try exporting keying material + echo_cmd "${PREFIX}Checking TLS 1.3 to export keying material..." + testdir=`create_testdir tls13-openssl-keymatexport` + eval "${GETPORT}" + LOGFILE="${testdir}/server.out" + launch_bare_server $$ s_server -accept "${PORT}" -keyform pem -certform pem ${OPENSSL_DH_PARAMS_OPT} -key "${RSA_KEY}" -cert "${RSA_CERT}" -CAfile "${CA_CERT}" -keymatexport label -keymatexportlen 20 + unset LOGFILE + PID=$! + wait_server ${PID} + + ${VALGRIND} "${CLI}" ${DEBUG} -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.3:+GROUP-ALL${ADD}" --keymatexport label --keymatexportsize 20| tee "${testdir}/client.out" >> ${OUTPUT} + grep '^- Key material: ' "${testdir}/client.out" | \ + sed -e 's/^.*: //' -e 'y/abcdef/ABCDEF/' > "${testdir}/client.key" || \ + fail ${PID} "Failed" + grep '^ Keying material: ' "${testdir}/server.out" | \ + sed -e 's/^.*: //' -e 'y/abcdef/ABCDEF/' > "${testdir}/server.key" || \ + fail ${PID} "Failed" + diff "${testdir}/client.key" "${testdir}/server.key" || \ + fail ${PID} "Failed" + kill ${PID} + wait + rm -rf "${testdir}" } -- cgit v1.2.1 From 54690004aea7fd6bc07aeee919ab0848bf4549e6 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 19 Apr 2019 08:12:56 +0200 Subject: tests: make datefudge check robuster When checking datefudge availability under cross-compiling environment with a binfmt wrapper, it is not sufficient to check against the host executable. This instead uses a test executable compiled for the target architecture. Signed-off-by: Daiki Ueno --- .gitignore | 1 + tests/Makefile.am | 4 ++++ tests/datefudge-check.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/scripts/common.sh | 2 +- 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/datefudge-check.c diff --git a/.gitignore b/.gitignore index 0e33b02d40..f7983c159b 100644 --- a/.gitignore +++ b/.gitignore @@ -369,6 +369,7 @@ tests/cve-2009-1415 tests/cve-2009-1416 tests/dane tests/dane-strcodes +tests/datefudge-check tests/dh-params tests/dhepskself tests/dhex509self diff --git a/tests/Makefile.am b/tests/Makefile.am index 3917967988..940e1ba605 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -527,6 +527,10 @@ sanity_cpp_CXXFLAGS = $(AM_CPPFLAGS) \ endif endif +if !WINDOWS +indirect_tests += datefudge-check +endif + check_PROGRAMS = $(cpptests) $(ctests) $(indirect_tests) TESTS = $(cpptests) $(ctests) $(dist_check_SCRIPTS) diff --git a/tests/datefudge-check.c b/tests/datefudge-check.c new file mode 100644 index 0000000000..f2d896d622 --- /dev/null +++ b/tests/datefudge-check.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 Red Hat + * + * Author: 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +int +main (void) +{ + char outstr[200]; + time_t t; + struct tm *tmp; + + t = time(NULL); + tmp = localtime(&t); + if (tmp == NULL) { + perror("localtime"); + exit(EXIT_FAILURE); + } + + if (strftime(outstr, sizeof(outstr), "%s", tmp) == 0) { + fprintf(stderr, "strftime returned 0"); + exit(EXIT_FAILURE); + } + + puts(outstr); + exit(EXIT_SUCCESS); +} diff --git a/tests/scripts/common.sh b/tests/scripts/common.sh index a714bcd608..d34915e1d7 100644 --- a/tests/scripts/common.sh +++ b/tests/scripts/common.sh @@ -76,7 +76,7 @@ check_for_datefudge() { return fi - TSTAMP=`datefudge -s "2006-09-23" date -u +%s || true` + TSTAMP=`datefudge -s "2006-09-23" "${top_builddir}/tests/datefudge-check" || true` if test "$TSTAMP" != "1158969600" || test "$WINDOWS" = 1; then echo $TSTAMP echo "You need datefudge to run this test" -- cgit v1.2.1 From 9b8c9835e3767e64383f935ead50cc743acc9569 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 19 Apr 2019 16:59:31 +0200 Subject: tls13/session_ticket: avoid UB regarding 64-bit time encoding On 32-bit platform, struct timespec.tv_sec can be signed 32-bit and thus right shifting 32 could be an undefined behavior. Signed-off-by: Daiki Ueno --- lib/tls13/session_ticket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c index b8371c5005..f0c4a0378a 100644 --- a/lib/tls13/session_ticket.c +++ b/lib/tls13/session_ticket.c @@ -79,7 +79,7 @@ pack_ticket(gnutls_session_t session, tls13_ticket_st *ticket, gnutls_datum_t *p memcpy(p, state.data, state.size); p += state.size; - _gnutls_write_uint32(ticket->creation_time.tv_sec >> 32, p); + _gnutls_write_uint32((uint64_t) ticket->creation_time.tv_sec >> 32, p); p += 4; _gnutls_write_uint32(ticket->creation_time.tv_sec & 0xFFFFFFFF, p); p += 4; @@ -106,6 +106,7 @@ unpack_ticket(gnutls_session_t session, gnutls_datum_t *packed, tls13_ticket_st const mac_entry_st *prf; uint8_t *p; ssize_t len; + uint64_t v; int ret; if (unlikely(packed == NULL || data == NULL)) @@ -168,10 +169,9 @@ unpack_ticket(gnutls_session_t session, gnutls_datum_t *packed, tls13_ticket_st p += state.size; DECR_LEN(len, 12); - creation_time.tv_sec = _gnutls_read_uint32(p); + v = _gnutls_read_uint32(p); p += 4; - creation_time.tv_sec <<= 32; - creation_time.tv_sec |= _gnutls_read_uint32(p); + creation_time.tv_sec = (v << 32) | _gnutls_read_uint32(p); p += 4; creation_time.tv_nsec = _gnutls_read_uint32(p); -- cgit v1.2.1 From 616edc7778a7364e28f2519d10c2287bc69c7095 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 19 Apr 2019 22:04:24 +0200 Subject: tls13/session_ticket: use the same ticket_age_add regardless of endianness Signed-off-by: Daiki Ueno --- lib/tls13/session_ticket.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c index f0c4a0378a..146aee9b17 100644 --- a/lib/tls13/session_ticket.c +++ b/lib/tls13/session_ticket.c @@ -223,7 +223,11 @@ generate_session_ticket(gnutls_session_t session, tls13_ticket_st *ticket) if ((ret = gnutls_rnd(GNUTLS_RND_NONCE, &ticket->age_add, sizeof(uint32_t))) < 0) return gnutls_assert_val(ret); - + /* This is merely to produce the same binder value on + * different endian architectures. */ +#ifdef WORDS_BIGENDIAN + ticket->age_add = bswap_32(ticket->age_add); +#endif ticket->prf = session->security_parameters.prf; -- cgit v1.2.1