]>
Commit | Line | Data |
---|---|---|
21079538 | 1 | /* |
5401a74d | 2 | * Copyright (C) 2023 Tobias Brunner |
21079538 | 3 | * Copyright (C) 2010 Martin Willi |
19ef2aec TB |
4 | * |
5 | * Copyright (C) secunet Security Networks AG | |
21079538 MW |
6 | * |
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>. | |
11 | * | |
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 | |
15 | * for more details. | |
16 | */ | |
17 | ||
18 | #include "eap_tls.h" | |
19 | ||
be751012 | 20 | #include <tls_eap.h> |
dcbbeb2d | 21 | |
21079538 MW |
22 | #include <daemon.h> |
23 | #include <library.h> | |
24 | ||
25 | typedef struct private_eap_tls_t private_eap_tls_t; | |
26 | ||
27 | /** | |
28 | * Private data of an eap_tls_t object. | |
29 | */ | |
30 | struct private_eap_tls_t { | |
31 | ||
32 | /** | |
33 | * Public interface. | |
34 | */ | |
35 | eap_tls_t public; | |
36 | ||
21079538 | 37 | /** |
5401a74d TB |
38 | * TLS stack, wrapped by EAP helper below |
39 | */ | |
40 | tls_t *tls; | |
41 | ||
42 | /** | |
43 | * EAP helper | |
21079538 | 44 | */ |
be751012 | 45 | tls_eap_t *tls_eap; |
5401a74d TB |
46 | |
47 | /** | |
48 | * Whether the "protected success indication" has been sent/received with | |
49 | * TLS 1.3 | |
50 | */ | |
51 | bool indication_sent_received; | |
21079538 MW |
52 | }; |
53 | ||
c8a2fca5 | 54 | /** Maximum number of EAP-TLS messages/fragments allowed */ |
6a5c86b7 | 55 | #define MAX_MESSAGE_COUNT 32 |
f9fc5f20 MW |
56 | /** Default size of a EAP-TLS fragment */ |
57 | #define MAX_FRAGMENT_LEN 1024 | |
b173819e | 58 | |
21079538 MW |
59 | METHOD(eap_method_t, initiate, status_t, |
60 | private_eap_tls_t *this, eap_payload_t **out) | |
61 | { | |
4c0124a0 | 62 | chunk_t data; |
b173819e | 63 | |
be751012 | 64 | if (this->tls_eap->initiate(this->tls_eap, &data) == NEED_MORE) |
4c0124a0 | 65 | { |
be751012 MW |
66 | *out = eap_payload_create_data(data); |
67 | free(data.ptr); | |
68 | return NEED_MORE; | |
b173819e | 69 | } |
be751012 | 70 | return FAILED; |
b173819e MW |
71 | } |
72 | ||
21079538 MW |
73 | METHOD(eap_method_t, process, status_t, |
74 | private_eap_tls_t *this, eap_payload_t *in, eap_payload_t **out) | |
75 | { | |
b173819e | 76 | status_t status; |
be751012 | 77 | chunk_t data; |
b173819e MW |
78 | |
79 | data = in->get_data(in); | |
be751012 | 80 | status = this->tls_eap->process(this->tls_eap, data, &data); |
b173819e MW |
81 | if (status == NEED_MORE) |
82 | { | |
be751012 MW |
83 | *out = eap_payload_create_data(data); |
84 | free(data.ptr); | |
5ff8c627 | 85 | } |
b173819e | 86 | return status; |
21079538 MW |
87 | } |
88 | ||
89 | METHOD(eap_method_t, get_type, eap_type_t, | |
f6e6fcd2 | 90 | private_eap_tls_t *this, pen_t *vendor) |
21079538 MW |
91 | { |
92 | *vendor = 0; | |
93 | return EAP_TLS; | |
94 | } | |
95 | ||
96 | METHOD(eap_method_t, get_msk, status_t, | |
97 | private_eap_tls_t *this, chunk_t *msk) | |
98 | { | |
5401a74d TB |
99 | if (this->tls->get_version_max(this->tls) < TLS_1_3 || |
100 | this->indication_sent_received) | |
51313a39 | 101 | { |
5401a74d TB |
102 | *msk = this->tls_eap->get_msk(this->tls_eap); |
103 | if (msk->len) | |
104 | { | |
105 | return SUCCESS; | |
106 | } | |
107 | } | |
108 | else | |
109 | { | |
110 | DBG1(DBG_TLS, "missing protected success indication for EAP-TLS with " | |
111 | "%N", tls_version_names, this->tls->get_version_max(this->tls)); | |
51313a39 | 112 | } |
21079538 MW |
113 | return FAILED; |
114 | } | |
115 | ||
b12c53ce | 116 | METHOD(eap_method_t, get_identifier, uint8_t, |
934216df AS |
117 | private_eap_tls_t *this) |
118 | { | |
119 | return this->tls_eap->get_identifier(this->tls_eap); | |
120 | } | |
121 | ||
122 | METHOD(eap_method_t, set_identifier, void, | |
b12c53ce | 123 | private_eap_tls_t *this, uint8_t identifier) |
934216df AS |
124 | { |
125 | this->tls_eap->set_identifier(this->tls_eap, identifier); | |
126 | } | |
127 | ||
21079538 MW |
128 | METHOD(eap_method_t, is_mutual, bool, |
129 | private_eap_tls_t *this) | |
130 | { | |
131 | return TRUE; | |
132 | } | |
133 | ||
de2a62cf MW |
134 | METHOD(eap_method_t, get_auth, auth_cfg_t*, |
135 | private_eap_tls_t *this) | |
136 | { | |
137 | return this->tls_eap->get_auth(this->tls_eap); | |
138 | } | |
139 | ||
21079538 MW |
140 | METHOD(eap_method_t, destroy, void, |
141 | private_eap_tls_t *this) | |
142 | { | |
be751012 | 143 | this->tls_eap->destroy(this->tls_eap); |
21079538 MW |
144 | free(this); |
145 | } | |
146 | ||
5401a74d TB |
147 | /** |
148 | * Application to send/process the "protected success indication" with TLS 1.3 | |
149 | * as specified in RFC 9190 | |
150 | */ | |
151 | typedef struct { | |
152 | ||
153 | /** | |
154 | * Public interface | |
155 | */ | |
156 | tls_application_t public; | |
157 | ||
158 | /** | |
159 | * Reference to the EAP-TLS object | |
160 | */ | |
161 | private_eap_tls_t *this; | |
162 | ||
163 | /** | |
164 | * Whether the server sent the indication | |
165 | */ | |
166 | bool indication_sent; | |
167 | ||
168 | } eap_tls_app_t; | |
169 | ||
170 | METHOD(tls_application_t, server_process, status_t, | |
171 | eap_tls_app_t *app, bio_reader_t *reader) | |
172 | { | |
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"); | |
176 | return FAILED; | |
177 | } | |
178 | ||
179 | METHOD(tls_application_t, server_build, status_t, | |
180 | eap_tls_app_t *app, bio_writer_t *writer) | |
181 | { | |
3d0d3f5d | 182 | if (app->this->indication_sent_received) |
5401a74d TB |
183 | { |
184 | return SUCCESS; | |
185 | } | |
3d0d3f5d | 186 | if (app->this->tls->get_version_max(app->this->tls) >= TLS_1_3) |
5401a74d | 187 | { |
3d0d3f5d TB |
188 | /* build() is called twice when sending the indication, return the same |
189 | * status but data only once */ | |
190 | if (app->indication_sent) | |
191 | { | |
192 | app->this->indication_sent_received = TRUE; | |
193 | } | |
194 | else | |
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; | |
199 | } | |
5401a74d TB |
200 | } |
201 | else | |
3d0d3f5d TB |
202 | { |
203 | /* with earlier TLS versions, return INVALID_STATE without data to send | |
204 | * the final handshake messages (returning SUCCESS immediately would | |
205 | * prevent that) */ | |
206 | app->this->indication_sent_received = TRUE; | |
5401a74d TB |
207 | } |
208 | return INVALID_STATE; | |
209 | } | |
210 | ||
211 | METHOD(tls_application_t, client_process, status_t, | |
212 | eap_tls_app_t *app, bio_reader_t *reader) | |
213 | { | |
214 | uint8_t indication; | |
215 | ||
216 | if (app->this->tls->get_version_max(app->this->tls) < TLS_1_3 || | |
217 | app->this->indication_sent_received) | |
218 | { | |
219 | DBG1(DBG_TLS, "peer sent unexpected TLS data"); | |
220 | return FAILED; | |
221 | } | |
222 | if (!reader->read_uint8(reader, &indication) || indication != 0) | |
223 | { | |
224 | DBG1(DBG_TLS, "received incorrect protected success indication via TLS"); | |
225 | return FAILED; | |
226 | } | |
227 | DBG2(DBG_TLS, "received protected success indication via TLS"); | |
228 | app->this->indication_sent_received = TRUE; | |
229 | return NEED_MORE; | |
230 | } | |
231 | ||
232 | METHOD(tls_application_t, client_build, status_t, | |
233 | eap_tls_app_t *app, bio_writer_t *writer) | |
234 | { | |
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; | |
239 | } | |
240 | return FAILED; | |
241 | } | |
242 | ||
243 | METHOD(tls_application_t, app_destroy, void, | |
244 | eap_tls_app_t *this) | |
245 | { | |
246 | free(this); | |
247 | } | |
248 | ||
249 | /** | |
250 | * Create the server/peer implementation to handle the "protected success | |
251 | * indication" with TLS 1.3 | |
252 | */ | |
253 | tls_application_t *eap_tls_app_create(private_eap_tls_t *this, bool is_server) | |
254 | { | |
255 | eap_tls_app_t *app; | |
256 | ||
257 | INIT(app, | |
258 | .public = { | |
259 | .process = _client_process, | |
260 | .build = _client_build, | |
261 | .destroy = _app_destroy, | |
262 | }, | |
263 | .this = this, | |
264 | ); | |
265 | if (is_server) | |
266 | { | |
267 | app->public.process = _server_process; | |
268 | app->public.build = _server_build; | |
269 | } | |
270 | return &app->public; | |
271 | } | |
272 | ||
21079538 MW |
273 | /** |
274 | * Generic private constructor | |
275 | */ | |
276 | static eap_tls_t *eap_tls_create(identification_t *server, | |
277 | identification_t *peer, bool is_server) | |
278 | { | |
279 | private_eap_tls_t *this; | |
5401a74d | 280 | tls_application_t *app; |
f9fc5f20 | 281 | size_t frag_size; |
de29e3a6 | 282 | int max_msg_count; |
2778b664 | 283 | bool include_length; |
21079538 MW |
284 | |
285 | INIT(this, | |
ba31fe1f MW |
286 | .public = { |
287 | .eap_method = { | |
288 | .initiate = _initiate, | |
289 | .process = _process, | |
290 | .get_type = _get_type, | |
291 | .is_mutual = _is_mutual, | |
292 | .get_msk = _get_msk, | |
934216df AS |
293 | .get_identifier = _get_identifier, |
294 | .set_identifier = _set_identifier, | |
de2a62cf | 295 | .get_auth = _get_auth, |
ba31fe1f MW |
296 | .destroy = _destroy, |
297 | }, | |
21079538 | 298 | }, |
21079538 | 299 | ); |
b173819e | 300 | |
f9fc5f20 | 301 | frag_size = lib->settings->get_int(lib->settings, |
42500c27 | 302 | "%s.plugins.eap-tls.fragment_size", MAX_FRAGMENT_LEN, |
d223fe80 | 303 | lib->ns); |
de29e3a6 | 304 | max_msg_count = lib->settings->get_int(lib->settings, |
42500c27 | 305 | "%s.plugins.eap-tls.max_message_count", MAX_MESSAGE_COUNT, |
d223fe80 | 306 | lib->ns); |
2778b664 | 307 | include_length = lib->settings->get_bool(lib->settings, |
d223fe80 | 308 | "%s.plugins.eap-tls.include_length", TRUE, lib->ns); |
5401a74d TB |
309 | app = eap_tls_app_create(this, is_server); |
310 | this->tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, app, | |
311 | NULL, 0); | |
312 | this->tls_eap = tls_eap_create(EAP_TLS, this->tls, frag_size, max_msg_count, | |
313 | include_length); | |
be751012 | 314 | if (!this->tls_eap) |
96b2fbcc MW |
315 | { |
316 | free(this); | |
317 | return NULL; | |
318 | } | |
21079538 MW |
319 | return &this->public; |
320 | } | |
321 | ||
322 | eap_tls_t *eap_tls_create_server(identification_t *server, | |
323 | identification_t *peer) | |
324 | { | |
325 | return eap_tls_create(server, peer, TRUE); | |
326 | } | |
327 | ||
328 | eap_tls_t *eap_tls_create_peer(identification_t *server, | |
329 | identification_t *peer) | |
330 | { | |
331 | return eap_tls_create(server, peer, FALSE); | |
332 | } |