From: Tobias Brunner Date: Tue, 17 Jan 2023 14:06:40 +0000 (+0100) Subject: eap-tls: Add support for TLS 1.3 X-Git-Tag: 5.9.10rc1~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5401a74d3608be19a4a883c10d4bd89e73c6ee60;p=thirdparty%2Fstrongswan.git eap-tls: Add support for TLS 1.3 As defined in RFC 9190, a "protected success indication" (0x00) is sent from the server to the client over the TLS connection when using TLS 1.3. The client responds with an empty EAP message, which is interpreted as acknowledgement in our stack. If we ever support session resumption with tunneled methods such as EAP-TTLS, we'd have to send such an indication there too. --- diff --git a/src/libcharon/plugins/eap_tls/eap_tls.c b/src/libcharon/plugins/eap_tls/eap_tls.c index 3d34d7a840..575488961e 100644 --- a/src/libcharon/plugins/eap_tls/eap_tls.c +++ b/src/libcharon/plugins/eap_tls/eap_tls.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2023 Tobias Brunner * Copyright (C) 2010 Martin Willi * * Copyright (C) secunet Security Networks AG @@ -34,9 +35,20 @@ struct private_eap_tls_t { eap_tls_t public; /** - * TLS stack, wrapped by EAP helper + * TLS stack, wrapped by EAP helper below + */ + tls_t *tls; + + /** + * EAP helper */ tls_eap_t *tls_eap; + + /** + * Whether the "protected success indication" has been sent/received with + * TLS 1.3 + */ + bool indication_sent_received; }; /** Maximum number of EAP-TLS messages/fragments allowed */ @@ -84,10 +96,19 @@ METHOD(eap_method_t, get_type, eap_type_t, METHOD(eap_method_t, get_msk, status_t, private_eap_tls_t *this, chunk_t *msk) { - *msk = this->tls_eap->get_msk(this->tls_eap); - if (msk->len) + if (this->tls->get_version_max(this->tls) < TLS_1_3 || + this->indication_sent_received) { - return SUCCESS; + *msk = this->tls_eap->get_msk(this->tls_eap); + if (msk->len) + { + return SUCCESS; + } + } + else + { + DBG1(DBG_TLS, "missing protected success indication for EAP-TLS with " + "%N", tls_version_names, this->tls->get_version_max(this->tls)); } return FAILED; } @@ -123,6 +144,123 @@ METHOD(eap_method_t, destroy, void, free(this); } +/** + * Application to send/process the "protected success indication" with TLS 1.3 + * as specified in RFC 9190 + */ +typedef struct { + + /** + * Public interface + */ + tls_application_t public; + + /** + * Reference to the EAP-TLS object + */ + private_eap_tls_t *this; + + /** + * Whether the server sent the indication + */ + bool indication_sent; + +} eap_tls_app_t; + +METHOD(tls_application_t, server_process, status_t, + eap_tls_app_t *app, bio_reader_t *reader) +{ + /* we don't expect any data from the client, the empty response to our + * indication is handled as ACK in tls_eap_t */ + DBG1(DBG_TLS, "peer sent unexpected TLS data"); + return FAILED; +} + +METHOD(tls_application_t, server_build, status_t, + eap_tls_app_t *app, bio_writer_t *writer) +{ + if (app->this->tls->get_version_max(app->this->tls) < TLS_1_3 || + app->this->indication_sent_received) + { + return SUCCESS; + } + /* build() is called twice when sending the indication, return the same + * status but data only once */ + if (app->indication_sent) + { + app->this->indication_sent_received = TRUE; + } + else + { /* send a single 0x00 */ + DBG2(DBG_TLS, "sending protected success indication via TLS"); + writer->write_uint8(writer, 0); + app->indication_sent = TRUE; + } + return INVALID_STATE; +} + +METHOD(tls_application_t, client_process, status_t, + eap_tls_app_t *app, bio_reader_t *reader) +{ + uint8_t indication; + + if (app->this->tls->get_version_max(app->this->tls) < TLS_1_3 || + app->this->indication_sent_received) + { + DBG1(DBG_TLS, "peer sent unexpected TLS data"); + return FAILED; + } + if (!reader->read_uint8(reader, &indication) || indication != 0) + { + DBG1(DBG_TLS, "received incorrect protected success indication via TLS"); + return FAILED; + } + DBG2(DBG_TLS, "received protected success indication via TLS"); + app->this->indication_sent_received = TRUE; + return NEED_MORE; +} + +METHOD(tls_application_t, client_build, status_t, + eap_tls_app_t *app, bio_writer_t *writer) +{ + if (app->this->tls->get_version_max(app->this->tls) < TLS_1_3 || + app->this->indication_sent_received) + { /* trigger an empty response/ACK */ + return INVALID_STATE; + } + return FAILED; +} + +METHOD(tls_application_t, app_destroy, void, + eap_tls_app_t *this) +{ + free(this); +} + +/** + * Create the server/peer implementation to handle the "protected success + * indication" with TLS 1.3 + */ +tls_application_t *eap_tls_app_create(private_eap_tls_t *this, bool is_server) +{ + eap_tls_app_t *app; + + INIT(app, + .public = { + .process = _client_process, + .build = _client_build, + .destroy = _app_destroy, + }, + .this = this, + ); + if (is_server) + { + app->public.process = _server_process; + app->public.build = _server_build; + } + return &app->public; +} + /** * Generic private constructor */ @@ -130,10 +268,10 @@ static eap_tls_t *eap_tls_create(identification_t *server, identification_t *peer, bool is_server) { private_eap_tls_t *this; + tls_application_t *app; size_t frag_size; int max_msg_count; bool include_length; - tls_t *tls; INIT(this, .public = { @@ -159,9 +297,11 @@ static eap_tls_t *eap_tls_create(identification_t *server, lib->ns); include_length = lib->settings->get_bool(lib->settings, "%s.plugins.eap-tls.include_length", TRUE, lib->ns); - tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, NULL, NULL, 0); - this->tls_eap = tls_eap_create(EAP_TLS, tls, frag_size, max_msg_count, - include_length); + app = eap_tls_app_create(this, is_server); + this->tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, app, + NULL, 0); + this->tls_eap = tls_eap_create(EAP_TLS, this->tls, frag_size, max_msg_count, + include_length); if (!this->tls_eap) { free(this); diff --git a/src/libtls/tls_eap.c b/src/libtls/tls_eap.c index a0e5d5be78..4b16504b55 100644 --- a/src/libtls/tls_eap.c +++ b/src/libtls/tls_eap.c @@ -369,6 +369,9 @@ METHOD(tls_eap_t, process, status_t, } else { + /* note that with TLS 1.3 the client sends an empty EAP packet after the + * server sent the "protected success indication" over the TLS + * connection, which is interpreted here as an ACK packet */ if (in.len == sizeof(eap_tls_packet_t)) { DBG2(DBG_TLS, "received %N acknowledgment packet",