The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
tls.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: e8a0f50fe8ff40abcba8d3bdf8653c5ab0d05b6a $
19 * @file lib/eap/tls.c
20 * @brief Implements the EAP part of EAP-TLS
21 *
22 * RFC 2716 Section 4.2. PPP EAP TLS Request Packet
23 @verbatim
24 0 1 2 3
25 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
26 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27 | Code | Identifier | Length |
28 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29 | Type | Flags | TLS Message Length
30 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31 | TLS Message Length | TLS Data...
32 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 @endverbatim
34 *
35 * Structure of an EAP-TLS packet
36 *
37 @verbatim
38 code = EAP-code
39 id = EAP-id
40 length = code + id + length + flags + tlsdata
41 = 1 + 1 + 2 + 1 + X
42 length = EAP-length - 1(EAP-Type = 1 octet)
43 flags = EAP-typedata[0] (1 octet)
44 data_len = EAP-typedata[1-4] (4 octets), if L flag set
45 = length - 5(code+id+length+flags), otherwise
46 data = EAP-typedata[5-n], if L flag set
47 = EAP-typedata[1-n], otherwise
48 packet = EAP-typedata (complete typedata)
49 @endverbatim
50 *
51 * The S flag is set only within the EAP-TLS start message sent from the EAP
52 * server to the peer.
53 *
54 * Similarly, when the EAP server receives an EAP-Response with the M bit set,
55 * it MUST respond with an EAP-Request with EAP-Type = EAP-TLS and no data.
56 * This serves as a fragment ACK. The EAP peer MUST wait.
57 *
58 * The Length field is two octets and indicates the length of the EAP
59 * packet including the Code, Identifier, Length, Type, and TLS data
60 * fields.
61 *
62 * The TLS Message Length field is four octets and indicates the
63 * complete reassembled length of the TLS record fragment.
64 *
65 * @copyright 2001 hereUare Communications, Inc. (raghud@hereuare.com)
66 * @copyright 2003 Alan DeKok (aland@freeradius.org)
67 * @copyright 2006,2015 The FreeRADIUS server project
68 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
69 */
70
71RCSID("$Id: e8a0f50fe8ff40abcba8d3bdf8653c5ab0d05b6a $")
72USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
73
74#include <freeradius-devel/unlang/action.h>
75#include <freeradius-devel/unlang/function.h>
76#include <freeradius-devel/server/pair.h>
77#include "tls.h"
78#include "attrs.h"
79
81 { L("invalid"), EAP_TLS_INVALID },
82 { L("established"), EAP_TLS_ESTABLISHED },
83 { L("fail"), EAP_TLS_FAIL },
84 { L("handled"), EAP_TLS_HANDLED },
85
86 { L("start"), EAP_TLS_START_SEND },
87 { L("request"), EAP_TLS_RECORD_SEND },
88 { L("ack"), EAP_TLS_ACK_SEND },
89
90 { L("first"), EAP_TLS_RECORD_RECV_FIRST },
91 { L("more"), EAP_TLS_RECORD_RECV_MORE },
92 { L("complete"), EAP_TLS_RECORD_RECV_COMPLETE }
93};
95
96/** Convert the EAP-TLS reply packet into an EAP packet
97 *
98 * The EAP packet will be written to eap_round->request, with the original reply
99 * being untouched.
100 *
101 * @param[in] request The current subrequest.
102 * @param[in] eap_session to continue.
103 * @param[in] status What type of packet we're sending.
104 * @param[in] flags to set. This is checked to determine if
105 * we need to include a length field.
106 * @param[in] record The record buffer to read from. This
107 * most only be set for EAP_TLS_RECORD_SEND packets.
108 * @param[in] record_len the length of the record we're sending.
109 * @param[in] frag_len the length of the fragment we're sending.
110 * @return
111 * - 0 on success.
112 * - -1 on failure.
113 */
115 fr_dbuff_t *record, size_t record_len, size_t frag_len)
116{
117 eap_round_t *eap_round = eap_session->this_round;
118 uint8_t *p;
119 size_t len = 1; /* Flags */
120
121 fr_assert(request->parent); /* must be a subrequest */
122
123 /*
124 * First output the flags (for debugging)
125 */
126 RDEBUG3("Setting flags %c%c%c%c%c%c%c%c",
127 TLS_START(flags) ? 'S' : '-',
128 TLS_MORE_FRAGMENTS(flags) ? 'M' : '-',
129 TLS_LENGTH_INCLUDED(flags) ? 'L' : '-',
130 TLS_RESERVED0(flags) ? 'R' : '-',
131 TLS_RESERVED1(flags) ? 'R' : '-',
132 TLS_RESERVED2(flags) ? 'R' : '-',
133 TLS_RESERVED3(flags) ? 'R' : '-',
134 TLS_RESERVED4(flags) ? 'R' : '-');
135
136 /*
137 * Determine the length (sans header) of our EAP-TLS
138 * packet. The reason for not including the length is
139 * that the fields are the same as normal EAP messages.
140 */
141 switch (status) {
143 if (TLS_LENGTH_INCLUDED(flags)) len += TLS_HEADER_LENGTH_FIELD_LEN; /* TLS record length field */
144 if (record) len += frag_len;
145 break;
146
148 if (record_len != 0) len += frag_len;
149 break;
150
151 default:
152 break;
153 }
154
155 /*
156 * When the EAP server receives an EAP-Response with the
157 * M bit set, it MUST respond with an EAP-Request with
158 * EAP-Type = EAP-TLS and no data. This serves as a
159 * fragment ACK. The EAP peer MUST wait until it receives
160 * the EAP-Request before sending another fragment.
161 *
162 * In order to prevent errors in the processing of
163 * fragments, the EAP server MUST use increment the
164 * Identifier value for each fragment ACK contained
165 * within an EAP-Request, and the peer MUST include this
166 * Identifier value in the subsequent fragment contained
167 * within an EAP-Reponse.
168 */
169 eap_round->request->type.data = p = talloc_array(eap_round->request, uint8_t, len);
170 if (!p) return -1;
171 eap_round->request->type.length = len;
172
173 *p++ = flags;
174
175 if (TLS_LENGTH_INCLUDED(flags)) {
176 uint32_t net_record_len;
177
178 /*
179 * If we need to add the length field,
180 * convert the total record length to
181 * network byte order and copy it in at the
182 * start of the packet.
183 */
184 net_record_len = htonl(record_len);
185 memcpy(p, &net_record_len, sizeof(net_record_len));
186 p += sizeof(net_record_len);
187 }
188
189 /*
190 * Limit the dbuff call to "frag_len". If we ask for
191 * more, then the dbuff code will try to extend the
192 * buffer, and we don't want that.
193 */
194 if (record) (void) fr_dbuff_out_memcpy(p, record, frag_len);
195
196 switch (status) {
197 case EAP_TLS_ACK_SEND:
200 eap_round->request->code = FR_EAP_CODE_REQUEST;
201 break;
202
204 eap_round->request->code = FR_EAP_CODE_SUCCESS;
205 break;
206
207 case EAP_TLS_FAIL:
208 eap_round->request->code = FR_EAP_CODE_FAILURE;
209 break;
210
211 default:
212 /* Should never enter here */
213 fr_assert(0);
214 break;
215 }
216
217 return 0;
218}
219
220/** Send an initial EAP-TLS request to the peer.
221 *
222 * Once having received the peer's Identity, the EAP server MUST respond with an
223 * EAP-TLS/Start packet, which is an EAP-Request packet with EAP-Type = EAP-TLS,
224 * the Start (S) bit set, and no data.
225 *
226 * The EAP-TLS conversation will then begin, with the peer sending an EAP-Response
227 * packet with EAP-Type = EAP-TLS. The data field of that packet will be the TLS data.
228 *
229 * The S flag is set only within the EAP-TLS start message sent from the EAP server to the peer.
230 *
231 * - len = header + type + tls_typedata
232 * - tls_typedata = flags(Start (S) bit set, and no data)
233 *
234 * Fragment length is Framed-MTU - 4.
235 *
236 * @param[in] request The current subrequest.
237 * @param[in] eap_session to initiate.
238 * @return
239 * - 0 on success.
240 * - -1 on failure.
241 */
243{
244 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
245
246 fr_assert(request->parent); /* must be a subrequest */
247
248 return eap_tls_compose(request, eap_session, EAP_TLS_START_SEND,
249 SET_START(eap_tls_session->base_flags), NULL, 0, 0);
250}
251
252/** Send an EAP-TLS success
253 *
254 * Composes an EAP-TLS-Success. This is a message with code EAP_TLS_ESTABLISHED.
255 * It contains no cryptographic material, and is not protected.
256 *
257 * We add the MPPE keys here. These are used by the NAS. The supplicant
258 * will derive the same keys separately.
259 *
260 * @param[in] request The current subrequest.
261 * @param[in] eap_session that completed successfully.
262 * @param[in] prf_label PRF label struct
263 * @return
264 * - 0 on success.
265 * - -1 on failure.
266 */
268{
269 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
270 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
271
272 fr_assert(request->parent); /* must be a subrequest */
273
274 eap_session->finished = true;
275
276 /*
277 * Build the success packet
278 */
280 eap_tls_session->base_flags, NULL, 0, 0) < 0) return -1;
281
282 if (!prf_label) return 0;
283
284 /*
285 * Automatically generate MPPE keying material.
286 */
287 if (eap_crypto_mppe_keys(request->parent, tls_session->ssl, prf_label) < 0) return -1;
288
289 /*
290 * Add the EAP session ID to the request
291 */
292 {
293 uint8_t *session_id;
294 fr_pair_t *vp;
295
297 if (eap_crypto_tls_session_id(vp, request, tls_session->ssl, prf_label,
298 &session_id, eap_session->type) < 0) {
300 return -1;
301 }
302 fr_pair_value_memdup_buffer_shallow(vp, session_id, false);
303
304 RINDENT();
305 RDEBUG2("reply.%pP", vp);
306 REXDENT();
307 }
308
309 return 0;
310}
311
312/** Send an EAP-TLS failure
313 *
314 * Composes an EAP-TLS-Failure. This is a message with code EAP_TLS_FAILURE.
315 * It contains no cryptographic material, and is not protected.
316 *
317 * In addition to sending the failure, will destroy any cached session data.
318 *
319 * The caller MUST set the caller's own p_result->rcode before calling this function.
320 *
321 * @param[in] request The current subrequest.
322 * @param[in] eap_session that failed.
323 * @return
324 * - UNLANG_ACTION_PUSHED_CHILD - cache sections are running.
325 * - UNLANG_ACTION_CALCULATE_RESULT - there was no cache work to do.
326 * - UNLANG_ACTION_FAIL - the frame could not be pushed.
327 */
329{
330 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
331 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
332
333 fr_assert(request->parent); /* must be a subrequest */
334
335 eap_session->finished = true;
336
337 if (eap_tls_compose(request, eap_session, EAP_TLS_FAIL,
338 eap_tls_session->base_flags, NULL, 0, 0) < 0) {
339 REDEBUG("Failed composing EAP-Failure");
340 }
341
342 /*
343 * Authentication failed. Run "fail session", cancel
344 * any queued "store session", and then run "clear
345 * session".
346 */
347 return fr_tls_session_fail_session(request, tls_session);
348}
349
350/** Frames the OpenSSL data that needs to be sent to the client in an EAP-Request
351 *
352 * A single TLS record may be up to 16384 octets in length, but a TLS message
353 * may span multiple TLS records, and a TLS certificate message may theoretically,
354 * be as big as 16MB.
355 *
356 * In EAP-TLS with no inner method, this is used primarily to send our certificate
357 * chain to the peer.
358 *
359 * In other methods this function is also called to package up application data
360 * for the inner tunnel method.
361 *
362 * The eap_tls_session->length_included flag determines whether we include the extra
363 * four byte length field in the request and set the L flag.
364 *
365 * If present, the tls_length field indicates the total length of the reassembled
366 * TLS record.
367 *
368 * If eap_tls_session->length_included this means we include L flag and the tls_length
369 * field in EVERY packet we send out.
370 *
371 * If !eap_tls_session->length_included this means we include L flag and tls_length
372 * field **ONLY** in First packet of a fragment series. We do not use it anywhere
373 * else.
374 *
375 * @param request the request
376 * @param eap_session that's continuing.
377 * @return
378 * - 0 on success.
379 * - -1 on failure.
380 */
382{
383 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
384 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
385 uint8_t flags = eap_tls_session->base_flags;
386 size_t frag_len;
387 bool length_included;
388
389 /*
390 * We don't need to always include the length
391 * (just in the first fragment) but it is
392 * configurable for compatibility.
393 */
394 length_included = eap_tls_session->include_length;
395
396 /*
397 * If this is the first fragment, record the complete
398 * TLS record length.
399 */
400 if (eap_tls_session->record_out_started == false) {
401 eap_tls_session->record_out_total_len = fr_dbuff_remaining(tls_session->dirty_out);
402 }
403
404 /*
405 * If the data we're sending is greater than the MTU
406 * then we need to fragment it.
407 */
408 if ((fr_dbuff_remaining(tls_session->dirty_out) +
409 (length_included ? TLS_HEADER_LENGTH_FIELD_LEN : 0)) > tls_session->mtu) {
410 if (eap_tls_session->record_out_started == false) length_included = true;
411
412 frag_len = length_included ? tls_session->mtu - TLS_HEADER_LENGTH_FIELD_LEN:
413 tls_session->mtu;
414
415 flags = SET_MORE_FRAGMENTS(flags);
416
417 /*
418 * Length MUST be included if we're record_out_started
419 * and this is the first fragment.
420 */
421 if (eap_tls_session->record_out_started == false) {
422 RDEBUG2("Complete TLS record (%zu bytes) larger than MTU (%zu bytes), will fragment",
423 eap_tls_session->record_out_total_len, frag_len); /* frag_len is correct here */
424 RDEBUG2("Sending first TLS record fragment (%zu bytes), %zu bytes remaining",
425 frag_len, fr_dbuff_remaining(tls_session->dirty_out) - frag_len);
426 } else {
427 RDEBUG2("Sending additional TLS record fragment (%zu bytes), %zu bytes remaining",
428 frag_len, fr_dbuff_remaining(tls_session->dirty_out) - frag_len);
429 }
430 eap_tls_session->record_out_started = true; /* Start a new series of fragments */
431 /*
432 * Otherwise, we're either sending a record smaller
433 * than the MTU or this is the final fragment.
434 */
435 } else {
436 frag_len = fr_dbuff_remaining(tls_session->dirty_out); /* Remaining data to drain */
437
438 if (eap_tls_session->record_out_started == false) {
439 RDEBUG2("Sending complete TLS record (%zu bytes)", frag_len);
440 } else {
441 RDEBUG2("Sending final TLS record fragment (%zu bytes)", frag_len);
442 }
443 eap_tls_session->record_out_started = false;
444 }
445
446 /*
447 * Update the flags to say we're including the
448 * TLS record length.
449 */
450 if (length_included) flags = SET_LENGTH_INCLUDED(flags);
451
452 return eap_tls_compose(request, eap_session, EAP_TLS_RECORD_SEND, flags,
453 tls_session->dirty_out, eap_tls_session->record_out_total_len, frag_len);
454}
455
456/** ACK a fragment of the TLS record from the peer
457 *
458 * EAP server sends an ACK when it determines there are More fragments to
459 * receive to make the complete TLS-record.
460 *
461 * When the EAP server receives an EAP-Response with the M bit set, it MUST
462 * respond with an EAP-Request with EAP-Type = EAP-TLS and no data. This serves
463 * as a fragment ACK.
464 *
465 * In order to prevent errors in the processing of fragments, the EAP server
466 * MUST use increment the Identifier value for each fragment ACK contained
467 * within an EAP-Request, and the peer MUST include this Identifier value in
468 * the subsequent fragment contained within an EAP-Reponse.
469 *
470 * @param[in] request The current subrequest.
471 * @param[in] eap_session that we're acking the fragment for.
472 */
473static int eap_tls_ack(request_t *request, eap_session_t *eap_session)
474{
475 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
476
477 fr_assert(request->parent); /* must be a subrequest */
478
479 RDEBUG2("ACKing Peer's TLS record fragment");
480 return eap_tls_compose(request, eap_session, EAP_TLS_ACK_SEND,
481 eap_tls_session->base_flags, NULL, 0, 0);
482}
483
484/** Reduce session states down into an easy to use status
485 *
486 * @param[in] request The current subrequest.
487 * @param[in] eap_session that we're acking the fragment for.
488 * @return
489 * - EAP_TLS_ESTABLISHED - Handshake completed.
490 * - EAP_TLS_FAIL - Fatal alert from the client.
491 * - EAP_TLS_RECORD_SEND - Need more data, or previous fragment was acked.
492 */
494{
495 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
496 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
497
498 if (tls_session == NULL){
499 REDEBUG("Unexpected ACK received: No ongoing SSL tls_session");
500 return EAP_TLS_INVALID;
501 }
502 if (!tls_session->info.initialized) {
503 RDEBUG2("No SSL info available. Waiting for more SSL data");
504 return EAP_TLS_RECORD_SEND;
505 }
506
507 if ((tls_session->info.content_type == SSL3_RT_HANDSHAKE) &&
508 (tls_session->info.origin == TLS_INFO_ORIGIN_RECORD_RECEIVED)) {
509 REDEBUG("Unexpected ACK received: We sent no previous messages");
510 return EAP_TLS_INVALID;
511 }
512
513 switch (tls_session->info.content_type) {
514 case SSL3_RT_ALERT:
515 RDEBUG2("Peer ACKed our alert");
516 return EAP_TLS_FAIL;
517
518 case SSL3_RT_HANDSHAKE:
519 if (fr_tls_session_is_init_finished(tls_session) && (fr_dbuff_remaining(tls_session->dirty_out) == 0)) {
520 RDEBUG2("Peer ACKed our handshake fragment. handshake is finished");
521
522 /*
523 * From now on all the content is
524 * application data set it here as nobody else
525 * sets it.
526 */
527 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
528 return EAP_TLS_ESTABLISHED;
529 } /* else more data to send */
530
531 RDEBUG2("Peer ACKed our handshake fragment");
532 /* Fragmentation handler, send next fragment */
533 return EAP_TLS_RECORD_SEND;
534
535 case SSL3_RT_APPLICATION_DATA:
536 RDEBUG2("Peer ACKed our application data fragment");
537 return EAP_TLS_RECORD_SEND;
538
539 /*
540 * For the rest of the conditions, switch over
541 * to the default section below.
542 */
543 default:
544 /*
545 * If the last message was from us, then the session is established or we're still
546 * sending the session ticket.
547 */
548 if (tls_session->info.origin == TLS_INFO_ORIGIN_RECORD_SENT) {
549 if (fr_dbuff_remaining(tls_session->dirty_out) == 0) return EAP_TLS_ESTABLISHED;
550 return EAP_TLS_RECORD_SEND;
551 }
552 REDEBUG("Invalid ACK received: %d", tls_session->info.content_type);
553 return EAP_TLS_INVALID;
554 }
555}
556
557/** Check that this EAP-TLS packet is correct and the progression of EAP-TLS packets is sane
558 *
559 * @note In the received packet, No data will be present in case of ACK or NAK
560 * in this case the packet->data pointer will be NULL.
561 *
562 * @param[in] request the current subrequest.
563 * @param[in] eap_session the current EAP session state.
564 * @return
565 * - EAP_TLS_INVALID if the TLS record or progression is invalid.
566 * - EAP_TLS_FAIL handshake failed.
567 * - EAP_TLS_RECORD_RECV_FIRST this is the start of a new sequence of record fragments.
568 * - EAP_TLS_RECORD_RECV_MORE this is a continuation of a sequence of fragments.
569 * - EAP_TLS_RECORD_RECV_COMPLETE we received a completed record.
570 * - EAP_TLS_RECORD_SEND send more data to peer.
571 * - EAP_TLS_ESTABLISHED handshake is complete, TLS session has been established.
572 */
574{
575 eap_round_t *this_round = eap_session->this_round;
576 eap_round_t *prev_round = eap_session->prev_round;
577 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
578
579 eap_tls_data_t *eap_tls_data;
580 size_t frag_len, header_len;
581
582 fr_assert(request->parent); /* must be a subrequest */
583
584 /*
585 * All EAP-TLS packets must contain type and flags fields.
586 */
587 if (this_round->response->length < (EAP_HEADER_LEN + 2)) {
588 REDEBUG("Invalid EAP-TLS packet: Expected at least %zu bytes got %zu bytes",
589 (size_t)EAP_HEADER_LEN + 2, this_round->response->length);
590 return EAP_TLS_INVALID;
591 }
592
593 /*
594 * We don't check ANY of the input parameters. It's all
595 * code which works together, so if something is wrong,
596 * we SHOULD core dump.
597 *
598 * e.g. if this_round is NULL, or if this_round->response is
599 * NULL, or if it's NOT an EAP-Response, or if the packet
600 * is too short. See eap_validate()., in ../../eap.c
601 */
602 eap_tls_data = (eap_tls_data_t *)this_round->response->type.data;
603 if (!eap_tls_data) {
604 REDEBUG("Invalid EAP-TLS packet; no data");
605 return EAP_TLS_INVALID;
606 }
607
608 /*
609 * First output the flags (for debugging)
610 */
611 RDEBUG3("Peer sent flags %c%c%c%c%c%c%c%c",
612 TLS_START(eap_tls_data->flags) ? 'S' : '-',
613 TLS_MORE_FRAGMENTS(eap_tls_data->flags) ? 'M' : '-',
614 TLS_LENGTH_INCLUDED(eap_tls_data->flags) ? 'L' : '-',
615 TLS_RESERVED0(eap_tls_data->flags) ? 'R' : '-',
616 TLS_RESERVED1(eap_tls_data->flags) ? 'R' : '-',
617 TLS_RESERVED2(eap_tls_data->flags) ? 'R' : '-',
618 TLS_RESERVED3(eap_tls_data->flags) ? 'R' : '-',
619 TLS_RESERVED4(eap_tls_data->flags) ? 'R' : '-');
620
621 /*
622 * This length includes the type and flags field and
623 * the message length field if the flags indicate it's present.
624 */
625 header_len = EAP_HEADER_LEN + (TLS_LENGTH_INCLUDED(eap_tls_data->flags) ? 6 : 2);
626 if (this_round->response->length < header_len) {
627 REDEBUG("Invalid EAP-TLS packet: Expected at least %zu bytes got %zu bytes",
628 header_len, this_round->response->length);
629 return EAP_TLS_INVALID;
630 }
631
632 /*
633 * check for ACK
634 *
635 * If there's no TLS data, or there's 1 byte of TLS data,
636 * with the flags set to zero, then it's an ACK.
637 *
638 * Find if this is a reply to the previous request sent
639 */
640 if ((this_round->response->length == EAP_HEADER_LEN + 2) &&
641 ((eap_tls_data->flags & 0xc0) == 0x00)) {
642 if (!prev_round || (prev_round->request->id != this_round->response->id)) {
643 REDEBUG("Received Invalid TLS ACK");
644 return EAP_TLS_INVALID;
645 }
646 return eap_tls_session_status(request, eap_session);
647 }
648
649 /*
650 * We send TLS_START, but do not receive it.
651 */
652 if (TLS_START(eap_tls_data->flags)) {
653 REDEBUG("Peer sent EAP-TLS Start message (only the server is allowed to do this)");
654 return EAP_TLS_INVALID;
655 }
656
657 /*
658 * Calculate this fragment's length
659 */
660 frag_len = this_round->response->length - header_len;
661
662 /*
663 * This fragment has no data, but the header says that there is more data!
664 */
665 if (!frag_len && TLS_MORE_FRAGMENTS(eap_tls_data->flags)) {
666 REDEBUG("Peer sent EAP-TLS with zero-length fragment and 'more' bit set - if there is no data, there should not be more!");
667 return EAP_TLS_INVALID;
668 }
669
670 /*
671 * The L bit (length included) is set to indicate the
672 * presence of the four octet TLS Message Length field,
673 * and MUST be set for the first fragment of a fragmented
674 * TLS message or set of messages.
675 *
676 * The M bit (more fragments) is set on all but the last
677 * fragment.
678 *
679 * The S bit (EAP-TLS start) is set in an EAP-TLS Start
680 * message. This differentiates the EAP-TLS Start message
681 * from a fragment acknowledgement.
682 */
683 if (TLS_LENGTH_INCLUDED(eap_tls_data->flags)) {
684 size_t total_len;
685
686 if (eap_tls_data->data[0] || eap_tls_data->data[1]) {
687 REDEBUG("TLS record length is > 65536");
688 return EAP_TLS_INVALID;
689 }
690
691 total_len = eap_tls_data->data[2] * 256 | eap_tls_data->data[3];
692 if (frag_len > total_len) {
693 REDEBUG("TLS fragment length (%zu bytes) greater than TLS record length (%zu bytes)",
694 frag_len, total_len);
695 return EAP_TLS_INVALID;
696 }
697
698 if (total_len > SSL3_RT_MAX_PLAIN_LENGTH) {
699 REDEBUG("Reassembled TLS record will be %zu bytes, "
700 "greater than our maximum record size (" STRINGIFY(SSL3_RT_MAX_PLAIN_LENGTH) " bytes)",
701 total_len);
702 return EAP_TLS_INVALID;
703 }
704
705 /*
706 * wpa_supplicant's implementation of PEAPv0, and likely other
707 * implementations of PEAPv0 will always include a Length flag
708 * for every record fragment if performing mutual TLS auth.
709 *
710 * If the eap_session says this is not the first fragment, then
711 * don't count this as a new record, and continue as if we
712 * hadn't seen the length flag.
713 */
714 if (eap_tls_session->record_in_started) goto ignore_length;
715
716 /*
717 * This is the first fragment of a fragmented TLS record transfer.
718 */
719 RDEBUG2("Peer indicated complete TLS record size will be %zu bytes", total_len);
720 if (TLS_MORE_FRAGMENTS(eap_tls_data->flags)) {
721 /*
722 * The peer is free to send fragments of wildly varying
723 * lengths, but the vast majority won't.
724 *
725 * In this calculation we take into account the fact that the future
726 * fragments are likely to be 4 bytes larger than the initial one
727 * as they won't contain the length field.
728 */
729 if (frag_len + 4) { /* check for wrap, else clang scan gets excited */
730 RDEBUG2("Expecting %i TLS record fragments",
731 (int)((((total_len - frag_len) + ((frag_len + 4) - 1)) / (frag_len + 4)) + 1));
732 }
733
734 /*
735 * First fragment. record_in_started bool was false,
736 * and we received a length included + more fragments packet.
737 */
738 RDEBUG2("Got first TLS record fragment (%zu bytes). Peer indicated more fragments "
739 "to follow", frag_len);
740 eap_tls_session->record_in_total_len = total_len;
741 eap_tls_session->record_in_recvd_len = frag_len;
742 eap_tls_session->record_in_started = true;
743
745 }
746
747 /*
748 * Else this is the complete TLS record.
749 */
750 if (total_len != frag_len) {
751 REDEBUG("Peer indicated no more fragments, but TLS record length (%zu bytes) "
752 "does not match EAP-TLS data length (%zu bytes)", total_len, frag_len);
753 return EAP_TLS_INVALID;
754 }
755
756 /*
757 * RFC5216 doesn't specify explicitly whether a non-fragmented
758 * packet should include the length or not.
759 *
760 * We support both options for maximum compatibility.
761 */
762 RDEBUG2("Got complete TLS record, with length field (%zu bytes)", frag_len);
764 }
765
766ignore_length:
767 if (TLS_MORE_FRAGMENTS(eap_tls_data->flags)) {
768 /*
769 * If this is not an ongoing transfer, and we have the M flag
770 * then this record transfer is invalid.
771 */
772 if (!eap_tls_session->record_in_started) {
773 REDEBUG("TLS More (M) flag set, but no fragmented record transfer was in progress");
774 return EAP_TLS_INVALID;
775 }
776
777 /*
778 * If this is an ongoing transfer, and we have the M flag,
779 * then this is just an additional fragment.
780 */
781 RDEBUG2("Got additional TLS record fragment (%zu bytes). Peer indicated more fragments to follow",
782 frag_len);
783 eap_tls_session->record_in_recvd_len += frag_len;
784 if (eap_tls_session->record_in_recvd_len > eap_tls_session->record_in_total_len) {
785 REDEBUG("Total received TLS record fragments (%zu bytes), exceeds "
786 "indicated TLS record length (%zu bytes)",
787 eap_tls_session->record_in_recvd_len, eap_tls_session->record_in_total_len);
788 return EAP_TLS_INVALID;
789 }
791 }
792
793 /*
794 * No L flag and no M flag. This is either the final fragment,
795 * or a new transfer that was not started with a L flag, which
796 * RFC5216 hints, may be acceptable.
797 *
798 * If it's an in-progress record transfer, check we now have
799 * the complete record.
800 */
801 if (eap_tls_session->record_in_started) {
802 eap_tls_session->record_in_started = false;
803
804 RDEBUG2("Got final TLS record fragment (%zu bytes)", frag_len);
805 eap_tls_session->record_in_recvd_len += frag_len;
806 if (eap_tls_session->record_in_recvd_len != eap_tls_session->record_in_total_len) {
807 REDEBUG("Total received TLS record fragments (%zu bytes), does not equal indicated "
808 "TLS record length (%zu bytes)",
809 eap_tls_session->record_in_recvd_len, eap_tls_session->record_in_total_len);
810 return EAP_TLS_INVALID;
811 }
813 }
814
815 /*
816 * None of the flags are set, it wasn't an in progress transfer,
817 * but it's still a valid EAP-TLS packet.
818 */
819 RDEBUG2("Got complete TLS record (%zu bytes)", frag_len);
820
822}
823
824/** Process the result from the last TLS handshake round
825 *
826 * @return
827 * - eap_tls_session->state == EAP_TLS_FAIL if the message is invalid.
828 * - eap_tls_session->state == EAP_TLS_HANDLED if we need to send an
829 * additional request to the peer.
830 * - eap_tls_session->state == EAP_TLS_ESTABLISHED if the handshake
831 * completed successfully, and there's no more data to send.
832 */
834{
835 eap_session_t *eap_session = talloc_get_type_abort(uctx, eap_session_t);
836 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
837 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->tls_session, fr_tls_session_t);
839
840 switch (tls_session->result) {
841 case FR_TLS_RESULT_IN_PROGRESS:
842 default:
843 fr_assert(0); /* Shouldn't have been called */
844 goto fail;
845
846 case FR_TLS_RESULT_ERROR:
847 REDEBUG("TLS receive handshake failed during operation");
848 goto fail;
849
850 case FR_TLS_RESULT_SUCCESS:
851 break;
852 }
853
854 /*
855 * RFC 9190 Section 2.5
856 *
857 * We need to signal the other end that TLS negotiation
858 * is done. We can't send a zero-length application data
859 * message, so we send application data which is one byte
860 * of zero. This also pushes out any stateless session
861 * tickets to the peer.
862 *
863 * Note this is only done for when there is no application
864 * data to be sent. So this is done always for EAP-TLS but
865 * notibly not for PEAP even on resumption.
866 *
867 * We only want to send this application data IF:
868 *
869 * * EAP-TLS / TTLS / PEAP - session was resumed
870 * * EAP-TLS
871 * * SSL init is finished (presumed to be checked elsewhere)
872 * * we saw the client cert
873 * * OR we're using unauthenticated EAP-TLS where
874 * the administrator has decided to not ask for
875 * the client cert
876 */
877 if ((tls_session->info.version == TLS1_3_VERSION) &&
878 (tls_session->peer_cert_ok || eap_tls_session->authentication_success || SSL_session_reused(tls_session->ssl))) {
879 if ((eap_session->type == FR_EAP_METHOD_TLS) || SSL_session_reused(tls_session->ssl)) {
880 eap_tls_session->authentication_success = true;
881
882 /*
883 * Ensure only a single instance of the application data is added.
884 * Some handshakes result in multiple passes through this path.
885 */
886 if (!tls_session->sent_commitment) {
887 RDEBUG2("(TLS) EAP Sending final Commitment Message.");
888 (void) fr_dbuff_in_bytes(&tls_session->clean_in, (uint8_t) 0x00);
889 tls_session->sent_commitment = true;
890 }
891
892 /*
893 * Write out the application data if the session is ready for it.
894 */
895 if (SSL_is_init_finished(tls_session->ssl)) fr_tls_session_send(request, tls_session);
896 } else {
897
898 /*
899 * Returns UNLANG_ACTION_PUSHED_CHILD unless something has failed
900 */
901 ret = fr_tls_session_async_handshake_push(request, tls_session);
902 if (ret != UNLANG_ACTION_FAIL) return ret;
903
904 REDEBUG("TLS receive handshake failed during operation");
905 goto fail;
906 }
907 }
908
909 /*
910 * FIXME: return success/fail.
911 *
912 * TLS proper can decide what to do, then.
913 */
914 if (fr_dbuff_remaining(tls_session->dirty_out) > 0) {
915 if (eap_tls_request(request, eap_session) < 0) {
916 REDEBUG("TLS failed composing a response");
917 goto fail;
918 }
919 eap_tls_session->state = EAP_TLS_HANDLED;
921 }
922
923 /*
924 * If there is no data to send, and
925 * if the SSL handshake is finished, then return
926 * EAP_TLS_ESTABLISHED.
927 *
928 * For EAP-TLS this translates to an EAP-Success, for others
929 * this begins phase2.
930 */
931 if (eap_tls_session->phase2 || fr_tls_session_is_init_finished(tls_session)) {
932 eap_tls_session->phase2 = true;
933
934 /*
935 * Init is finished. The rest is
936 * application data.
937 */
938 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
939 eap_tls_session->state = EAP_TLS_ESTABLISHED;
941 }
942
943 /*
944 * Who knows what happened...
945 */
946 REDEBUG("TLS failed during operation");
947fail:
948 eap_tls_session->state = EAP_TLS_FAIL;
949
950 /*
951 * Record that the handshake failed, and let the caller deal
952 * with it.
953 *
954 * Every caller reaches eap_tls_fail(), which runs
955 * "fail session" and discards the session. Doing either of
956 * those here as well would run the policy twice for one
957 * failure.
958 */
960}
961
962/** Push functions to continue the handshake asynchronously
963 *
964 * @param[in] request the current subrequest.
965 * @param[in] eap_session to continue.
966 * @return
967 * - UNLANG_ACTION_PUSHED_CHILD
968 */
969static inline CC_HINT(always_inline) unlang_action_t eap_tls_handshake_push(request_t *request, eap_session_t *eap_session)
970{
971 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
972 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->tls_session, fr_tls_session_t);
974
975 /*
976 * Will run after the handshake round completes
977 */
979 NULL,
981 NULL,
983 eap_session) < 0) return UNLANG_ACTION_FAIL;
984
985 if (!fr_cond_assert((ua = fr_tls_session_async_handshake_push(request, tls_session)) == UNLANG_ACTION_PUSHED_CHILD)) {
986 unlang_interpet_frame_discard(request); /* Pop the resume function */
987 return UNLANG_ACTION_FAIL;
988 }
989
990 return ua;
991}
992
993/** Process an EAP TLS request
994 *
995 * Here we implement a basic state machine. The state machine is implicit and
996 * is driven by the state of the TLS session and the flags sent.
997 * INCOMING DATA:
998 * 1. EAP-TLS should get the complete TLS data from the peer.
999 * 2. Store that data in a data structure with any other required info
1000 * 3. Hand this data structure to the TLS module.
1001 * 4. TLS module will perform its operations on the data and hands back to EAP-TLS
1002 * OUTGOING DATA:
1003 * 1. EAP-TLS if necessary will fragment it and send it to the destination.
1004 *
1005 * During EAP-TLS initialization, TLS Context object will be initialised and stored.
1006 * For every new authentication request, TLS will open a new session object and that
1007 * session object SHOULD be maintained even after the session is completed, for session
1008 * resumption.
1009 *
1010 * Note that we never return FAIL to the interpreter. Instead, we
1011 * send the EAP failure back to the supplicant.
1012 *
1013 * @param request the request
1014 * @param eap_session to continue.
1015 * @return
1016 * - UNLANG_ACTION_CALCULATE_RESULT
1017 */
1019{
1020 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
1021 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
1022
1023 eap_round_t *this_round = eap_session->this_round;
1024
1025 eap_tls_data_t *eap_tls_data;
1026 uint8_t *data;
1027 size_t data_len;
1028
1029 fr_assert(request->parent); /* must be a subrequest */
1030
1031 RDEBUG2("Continuing EAP-TLS");
1032
1033 /*
1034 * Call eap_tls_verify to sanity check the incoming EAP data.
1035 */
1036 eap_tls_session->state = eap_tls_verify(request, eap_session);
1037 switch (eap_tls_session->state) {
1038 case EAP_TLS_INVALID:
1039 case EAP_TLS_FAIL:
1040 REDEBUG("[eap-tls verify] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
1041 break;
1042
1043 default:
1044 RDEBUG2("[eap-tls verify] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
1045 break;
1046 }
1047
1048 /*
1049 * Status in this here means 'state'. Our state is determined passively
1050 * for EAP-TLS, based on what state OpenSSL reported the TLS session
1051 * to be in, and what flags were last received from the peer.
1052 */
1053 switch (eap_tls_session->state) {
1054 /*
1055 * We've received a complete TLS record, this is the same as receiving a
1056 * fragment, except we also process the complete record.
1057 */
1059 /*
1060 * We've received a fragment of a TLS record
1061 *
1062 * Determine where the TLS record starts.
1063 *
1064 * If the length included flag is set, we need to skip over the 4 byte
1065 * message length field.
1066 *
1067 * Next - Copy the fragment data into OpenSSL's dirty in buffer so that it
1068 * can process it in a later call.
1069 */
1072 eap_tls_data = (eap_tls_data_t *)this_round->response->type.data;
1073 if (TLS_LENGTH_INCLUDED(eap_tls_data->flags)) {
1074 data = (this_round->response->type.data + 5); /* flags + TLS-Length */
1075 data_len = this_round->response->type.length - 5; /* flags + TLS-Length */
1076 } else {
1077 data = this_round->response->type.data + 1; /* flags */
1078 data_len = this_round->response->type.length - 1; /* flags */
1079 }
1080
1081 /*
1082 * Update the dirty_in buffer (data for reading by OpenSSL)
1083 *
1084 * OpenSSL reads this, and writes clean data out.
1085 * The dirty_in buffer may contain partial TLS
1086 * records on exit.
1087 */
1088 if (fr_dbuff_in_memcpy_partial(tls_session->dirty_in, data, data_len) != data_len) {
1089 REDEBUG("Exceeded maximum record size");
1090 eap_tls_session->state = EAP_TLS_FAIL;
1091 goto done;
1092 }
1093
1094 /*
1095 * ACK fragments until we get a complete TLS record.
1096 */
1097 if (eap_tls_session->state != EAP_TLS_RECORD_RECV_COMPLETE) {
1098 if (eap_tls_ack(request, eap_session) < 0) {
1099 eap_tls_session->state = EAP_TLS_FAIL;
1100 } else {
1101 eap_tls_session->state = EAP_TLS_HANDLED;
1102 }
1103 goto done;
1104 }
1105
1106 /*
1107 * We have a complete record. If the handshake is finished
1108 * process it as application data, otherwise continue
1109 * the handshake.
1110 */
1111 if (eap_tls_session->phase2 || fr_tls_session_is_init_finished(tls_session)) {
1112 int ret;
1113
1114 eap_tls_session->phase2 = true;
1115
1116 ret = fr_tls_session_recv(request, tls_session);
1117 switch (ret) {
1118 case 0:
1119 eap_tls_session->state = EAP_TLS_RECORD_RECV_COMPLETE;
1120 break;
1121
1122 case 1:
1123 eap_tls_session->state = EAP_TLS_RECORD_RECV_MORE;
1124 break;
1125
1126 default:
1127 eap_tls_session->state = EAP_TLS_FAIL;
1128 break;
1129 }
1130 } else {
1131 /*
1132 * Asynchronously process more handshake data
1133 */
1134 return eap_tls_handshake_push(request, eap_session);
1135 }
1136 break;
1137 /*
1138 * We have fragments or records to send to the peer
1139 */
1141 /*
1142 * Return a "yes we're done" if there's no more data to send,
1143 * and we've just managed to finish the SSL session initialization.
1144 */
1145 if (!eap_tls_session->phase2 && (fr_dbuff_remaining(tls_session->dirty_out) == 0) &&
1146 fr_tls_session_is_init_finished(tls_session)) {
1147 eap_tls_session->phase2 = true;
1148 eap_tls_session->state = EAP_TLS_ESTABLISHED;
1149 goto done;
1150 }
1151
1152 if (eap_tls_request(request, eap_session) < 0) {
1153 eap_tls_session->state = EAP_TLS_FAIL;
1154 } else {
1155 eap_tls_session->state = EAP_TLS_HANDLED;
1156 }
1157 goto done;
1158
1159 /*
1160 * Bad things happened and we're unable to continue.
1161 */
1162 case EAP_TLS_INVALID:
1163 case EAP_TLS_FAIL:
1164 /*
1165 * Established means that we're done the initial handshake.
1166 *
1167 * For TTLS and PEAP that means begin phase2
1168 */
1170 default:
1171 goto done;
1172 }
1173
1174 done:
1175
1177}
1178
1179/** Create a new fr_tls_session_t associated with an #eap_session_t
1180 *
1181 * Creates a new server fr_tls_session_t and associates it with an #eap_session_t
1182 * adding EAP specific opaque data to the SSL session created during fr_tls_session_t
1183 * initialisation.
1184 *
1185 * @param[in] request The current subrequest.
1186 * @param[in] eap_session to use as a context for the eap_tls_session_t
1187 * @param[in] ssl_ctx to use to configure the fr_tls_session_t.
1188 * @param[in] client_cert Whether we require the peer to prevent a certificate.
1189 * @return
1190 * - A new eap_tls_session on success.
1191 * - NULL on error.
1192 */
1194 SSL_CTX *ssl_ctx, bool client_cert)
1195{
1196 eap_tls_session_t *eap_tls_session;
1197 fr_tls_session_t *tls_session;
1198 fr_tls_conf_t *conf = fr_tls_ctx_conf(ssl_ctx);
1199 fr_pair_t *vp;
1200 fr_pair_t *tls_max, *tls_min;
1201
1202 fr_assert(request->parent); /* must be a subrequest */
1203
1204 /*
1205 * This EAP session is associated with a TLS session
1206 */
1207 eap_session->tls = true;
1208 MEM(eap_tls_session = talloc_zero(eap_session, eap_tls_session_t));
1209
1210 /*
1211 * Initial state.
1212 */
1213 eap_tls_session->state = EAP_TLS_START_SEND;
1214
1215 /*
1216 * As per the RFC...
1217 *
1218 * Broken protocols like PEAPv0 need this set to false.
1219 */
1220 eap_tls_session->include_length = true;
1221
1222 /*
1223 * We use default fragment size, unless the Framed-MTU
1224 * tells us it's too big. Note that we do NOT account
1225 * for the EAP-TLS headers if conf->fragment_size is
1226 * large, because that config item looks to be confusing.
1227 *
1228 * i.e. it should REALLY be called MTU, and the code here
1229 * should figure out what that means for TLS fragment size.
1230 * asking the administrator to know the internal details
1231 * of EAP-TLS in order to calculate fragment sizes is
1232 * just too much.
1233 */
1234 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_framed_mtu);
1235
1236 /*
1237 * TLS 1.3 introduces the concept of early data (also known as zero
1238 * round trip data or 0-RTT data). Early data allows a client to send
1239 * data to a server in the first round trip of a connection, without
1240 * waiting for the TLS handshake to complete if the client has spoken
1241 * to the same server recently. This doesn't work for EAP, so we
1242 * disable early data.
1243 */
1244 SSL_CTX_set_max_early_data(ssl_ctx, 0);
1245
1246 /*
1247 * Every new session is started only from EAP-TLS-START.
1248 * Before Sending our initial EAP-TLS start open a new
1249 * SSL session.
1250 * Create all the required data structures & store them
1251 * in the SSL session's opaque data so that we can use
1252 * these data structures when we get the response.
1253 */
1254 eap_tls_session->tls_session = tls_session = fr_tls_session_alloc_server(eap_tls_session, ssl_ctx,
1255 request, client_cert);
1256 if (unlikely(!tls_session)) return NULL;
1257
1258 /*
1259 * Set our MTU, and enforce dynamic MTU
1260 *
1261 * Account for the EAP header (4), and the EAP-TLS header
1262 * (6), as per Section 4.2 of RFC 2716. What's left is
1263 * the maximum amount of data we read from a TLS buffer.
1264 */
1265 tls_session->mtu = conf->fragment_size - 10;
1266 if (vp && (vp->vp_uint32 > 100) && (vp->vp_uint32 < tls_session->mtu)) {
1267 RDEBUG2("Setting fragment_len from %pP", vp);
1268 tls_session->mtu = vp->vp_uint32;
1269 }
1270
1271 /*
1272 * Add the EAP-Identity value to the TLS session so
1273 * it's available in all the TLS callbacks.
1274 */
1275 {
1276 fr_pair_t *identity;
1277
1278 MEM(identity = fr_pair_afrom_da(tls_session, attr_eap_identity));
1279 fr_pair_value_bstrdup_buffer(identity, eap_session->identity, true);
1280 fr_tls_session_extra_pair_add_shallow(tls_session, identity);
1281 }
1282
1283 /*
1284 * Add the EAP-Type we're running to the subrequest.
1285 */
1286 {
1287 fr_pair_t *type_vp;
1288
1289 MEM(type_vp = fr_pair_afrom_da(tls_session, attr_eap_type));
1290 type_vp->vp_uint32 = eap_session->type;
1291 fr_tls_session_extra_pair_add_shallow(tls_session, type_vp);
1292 }
1293
1294 /*
1295 * Associate various bits of opaque data with the session.
1296 */
1297 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_EAP_SESSION, (void *)eap_session);
1298 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (void *)tls_session);
1299 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf);
1300 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_IDENTITY, (void *)&(eap_session->identity));
1301
1302 tls_max = fr_pair_find_by_da(&request->control_pairs, NULL, attr_tls_max_version);
1303 tls_min = fr_pair_find_by_da(&request->control_pairs, NULL, attr_tls_min_version);
1304 if (tls_max && tls_min && (tls_min->vp_float32 > tls_max->vp_float32)) {
1305 RERROR("Can't set TLS min version greater than max version");
1306 goto skip_tls_version;
1307 }
1308
1309#define SET_TLS_VERSION(_type) \
1310 if (tls_ ## _type) { \
1311 int tls_version = 0; \
1312 if (tls_ ## _type->vp_float32 >= (float) 1.3) { \
1313 tls_version = TLS1_3_VERSION; \
1314 } else if (tls_ ## _type->vp_float32 >= (float) 1.2) { \
1315 tls_version = TLS1_2_VERSION; \
1316 } else if (tls_ ## _type->vp_float32 >= (float) 1.1) { \
1317 tls_version = TLS1_1_VERSION; \
1318 } \
1319 if (tls_version) { \
1320 if (SSL_set_ ## _type ## _proto_version(tls_session->ssl, tls_version) != 1) {\
1321 RERROR("Failed to set %pP", tls_ ## _type); \
1322 } else { \
1323 RDEBUG2("Setting TLS " #_type " version to %0.1f", (double) tls_ ## _type->vp_float32); \
1324 } \
1325 } else { \
1326 RWARN("Invalid value %pP", tls_ ## _type); \
1327 } \
1328 }
1329
1332skip_tls_version:
1333
1334 return eap_tls_session;
1335}
1336
1337/** Apply the limits that EAP puts on a parsed `tls { ... }` section
1338 *
1339 * The submodule's own rules parse the section, through the
1340 * `FR_CONF_SUBSECTION_ALLOC` row that names `fr_tls_server_config`.
1341 *
1342 * @param[in] cs the submodule's section.
1343 * @param[in,out] tls_conf parsed from the `tls { ... }` subsection.
1344 */
1345void eap_tls_conf_check(CONF_SECTION *cs, fr_tls_conf_t *tls_conf)
1346{
1347 /*
1348 * There isn't any point to having EAP sessions cache
1349 * lifetimes which are very low. Arguably, the minimum
1350 * lifetime should be a few hours. We only limit it here
1351 * to 15min, because anything lower is pretty much
1352 * ridiculous.
1353 *
1354 * If the administrator also sets it too low, then we
1355 * raise it.
1356 */
1357 if (!tls_conf->cache.min_lifetime_is_set ||
1358 fr_time_delta_lt(tls_conf->cache.min_lifetime, fr_time_delta_from_sec(15 * 60))) {
1359 tls_conf->cache.min_lifetime = fr_time_delta_from_sec(15 * 60);
1360 cf_log_warn_by_child(cs, "tls", "Raising EAP session.min_lifetime to %pV",
1361 fr_box_time_delta(tls_conf->cache.min_lifetime));
1362 }
1363}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:40
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:38
static uint8_t request[4]
#define USES_APPLE_DEPRECATED_API
Definition build.h:590
#define RCSID(id)
Definition build.h:603
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:245
#define STRINGIFY(x)
Definition build.h:233
#define unlikely(_x)
Definition build.h:486
#define NUM_ELEMENTS(_t)
Definition build.h:437
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
#define cf_log_warn_by_child(_parent, _child, _fmt,...)
Log a warning message against a specified child.
Definition cf_util.h:386
eap_type_data_t type
Definition compose.h:38
size_t length
Definition compose.h:37
eap_packet_t * response
Packet we received from the peer.
Definition compose.h:48
eap_code_t code
Definition compose.h:35
uint8_t id
Definition compose.h:36
eap_packet_t * request
Packet we will send to the peer.
Definition compose.h:49
Contains a pair of request and response packets.
Definition compose.h:47
static size_t min(size_t x, size_t y)
Definition dbuff.c:66
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
Definition dbuff.h:1785
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition dbuff.h:795
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
Definition dbuff.h:1518
#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen)
Copy at most _inlen bytes into the dbuff.
Definition dbuff.h:1491
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:177
#define MEM(x)
Definition debug.h:38
@ FR_EAP_METHOD_TLS
Definition types.h:58
size_t length
Definition types.h:111
#define EAP_HEADER_LEN
Definition types.h:34
uint8_t * data
Definition types.h:112
@ FR_EAP_CODE_FAILURE
Definition types.h:40
@ FR_EAP_CODE_REQUEST
Definition types.h:37
@ FR_EAP_CODE_SUCCESS
Definition types.h:39
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition function.h:181
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition interpret.c:2511
#define UNLANG_SUB_FRAME
Definition interpret.h:37
HIDDEN fr_dict_attr_t const * attr_eap_identity
Definition base.c:89
HIDDEN fr_dict_attr_t const * attr_tls_min_version
Definition base.c:102
HIDDEN fr_dict_attr_t const * attr_framed_mtu
Definition base.c:97
HIDDEN fr_dict_attr_t const * attr_eap_session_id
Definition base.c:88
HIDDEN fr_dict_attr_t const * attr_tls_max_version
Definition base.c:103
HIDDEN fr_dict_attr_t const * attr_eap_type
Definition base.c:90
int eap_crypto_mppe_keys(request_t *request, SSL *ssl, eap_tls_prf_label_t *prf_label)
Generate keys according to RFC 5216 and add to the reply.
Definition crypto.c:83
int eap_crypto_tls_session_id(TALLOC_CTX *ctx, request_t *request, SSL *ssl, eap_tls_prf_label_t *prf_label, uint8_t **out, uint8_t eap_type)
Definition crypto.c:130
char * identity
NAI (User-Name) from EAP-Identity.
Definition session.h:56
void * opaque
Opaque data used by EAP methods.
Definition session.h:63
bool tls
Whether EAP method uses TLS.
Definition session.h:71
eap_type_t type
EAP method number.
Definition session.h:50
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
Definition session.h:60
eap_round_t * prev_round
Previous response/request pair.
Definition session.h:58
bool finished
Whether we consider this session complete.
Definition session.h:72
Tracks the progress of a single session of any EAP method.
Definition session.h:41
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:460
#define RDEBUG3(fmt,...)
Definition log.h:360
#define RERROR(fmt,...)
Definition log.h:315
#define RINDENT()
Indent R* messages by one level.
Definition log.h:447
unsigned int uint32_t
unsigned char uint8_t
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:707
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:284
int fr_pair_value_memdup_buffer_shallow(fr_pair_t *vp, uint8_t const *src, bool tainted)
Assign a talloced buffer to a "octets" type value pair.
Definition pair.c:2972
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
static bool done
Definition radclient.c:80
static rs_t * conf
Definition radsniff.c:52
#define pair_delete_reply(_pair_or_da)
Delete a fr_pair_t in the reply list.
Definition pair.h:181
#define pair_append_reply(_attr, _da)
Allocate and append a fr_pair_t to reply list.
Definition pair.h:47
@ FR_SIGNAL_NONE
No signals.
Definition signal.h:39
fr_pair_value_bstrdup_buffer(vp, eap_session->identity, true)
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
#define fr_time_delta_lt(_a, _b)
Definition time.h:285
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
int eap_tls_success(request_t *request, eap_session_t *eap_session, eap_tls_prf_label_t *prf_label)
Send an EAP-TLS success.
Definition tls.c:267
static eap_tls_status_t eap_tls_verify(request_t *request, eap_session_t *eap_session)
Check that this EAP-TLS packet is correct and the progression of EAP-TLS packets is sane.
Definition tls.c:573
eap_tls_session_t * eap_tls_session_init(request_t *request, eap_session_t *eap_session, SSL_CTX *ssl_ctx, bool client_cert)
Create a new fr_tls_session_t associated with an eap_session_t.
Definition tls.c:1193
static unlang_action_t eap_tls_handshake_push(request_t *request, eap_session_t *eap_session)
Push functions to continue the handshake asynchronously.
Definition tls.c:969
static int eap_tls_ack(request_t *request, eap_session_t *eap_session)
ACK a fragment of the TLS record from the peer.
Definition tls.c:473
void eap_tls_conf_check(CONF_SECTION *cs, fr_tls_conf_t *tls_conf)
Apply the limits that EAP puts on a parsed tls { ... } section.
Definition tls.c:1345
size_t eap_tls_status_table_len
Definition tls.c:94
int eap_tls_compose(request_t *request, eap_session_t *eap_session, eap_tls_status_t status, uint8_t flags, fr_dbuff_t *record, size_t record_len, size_t frag_len)
Convert the EAP-TLS reply packet into an EAP packet.
Definition tls.c:114
int eap_tls_start(request_t *request, eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
Definition tls.c:242
int eap_tls_request(request_t *request, eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
Definition tls.c:381
#define SET_TLS_VERSION(_type)
unlang_action_t eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition tls.c:328
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
Definition tls.c:80
static eap_tls_status_t eap_tls_session_status(request_t *request, eap_session_t *eap_session)
Reduce session states down into an easy to use status.
Definition tls.c:493
static unlang_action_t eap_tls_handshake_resume(request_t *request, void *uctx)
Process the result from the last TLS handshake round.
Definition tls.c:833
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
Definition tls.c:1018
Generic EAP over TLS API.
uint8_t data[]
Definition tls.h:112
int base_flags
Some protocols use the reserved bits of the EAP-TLS flags (such as PEAP).
Definition tls.h:128
eap_tls_status_t
Definition tls.h:86
@ EAP_TLS_RECORD_RECV_FIRST
Received first fragment of a record.
Definition tls.h:105
@ EAP_TLS_INVALID
Invalid, don't reply.
Definition tls.h:87
@ EAP_TLS_HANDLED
TLS code has handled it.
Definition tls.h:90
@ EAP_TLS_RECORD_RECV_MORE
Received additional fragment of a record.
Definition tls.h:106
@ EAP_TLS_ACK_SEND
Acknowledge receipt of a record or record fragment.
Definition tls.h:98
@ EAP_TLS_RECORD_SEND
We're sending a record.
Definition tls.h:97
@ EAP_TLS_RECORD_RECV_COMPLETE
Received final fragment of a record.
Definition tls.h:107
@ EAP_TLS_START_SEND
We're starting a new TLS session.
Definition tls.h:96
@ EAP_TLS_FAIL
Fail, send fail.
Definition tls.h:89
@ EAP_TLS_ESTABLISHED
Session established, send success (or start phase2).
Definition tls.h:88
eap_tls_status_t state
The state of the EAP-TLS session.
Definition tls.h:123
bool phase2
Whether we're in phase 2.
Definition tls.h:132
#define TLS_RESERVED1(x)
Definition tls.h:76
#define TLS_MORE_FRAGMENTS(x)
Definition tls.h:79
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
Definition tls.h:125
bool record_in_started
Whether a record transfer from the peer is currently in progress.
Definition tls.h:143
size_t record_out_total_len
Actual/Total TLS message length we're sending.
Definition tls.h:141
#define SET_START(x)
Definition tls.h:82
#define TLS_RESERVED3(x)
Definition tls.h:74
#define SET_LENGTH_INCLUDED(x)
Definition tls.h:84
uint8_t flags
Definition tls.h:111
#define TLS_START(x)
Definition tls.h:78
size_t record_in_total_len
How long the peer indicated the complete tls record would be.
Definition tls.h:145
#define TLS_RESERVED0(x)
Definition tls.h:77
bool record_out_started
for methods with inner auth, if the inner auth succeeded.
Definition tls.h:139
size_t record_in_recvd_len
How much of the record we've received so far.
Definition tls.h:147
#define TLS_LENGTH_INCLUDED(x)
Definition tls.h:80
#define TLS_RESERVED2(x)
Definition tls.h:75
#define TLS_RESERVED4(x)
Definition tls.h:73
#define TLS_HEADER_LENGTH_FIELD_LEN
Definition tls.h:56
#define SET_MORE_FRAGMENTS(x)
Definition tls.h:83
bool authentication_success
Definition tls.h:137
bool include_length
A flag to include length in every TLS Data/Alert packet.
Definition tls.h:134
Tracks the state of an EAP-TLS session.
Definition tls.h:122
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
Definition value.h:1061
static fr_slen_t data
Definition value.h:1366
static fr_sbuff_err_t char size_t * len
Definition value.h:1061
#define fr_box_time_delta(_val)
Definition value.h:397