The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_eap_ttls.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: b94c411f097dba222f9733ee38362a2b04211126 $
19 * @file rlm_eap_ttls.c
20 * @brief EAP-TTLS as defined by RFC 5281
21 *
22 * @copyright 2003 Alan DeKok (aland@freeradius.org)
23 * @copyright 2006 The FreeRADIUS server project
24 */
25
26RCSID("$Id: b94c411f097dba222f9733ee38362a2b04211126 $")
27USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
28
29#include <freeradius-devel/eap/tls.h>
30#include <freeradius-devel/eap/chbind.h>
31#include <freeradius-devel/tls/strerror.h>
32
33typedef struct {
34 SSL_CTX *ssl_ctx; //!< Thread local SSL_CTX.
36
37typedef struct {
38 /*
39 * TLS configuration
40 */
41 char const *tls_conf_name;
42 fr_tls_conf_t *tls_conf;
43
44 /*
45 * RFC 5281 (TTLS) says that the length field MUST NOT be
46 * in fragments after the first one. However, we've done
47 * it that way for years, and no one has complained.
48 *
49 * In the interests of allowing the server to follow the
50 * RFC, we add the option here. If set to "no", it sends
51 * the length field in ONLY the first fragment.
52 */
54
55 /*
56 * Virtual server for inner tunnel session.
57 */
60
61 /*
62 * Do we do require a client cert?
63 */
66
71
73 { FR_CONF_OFFSET("tls", rlm_eap_ttls_t, tls_conf_name) },
74 { FR_CONF_DEPRECATED("copy_request_to_tunnel", rlm_eap_ttls_t, NULL), .dflt = "no" },
75 { FR_CONF_DEPRECATED("use_tunneled_reply", rlm_eap_ttls_t, NULL), .dflt = "no" },
78 .uctx = &(virtual_server_cf_parse_uctx_t){ .process_module_name = "radius"} },
79 { FR_CONF_OFFSET("include_length", rlm_eap_ttls_t, include_length), .dflt = "yes" },
80 { FR_CONF_OFFSET("require_client_cert", rlm_eap_ttls_t, req_client_cert), .dflt = "no" },
82};
83
85static fr_dict_t const *dict_radius;
86
89 { .out = &dict_freeradius, .proto = "freeradius" },
90 { .out = &dict_radius, .proto = "radius" },
92};
93
95
105
108 { .out = &attr_eap_tls_require_client_cert, .name = "EAP-TLS-Require-Client-Cert", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
109
110 { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
111 { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
112 { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
113 { .out = &attr_ms_chap2_success, .name = "Vendor-Specific.Microsoft.CHAP2-Success", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
114 { .out = &attr_reply_message, .name = "Reply-Message", .type = FR_TYPE_STRING, .dict = &dict_radius },
115 { .out = &attr_eap_channel_binding_message, .name = "Vendor-Specific.UKERNA.EAP-Channel-Binding-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
116 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
117 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
118 { .out = &attr_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_VSA, .dict = &dict_radius },
120};
121
122
123#define FR_DIAMETER_AVP_FLAG_VENDOR 0x80
124#define FR_DIAMETER_AVP_FLAG_MANDATORY 0x40
125/*
126 * 0 1 2 3
127 * 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
128 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
129 * | AVP Code |
130 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131 * |V M r r r r r r| AVP Length |
132 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133 * | Vendor-ID (opt) |
134 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135 * | Data ...
136 * +-+-+-+-+-+-+-+-+
137 */
138
139/*
140 * Verify that the diameter packet is valid.
141 */
142static int diameter_verify(request_t *request, uint8_t const *data, unsigned int data_len)
143{
144 uint32_t attr;
145 uint32_t length;
146 unsigned int hdr_len;
147 unsigned int remaining = data_len;
148
149 while (remaining > 0) {
150 hdr_len = 8; /* 4 octet attr + 4 octet length */
151
152 if (remaining < hdr_len) {
153 RDEBUG2("Diameter attribute is too small (%u) to contain a Diameter header", remaining);
154 return 0;
155 }
156
157 memcpy(&attr, data, sizeof(attr));
158 attr = ntohl(attr);
159 memcpy(&length, data + 4, sizeof(length));
160 length = ntohl(length);
161
162 if ((data[4] & 0x80) != 0) {
163 hdr_len += 4;
164
165 if (remaining < hdr_len) {
166 RDEBUG2("Diameter attribute is too small to contain a Diameter header with Vendor-Id");
167 return 0;
168 }
169 }
170
171 /*
172 * Get the length. If it's too big, die.
173 */
174 length &= 0x00ffffff;
175
176 /*
177 * Too short or too long is bad.
178 */
179 if (length < hdr_len) {
180 RDEBUG2("Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr,
181 length, hdr_len);
182 return 0;
183 }
184
185 if (length > remaining) {
186 RDEBUG2("Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr,
187 length, remaining);
188 return 0;
189 }
190
191 /*
192 * Check for broken implementations, which don't
193 * pad the AVP to a 4-octet boundary.
194 */
195 if (remaining == length) break;
196
197 /*
198 * The length does NOT include the padding, so
199 * we've got to account for it here by rounding up
200 * to the nearest 4-byte boundary.
201 */
202 length += 0x03;
203 length &= ~0x03;
204
205 /*
206 * If the rest of the diameter packet is larger than
207 * this attribute, continue.
208 *
209 * Otherwise, if the attribute over-flows the end
210 * of the packet, die.
211 */
212 if (remaining < length) {
213 REDEBUG2("Diameter attribute overflows packet!");
214 return 0;
215 }
216
217 /*
218 * remaining > length, continue.
219 */
220 remaining -= length;
221 data += length;
222 }
223
224 /*
225 * We got this far. It looks OK.
226 */
227 return 1;
228}
229
230/*
231 * Convert diameter attributes to our fr_pair_t's
232 */
233static ssize_t eap_ttls_decode_pair(request_t *request, TALLOC_CTX *ctx, fr_pair_list_t *out,
234 fr_dict_attr_t const *parent,
235 uint8_t const *data, size_t data_len,
236 void *decode_ctx)
237{
238 uint8_t const *p = data, *end = p + data_len;
239
240 fr_pair_t *vp = NULL;
241 SSL *ssl = decode_ctx;
242 fr_dict_attr_t const *attr_radius;
243 fr_dict_attr_t const *da, *da_unknown;
244 TALLOC_CTX *tmp_ctx = NULL;
245
246 attr_radius = fr_dict_root(dict_radius);
247
248 while (p < end) {
249 ssize_t ret;
250 uint32_t attr, vendor;
251 uint64_t value_len;
252 uint8_t flags;
253 fr_dict_attr_t const *our_parent = parent;
254
255 if ((end - p) < 8) {
256 fr_strerror_printf("Malformed diameter attribute at offset %zu. Needed at least 8 bytes, got %zu bytes",
257 p - data, end - p);
258 error:
259 talloc_free(tmp_ctx);
261 return -1;
262 }
263
264 RDEBUG3("%04zu %02x%02x%02x%02x %02x%02x%02x%02x ...", p - data,
265 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
266
267 attr = fr_nbo_to_uint32(p);
268 p += 4;
269
270 flags = p[0];
271 p++;
272
273 value_len = fr_nbo_to_uint64v(p, 3); /* Yes, that is a 24 bit length field */
274 p += 3;
275
276 if (value_len < 8) {
277 fr_strerror_printf("Malformed diameter attribute at offset %zu. Needed at least length of 8, got %u",
278 p - data, (unsigned int) value_len);
279 goto error;
280 }
281
282 /*
283 * Account for the 8 bytes we've already read from the packet.
284 */
285 if ((p + ((value_len + 0x03) & ~0x03)) - 8 > end) {
286 overflow:
287 fr_strerror_printf("Malformed diameter attribute at offset %zu. Value length %u overflows input",
288 p - data, (unsigned int) value_len);
289 goto error;
290 }
291
292 value_len -= 8; /* -= 8 for AVP code (4), flags (1), AVP length (3) */
293
294 /*
295 * Do we have a vendor field?
296 */
297 if (flags & FR_DIAMETER_AVP_FLAG_VENDOR) {
298 vendor = fr_nbo_to_uint32(p);
299 p += 4;
300
301 if (value_len <= 4) goto overflow;
302
303 value_len -= 4; /* -= 4 for the vendor ID field */
304
306 if (!our_parent) {
307 if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
308 fr_strerror_printf("Mandatory bit set and no vendor %u found", vendor);
309 goto error;
310 }
311
312 if (!tmp_ctx) {
314
315 MEM(our_parent = n = fr_dict_attr_unknown_vendor_afrom_num(ctx, parent, vendor));
316 tmp_ctx = n;
317 } else {
318 MEM(our_parent = fr_dict_attr_unknown_vendor_afrom_num(tmp_ctx, parent, vendor));
319 }
320 }
321 } else {
322 our_parent = attr_radius;
323 }
324
325 /*
326 * Is the attribute known?
327 */
328 da_unknown = NULL;
329 da = fr_dict_attr_child_by_num(our_parent, attr);
330 if (!da) {
331 if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
332 fr_strerror_printf("Mandatory bit set and no attribute %u defined for parent %s", attr, parent->name);
333 goto error;
334 }
335
336 MEM(da_unknown = fr_dict_attr_unknown_raw_afrom_num(ctx, our_parent, attr));
337 da = da_unknown;
338 }
339
340 MEM(vp = fr_pair_afrom_da_nested(ctx, out, da));
341 fr_dict_attr_unknown_free(&da_unknown);
342
343 ret = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
344 &FR_DBUFF_TMP(p, (size_t)value_len), value_len, true);
345 if (ret < 0) {
346 /*
347 * Mandatory bit is set, and the attribute
348 * is malformed. Fail.
349 */
350 if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
351 fr_strerror_const("Mandatory bit is set and attribute is malformed");
352 goto error;
353 }
354
355 fr_pair_raw_afrom_pair(vp, p, value_len);
356 }
357
358 /*
359 * The length does NOT include the padding, so
360 * we've got to account for it here by rounding up
361 * to the nearest 4-byte boundary.
362 */
363 p += (value_len + 0x03) & ~0x03;
364
365 if (vp->da->flags.is_unknown) continue;
366
367 /*
368 * Ensure that the client is using the correct challenge.
369 *
370 * This weirdness is to protect against against replay
371 * attacks, where anyone observing the CHAP exchange could
372 * pose as that user, by simply choosing to use the same
373 * challenge.
374 * By using a challenge based on information from the
375 * current session, we can guarantee that the client is
376 * not *choosing* a challenge. We're a little forgiving in
377 * that we have loose checks on the length, and we do NOT
378 * check the Id (first octet of the response to the
379 * challenge) But if the client gets the challenge correct,
380 * we're not too worried about the Id.
381 */
383 uint8_t challenge[17];
384 static const char label[] = "ttls challenge";
385
386 if ((vp->vp_length < 8) || (vp->vp_length > 16)) {
387 fr_strerror_const("Tunneled challenge has invalid length");
388 goto error;
389 }
390
391 /*
392 * TLSv1.3 exports a different key depending on the length
393 * requested so ask for *exactly* what the spec requires
394 */
395 if (SSL_export_keying_material(ssl, challenge, vp->vp_length + 1,
396 label, sizeof(label) - 1, NULL, 0, 0) != 1) {
397 fr_tls_strerror_printf("Failed generating phase2 challenge");
398 goto error;
399 }
400
401 if (memcmp(challenge, vp->vp_octets, vp->vp_length) != 0) {
402 fr_strerror_const("Tunneled challenge is incorrect");
403 goto error;
404 }
405 }
406
407 /*
408 * Diameter pads strings (i.e. User-Password) with trailing zeros.
409 */
410 if (vp->vp_type == FR_TYPE_STRING) fr_pair_value_strtrim(vp);
411 }
412
413 /*
414 * We got this far. It looks OK.
415 */
416 talloc_free(tmp_ctx);
417 return p - data;
418}
419
420/*
421 * Convert fr_pair_t's to diameter attributes, and write them
422 * to an SSL session.
423 *
424 * The ONLY fr_pair_t's which may be passed to this function
425 * are ones which can go inside of a RADIUS (i.e. diameter)
426 * packet. So no server-configuration attributes, or the like.
427 */
428static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
429{
430 /*
431 * RADIUS packets are no more than 4k in size, so if
432 * we've got more than 4k of data to write, it's very
433 * bad.
434 */
435 uint8_t buffer[4096];
436 uint8_t *p;
437 uint32_t attr;
438 uint32_t length;
439 uint32_t vendor;
440 size_t total;
441 uint64_t attr64;
442 fr_pair_t *vp;
443
444 p = buffer;
445 total = 0;
446
447 for (vp = fr_pair_list_head(list);
448 vp;
449 vp = fr_pair_list_next(list, vp)) {
450 /*
451 * Too much data: die.
452 */
453 if ((total + vp->vp_length + 12 + 3) >= sizeof(buffer)) {
454 RDEBUG2("output buffer is full!");
455 return 0;
456 }
457
458 /*
459 * Hmm... we don't group multiple EAP-Messages
460 * together. Maybe we should...
461 */
462
463 length = vp->vp_length;
464 if (length >= ((1 << 24) - 12)) {
465 RDEBUG2("Attribute is too long!");
466 return 0;
467 }
468
469 vendor = fr_dict_vendor_num_by_da(vp->da);
470 if (vendor != 0) {
471 attr = vp->da->attr & 0xffff;
472 length |= ((uint32_t)1 << 31);
473 } else {
474 attr = vp->da->attr;
475 }
476
477 /*
478 * Hmm... set the M bit for all attributes?
479 */
480 length |= (1 << 30);
481
482 attr = ntohl(attr);
483
484 memcpy(p, &attr, sizeof(attr));
485 p += 4;
486 total += 4;
487
488 length += 8; /* includes 8 bytes of attr & length */
489
490 if (vendor != 0) {
491 length += 4; /* include 4 bytes of vendor */
492
493 length = ntohl(length);
494 memcpy(p, &length, sizeof(length));
495 p += 4;
496 total += 4;
497
498 vendor = ntohl(vendor);
499 memcpy(p, &vendor, sizeof(vendor));
500 p += 4;
501 total += 4;
502 } else {
503 length = ntohl(length);
504 memcpy(p, &length, sizeof(length));
505 p += 4;
506 total += 4;
507 }
508
509 switch (vp->vp_type) {
510 case FR_TYPE_DATE:
511 attr = htonl(fr_unix_time_to_sec(vp->vp_date)); /* stored in host order */
512 memcpy(p, &attr, sizeof(attr));
513 length = 4;
514 break;
515
516 case FR_TYPE_UINT32:
517 attr = htonl(vp->vp_uint32); /* stored in host order */
518 memcpy(p, &attr, sizeof(attr));
519 length = 4;
520 break;
521
522 case FR_TYPE_UINT64:
523 attr64 = htonll(vp->vp_uint64); /* stored in host order */
524 memcpy(p, &attr64, sizeof(attr64));
525 length = 8;
526 break;
527
529 memcpy(p, &vp->vp_ipv4addr, 4); /* network order */
530 length = 4;
531 break;
532
533 case FR_TYPE_STRING:
534 case FR_TYPE_OCTETS:
535 default:
536 memcpy(p, vp->vp_strvalue, vp->vp_length);
537 length = vp->vp_length;
538 break;
539 }
540
541 /*
542 * Skip to the end of the data.
543 */
544 p += length;
545 total += length;
546
547 /*
548 * Align the data to a multiple of 4 bytes.
549 */
550 if ((total & 0x03) != 0) {
551 size_t i;
552
553 length = 4 - (total & 0x03);
554 for (i = 0; i < length; i++) {
555 *p = '\0';
556 p++;
557 total++;
558 }
559 }
560 } /* loop over the VP's to write. */
561
562 /*
563 * Write the data in the buffer to the SSL session.
564 */
565 if (total > 0) {
566 (tls_session->record_from_buff)(&tls_session->clean_in, buffer, total);
567
568 /*
569 * FIXME: Check the return code.
570 */
571 fr_tls_session_send(request, tls_session);
572 }
573
574 /*
575 * Everything's OK.
576 */
577 return 1;
578}
579
580
582{
583 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
584 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
585 eap_tls_prf_label_t prf_label;
586
587 eap_crypto_prf_label_init(&prf_label, eap_session,
588 "ttls keying material",
589 sizeof("ttls keying material") - 1);
590 /*
591 * Success: Automatically return MPPE keys.
592 */
593 if (eap_tls_success(request, eap_session, &prf_label) < 0) RETURN_UNLANG_FAIL;
594
595 /*
596 * Result is always OK, even if we fail to persist the
597 * session data.
598 */
599 p_result->rcode = RLM_MODULE_OK;
600
601 /*
602 * Write the session to the session cache
603 *
604 * We do this here (instead of relying on OpenSSL to call the
605 * session caching callback), because we only want to write
606 * session data to the cache if all phases were successful.
607 *
608 * If we wrote out the cache data earlier, and the server
609 * exited whilst the session was in progress, the supplicant
610 * could resume the session (and get access) even if phase2
611 * never completed.
612 */
613 return fr_tls_cache_pending_push(request, tls_session);
614}
615
616
617/*
618 * Use a reply packet to determine what to do.
619 */
621{
622 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
623 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
624 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
625 fr_pair_t *vp = NULL, *copy;
626 fr_pair_list_t tunnel_vps;
627 ttls_tunnel_t *t = tls_session->opaque;
628 fr_packet_t *reply = request->reply;
629
630 fr_pair_list_init(&tunnel_vps);
631 fr_assert(eap_session->request == request->parent);
632
633 /*
634 * If the response packet was Access-Accept, then
635 * we're OK. If not, die horribly.
636 *
637 * FIXME: Take MS-CHAP2-Success attribute, and
638 * tunnel it back to the client, to authenticate
639 * ourselves to the client.
640 *
641 * FIXME: If we have an Access-Challenge, then
642 * the Reply-Message is tunneled back to the client.
643 *
644 * FIXME: If we have an EAP-Message, then that message
645 * must be tunneled back to the client.
646 *
647 * FIXME: If we have an Access-Challenge with a State
648 * attribute, then do we tunnel that to the client, or
649 * keep track of it ourselves?
650 *
651 * FIXME: EAP-Messages can only start with 'identity',
652 * NOT 'eap start', so we should check for that....
653 */
654 switch (reply->code) {
656 RDEBUG2("Got tunneled Access-Accept");
657
658 /*
659 * Copy what we need into the TTLS tunnel and leave
660 * the rest to be cleaned up.
661 */
662 if ((vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_ms_chap2_success))) {
663 RDEBUG2("Got MS-CHAP2-Success, tunneling it to the client in a challenge");
664 } else {
665 vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_eap_channel_binding_message);
666 }
667 if (vp) {
668 t->authenticated = true;
669 MEM(copy = fr_pair_copy(tls_session, vp));
670 fr_pair_prepend(&tunnel_vps, copy);
672 break;
673 }
674
675 /*
676 * Success: Automatically return MPPE keys.
677 */
678 return eap_ttls_success(p_result, request, eap_session);
679
681 REDEBUG("Got tunneled Access-Reject");
682 eap_tls_fail(request, eap_session);
684
685 /*
686 * Handle Access-Challenge, but only if we
687 * send tunneled reply data. This is because
688 * an Access-Challenge means that we MUST tunnel
689 * a Reply-Message to the client.
690 */
692 RDEBUG2("Got tunneled Access-Challenge");
693
694 /*
695 * Copy what we need into the TTLS tunnel and leave
696 * the rest to be cleaned up.
697 */
698 vp = NULL;
699 while ((vp = fr_pair_list_next(&request->reply_pairs, vp))) {
700 if ((vp->da == attr_eap_message) || (vp->da == attr_reply_message)) {
701 MEM(copy = fr_pair_copy(tls_session, vp));
702 fr_pair_prepend(&tunnel_vps, copy);
703 } else if (vp->da == attr_eap_channel_binding_message) {
704 MEM(copy = fr_pair_copy(tls_session, vp));
705 fr_pair_prepend(&tunnel_vps, copy);
706 }
707 }
708 break;
709
710 default:
711 REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
712 eap_tls_fail(request, eap_session);
714 }
715
716
717 /*
718 * Pack any tunneled VPs and send them back
719 * to the supplicant.
720 */
721 if (!fr_pair_list_empty(&tunnel_vps)) {
722 RDEBUG2("Sending tunneled reply attributes");
723 log_request_pair_list(L_DBG_LVL_2, request, NULL, &tunnel_vps, NULL);
724
725 vp2diameter(request, tls_session, &tunnel_vps);
726 fr_pair_list_free(&tunnel_vps);
727 }
728
729 eap_tls_request(request, eap_session);
731}
732
733/*
734 * Process the "diameter" contents of the tunneled data.
735 */
737 request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
738{
739 fr_pair_t *vp = NULL;
740 ttls_tunnel_t *t;
741 uint8_t const *data;
742 size_t data_len;
743 chbind_packet_t *chbind;
744 fr_pair_t *username;
745 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
746
747 /*
748 * Just look at the buffer directly, without doing
749 * record_to_buff.
750 */
751 data_len = tls_session->clean_out.used;
752 tls_session->clean_out.used = 0;
753 data = tls_session->clean_out.data;
754
755 t = (ttls_tunnel_t *) tls_session->opaque;
756
757 /*
758 * If there's no data, maybe this is an ACK to an
759 * MS-CHAP2-Success.
760 */
761 if (data_len == 0) {
762 if (t->authenticated) {
763 RDEBUG2("Got ACK, and the user was already authenticated");
764 return eap_ttls_success(p_result, request, eap_session);
765 } /* else no session, no data, die. */
766
767 /*
768 * FIXME: Call SSL_get_error() to see what went
769 * wrong.
770 */
771 RDEBUG2("SSL_read Error");
772 return UNLANG_ACTION_FAIL;
773 }
774
775 if (!diameter_verify(request, data, data_len)) return UNLANG_ACTION_FAIL;
776
777 /*
778 * Add the tunneled attributes to the request request.
779 */
780 if (eap_ttls_decode_pair(request, request->request_ctx, &request->request_pairs, fr_dict_root(fr_dict_internal()),
781 data, data_len, tls_session->ssl) < 0) {
782 RPEDEBUG("Decoding TTLS TLVs failed");
783 return UNLANG_ACTION_FAIL;
784 }
785
786 /*
787 * Update other items in the request_t data structure.
788 */
789
790 /*
791 * No User-Name, try to create one from stored data.
792 */
793 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
794 if (!username) {
795 /*
796 * No User-Name in the stored data, look for
797 * an EAP-Identity, and pull it out of there.
798 */
799 if (!t->username) {
800 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_message);
801 if (vp &&
802 (vp->vp_length >= EAP_HEADER_LEN + 2) &&
803 (vp->vp_strvalue[0] == FR_EAP_CODE_RESPONSE) &&
804 (vp->vp_strvalue[EAP_HEADER_LEN] == FR_EAP_METHOD_IDENTITY) &&
805 (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
806 /*
807 * Create & remember a User-Name
808 */
810 t->username->vp_tainted = true;
811
813 (char const *)vp->vp_octets + 5, vp->vp_length - 5, true);
814
815 RDEBUG2("Got tunneled identity of %pV", &t->username->data);
816 } else {
817 /*
818 * Don't reject the request outright,
819 * as it's permitted to do EAP without
820 * user-name.
821 */
822 RWDEBUG2("No EAP-Identity found to start EAP conversation");
823 }
824 } /* else there WAS a t->username */
825
826 if (t->username) {
827 MEM(vp = fr_pair_copy(request->request_ctx, t->username));
828 fr_pair_append(&request->request_pairs, vp);
829 }
830 } /* else the request ALREADY had a User-Name */
831
832 /*
833 * Process channel binding.
834 */
835 chbind = eap_chbind_vp2packet(request, &request->request_pairs);
836 if (chbind) {
837 fr_radius_packet_code_t chbind_code;
838 CHBIND_REQ *req = talloc_zero(request, CHBIND_REQ);
839
840 RDEBUG2("received chbind request");
841 req->request = chbind;
842 if (username) {
843 req->username = username;
844 } else {
845 req->username = NULL;
846 }
847 chbind_code = chbind_process(request, req);
848
849 /* encapsulate response here */
850 if (req->response) {
851 RDEBUG2("sending chbind response");
852 fr_pair_append(&request->reply_pairs,
853 eap_chbind_packet2vp(request->reply_ctx, req->response));
854 } else {
855 RDEBUG2("no chbind response");
856 }
857
858 /* clean up chbind req */
859 talloc_free(req);
860
861 if (chbind_code != FR_RADIUS_CODE_ACCESS_ACCEPT) return UNLANG_ACTION_FAIL;
862 }
863
864 /*
865 * For this round, when the virtual server returns
866 * we run the process reply function.
867 */
868 if (unlikely(unlang_module_yield(request, process_reply, NULL, 0, eap_session) != UNLANG_ACTION_YIELD)) {
869 return UNLANG_ACTION_FAIL;
870 }
871
872 /*
873 * Call authentication recursively, which will
874 * do PAP, CHAP, MS-CHAP, etc.
875 */
876 return eap_virtual_server(request, eap_session, inst->virtual_server);
877}
878
879/*
880 * Allocate the TTLS per-session data
881 */
882static ttls_tunnel_t *ttls_alloc(TALLOC_CTX *ctx)
883{
884 ttls_tunnel_t *t;
885
886 t = talloc_zero(ctx, ttls_tunnel_t);
887
888 return t;
889}
890
892{
893 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
894 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
895 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
896
897 ttls_tunnel_t *tunnel = talloc_get_type_abort(tls_session->opaque, ttls_tunnel_t);
898
899 if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
900 REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
901 } else {
902 RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
903 }
904
905 switch (eap_tls_session->state) {
906 /*
907 * EAP-TLS handshake was successful, tell the
908 * client to keep talking.
909 *
910 * If this was EAP-TLS, we would just return
911 * an EAP-TLS-Success packet here.
912 */
914 if (SSL_session_reused(tls_session->ssl)) {
915 RDEBUG2("Skipping Phase2 due to session resumption");
916 return eap_ttls_success(p_result, request, eap_session);
917 }
918
919 if (tunnel && tunnel->authenticated) return eap_ttls_success(p_result, request, eap_session);
920
921 eap_tls_request(request, eap_session);
923
924 /*
925 * The TLS code is still working on the TLS
926 * exchange, and it's a valid TLS request.
927 * do nothing.
928 */
929 case EAP_TLS_HANDLED:
931
932 /*
933 * Handshake is done, proceed with decoding tunneled
934 * data.
935 */
937 break;
938
939 /*
940 * Anything else: fail.
941 */
942 default:
944 }
945
946 /*
947 * Session is established, proceed with decoding
948 * tunneled data.
949 */
950 RDEBUG2("Session established. Decoding Diameter attributes");
951
952 /*
953 * Process the TTLS portion of the request.
954 */
955 return eap_ttls_process(p_result, mctx, request, eap_session, tls_session);
956}
957
958/*
959 * Do authentication, by letting EAP-TLS do most of the work.
960 */
962 request_t *request)
963{
964 eap_session_t *eap_session = eap_session_get(request->parent);
965
966 /*
967 * Setup the resumption frame to process the result
968 */
969 (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
970
971 /*
972 * Process TLS layer until done.
973 */
974 return eap_tls_process(request, eap_session);
975}
976
978{
979 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
980 rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
981 eap_session_t *eap_session = eap_session_get(request->parent);
982
983 eap_tls_session_t *eap_tls_session;
984 fr_tls_session_t *tls_session;
985 fr_pair_t *vp;
986 bool client_cert;
987
988 /*
989 * EAP-TLS-Require-Client-Cert attribute will override
990 * the require_client_cert configuration option.
991 */
992 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
993 if (vp) {
994 client_cert = vp->vp_uint32 ? true : false;
995 } else {
996 client_cert = inst->req_client_cert;
997 }
998
999 eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, t->ssl_ctx, client_cert);
1000 if (!eap_tls_session) RETURN_UNLANG_FAIL;
1001 tls_session = eap_tls_session->tls_session;
1002
1003 eap_tls_session->include_length = inst->include_length;
1004
1005 /*
1006 * TLS session initialization is over. Now handle TLS
1007 * related handshaking or application data.
1008 */
1009 if (eap_tls_start(request, eap_session) < 0) {
1010 talloc_free(eap_tls_session);
1012 }
1013
1014 tls_session->opaque = ttls_alloc(tls_session);
1015
1016 eap_session->process = mod_handshake_process;
1017
1019}
1020
1021/*
1022 * Send an initial eap-tls request to the peer, using the libeap functions.
1023 */
1025{
1026 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
1027 eap_session_t *eap_session = eap_session_get(request->parent);
1028
1029 eap_session->tls = true;
1030
1031 (void) unlang_module_yield(request, mod_session_init_resume, NULL, 0, NULL);
1032
1033 if (inst->tls_conf->new_session) return fr_tls_new_session_push(request, inst->tls_conf);
1034
1036}
1037
1039{
1040 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
1041 rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
1042
1043 t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
1044 if (!t->ssl_ctx) return -1;
1045
1046 return 0;
1047}
1048
1050{
1051 rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
1052
1053 if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
1054 t->ssl_ctx = NULL;
1055
1056 return 0;
1057}
1058
1059/*
1060 * Attach the module.
1061 */
1062static int mod_instantiate(module_inst_ctx_t const *mctx)
1063{
1064 rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
1065 CONF_SECTION *conf = mctx->mi->conf;
1066
1067 inst->server_cs = virtual_server_cs(inst->virtual_server);
1068
1069 /*
1070 * Read tls configuration, either from group given by 'tls'
1071 * option, or from the eap-tls configuration.
1072 */
1073 inst->tls_conf = eap_tls_conf_parse(conf);
1074 if (!inst->tls_conf) {
1075 cf_log_err(conf, "Failed initializing SSL context");
1076 return -1;
1077 }
1078
1079 return 0;
1080}
1081
1082/*
1083 * The module name should be the only globally exported symbol.
1084 * That is, everything else should be 'static'.
1085 */
1088 .common = {
1089 .magic = MODULE_MAGIC_INIT,
1090 .name = "eap_ttls",
1091
1092 .inst_size = sizeof(rlm_eap_ttls_t),
1094 .instantiate = mod_instantiate, /* Create new submodule instance */
1095
1096 .thread_inst_size = sizeof(rlm_eap_ttls_thread_t),
1097 .thread_instantiate = mod_thread_instantiate,
1098 .thread_detach = mod_thread_detach,
1099 },
1100 .provides = { FR_EAP_METHOD_TTLS },
1101 .session_init = mod_session_init, /* Initialise a new EAP session */
1102};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ 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:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:41
static int const char char buffer[256]
Definition acutest.h:576
int n
Definition acutest.h:577
#define USES_APPLE_DEPRECATED_API
Definition build.h:493
#define RCSID(id)
Definition build.h:506
#define unlikely(_x)
Definition build.h:402
#define UNUSED
Definition build.h:336
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:611
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
Definition cf_parse.h:409
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:429
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:447
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:238
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:285
fr_pair_t * eap_chbind_packet2vp(TALLOC_CTX *ctx, chbind_packet_t *chbind)
Definition chbind.c:316
fr_radius_packet_code_t chbind_process(request_t *request, CHBIND_REQ *chbind)
Definition chbind.c:172
chbind_packet_t * eap_chbind_vp2packet(TALLOC_CTX *ctx, fr_pair_list_t *vps)
Definition chbind.c:271
chbind_packet_t * response
Definition chbind.h:49
fr_pair_t * username
Definition chbind.h:47
chbind_packet_t * request
Definition chbind.h:48
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:522
#define MEM(x)
Definition debug.h:46
fr_radius_packet_code_t
RADIUS packet codes.
Definition defs.h:31
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
Definition defs.h:43
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition defs.h:34
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
Definition defs.h:35
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
Definition dict.h:604
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition dict.h:611
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2665
fr_dict_attr_t const * fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
Return vendor attribute for the specified dictionary and pen.
Definition dict_util.c:2960
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4928
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3593
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
Definition dict_ext.h:176
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
void eap_crypto_prf_label_init(eap_tls_prf_label_t *prf_label, eap_session_t *eap_session, char const *keying_prf_label, size_t keying_prf_label_len)
Initialize the PRF label fields.
Definition crypto.c:48
@ FR_EAP_CODE_RESPONSE
Definition types.h:38
#define EAP_HEADER_LEN
Definition types.h:34
@ FR_EAP_METHOD_TTLS
Definition types.h:66
@ FR_EAP_METHOD_IDENTITY
Definition types.h:46
talloc_free(hp)
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:134
unlang_action_t eap_virtual_server(request_t *request, eap_session_t *eap_session, virtual_server_t *virtual_server)
Run a subrequest through a virtual server.
Definition base.c:387
static eap_session_t * eap_session_get(request_t *request)
Definition session.h:85
void * opaque
Opaque data used by EAP methods.
Definition session.h:63
bool tls
Whether EAP method uses TLS.
Definition session.h:71
module_method_t process
Callback that should be used to process the next round.
Definition session.h:65
request_t * request
Current request.
Definition session.h:52
Tracks the progress of a single session of any EAP method.
Definition session.h:41
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
Definition log.c:831
#define RDEBUG3(fmt,...)
Definition log.h:355
#define RWDEBUG2(fmt,...)
Definition log.h:374
#define RPEDEBUG(fmt,...)
Definition log.h:388
#define REDEBUG2(fmt,...)
Definition log.h:384
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition log.h:68
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
static uint64_t fr_nbo_to_uint64v(uint8_t const *data, size_t data_len)
Read an unsigned 64bit integer from wire format (big endian) with a variable length encoding.
Definition nbo.h:196
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
Definition nbo.h:167
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition pair.c:784
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
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1352
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:290
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition pair.c:2812
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:503
int fr_pair_value_strtrim(fr_pair_t *vp)
Trim the length of the string buffer to match the length of the C string.
Definition pair.c:2706
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
Definition pair.c:480
int fr_pair_prepend(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the start of the list.
Definition pair.c:1321
int fr_pair_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Mark malformed attribute as raw.
Definition pair.c:609
static const conf_parser_t config[]
Definition base.c:163
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
static rs_t * conf
Definition radsniff.c:52
#define RETURN_UNLANG_HANDLED
Definition rcode.h:65
#define RETURN_UNLANG_INVALID
Definition rcode.h:66
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
#define RETURN_UNLANG_REJECT
Definition rcode.h:62
#define RETURN_UNLANG_OK
Definition rcode.h:64
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:49
static unlang_action_t mod_handshake_process(UNUSED unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_handshake_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_attr_t const * attr_user_password
char const * tls_conf_name
virtual_server_t * virtual_server
static fr_dict_attr_t const * attr_eap_message
static fr_dict_attr_t const * attr_eap_channel_binding_message
#define FR_DIAMETER_AVP_FLAG_MANDATORY
static fr_dict_t const * dict_freeradius
static fr_dict_attr_t const * attr_eap_tls_require_client_cert
fr_pair_t * username
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
static fr_dict_attr_t const * attr_ms_chap2_success
static unlang_action_t mod_session_init_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_t const * dict_radius
static fr_dict_attr_t const * attr_ms_chap_challenge
static fr_dict_attr_t const * attr_chap_challenge
static fr_dict_attr_t const * attr_vendor_specific
static fr_dict_attr_t const * attr_reply_message
static unlang_action_t eap_ttls_success(unlang_result_t *p_result, request_t *request, eap_session_t *eap_session)
static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
static unlang_action_t process_reply(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static int diameter_verify(request_t *request, uint8_t const *data, unsigned int data_len)
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
fr_tls_conf_t * tls_conf
CONF_SECTION * server_cs
static ssize_t eap_ttls_decode_pair(request_t *request, TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
static fr_dict_attr_t const * attr_user_name
static conf_parser_t submodule_config[]
#define FR_DIAMETER_AVP_FLAG_VENDOR
static unlang_action_t mod_session_init(UNUSED unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
fr_dict_attr_autoload_t rlm_eap_ttls_dict_attr[]
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static unlang_action_t eap_ttls_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_dict_autoload_t rlm_eap_ttls_dict[]
rlm_eap_submodule_t rlm_eap_ttls
static ttls_tunnel_t * ttls_alloc(TALLOC_CTX *ctx)
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:351
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:293
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition module.c:431
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
module_t common
Common fields provided by all modules.
Definition submodule.h:50
Interface exported by EAP submodules.
Definition submodule.h:49
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
Definition time.h:506
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:263
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:1155
int eap_tls_start(request_t *request, eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
Definition tls.c:238
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:371
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition tls.c:321
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
Definition tls.c:79
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs)
Parse TLS configuration.
Definition tls.c:1287
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
Definition tls.c:981
eap_tls_status_t state
The state of the EAP-TLS session.
Definition tls.h:123
@ 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_COMPLETE
Received final fragment of a record.
Definition tls.h:107
@ EAP_TLS_FAIL
Fail, send fail.
Definition tls.h:89
@ EAP_TLS_ESTABLISHED
Session established, send success (or start phase2).
Definition tls.h:88
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
Definition tls.h:125
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
unsigned int code
Packet code (type).
Definition packet.h:61
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition pair_inline.c:69
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:42
static fr_slen_t parent
Definition pair.h:858
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
Definition value.c:1892
static fr_slen_t data
Definition value.h:1340
static size_t char ** out
Definition value.h:1030
int virtual_server_cf_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Wrapper for the config parser to allow pass1 resolution of virtual servers.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
Additional validation rules for virtual server lookup.