From f41df13ec8b77414ff8e682d8234c089bd24e7e9 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 7 May 2018 09:52:32 +0200 Subject: handshake: do not send TLS extensions under DTLS and vice versa That is, introduce the notion of TLS-only and DTLS-only extensions, providing a framework to prevent sending extensions which are registered for example for TLS 1.3, under DTLS and vice versa. Resolves #440 Signed-off-by: Nikos Mavrogiannopoulos --- lib/ext/alpn.c | 5 +- lib/ext/cookie.c | 4 +- lib/ext/dumbfw.c | 3 +- lib/ext/ecc.c | 8 +- lib/ext/etm.c | 4 +- lib/ext/ext_master_secret.c | 4 +- lib/ext/heartbeat.c | 4 +- lib/ext/key_share.c | 4 +- lib/ext/max_record.c | 4 +- lib/ext/post_handshake.c | 3 +- lib/ext/pre_shared_key.c | 2 +- lib/ext/psk_ke_modes.c | 2 +- lib/ext/safe_renegotiation.c | 4 +- lib/ext/server_name.c | 4 +- lib/ext/session_ticket.c | 4 +- lib/ext/signature.c | 3 +- lib/ext/srp.c | 3 +- lib/ext/srtp.c | 4 +- lib/ext/status_request.c | 3 +- lib/ext/supported_versions.c | 5 +- lib/hello_ext.c | 73 ++++++++-- lib/hello_ext.h | 12 +- lib/includes/gnutls/gnutls.h.in | 6 +- tests/Makefile.am | 2 +- tests/tls-ext-not-in-dtls.c | 288 ++++++++++++++++++++++++++++++++++++++++ 25 files changed, 401 insertions(+), 57 deletions(-) create mode 100644 tests/tls-ext-not-in-dtls.c diff --git a/lib/ext/alpn.c b/lib/ext/alpn.c index bac3ccb68f..24e7153a59 100644 --- a/lib/ext/alpn.c +++ b/lib/ext/alpn.c @@ -40,8 +40,9 @@ const hello_ext_entry_st ext_mod_alpn = { .gid = GNUTLS_EXTENSION_ALPN, /* this extension must be parsed even on resumption */ .parse_type = GNUTLS_EXT_MANDATORY, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_EE|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | + GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_EE | + GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .recv_func = _gnutls_alpn_recv_params, .send_func = _gnutls_alpn_send_params, .deinit_func = _gnutls_alpn_deinit_data, diff --git a/lib/ext/cookie.c b/lib/ext/cookie.c index eff4f1890d..1da7b0382f 100644 --- a/lib/ext/cookie.c +++ b/lib/ext/cookie.c @@ -39,9 +39,9 @@ const hello_ext_entry_st ext_mod_cookie = { .name = "Cookie", .tls_id = 44, .gid = GNUTLS_EXTENSION_COOKIE, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_HRR|GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_HRR | GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST, .parse_type = GNUTLS_EXT_MANDATORY, /* force parsing prior to EXT_TLS extensions */ - .recv_func = cookie_recv_params, .send_func = cookie_send_params, .pack_func = NULL, diff --git a/lib/ext/dumbfw.c b/lib/ext/dumbfw.c index 4e56192337..adb3a18381 100644 --- a/lib/ext/dumbfw.c +++ b/lib/ext/dumbfw.c @@ -41,8 +41,7 @@ const hello_ext_entry_st ext_mod_dumbfw = { .tls_id = 21, .gid = GNUTLS_EXTENSION_DUMBFW, .parse_type = GNUTLS_EXT_APPLICATION, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO, .recv_func = NULL, .send_func = _gnutls_dumbfw_send_params, .pack_func = NULL, diff --git a/lib/ext/ecc.c b/lib/ext/ecc.c index 50cd862211..164b6150db 100644 --- a/lib/ext/ecc.c +++ b/lib/ext/ecc.c @@ -54,8 +54,8 @@ const hello_ext_entry_st ext_mod_supported_ecc = { .tls_id = 10, .gid = GNUTLS_EXTENSION_SUPPORTED_ECC, .parse_type = GNUTLS_EXT_TLS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_EE|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .recv_func = _gnutls_supported_ecc_recv_params, .send_func = _gnutls_supported_ecc_send_params, .pack_func = NULL, @@ -69,8 +69,8 @@ const hello_ext_entry_st ext_mod_supported_ecc_pf = { .tls_id = 11, .gid = GNUTLS_EXTENSION_SUPPORTED_ECC_PF, .parse_type = GNUTLS_EXT_TLS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | + GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .recv_func = _gnutls_supported_ecc_pf_recv_params, .send_func = _gnutls_supported_ecc_pf_send_params, .pack_func = NULL, diff --git a/lib/ext/etm.c b/lib/ext/etm.c index ca4638b7e9..ad542771d1 100644 --- a/lib/ext/etm.c +++ b/lib/ext/etm.c @@ -40,8 +40,8 @@ const hello_ext_entry_st ext_mod_etm = { .tls_id = 22, .gid = GNUTLS_EXTENSION_ETM, .parse_type = GNUTLS_EXT_MANDATORY, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .recv_func = _gnutls_ext_etm_recv_params, .send_func = _gnutls_ext_etm_send_params, .pack_func = NULL, diff --git a/lib/ext/ext_master_secret.c b/lib/ext/ext_master_secret.c index 16feac4ea0..c9ee5cfe8c 100644 --- a/lib/ext/ext_master_secret.c +++ b/lib/ext/ext_master_secret.c @@ -40,8 +40,8 @@ const hello_ext_entry_st ext_mod_ext_master_secret = { .tls_id = 23, .gid = GNUTLS_EXTENSION_EXT_MASTER_SECRET, .parse_type = GNUTLS_EXT_MANDATORY, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS|GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .recv_func = _gnutls_ext_master_secret_recv_params, .send_func = _gnutls_ext_master_secret_send_params, .pack_func = NULL, diff --git a/lib/ext/heartbeat.c b/lib/ext/heartbeat.c index 0772ec5e1f..13b7cf2e84 100644 --- a/lib/ext/heartbeat.c +++ b/lib/ext/heartbeat.c @@ -527,8 +527,8 @@ const hello_ext_entry_st ext_mod_heartbeat = { .tls_id = 15, .gid = GNUTLS_EXTENSION_HEARTBEAT, .parse_type = GNUTLS_EXT_TLS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_EE|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .recv_func = _gnutls_heartbeat_recv_params, .send_func = _gnutls_heartbeat_send_params, .pack_func = _gnutls_heartbeat_pack, diff --git a/lib/ext/key_share.c b/lib/ext/key_share.c index c46f0c733e..5802e47679 100644 --- a/lib/ext/key_share.c +++ b/lib/ext/key_share.c @@ -48,8 +48,8 @@ const hello_ext_entry_st ext_mod_key_share = { .tls_id = 51, .gid = GNUTLS_EXTENSION_KEY_SHARE, .parse_type = _GNUTLS_EXT_TLS_POST_CS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO|GNUTLS_EXT_FLAG_HRR, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | + GNUTLS_EXT_FLAG_HRR, .recv_func = key_share_recv_params, .send_func = key_share_send_params, .pack_func = NULL, diff --git a/lib/ext/max_record.c b/lib/ext/max_record.c index 9fbd94e72d..8314d16193 100644 --- a/lib/ext/max_record.c +++ b/lib/ext/max_record.c @@ -52,8 +52,8 @@ const hello_ext_entry_st ext_mod_max_record_size = { .tls_id = 1, .gid = GNUTLS_EXTENSION_MAX_RECORD_SIZE, .parse_type = GNUTLS_EXT_TLS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_EE|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .recv_func = _gnutls_max_record_recv_params, .send_func = _gnutls_max_record_send_params, .pack_func = _gnutls_max_record_pack, diff --git a/lib/ext/post_handshake.c b/lib/ext/post_handshake.c index 97b94afef8..ff9df4b9a9 100644 --- a/lib/ext/post_handshake.c +++ b/lib/ext/post_handshake.c @@ -41,8 +41,7 @@ const hello_ext_entry_st ext_mod_post_handshake = { .tls_id = 49, .gid = GNUTLS_EXTENSION_POST_HANDSHAKE, .parse_type = GNUTLS_EXT_TLS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO, .recv_func = _gnutls_post_handshake_recv_params, .send_func = _gnutls_post_handshake_send_params, .pack_func = NULL, diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c index 21dd6069c7..0d3468c40d 100644 --- a/lib/ext/pre_shared_key.c +++ b/lib/ext/pre_shared_key.c @@ -498,7 +498,7 @@ const hello_ext_entry_st ext_pre_shared_key = { .tls_id = 41, .gid = GNUTLS_EXTENSION_PRE_SHARED_KEY, .parse_type = GNUTLS_EXT_TLS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO, .send_func = _gnutls_psk_send_params, .recv_func = _gnutls_psk_recv_params }; diff --git a/lib/ext/psk_ke_modes.c b/lib/ext/psk_ke_modes.c index 4427f552c9..af136fd3ca 100644 --- a/lib/ext/psk_ke_modes.c +++ b/lib/ext/psk_ke_modes.c @@ -184,7 +184,7 @@ const hello_ext_entry_st ext_psk_ke_modes = { .tls_id = 45, .gid = GNUTLS_EXTENSION_PSK_KE_MODES, .parse_type = GNUTLS_EXT_TLS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO, .send_func = psk_ke_modes_send_params, .recv_func = psk_ke_modes_recv_params }; diff --git a/lib/ext/safe_renegotiation.c b/lib/ext/safe_renegotiation.c index 7fb80b4dc4..26d25165bc 100644 --- a/lib/ext/safe_renegotiation.c +++ b/lib/ext/safe_renegotiation.c @@ -35,9 +35,9 @@ const hello_ext_entry_st ext_mod_sr = { .name = "Safe Renegotiation", .tls_id = 65281, .gid = GNUTLS_EXTENSION_SAFE_RENEGOTIATION, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .parse_type = GNUTLS_EXT_MANDATORY, - .recv_func = _gnutls_sr_recv_params, .send_func = _gnutls_sr_send_params, .pack_func = NULL, diff --git a/lib/ext/server_name.c b/lib/ext/server_name.c index e640e57a52..1f9f3814f1 100644 --- a/lib/ext/server_name.c +++ b/lib/ext/server_name.c @@ -44,9 +44,9 @@ const hello_ext_entry_st ext_mod_server_name = { .name = "Server Name Indication", .tls_id = 0, .gid = GNUTLS_EXTENSION_SERVER_NAME, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_EE|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .parse_type = GNUTLS_EXT_MANDATORY, - .recv_func = _gnutls_server_name_recv_params, .send_func = _gnutls_server_name_send_params, .pack_func = _gnutls_hello_ext_default_pack, diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c index 7e0a0b2f8d..69dc138a42 100644 --- a/lib/ext/session_ticket.c +++ b/lib/ext/session_ticket.c @@ -63,9 +63,9 @@ const hello_ext_entry_st ext_mod_session_ticket = { .name = "Session Ticket", .tls_id = 35, .gid = GNUTLS_EXTENSION_SESSION_TICKET, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .parse_type = GNUTLS_EXT_TLS, - .recv_func = session_ticket_recv_params, .send_func = session_ticket_send_params, .pack_func = session_ticket_pack, diff --git a/lib/ext/signature.c b/lib/ext/signature.c index 7bf2761fdf..a0e6e20b89 100644 --- a/lib/ext/signature.c +++ b/lib/ext/signature.c @@ -53,9 +53,8 @@ const hello_ext_entry_st ext_mod_sig = { .name = "Signature Algorithms", .tls_id = 13, .gid = GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO, .parse_type = GNUTLS_EXT_TLS, - .recv_func = _gnutls_signature_algorithm_recv_params, .send_func = _gnutls_signature_algorithm_send_params, .pack_func = signature_algorithms_pack, diff --git a/lib/ext/srp.c b/lib/ext/srp.c index 2c1ab90d1a..73c7936655 100644 --- a/lib/ext/srp.c +++ b/lib/ext/srp.c @@ -47,8 +47,7 @@ const hello_ext_entry_st ext_mod_srp = { .tls_id = 12, .gid = GNUTLS_EXTENSION_SRP, .parse_type = GNUTLS_EXT_TLS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO, - + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO, .recv_func = _gnutls_srp_recv_params, .send_func = _gnutls_srp_send_params, .pack_func = _gnutls_srp_pack, diff --git a/lib/ext/srtp.c b/lib/ext/srtp.c index 811d5419b5..b55ca29753 100644 --- a/lib/ext/srtp.c +++ b/lib/ext/srtp.c @@ -43,9 +43,9 @@ const hello_ext_entry_st ext_mod_srtp = { .name = "SRTP", .tls_id = 14, .gid = GNUTLS_EXTENSION_SRTP, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_EE|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .parse_type = GNUTLS_EXT_APPLICATION, - .recv_func = _gnutls_srtp_recv_params, .send_func = _gnutls_srtp_send_params, .pack_func = _gnutls_srtp_pack, diff --git a/lib/ext/status_request.c b/lib/ext/status_request.c index 550b4307d3..f238a8fbcb 100644 --- a/lib/ext/status_request.c +++ b/lib/ext/status_request.c @@ -326,7 +326,8 @@ const hello_ext_entry_st ext_mod_status_request = { .name = "OCSP Status Request", .tls_id = STATUS_REQUEST_TLS_ID, .gid = GNUTLS_EXTENSION_STATUS_REQUEST, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, + .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, .parse_type = _GNUTLS_EXT_TLS_POST_CS, .recv_func = _gnutls_status_request_recv_params, .send_func = _gnutls_status_request_send_params, diff --git a/lib/ext/supported_versions.c b/lib/ext/supported_versions.c index e2857c5e84..f1a85022b6 100644 --- a/lib/ext/supported_versions.c +++ b/lib/ext/supported_versions.c @@ -41,10 +41,9 @@ const hello_ext_entry_st ext_mod_supported_versions = { .name = "Supported Versions", .tls_id = 43, .gid = GNUTLS_EXTENSION_SUPPORTED_VERSIONS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO| - GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO|GNUTLS_EXT_FLAG_HRR, + .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO | + GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | GNUTLS_EXT_FLAG_HRR|GNUTLS_EXT_FLAG_TLS, .parse_type = GNUTLS_EXT_VERSION_NEG, /* force parsing prior to EXT_TLS extensions */ - .recv_func = supported_versions_recv_params, .send_func = supported_versions_send_params, .pack_func = NULL, diff --git a/lib/hello_ext.c b/lib/hello_ext.c index 57583231a3..d61f846f51 100644 --- a/lib/hello_ext.c +++ b/lib/hello_ext.c @@ -208,12 +208,21 @@ int hello_ext_parse(void *_ctx, unsigned tls_id, const uint8_t *data, unsigned d ext = tls_id_to_ext_entry(session, tls_id, ctx->parse_type); if (ext == NULL || ext->recv_func == NULL) { - if (ext) { - _gnutls_hard_log - ("EXT[%p]: Ignoring extension '%s/%d'\n", session, - ext->name, (int)tls_id); + goto ignore; + } + + /* we do not hard fail when extensions defined for TLS are used for + * DTLS and vice-versa. They may extend their role in the future. */ + if (IS_DTLS(session)) { + if (!(ext->validity & GNUTLS_EXT_FLAG_DTLS)) { + gnutls_assert(); + goto ignore; + } + } else { + if (!(ext->validity & GNUTLS_EXT_FLAG_TLS)) { + gnutls_assert(); + goto ignore; } - return 0; } if (session->security_parameters.entity == GNUTLS_CLIENT) { @@ -250,6 +259,14 @@ int hello_ext_parse(void *_ctx, unsigned tls_id, const uint8_t *data, unsigned d } return 0; + + ignore: + if (ext) { + _gnutls_handshake_log + ("EXT[%p]: Ignoring extension '%s/%d'\n", session, + ext->name, (int)tls_id); + } + return 0; } int @@ -261,6 +278,8 @@ _gnutls_parse_hello_extensions(gnutls_session_t session, int ret; hello_ext_ctx_st ctx; + msg &= GNUTLS_EXT_FLAG_SET_ONLY_FLAGS_MASK; + ctx.session = session; ctx.msg = msg; ctx.parse_type = parse_type; @@ -290,11 +309,20 @@ int hello_ext_send(void *_ctx, gnutls_buffer_st *buf) return 0; } + if (IS_DTLS(session)) { + if (!(p->validity & GNUTLS_EXT_FLAG_DTLS)) { + gnutls_assert(); + goto skip; + } + } else { + if (!(p->validity & GNUTLS_EXT_FLAG_TLS)) { + gnutls_assert(); + goto skip; + } + } + if ((ctx->msg & p->validity) == 0) { - _gnutls_hard_log("EXT[%p]: Not sending extension (%s/%d) for '%s'\n", session, - p->name, (int)p->tls_id, - ext_msg_validity_to_str(ctx->msg)); - return 0; + goto skip; } else { _gnutls_handshake_log("EXT[%p]: Preparing extension (%s/%d) for '%s'\n", session, p->name, (int)p->tls_id, @@ -335,6 +363,12 @@ int hello_ext_send(void *_ctx, gnutls_buffer_st *buf) } return ret; + + skip: + _gnutls_handshake_log("EXT[%p]: Not sending extension (%s/%d) for '%s'\n", session, + p->name, (int)p->tls_id, + ext_msg_validity_to_str(ctx->msg)); + return 0; } int @@ -347,6 +381,8 @@ _gnutls_gen_hello_extensions(gnutls_session_t session, size_t i; hello_ext_ctx_st ctx; + msg &= GNUTLS_EXT_FLAG_SET_ONLY_FLAGS_MASK; + ctx.session = session; ctx.msg = msg; ctx.parse_type = parse_type; @@ -752,7 +788,8 @@ gnutls_ext_register(const char *name, int id, gnutls_ext_parse_type_t parse_type tmp_mod->deinit_func = deinit_func; tmp_mod->pack_func = pack_func; tmp_mod->unpack_func = unpack_func; - tmp_mod->validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO|GNUTLS_EXT_FLAG_EE; + tmp_mod->validity = GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO | + GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_TLS; assert(extfunc[gid] == NULL); extfunc[gid] = tmp_mod; @@ -760,9 +797,9 @@ gnutls_ext_register(const char *name, int id, gnutls_ext_parse_type_t parse_type return 0; } -#define VALIDITY_MASK (GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO| \ - GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO| \ - GNUTLS_EXT_FLAG_EE|GNUTLS_EXT_FLAG_HRR) +#define VALIDITY_MASK (GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO | \ + GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | \ + GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_HRR) /** * gnutls_session_ext_register: @@ -854,7 +891,15 @@ gnutls_session_ext_register(gnutls_session_t session, tmp_mod.validity = flags; if ((tmp_mod.validity & VALIDITY_MASK) == 0) { - tmp_mod.validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO|GNUTLS_EXT_FLAG_EE; + tmp_mod.validity = GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO | + GNUTLS_EXT_FLAG_EE; + } + + if ((tmp_mod.validity & (GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_TLS)) == 0) { + if (IS_DTLS(session)) + tmp_mod.validity |= GNUTLS_EXT_FLAG_DTLS; + else + tmp_mod.validity |= GNUTLS_EXT_FLAG_TLS; } exts = gnutls_realloc(session->internals.rexts, (session->internals.rexts_size+1)*sizeof(*exts)); diff --git a/lib/hello_ext.h b/lib/hello_ext.h index f0fcf056c7..ac0a4613a7 100644 --- a/lib/hello_ext.h +++ b/lib/hello_ext.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2000-2012 Free Software Foundation, Inc. + * Copyright (C) 2015-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -52,10 +53,17 @@ int _gnutls_hello_ext_get_resumed_priv(gnutls_session_t session, extensions_t ext, gnutls_ext_priv_data_t * data); +#define GNUTLS_EXT_FLAG_MSG_MASK (GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO| \ + GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | GNUTLS_EXT_FLAG_EE | GNUTLS_EXT_FLAG_HRR) + +/* these flags can only be set in the extensions, but cannot be requested; + * they are handled internally by the hello parsing/generating functions. */ +#define GNUTLS_EXT_FLAG_SET_ONLY_FLAGS_MASK ~(GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_TLS) + /* obtain the message this extension was received at */ inline static gnutls_ext_flags_t _gnutls_ext_get_msg(gnutls_session_t session) { - return session->internals.ext_msg; + return session->internals.ext_msg & GNUTLS_EXT_FLAG_MSG_MASK; } inline static void _gnutls_ext_set_msg(gnutls_session_t session, gnutls_ext_flags_t msg) @@ -86,6 +94,8 @@ int _gnutls_hello_ext_unpack(gnutls_session_t session, inline static const char *ext_msg_validity_to_str(gnutls_ext_flags_t msg) { + msg &= GNUTLS_EXT_FLAG_MSG_MASK; + switch(msg) { case GNUTLS_EXT_FLAG_CLIENT_HELLO: return "client hello"; diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index b6473b98b5..fd3b07af78 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -2761,6 +2761,8 @@ typedef enum { * @GNUTLS_EXT_FLAG_EE: This extension can be present in encrypted extensions message * @GNUTLS_EXT_FLAG_HRR: This extension can be present in hello retry request message * @GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST: When flag is present, this extension will be send even if the server didn't advertise it. An extension of this type is the Cookie TLS1.3 extension. + * @GNUTLS_EXT_FLAG_DTLS: This extension can be present under DTLS; otherwise ignored. + * @GNUTLS_EXT_FLAG_TLS: This extension can be present under TLS; otherwise ignored. * * Enumeration of different TLS extension registration flags. */ @@ -2771,7 +2773,9 @@ typedef enum { GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO = (1<<3), GNUTLS_EXT_FLAG_EE = (1<<4), /* ENCRYPTED */ GNUTLS_EXT_FLAG_HRR = (1<<5), - GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST = (1<<6) + GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST = (1<<6), + GNUTLS_EXT_FLAG_TLS = (1<<7), + GNUTLS_EXT_FLAG_DTLS = (1<<8) } gnutls_ext_flags_t; /* Register a custom tls extension diff --git a/tests/Makefile.am b/tests/Makefile.am index f29da98724..290387bdac 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -180,7 +180,7 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei safe-renegotiation/srn0 safe-renegotiation/srn1 safe-renegotiation/srn2 \ safe-renegotiation/srn3 safe-renegotiation/srn4 safe-renegotiation/srn5 \ rsa-illegal-import set_x509_ocsp_multi_invalid set_key set_x509_key_file_ocsp_multi2 \ - set_x509_ocsp_multi_unknown set_x509_ocsp_multi_pem \ + set_x509_ocsp_multi_unknown set_x509_ocsp_multi_pem tls-ext-not-in-dtls \ set_key_utf8 set_x509_key_utf8 insecure_key handshake-large-packet \ client_dsa_key server_ecdsa_key tls-session-ext-register tls-session-supplemental \ multi-alerts naked-alerts pkcs7-cat-parse set_known_dh_params_x509 \ diff --git a/tests/tls-ext-not-in-dtls.c b/tests/tls-ext-not-in-dtls.c new file mode 100644 index 0000000000..1bbf2e2887 --- /dev/null +++ b/tests/tls-ext-not-in-dtls.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2017-2018 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * 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 + +#if defined(_WIN32) + +int main() +{ + exit(77); +} + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "cert-common.h" + +enum { +TEST_DEF_HANDHAKE, +TEST_CUSTOM_EXT +}; + +/* This program tests whether the Post Handshake Auth extension is + * present in the client hello, and whether it is missing from server + * hello. In addition it contains basic functionality test for + * post handshake authentication. + */ + +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 ext_send(gnutls_session_t session, gnutls_buffer_t extdata) +{ + gnutls_buffer_append_data(extdata, "\xff", 1); + return 0; +} + +static int ext_recv(gnutls_session_t session, const unsigned char *buf, size_t buflen) +{ + return 0; +} + +#define TLS_EXT_IMPL_DTLS 0xfeee +#define TLS_EXT_EXPL_TLS 0xfeea + +static void client(int fd, int type) +{ + int ret; + gnutls_certificate_credentials_t x509_cred; + gnutls_session_t session; + + assert(gnutls_global_init() >= 0); + + gnutls_global_set_log_function(client_log_func); + + assert(gnutls_certificate_allocate_credentials(&x509_cred) >= 0); + + assert(gnutls_init(&session, GNUTLS_CLIENT|GNUTLS_DATAGRAM) >= 0); + + if (type == TEST_CUSTOM_EXT) { + assert(gnutls_session_ext_register(session, "implicit-dtls", TLS_EXT_IMPL_DTLS, GNUTLS_EXT_TLS, ext_recv, ext_send, NULL, NULL, NULL, GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO|GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO)>=0); + assert(gnutls_session_ext_register(session, "explicit-tls", TLS_EXT_EXPL_TLS, GNUTLS_EXT_TLS, ext_recv, ext_send, NULL, NULL, NULL, GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO|GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO|GNUTLS_EXT_FLAG_TLS)>=0); + } + + gnutls_handshake_set_timeout(session, 20 * 1000); + + assert(gnutls_priority_set_direct(session, "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.0", NULL) >= 0); + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + gnutls_transport_set_int(session, fd); + + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret < 0) + fail("handshake: %s\n", gnutls_strerror(ret)); + + close(fd); + + gnutls_deinit(session); + + gnutls_certificate_free_credentials(x509_cred); + + gnutls_global_deinit(); +} + +#define TLS_EXT_KEY_SHARE 51 +#define TLS_EXT_POST_HANDSHAKE 49 + +struct ext_ctx_st { + int extno; + int found; +}; + +static int parse_ext(void *ctx, unsigned tls_id, const unsigned char *data, unsigned data_size) +{ + struct ext_ctx_st *s = ctx; + + if (s->extno == (int)tls_id) + s->found = 1; + + return 0; +} + +static unsigned find_client_extension(const gnutls_datum_t *msg, int extno) +{ + int ret; + struct ext_ctx_st s; + + memset(&s, 0, sizeof(s)); + s.extno = extno; + + ret = gnutls_ext_raw_parse(&s, parse_ext, msg, GNUTLS_EXT_RAW_FLAG_DTLS_CLIENT_HELLO); + assert(ret>=0); + + if (s.found) + return 1; + + return 0; +} + +static int hellos_callback(gnutls_session_t session, unsigned int htype, + unsigned post, unsigned int incoming, const gnutls_datum_t *msg) +{ + int *type; + + if (htype != GNUTLS_HANDSHAKE_CLIENT_HELLO || post != GNUTLS_HOOK_PRE) + return 0; + + type = gnutls_session_get_ptr(session); + + if (find_client_extension(msg, TLS_EXT_KEY_SHARE)) + fail("Key share extension seen in client hello!\n"); + + if (find_client_extension(msg, TLS_EXT_POST_HANDSHAKE)) + fail("Key share extension seen in client hello!\n"); + + if (*type == TEST_CUSTOM_EXT) { + if (!find_client_extension(msg, TLS_EXT_IMPL_DTLS)) + fail("Implicit DTLS extension not seen in client hello!\n"); + + if (find_client_extension(msg, TLS_EXT_EXPL_TLS)) + fail("Explicit TLS extension seen in client hello!\n"); + } + + return 0; +} + +static void server(int fd, int type) +{ + int ret; + gnutls_session_t session; + gnutls_certificate_credentials_t x509_cred; + + assert(gnutls_global_init() >= 0); + + gnutls_global_set_log_function(server_log_func); + + assert(gnutls_certificate_allocate_credentials(&x509_cred) >= 0); + assert(gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert, + &server_key, + GNUTLS_X509_FMT_PEM) >= 0); + + assert(gnutls_init(&session, GNUTLS_SERVER|GNUTLS_POST_HANDSHAKE_AUTH|GNUTLS_DATAGRAM) >= 0); + + gnutls_handshake_set_timeout(session, 20 * 1000); + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_ANY, + GNUTLS_HOOK_BOTH, + hellos_callback); + + gnutls_session_set_ptr(session, &type); + assert(gnutls_priority_set_direct(session, "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.3:+VERS-TLS1.2", NULL) >= 0); + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + gnutls_transport_set_int(session, fd); + + 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)); + + close(fd); + gnutls_deinit(session); + + gnutls_certificate_free_credentials(x509_cred); + + gnutls_global_deinit(); +} + +static void ch_handler(int sig) +{ + int status; + wait(&status); + check_wait_status(status); + return; +} + +static +void start(const char *name, int type) +{ + int fd[2]; + int ret; + pid_t child; + + signal(SIGCHLD, ch_handler); + success("%s\n", name); + + 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], type); + kill(child, SIGTERM); + } else { + close(fd[0]); + client(fd[1], type); + exit(0); + } + +} + +void doit(void) { + start("check default extensions", TEST_DEF_HANDHAKE); + start("check registered extensions", TEST_CUSTOM_EXT); +} + +#endif /* _WIN32 */ -- cgit v1.2.1