2 * Copyright (C) 2023 Tobias Brunner
3 * Copyright (C) 2010 Martin Willi
5 * Copyright (C) secunet Security Networks AG
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 typedef struct private_eap_tls_t private_eap_tls_t
;
28 * Private data of an eap_tls_t object.
30 struct private_eap_tls_t
{
38 * TLS stack, wrapped by EAP helper below
48 * Whether the "protected success indication" has been sent/received with
51 bool indication_sent_received
;
54 /** Maximum number of EAP-TLS messages/fragments allowed */
55 #define MAX_MESSAGE_COUNT 32
56 /** Default size of a EAP-TLS fragment */
57 #define MAX_FRAGMENT_LEN 1024
59 METHOD(eap_method_t
, initiate
, status_t
,
60 private_eap_tls_t
*this, eap_payload_t
**out
)
64 if (this->tls_eap
->initiate(this->tls_eap
, &data
) == NEED_MORE
)
66 *out
= eap_payload_create_data(data
);
73 METHOD(eap_method_t
, process
, status_t
,
74 private_eap_tls_t
*this, eap_payload_t
*in
, eap_payload_t
**out
)
79 data
= in
->get_data(in
);
80 status
= this->tls_eap
->process(this->tls_eap
, data
, &data
);
81 if (status
== NEED_MORE
)
83 *out
= eap_payload_create_data(data
);
89 METHOD(eap_method_t
, get_type
, eap_type_t
,
90 private_eap_tls_t
*this, pen_t
*vendor
)
96 METHOD(eap_method_t
, get_msk
, status_t
,
97 private_eap_tls_t
*this, chunk_t
*msk
)
99 if (this->tls
->get_version_max(this->tls
) < TLS_1_3
||
100 this->indication_sent_received
)
102 *msk
= this->tls_eap
->get_msk(this->tls_eap
);
110 DBG1(DBG_TLS
, "missing protected success indication for EAP-TLS with "
111 "%N", tls_version_names
, this->tls
->get_version_max(this->tls
));
116 METHOD(eap_method_t
, get_identifier
, uint8_t,
117 private_eap_tls_t
*this)
119 return this->tls_eap
->get_identifier(this->tls_eap
);
122 METHOD(eap_method_t
, set_identifier
, void,
123 private_eap_tls_t
*this, uint8_t identifier
)
125 this->tls_eap
->set_identifier(this->tls_eap
, identifier
);
128 METHOD(eap_method_t
, is_mutual
, bool,
129 private_eap_tls_t
*this)
134 METHOD(eap_method_t
, get_auth
, auth_cfg_t
*,
135 private_eap_tls_t
*this)
137 return this->tls_eap
->get_auth(this->tls_eap
);
140 METHOD(eap_method_t
, destroy
, void,
141 private_eap_tls_t
*this)
143 this->tls_eap
->destroy(this->tls_eap
);
148 * Application to send/process the "protected success indication" with TLS 1.3
149 * as specified in RFC 9190
156 tls_application_t
public;
159 * Reference to the EAP-TLS object
161 private_eap_tls_t
*this;
164 * Whether the server sent the indication
166 bool indication_sent
;
170 METHOD(tls_application_t
, server_process
, status_t
,
171 eap_tls_app_t
*app
, bio_reader_t
*reader
)
173 /* we don't expect any data from the client, the empty response to our
174 * indication is handled as ACK in tls_eap_t */
175 DBG1(DBG_TLS
, "peer sent unexpected TLS data");
179 METHOD(tls_application_t
, server_build
, status_t
,
180 eap_tls_app_t
*app
, bio_writer_t
*writer
)
182 if (app
->this->indication_sent_received
)
186 if (app
->this->tls
->get_version_max(app
->this->tls
) >= TLS_1_3
)
188 /* build() is called twice when sending the indication, return the same
189 * status but data only once */
190 if (app
->indication_sent
)
192 app
->this->indication_sent_received
= TRUE
;
195 { /* send a single 0x00 */
196 DBG2(DBG_TLS
, "sending protected success indication via TLS");
197 writer
->write_uint8(writer
, 0);
198 app
->indication_sent
= TRUE
;
203 /* with earlier TLS versions, return INVALID_STATE without data to send
204 * the final handshake messages (returning SUCCESS immediately would
206 app
->this->indication_sent_received
= TRUE
;
208 return INVALID_STATE
;
211 METHOD(tls_application_t
, client_process
, status_t
,
212 eap_tls_app_t
*app
, bio_reader_t
*reader
)
216 if (app
->this->tls
->get_version_max(app
->this->tls
) < TLS_1_3
||
217 app
->this->indication_sent_received
)
219 DBG1(DBG_TLS
, "peer sent unexpected TLS data");
222 if (!reader
->read_uint8(reader
, &indication
) || indication
!= 0)
224 DBG1(DBG_TLS
, "received incorrect protected success indication via TLS");
227 DBG2(DBG_TLS
, "received protected success indication via TLS");
228 app
->this->indication_sent_received
= TRUE
;
232 METHOD(tls_application_t
, client_build
, status_t
,
233 eap_tls_app_t
*app
, bio_writer_t
*writer
)
235 if (app
->this->tls
->get_version_max(app
->this->tls
) < TLS_1_3
||
236 app
->this->indication_sent_received
)
237 { /* trigger an empty response/ACK */
238 return INVALID_STATE
;
243 METHOD(tls_application_t
, app_destroy
, void,
250 * Create the server/peer implementation to handle the "protected success
251 * indication" with TLS 1.3
253 tls_application_t
*eap_tls_app_create(private_eap_tls_t
*this, bool is_server
)
259 .process
= _client_process
,
260 .build
= _client_build
,
261 .destroy
= _app_destroy
,
267 app
->public.process
= _server_process
;
268 app
->public.build
= _server_build
;
274 * Generic private constructor
276 static eap_tls_t
*eap_tls_create(identification_t
*server
,
277 identification_t
*peer
, bool is_server
)
279 private_eap_tls_t
*this;
280 tls_application_t
*app
;
288 .initiate
= _initiate
,
290 .get_type
= _get_type
,
291 .is_mutual
= _is_mutual
,
293 .get_identifier
= _get_identifier
,
294 .set_identifier
= _set_identifier
,
295 .get_auth
= _get_auth
,
301 frag_size
= lib
->settings
->get_int(lib
->settings
,
302 "%s.plugins.eap-tls.fragment_size", MAX_FRAGMENT_LEN
,
304 max_msg_count
= lib
->settings
->get_int(lib
->settings
,
305 "%s.plugins.eap-tls.max_message_count", MAX_MESSAGE_COUNT
,
307 include_length
= lib
->settings
->get_bool(lib
->settings
,
308 "%s.plugins.eap-tls.include_length", TRUE
, lib
->ns
);
309 app
= eap_tls_app_create(this, is_server
);
310 this->tls
= tls_create(is_server
, server
, peer
, TLS_PURPOSE_EAP_TLS
, app
,
312 this->tls_eap
= tls_eap_create(EAP_TLS
, this->tls
, frag_size
, max_msg_count
,
319 return &this->public;
322 eap_tls_t
*eap_tls_create_server(identification_t
*server
,
323 identification_t
*peer
)
325 return eap_tls_create(server
, peer
, TRUE
);
328 eap_tls_t
*eap_tls_create_peer(identification_t
*server
,
329 identification_t
*peer
)
331 return eap_tls_create(server
, peer
, FALSE
);