The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_eap_fast.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: 756481694ebbac27c9f757c3fa5468974ba777da $
19 * @file rlm_eap_fast.c
20 * @brief contains the interfaces that are called from eap
21 *
22 * @author Alexander Clouter (alex@digriz.org.uk)
23 *
24 * @copyright 2016 Alan DeKok (aland@freeradius.org)
25 * @copyright 2016 The FreeRADIUS server project
26 */
27RCSID("$Id: 756481694ebbac27c9f757c3fa5468974ba777da $")
28USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
29
30#include <freeradius-devel/util/md5.h>
31#include <freeradius-devel/tls/utils.h>
32#include <openssl/rand.h>
33#include <openssl/ssl.h>
34#include "eap_fast.h"
35#include "eap_fast_crypto.h"
36
37typedef struct {
38 SSL_CTX *ssl_ctx; //!< Thread local SSL_CTX.
40
41/*
42 * An instance of EAP-FAST
43 */
44typedef struct {
45 char const *tls_conf_name; //!< Name of shared TLS config.
46 fr_tls_conf_t *tls_conf; //!< TLS config pointer.
47
50
51 virtual_server_t *virtual_server; //!< Virtual server to use for processing
52 //!< inner EAP method.
53 char const *cipher_list; //!< cipher list specific to EAP-FAST
54 bool req_client_cert; //!< Whether we require a client cert
55 //!< in the outer tunnel.
56
57 int stage; //!< Processing stage.
58
59 fr_time_delta_t pac_lifetime; //!< seconds to add to current time to describe PAC lifetime
60 char const *authority_identity; //!< The identity we present in the EAP-TLS
61 uint8_t a_id[PAC_A_ID_LENGTH]; //!< The identity we present in the EAP-TLS
62 char const *pac_opaque_key; //!< The key used to encrypt PAC-Opaque
64
65
67 { FR_CONF_OFFSET("tls", rlm_eap_fast_t, tls_conf_name) },
68
69 { FR_CONF_OFFSET("default_provisioning_eap_type", rlm_eap_fast_t, default_provisioning_method_name), .dflt = "mschapv2" },
70
73 .uctx = &(virtual_server_cf_parse_uctx_t){ .process_module_name = "eap_fast"} },
74
75 { FR_CONF_OFFSET("cipher_list", rlm_eap_fast_t, cipher_list) },
76
77 { FR_CONF_OFFSET("require_client_cert", rlm_eap_fast_t, req_client_cert), .dflt = "no" },
78
79 { FR_CONF_OFFSET("pac_lifetime", rlm_eap_fast_t, pac_lifetime), .dflt = "604800" },
80 { FR_CONF_OFFSET_FLAGS("authority_identity", CONF_FLAG_REQUIRED, rlm_eap_fast_t, authority_identity) },
81 { FR_CONF_OFFSET_FLAGS("pac_opaque_key", CONF_FLAG_REQUIRED, rlm_eap_fast_t, pac_opaque_key) },
82
84};
85
87static fr_dict_t const *dict_radius;
89
92 { .out = &dict_freeradius, .proto = "freeradius" },
93 { .out = &dict_radius, .proto = "radius" },
94 { .out = &dict_eap_fast, .base_dir = "eap/fast", .proto = "eap-fast" },
95 { NULL }
96};
97
105
112
139
142 { .out = &attr_eap_emsk, .name = "EAP-EMSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
143 { .out = &attr_eap_msk, .name = "EAP-MSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
144 { .out = &attr_eap_tls_require_client_cert, .name = "EAP-TLS-Require-Client-Cert", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
145 { .out = &attr_eap_type, .name = "EAP-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
146 { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
147 { .out = &attr_ms_chap_peer_challenge, .name = "MS-CHAP-Peer-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
148 { .out = &attr_proxy_to_realm, .name = "Proxy-To-Realm", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
149
150 { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
151 { .out = &attr_freeradius_proxied_to, .name = "Vendor-Specific.FreeRADIUS.Proxied-To", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
152 { .out = &attr_ms_mppe_send_key, .name = "Vendor-Specific.Microsoft.MPPE-Send-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
153 { .out = &attr_ms_mppe_recv_key, .name = "Vendor-Specific.Microsoft.MPPE-Recv-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
154 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
155 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
156
157 { .out = &attr_eap_fast_crypto_binding, .name = "Crypto-Binding", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
158 { .out = &attr_eap_fast_eap_payload, .name = "EAP-Payload", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
159 { .out = &attr_eap_fast_error, .name = "Error", .type = FR_TYPE_UINT32, .dict = &dict_eap_fast },
160 { .out = &attr_eap_fast_intermediate_result, .name = "Intermediate-Result", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
161 { .out = &attr_eap_fast_nak, .name = "NAK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
162 { .out = &attr_eap_fast_pac_a_id, .name = "PAC.A-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
163 { .out = &attr_eap_fast_pac_a_id_info, .name = "PAC.A-ID-Info", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
164 { .out = &attr_eap_fast_pac_acknowledge, .name = "PAC.Acknowledge", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
165 { .out = &attr_eap_fast_pac_i_id, .name = "PAC.I-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
166 { .out = &attr_eap_fast_pac_info_a_id, .name = "PAC.Info.A-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
167 { .out = &attr_eap_fast_pac_info_a_id_info, .name = "PAC.Info.A-ID-Info", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
168 { .out = &attr_eap_fast_pac_info_i_id, .name = "PAC.Info.I-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
169 { .out = &attr_eap_fast_pac_info_pac_lifetime, .name = "PAC.Info.PAC-Lifetime", .type = FR_TYPE_UINT32, .dict = &dict_eap_fast },
170 { .out = &attr_eap_fast_pac_info_pac_type, .name = "PAC.Info.PAC-Type", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
171 { .out = &attr_eap_fast_pac_info_tlv, .name = "PAC.Info", .type = FR_TYPE_TLV, .dict = &dict_eap_fast },
172 { .out = &attr_eap_fast_pac_key, .name = "PAC.Key", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
173 { .out = &attr_eap_fast_pac_lifetime, .name = "PAC.Lifetime", .type = FR_TYPE_UINT32, .dict = &dict_eap_fast },
174 { .out = &attr_eap_fast_pac_opaque_i_id, .name = "PAC.Opaque.I-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
175 { .out = &attr_eap_fast_pac_opaque_pac_key, .name = "PAC.Opaque.PAC-Key", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
176 { .out = &attr_eap_fast_pac_opaque_pac_lifetime, .name = "PAC.Opaque.PAC-Lifetime", .type = FR_TYPE_UINT32, .dict = &dict_eap_fast },
177 { .out = &attr_eap_fast_pac_opaque_pac_type, .name = "PAC.Opaque.PAC-Type", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
178 { .out = &attr_eap_fast_pac_opaque_tlv, .name = "PAC.Opaque", .type = FR_TYPE_TLV, .dict = &dict_eap_fast },
179 { .out = &attr_eap_fast_pac_tlv, .name = "PAC", .type = FR_TYPE_TLV, .dict = &dict_eap_fast },
180 { .out = &attr_eap_fast_pac_type, .name = "PAC.Type", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
181 { .out = &attr_eap_fast_result, .name = "Result", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
182 { .out = &attr_eap_fast_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
183
184 { NULL }
185};
186
187#define RANDFILL(x) do { fr_assert(sizeof(x) % sizeof(uint32_t) == 0); for (size_t i = 0; i < sizeof(x); i += sizeof(uint32_t)) *((uint32_t *)&x[i]) = fr_rand(); } while(0)
188
189/**
190 * RFC 4851 section 5.1 - EAP-FAST Authentication Phase 1: Key Derivations
191 */
192static void eap_fast_init_keys(request_t *request, fr_tls_session_t *tls_session)
193{
194 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
195 uint8_t *buf;
196 uint8_t *scratch;
197 size_t ksize;
198
199 RDEBUG2("Deriving EAP-FAST keys");
200
201 fr_assert(t->s_imck == NULL);
202
203 ksize = fr_tls_utils_keyblock_size_get(request, tls_session->ssl);
204 fr_assert(ksize > 0);
205 buf = talloc_array(request, uint8_t, ksize + sizeof(*t->keyblock));
206 scratch = talloc_array(request, uint8_t, ksize + sizeof(*t->keyblock));
207
208 t->keyblock = talloc(t, eap_fast_keyblock_t);
209
210 eap_fast_tls_gen_challenge(tls_session->ssl, buf, scratch, ksize + sizeof(*t->keyblock), "key expansion");
211 memcpy(t->keyblock, &buf[ksize], sizeof(*t->keyblock));
212 memset(buf, 0, ksize + sizeof(*t->keyblock));
213
214 t->s_imck = talloc_array(t, uint8_t, EAP_FAST_SIMCK_LEN);
215 memcpy(t->s_imck, t->keyblock, EAP_FAST_SKS_LEN); /* S-IMCK[0] = session_key_seed */
216
217 t->cmk = talloc_array(t, uint8_t, EAP_FAST_CMK_LEN); /* note that CMK[0] is not defined */
218 t->imck_count = 0;
219
220 talloc_free(buf);
221 talloc_free(scratch);
222}
223
224/**
225 * RFC 4851 section 5.2 - Intermediate Compound Key Derivations
226 */
227static void eap_fast_update_icmk(request_t *request, fr_tls_session_t *tls_session, uint8_t *msk)
228{
229 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
231
232 RDEBUG2("Updating ICMK");
233
234 T_PRF(t->s_imck, EAP_FAST_SIMCK_LEN, "Inner Methods Compound Keys", msk, 32, imck, sizeof(imck)); //-V512
235
236 memcpy(t->s_imck, imck, EAP_FAST_SIMCK_LEN);
237 RHEXDUMP3(t->s_imck, EAP_FAST_SIMCK_LEN, "S-IMCK[j]");
238
239 memcpy(t->cmk, &imck[EAP_FAST_SIMCK_LEN], EAP_FAST_CMK_LEN);
240 RHEXDUMP3(t->cmk, EAP_FAST_CMK_LEN, "CMK[j]");
241
242 t->imck_count++;
243
244 /*
245 * Calculate MSK/EMSK at the same time as they are coupled to ICMK
246 *
247 * RFC 4851 section 5.4 - EAP Master Session Key Generation
248 */
249 t->msk = talloc_array(t, uint8_t, EAP_FAST_KEY_LEN);
250 T_PRF(t->s_imck, EAP_FAST_SIMCK_LEN, "Session Key Generating Function", NULL, 0, t->msk, EAP_FAST_KEY_LEN);
251 RHEXDUMP3(t->msk, EAP_FAST_KEY_LEN, "MSK");
252
253 t->emsk = talloc_array(t, uint8_t, EAP_EMSK_LEN);
254 T_PRF(t->s_imck, EAP_FAST_SIMCK_LEN, "Extended Session Key Generating Function", NULL, 0, t->emsk, EAP_EMSK_LEN);
255 RHEXDUMP3(t->emsk, EAP_EMSK_LEN, "EMSK");
256}
257
258static void eap_fast_tlv_append(fr_tls_session_t *tls_session, fr_dict_attr_t const *tlv, bool mandatory, int length, void const *data)
259{
260 uint16_t hdr[2];
261
262 hdr[0] = (mandatory) ? htons(tlv->attr | EAP_FAST_TLV_MANDATORY) : htons(tlv->attr);
263 hdr[1] = htons(length);
264
265 tls_session->record_from_buff(&tls_session->clean_in, &hdr, 4);
266 tls_session->record_from_buff(&tls_session->clean_in, data, length);
267}
268
269static void eap_fast_send_error(fr_tls_session_t *tls_session, int error)
270{
272 value = htonl(error);
273
274 eap_fast_tlv_append(tls_session, attr_eap_fast_error, true, sizeof(value), &value);
275}
276
277static void eap_fast_append_result(fr_tls_session_t *tls_session, fr_radius_packet_code_t code)
278{
279 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
280 uint16_t state;
281 fr_dict_attr_t const *da;
282
283
286
287 eap_fast_tlv_append(tls_session, da, true, sizeof(state), &state);
288}
289
290static void eap_fast_send_identity_request(request_t *request, fr_tls_session_t *tls_session, eap_session_t *eap_session)
291{
292 eap_packet_raw_t eap_packet;
293
294 RDEBUG2("Sending EAP-Identity");
295
296 eap_packet.code = FR_EAP_CODE_REQUEST;
297 eap_packet.id = eap_session->this_round->response->id + 1;
298 eap_packet.length[0] = 0;
299 eap_packet.length[1] = EAP_HEADER_LEN + 1;
300 eap_packet.data[0] = FR_EAP_METHOD_IDENTITY;
301
302 eap_fast_tlv_append(tls_session, attr_eap_fast_eap_payload, true, sizeof(eap_packet), &eap_packet);
303}
304
305static void eap_fast_send_pac_tunnel(request_t *request, fr_tls_session_t *tls_session)
306{
307 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
308 eap_fast_pac_t pac;
310 int alen, dlen;
311
312 memset(&pac, 0, sizeof(pac));
313 memset(&opaque_plaintext, 0, sizeof(opaque_plaintext));
314
315 RDEBUG2("Sending Tunnel PAC");
316
318 pac.key.hdr.length = htons(sizeof(pac.key.data));
319 fr_assert(sizeof(pac.key.data) % sizeof(uint32_t) == 0);
320 RANDFILL(pac.key.data);
321
323 pac.info.lifetime.hdr.length = htons(sizeof(pac.info.lifetime.data));
324 pac.info.lifetime.data = htonl(fr_time_to_sec(fr_time_add(request->packet->timestamp, t->pac_lifetime)));
325
327 pac.info.a_id.hdr.length = htons(sizeof(pac.info.a_id.data));
328 memcpy(pac.info.a_id.data, t->a_id, sizeof(pac.info.a_id.data));
329
330 pac.info.a_id_info.hdr.type = htons(attr_eap_fast_pac_a_id->attr);
331 pac.info.a_id_info.hdr.length = htons(sizeof(pac.info.a_id_info.data));
332
333#define MIN(a,b) (((a)>(b)) ? (b) : (a))
334 alen = MIN(talloc_array_length(t->authority_identity) - 1, sizeof(pac.info.a_id_info.data));
335 memcpy(pac.info.a_id_info.data, t->authority_identity, alen);
336
338 pac.info.type.hdr.length = htons(sizeof(pac.info.type.data));
339 pac.info.type.data = htons(PAC_TYPE_TUNNEL);
340
342 pac.info.hdr.length = htons(sizeof(pac.info.lifetime)
343 + sizeof(pac.info.a_id)
344 + sizeof(pac.info.a_id_info)
345 + sizeof(pac.info.type));
346
347 memcpy(&opaque_plaintext.type, &pac.info.type, sizeof(opaque_plaintext.type));
348 memcpy(&opaque_plaintext.lifetime, &pac.info.lifetime, sizeof(opaque_plaintext.lifetime));
349 memcpy(&opaque_plaintext.key, &pac.key, sizeof(opaque_plaintext.key));
350
351 RHEXDUMP3((uint8_t const *)&opaque_plaintext, sizeof(opaque_plaintext), "PAC-Opaque plaintext data section");
352
353 fr_assert(PAC_A_ID_LENGTH <= EVP_GCM_TLS_TAG_LEN);
354 memcpy(pac.opaque.aad, t->a_id, PAC_A_ID_LENGTH);
355 fr_assert(RAND_bytes(pac.opaque.iv, sizeof(pac.opaque.iv)) != 0);
356 dlen = eap_fast_encrypt((unsigned const char *)&opaque_plaintext, sizeof(opaque_plaintext),
358 pac.opaque.data, pac.opaque.tag);
359
361 pac.opaque.hdr.length = htons(sizeof(pac.opaque) - sizeof(pac.opaque.hdr) - sizeof(pac.opaque.data) + dlen);
362 RHEXDUMP3((uint8_t const *)&pac.opaque, sizeof(pac.opaque) - sizeof(pac.opaque.data) + dlen, "PAC-Opaque");
363
364 eap_fast_tlv_append(tls_session, attr_eap_fast_pac_tlv, true, sizeof(pac) - sizeof(pac.opaque.data) + dlen, &pac);
365}
366
367static void eap_fast_append_crypto_binding(request_t *request, fr_tls_session_t *tls_session)
368{
369 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
370 eap_tlv_crypto_binding_tlv_t binding = {0};
371 int const len = sizeof(binding) - (&binding.reserved - (uint8_t *)&binding);
372
373 RDEBUG2("Sending Cryptobinding");
374
376 binding.length = htons(len);
377 binding.version = EAP_FAST_VERSION;
378 binding.received_version = EAP_FAST_VERSION; /* FIXME use the clients value */
380
381 fr_assert(sizeof(binding.nonce) % sizeof(uint32_t) == 0);
382 RANDFILL(binding.nonce);
383 binding.nonce[sizeof(binding.nonce) - 1] &= ~0x01; /* RFC 4851 section 4.2.8 */
384 RHEXDUMP3(binding.nonce, sizeof(binding.nonce), "NONCE");
385
386 RHEXDUMP3((uint8_t const *) &binding, sizeof(binding), "Crypto-Binding TLV for Compound MAC calculation");
387
388 fr_hmac_sha1(binding.compound_mac, (uint8_t *)&binding, sizeof(binding), t->cmk, EAP_FAST_CMK_LEN);
389 RHEXDUMP3(binding.compound_mac, sizeof(binding.compound_mac), "Compound MAC");
390
391 eap_fast_tlv_append(tls_session, attr_eap_fast_crypto_binding, true, len, &binding.reserved);
392}
393
394#define EAP_FAST_TLV_MAX 11
395
396static int eap_fast_verify(request_t *request, fr_tls_session_t *tls_session, uint8_t const *data, unsigned int data_len)
397{
398 uint16_t attr;
399 uint16_t length;
400 unsigned int remaining = data_len;
401 int total = 0;
402 int num[EAP_FAST_TLV_MAX] = {0};
403 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
404 uint32_t present = 0;
405
406 fr_assert(sizeof(present) * 8 > EAP_FAST_TLV_MAX);
407
408 while (remaining > 0) {
409 if (remaining < 4) {
410 RDEBUG2("EAP-FAST TLV is too small (%u) to contain a EAP-FAST TLV header", remaining);
411 return 0;
412 }
413
414 memcpy(&attr, data, sizeof(attr));
415 attr = ntohs(attr) & EAP_FAST_TLV_TYPE;
416
417 if ((attr == attr_eap_fast_result->attr) ||
418 (attr == attr_eap_fast_nak->attr) ||
419 (attr == attr_eap_fast_error->attr) ||
420 (attr == attr_eap_fast_vendor_specific->attr) ||
421 (attr == attr_eap_fast_eap_payload->attr) ||
422 (attr == attr_eap_fast_intermediate_result->attr) ||
423 (attr == attr_eap_fast_pac_tlv->attr) ||
424 (attr == attr_eap_fast_crypto_binding->attr)) {
425 num[attr]++;
426 present |= 1 << attr;
427
428 if (num[attr_eap_fast_eap_payload->attr] > 1) {
429 REDEBUG("Too many EAP-Payload TLVs");
430unexpected:
431 for (int i = 0; i < EAP_FAST_TLV_MAX; i++) {
432 if (present & (1 << i)) RDEBUG2(" - attribute %d is present", i);
433 }
435 return 0;
436 }
437
438 if (num[attr_eap_fast_intermediate_result->attr] > 1) {
439 REDEBUG("Too many Intermediate-Result TLVs");
440 goto unexpected;
441 }
442 } else {
443 if ((data[0] & 0x80) != 0) {
444 REDEBUG("Unknown mandatory TLV %02x", attr);
445 goto unexpected;
446 }
447
448 num[0]++;
449 }
450
451 total++;
452
453 memcpy(&length, data + 2, sizeof(length));
454 length = ntohs(length);
455
456 data += 4;
457 remaining -= 4;
458
459 if (length > remaining) {
460 RDEBUG2("EAP-FAST TLV %u is longer than room remaining in the packet (%u > %u).", attr,
461 length, remaining);
462 return 0;
463 }
464
465 /*
466 * If the rest of the TLVs are larger than
467 * this attribute, continue.
468 *
469 * Otherwise, if the attribute over-flows the end
470 * of the TLCs, die.
471 */
472 if (remaining < length) {
473 RDEBUG2("EAP-FAST TLV overflows packet!");
474 return 0;
475 }
476
477 /*
478 * If there's an error, we bail out of the
479 * authentication process before allocating
480 * memory.
481 */
482 if ((attr == attr_eap_fast_intermediate_result->attr) || (attr == attr_eap_fast_result->attr)) {
483 uint16_t status;
484
485 if (length < 2) {
486 REDEBUG("EAP-FAST TLV %u is too short. Expected 2, got %d", attr, length);
487 return 0;
488 }
489
490 memcpy(&status, data, 2);
491 status = ntohs(status);
492
493 if (status == EAP_FAST_TLV_RESULT_FAILURE) {
494 REDEBUG("EAP-FAST TLV %u indicates failure. Rejecting request", attr);
495 return 0;
496 }
497
498 if (status != EAP_FAST_TLV_RESULT_SUCCESS) {
499 REDEBUG("EAP-FAST TLV %u contains unknown value. Rejecting request", attr);
500 goto unexpected;
501 }
502 }
503
504 /*
505 * remaining > length, continue.
506 */
507 remaining -= length;
508 data += length;
509 }
510
511 /*
512 * Check if the peer mixed & matched TLVs.
513 */
514 if ((num[attr_eap_fast_nak->attr] > 0) && (num[attr_eap_fast_nak->attr] != total)) {
515 REDEBUG("NAK TLV sent with non-NAK TLVs. Rejecting request");
516 goto unexpected;
517 }
518
519 if (num[attr_eap_fast_intermediate_result->attr] > 0) {
520 REDEBUG("NAK TLV sent with non-NAK TLVs. Rejecting request");
521 goto unexpected;
522 }
523
524 /*
525 * Check mandatory or not mandatory TLVs.
526 */
527 switch (t->stage) {
529 if (present) {
530 REDEBUG("Unexpected TLVs in TLS Session Handshake stage");
531 goto unexpected;
532 }
533 break;
535 if (present != (uint32_t)(1 << attr_eap_fast_eap_payload->attr)) {
536 REDEBUG("Unexpected TLVs in authentication stage");
537 goto unexpected;
538 }
539 break;
541 {
542 uint32_t bits = (t->result_final)
543 ? 1 << attr_eap_fast_result->attr
545 if (present & ~(bits | (1 << attr_eap_fast_crypto_binding->attr) | (1 << attr_eap_fast_pac_tlv->attr))) {
546 REDEBUG("Unexpected TLVs in cryptobind checking stage");
547 goto unexpected;
548 }
549 break;
550 }
552 if (present & ~((1 << attr_eap_fast_pac_tlv->attr) | (1 << attr_eap_fast_result->attr))) {
553 REDEBUG("Unexpected TLVs in provisioning stage");
554 goto unexpected;
555 }
556 break;
558 if (present) {
559 REDEBUG("Unexpected TLVs in complete stage");
560 goto unexpected;
561 }
562 break;
563 default:
564 REDEBUG("Unexpected stage %d", t->stage);
565 return 0;
566 }
567
568 /*
569 * We got this far. It looks OK.
570 */
571 return 1;
572}
573
574/**
575 *
576 * FIXME do something with mandatory
577 */
579 uint8_t const *data, size_t data_len,
580 void *decode_ctx)
581{
582 fr_dict_attr_t const *da;
583 uint8_t const *p = data, *end = p + data_len;
584
585 /*
586 * Decode the TLVs
587 */
588 while (p < end) {
589 ssize_t ret;
590 uint16_t attr;
591 uint16_t len;
592 fr_pair_t *vp;
593
595 p += 2;
596 len = fr_nbo_to_uint16(p);
597 p += 2;
598
600 if (!da) {
601 MEM(vp = fr_pair_afrom_child_num(ctx, parent, attr));
602
603 } else if (da->type == FR_TYPE_TLV) {
604 p += (size_t) eap_fast_decode_pair(ctx, out, parent, p, len, decode_ctx);
605 continue;
606
607 } else {
608 MEM(vp = fr_pair_afrom_da(ctx, da));
609 }
610
611 ret = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
612 &FR_DBUFF_TMP(p, (size_t)len), len, true);
613 if (ret != len) {
614 fr_pair_raw_afrom_pair(vp, p, len);
615 }
617 p += len;
618 }
619
620 return p - data;
621}
622
623
624/*
625 * Use a reply packet to determine what to do.
626 */
628 fr_tls_session_t *tls_session,
629 request_t *request,
630 fr_packet_t *reply, fr_pair_list_t *reply_list)
631{
633 fr_pair_t *vp;
634 fr_dcursor_t cursor;
635
636 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
637
638 /*
639 * If the response packet was Access-Accept, then
640 * we're OK. If not, die horribly.
641 *
642 * FIXME: EAP-Messages can only start with 'identity',
643 * NOT 'eap start', so we should check for that....
644 */
645 switch (reply->code) {
647 RDEBUG2("Got tunneled Access-Accept");
648
649 rcode = RLM_MODULE_OK;
650
651 /*
652 * Copy what we need into the TTLS tunnel and leave
653 * the rest to be cleaned up.
654 */
655 for (vp = fr_pair_list_head(reply_list); vp; vp = fr_pair_list_next(reply_list, vp)) {
657
658 /* FIXME must be a better way to capture/re-derive this later for ISK */
659 switch (vp->da->attr) {
661 if (vp->vp_length != MD5_DIGEST_LENGTH) {
662 wrong_length:
663 REDEBUG("Found %s with incorrect length. Expected %u, got %zu",
664 vp->da->name, MD5_DIGEST_LENGTH, vp->vp_length);
665 rcode = RLM_MODULE_INVALID;
666 break;
667 }
668
669 memcpy(t->isk.mppe_send, vp->vp_octets, MD5_DIGEST_LENGTH);
670 break;
671
673 if (vp->vp_length != MD5_DIGEST_LENGTH) goto wrong_length;
674 memcpy(t->isk.mppe_recv, vp->vp_octets, MD5_DIGEST_LENGTH);
675 break;
676
678 RDEBUG2("Got %s, tunneling it to the client in a challenge", vp->da->name);
679 rcode = RLM_MODULE_HANDLED;
680 t->authenticated = true;
681 break;
682
683 default:
684 break;
685 }
686 }
687 RHEXDUMP3((uint8_t *)&t->isk, 2 * MD5_DIGEST_LENGTH, "ISK[j]"); /* FIXME (part of above) */
688 break;
689
691 REDEBUG("Got tunneled Access-Reject");
692 rcode = RLM_MODULE_REJECT;
693 break;
694
696 RDEBUG2("Got tunneled Access-Challenge");
697
698 /*
699 * Copy the EAP-Message back to the tunnel.
700 */
701
702 for (vp = fr_pair_dcursor_by_da_init(&cursor, reply_list, attr_eap_message);
703 vp;
704 vp = fr_dcursor_next(&cursor)) {
705 eap_fast_tlv_append(tls_session, attr_eap_fast_eap_payload, true, vp->vp_length, vp->vp_octets);
706 }
707
708 rcode = RLM_MODULE_HANDLED;
709 break;
710
711 default:
712 REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
713 rcode = RLM_MODULE_INVALID;
714 break;
715 }
716
717 return rcode;
718}
719
721 fr_tls_session_t *tls_session, fr_pair_t *tlv_eap_payload)
722{
724 rlm_rcode_t rcode;
725 fr_pair_t *vp;
728 rlm_eap_fast_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_fast_t);
729
730 RDEBUG2("Processing received EAP Payload");
731
732 /*
733 * Allocate a fake request_t structure.
734 */
735 fake = request_local_alloc_internal(request, &(request_init_args_t){ .parent = request });
736 fr_assert(fr_pair_list_empty(&fake->request_pairs));
737
738 t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
739
740 /*
741 * Add the tunneled attributes to the fake request.
742 */
743
744 MEM(vp = fr_pair_afrom_da(fake->request_ctx, attr_eap_message));
745 fr_pair_append(&fake->request_pairs, vp);
746 fr_pair_value_memdup(vp, tlv_eap_payload->vp_octets, tlv_eap_payload->vp_length, false);
747
748 RDEBUG2("Got tunneled request");
749 log_request_pair_list(L_DBG_LVL_1, fake, NULL, &fake->request_pairs, NULL);
750
751 /*
752 * Tell the request that it's a fake one.
753 */
754 MEM(fr_pair_prepend_by_da(fake->request_ctx, &vp, &fake->request_pairs, attr_freeradius_proxied_to) >= 0);
755 (void)fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1") - 1, NULL, false);
756
757 /*
758 * If there's no User-Name in the stored data, look for
759 * an EAP-Identity, and pull it out of there.
760 */
761 if (!t->username) {
762 fr_assert(vp->da == attr_eap_message); /* cached from above */
763
764 if ((vp->vp_length >= EAP_HEADER_LEN + 2) &&
765 (vp->vp_strvalue[0] == FR_EAP_CODE_RESPONSE) &&
766 (vp->vp_strvalue[EAP_HEADER_LEN] == FR_EAP_METHOD_IDENTITY) &&
767 (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
768 /*
769 * Create and remember a User-Name
770 */
772 t->username->vp_tainted = true;
773 fr_pair_value_bstrndup(t->username, (char const *)vp->vp_octets + 5, vp->vp_length - 5, true);
774
775 RDEBUG2("Got tunneled identity of %pV", &t->username->data);
776 } else {
777 /*
778 * Don't reject the request outright,
779 * as it's permitted to do EAP without
780 * user-name.
781 */
782 RWDEBUG2("No EAP-Identity found to start EAP conversation");
783 }
784 } /* else there WAS a t->username */
785
786 if (t->username) {
787 vp = fr_pair_copy(fake->request_ctx, t->username);
788 fr_pair_append(&fake->request_pairs, vp);
789 }
790
791 if (t->stage == EAP_FAST_AUTHENTICATION) { /* FIXME do this only for MSCHAPv2 */
792 fr_pair_t *tvp;
793
795 tvp->vp_uint32 = t->default_provisioning_method;
796 fr_pair_append(&fake->control_pairs, tvp);
797
798 /*
799 * RFC 5422 section 3.2.3 - Authenticating Using EAP-FAST-MSCHAPv2
800 */
804 fr_pair_append(&fake->control_pairs, tvp);
805 RHEXDUMP3(t->keyblock->server_challenge, MD5_DIGEST_LENGTH, "MSCHAPv2 auth_challenge");
806
809 fr_pair_append(&fake->control_pairs, tvp);
810 RHEXDUMP3(t->keyblock->client_challenge, MD5_DIGEST_LENGTH, "MSCHAPv2 peer_challenge");
811 }
812 }
813
814 /*
815 * Call authentication recursively, which will
816 * do PAP, CHAP, MS-CHAP, etc.
817 */
818 eap_virtual_server(request, eap_session, inst->virtual_server);
819
820 /*
821 * Decide what to do with the reply.
822 */
823 switch (fake->reply->code) {
824 case 0: /* No reply code, must be proxied... */
825#ifdef WITH_PROXY
826 vp = fr_pair_find_by_da(&fake->control, NULL, attr_proxy_to_realm);
827 if (vp) {
828 int ret;
829 eap_tunnel_data_t *tunnel;
830
831 RDEBUG2("Tunneled authentication will be proxied to %pV", &vp->data);
832
833 /*
834 * Tell the original request that it's going to be proxied.
835 */
836 fr_pair_list_copy_by_da(request->control_ctx, &request->control_pairs,
837 &fake->control_pairs, attr_proxy_to_realm, 0);
838
839 /*
840 * Seed the proxy packet with the tunneled request.
841 */
842 fr_assert(!request->proxy);
843
844 /*
845 * FIXME: Actually proxy stuff
846 */
847 request->proxy = request_alloc_internal(request, &(request_init_args_t){ .parent = request });
848
849 request->proxy->packet = talloc_steal(request->proxy, fake->packet);
850 memset(&request->proxy->packet->src_ipaddr, 0,
851 sizeof(request->proxy->packet->src_ipaddr));
852 memset(&request->proxy->packet->src_ipaddr, 0,
853 sizeof(request->proxy->packet->src_ipaddr));
854 request->proxy->packet->src_port = 0;
855 request->proxy->packet->dst_port = 0;
856 fake->packet = NULL;
857 fr_packet_free(&fake->reply);
858 fake->reply = NULL;
859
860 /*
861 * Set up the callbacks for the tunnel
862 */
863 tunnel = talloc_zero(request, eap_tunnel_data_t);
864 tunnel->tls_session = tls_session;
865
866 /*
867 * Associate the callback with the request.
868 */
869 ret = request_data_add(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK,
870 tunnel, false, false, false);
871 fr_cond_assert(ret == 0);
872
873 /*
874 * rlm_eap.c has taken care of associating the eap_session
875 * with the fake request.
876 *
877 * So we associate the fake request with this request.
878 */
879 ret = request_data_add(request, request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
880 fake, true, false, false);
881 fr_cond_assert(ret == 0);
882
883 fake = NULL;
884
885 /*
886 * Didn't authenticate the packet, but we're proxying it.
887 */
889
890 } else
891#endif /* WITH_PROXY */
892 {
893 REDEBUG("No tunneled reply was found, and the request was not proxied: rejecting the user");
895 }
896 break;
897
898 default:
899 /*
900 * Returns RLM_MODULE_FOO, and we want to return FR_FOO
901 */
902 rcode = process_reply(eap_session, tls_session, request, fake->reply, &fake->reply_pairs);
903 switch (rcode) {
906 break;
907
910 break;
911
912 case RLM_MODULE_OK:
914 break;
915
916 default:
918 break;
919 }
920 break;
921 }
922
924
925 return code;
926}
927
929 fr_tls_session_t *tls_session, eap_tlv_crypto_binding_tlv_t *binding)
930{
931 uint8_t cmac[sizeof(binding->compound_mac)];
932 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
933
934 memcpy(cmac, binding->compound_mac, sizeof(cmac));
935 memset(binding->compound_mac, 0, sizeof(binding->compound_mac));
936
937 RHEXDUMP3((uint8_t const *) binding, sizeof(*binding), "Crypto-Binding TLV for Compound MAC calculation");
938 RHEXDUMP3(cmac, sizeof(cmac), "Received Compound MAC");
939
940 fr_hmac_sha1(binding->compound_mac, (uint8_t *)binding, sizeof(*binding), t->cmk, EAP_FAST_CMK_LEN);
941 if (memcmp(binding->compound_mac, cmac, sizeof(cmac))) {
942 RDEBUG2("Crypto-Binding TLV mismatch");
943 RHEXDUMP3((uint8_t const *) binding->compound_mac,
944 sizeof(binding->compound_mac), "Calculated Compound MAC");
946 }
947
949}
950
952 fr_tls_session_t *tls_session, fr_pair_list_t *fast_vps)
953{
954 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
955 fr_pair_t *vp;
956 eap_tlv_crypto_binding_tlv_t my_binding, *binding = NULL;
957
958 memset(&my_binding, 0, sizeof(my_binding));
959
960 for (vp = fr_pair_list_head(fast_vps);
961 vp;
962 vp = fr_pair_list_next(fast_vps, vp)) {
964 if (vp->da->parent == fr_dict_root(dict_eap_fast)) {
966 code = eap_fast_eap_payload(request, mctx, eap_session, tls_session, vp);
968 } else if ((vp->da == attr_eap_fast_result) ||
972 } else {
973 RDEBUG2("ignoring unknown %pP", vp);
974 continue;
975 }
976 } else if (vp->da->parent == attr_eap_fast_crypto_binding) {
977 binding = &my_binding;
978
979 /*
980 * fr_radius_encode_pair() does not work for structures
981 */
982 switch (vp->da->attr) {
983 case 1: /* FR_EAP_FAST_CRYPTO_BINDING_RESERVED */
984 binding->reserved = vp->vp_uint8;
985 break;
986 case 2: /* FR_EAP_FAST_CRYPTO_BINDING_VERSION */
987 binding->version = vp->vp_uint8;
988 break;
989 case 3: /* FR_EAP_FAST_CRYPTO_BINDING_RECV_VERSION */
990 binding->received_version = vp->vp_uint8;
991 break;
992 case 4: /* FR_EAP_FAST_CRYPTO_BINDING_SUB_TYPE */
993 binding->subtype = vp->vp_uint8;
994 break;
995 case 5: /* FR_EAP_FAST_CRYPTO_BINDING_NONCE */
996 if (vp->vp_length >= sizeof(binding->nonce)) {
997 memcpy(binding->nonce, vp->vp_octets, vp->vp_length);
998 }
999 break;
1000 case 6: /* FR_EAP_FAST_CRYPTO_BINDING_COMPOUND_MAC */
1001 if (vp->vp_length >= sizeof(binding->compound_mac)) {
1002 memcpy(binding->compound_mac, vp->vp_octets, sizeof(binding->compound_mac));
1003 }
1004 break;
1005 }
1006 continue;
1007 } else if (vp->da->parent == attr_eap_fast_pac_tlv) {
1009 if (vp->vp_uint32 == EAP_FAST_TLV_RESULT_SUCCESS) {
1011 t->pac.expires = fr_time_max();
1012 t->pac.expired = false;
1014 }
1015 } else if (vp->da == attr_eap_fast_pac_info_pac_type) {
1016 if (vp->vp_uint32 != PAC_TYPE_TUNNEL) {
1017 RDEBUG2("only able to serve Tunnel PAC's, ignoring request");
1018 continue;
1019 }
1020 t->pac.send = true;
1021 continue;
1022 } else {
1023 RDEBUG2("ignoring unknown EAP-FAST-PAC-TLV %pP", vp);
1024 continue;
1025 }
1026 } else {
1027 RDEBUG2("ignoring non-EAP-FAST TLV %pP", vp);
1028 continue;
1029 }
1030
1032 }
1033
1034 if (binding) {
1035 fr_radius_packet_code_t code = eap_fast_crypto_binding(request, eap_session, tls_session, binding);
1036 if (code == FR_RADIUS_CODE_ACCESS_ACCEPT) {
1038 }
1039 return code;
1040 }
1041
1043}
1044
1045
1046/*
1047 * Process the inner tunnel data
1048 */
1049static fr_radius_packet_code_t eap_fast_process(request_t *request, module_ctx_t const *mctx, eap_session_t *eap_session, fr_tls_session_t *tls_session)
1050{
1052 fr_pair_list_t fast_vps;
1053 uint8_t const *data;
1054 size_t data_len;
1056
1057 fr_pair_list_init(&fast_vps);
1058 /*
1059 * Just look at the buffer directly, without doing
1060 * record_to_buff.
1061 */
1062 data_len = tls_session->clean_out.used;
1063 tls_session->clean_out.used = 0;
1064 data = tls_session->clean_out.data;
1065
1066 t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
1067
1068 /*
1069 * See if the tunneled data is well formed.
1070 */
1071 if (!eap_fast_verify(request, tls_session, data, data_len)) return FR_RADIUS_CODE_ACCESS_REJECT;
1072
1074 char buf[256];
1075
1077
1078 if (strstr(SSL_CIPHER_description(SSL_get_current_cipher(tls_session->ssl),
1079 buf, sizeof(buf)), "Au=None")) {
1080 /* FIXME enforce MSCHAPv2 - RFC 5422 section 3.2.2 */
1081 RDEBUG2("Using anonymous provisioning");
1083 t->pac.send = true;
1084 } else {
1085 fr_time_t renew;
1086
1087 if (SSL_session_reused(tls_session->ssl)) {
1088 RDEBUG2("Session Resumed from PAC");
1090 } else {
1091 RDEBUG2("Using authenticated provisioning");
1093 }
1094
1095 /*
1096 * Send a new pac at 60% of the lifetime,
1097 * or if the PAC has expired, or if no lifetime was set.
1098 */
1099 renew = fr_time_add(request->packet->timestamp,
1101
1102 if (t->pac.expired || fr_time_eq(t->pac.expires, fr_time_wrap(0)) ||
1103 fr_time_lteq(t->pac.expires, renew)) {
1104 t->pac.send = true;
1105 }
1106 }
1107
1108 eap_fast_init_keys(request, tls_session);
1109
1110 eap_fast_send_identity_request(request, tls_session, eap_session);
1111
1114 }
1115
1116 if (eap_fast_decode_pair(request, &fast_vps, fr_dict_root(dict_eap_fast),
1117 data, data_len, NULL) < 0) return FR_RADIUS_CODE_ACCESS_REJECT;
1118
1119 RDEBUG2("Got Tunneled FAST TLVs");
1120 log_request_pair_list(L_DBG_LVL_1, request, NULL, &fast_vps, NULL);
1121 code = eap_fast_process_tlvs(request, mctx, eap_session, tls_session, &fast_vps);
1122 fr_pair_list_free(&fast_vps);
1123
1125
1126 switch (t->stage) {
1129 break;
1130
1132 {
1133 if (t->mode != EAP_FAST_PROVISIONING_ANON && !t->pac.send)
1134 t->result_final = true;
1135
1136 eap_fast_append_result(tls_session, code);
1137
1138 eap_fast_update_icmk(request, tls_session, (uint8_t *)&t->isk);
1139 eap_fast_append_crypto_binding(request, tls_session);
1140
1142 break;
1143 }
1145 t->result_final = true;
1146
1147 eap_fast_append_result(tls_session, code);
1148
1149 if (t->pac.send) {
1150 RDEBUG2("Peer requires new PAC");
1151 eap_fast_send_pac_tunnel(request, tls_session);
1153 break;
1154 }
1155
1158
1159 case EAP_FAST_COMPLETE:
1160 /*
1161 * RFC 5422 section 3.5 - Network Access after EAP-FAST Provisioning
1162 */
1163 if (t->pac.type && t->pac.expired) {
1164 REDEBUG("Rejecting expired PAC.");
1166 break;
1167 }
1168
1169 if (t->mode == EAP_FAST_PROVISIONING_ANON) {
1170 REDEBUG("Rejecting unauthenticated provisioning");
1172 break;
1173 }
1174
1175 /*
1176 * eap_crypto_mppe_keys() is unsuitable for EAP-FAST as Cisco decided
1177 * it would be a great idea to flip the recv/send keys around
1178 */
1179 #define EAPTLS_MPPE_KEY_LEN 32
1184
1185 break;
1186
1187 default:
1188 RERROR("Internal sanity check failed in EAP-FAST at %d", t->stage);
1190 }
1191
1192 return code;
1193}
1194
1195/** Allocate the FAST per-session data
1196 *
1197 */
1198static eap_fast_tunnel_t *eap_fast_alloc(TALLOC_CTX *ctx, rlm_eap_fast_t const *inst)
1199{
1200 eap_fast_tunnel_t *t = talloc_zero(ctx, eap_fast_tunnel_t);
1201
1204
1205 t->default_provisioning_method = inst->default_provisioning_method;
1206
1207 t->pac_lifetime = inst->pac_lifetime;
1208 t->authority_identity = inst->authority_identity;
1209 t->a_id = inst->a_id;
1210 t->pac_opaque_key = (uint8_t const *)inst->pac_opaque_key;
1211
1212 return t;
1213}
1214
1215static void eap_fast_session_ticket(fr_tls_session_t *tls_session, const SSL *s,
1216 uint8_t *secret, int *secret_len)
1217{
1218 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
1219 uint8_t seed[2 * SSL3_RANDOM_SIZE];
1220
1221 fr_assert(t->pac.key);
1222
1223 SSL_get_server_random(s, seed, SSL3_RANDOM_SIZE);
1224 SSL_get_client_random(s, &seed[SSL3_RANDOM_SIZE], SSL3_RANDOM_SIZE);
1225
1226 T_PRF(t->pac.key, PAC_KEY_LENGTH, "PAC to master secret label hash",
1227 seed, sizeof(seed), secret, SSL_MAX_MASTER_KEY_LENGTH);
1228 *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
1229}
1230
1231static int _session_secret(SSL *s, void *secret, int *secret_len,
1232 UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers,
1233 UNUSED SSL_CIPHER const **cipher, void *arg)
1234{
1235 // FIXME enforce non-anon cipher
1236
1237 request_t *request = fr_tls_session_request(s);
1238 fr_tls_session_t *tls_session = arg;
1240
1241 if (!tls_session) return 0;
1242
1243 t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
1244
1245 if (!t->pac.key) return 0;
1246
1247 RDEBUG2("processing PAC-Opaque");
1248
1249 eap_fast_session_ticket(tls_session, s, secret, secret_len);
1250
1251 memset(t->pac.key, 0, PAC_KEY_LENGTH);
1252 talloc_free(t->pac.key);
1253 t->pac.key = NULL;
1254
1255 return 1;
1256}
1257
1258/*
1259 * hints from hostap:src/crypto/tls_openssl.c:fr_tls_session_ticket_ext_cb()
1260 *
1261 * N.B. we actually always tell OpenSSL we have digested the ticket so that
1262 * it does not cause a fail loop and enables us to update the PAC easily
1263 *
1264 */
1265static int _session_ticket(SSL *s, uint8_t const *data, int len, void *arg)
1266{
1267 fr_tls_session_t *tls_session = talloc_get_type_abort(arg, fr_tls_session_t);
1268 request_t *request = fr_tls_session_request(s);
1270 fr_pair_list_t fast_vps;
1271 fr_pair_t *vp;
1272 char const *errmsg;
1273 int dlen, plen;
1274 uint16_t length;
1276 eap_fast_attr_pac_opaque_t opaque_plaintext;
1277
1278 if (!tls_session) return 0;
1279
1280 fr_pair_list_init(&fast_vps);
1281 t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
1282
1283 RDEBUG2("PAC provided via ClientHello SessionTicket extension");
1284 RHEXDUMP3(data, len, "PAC-Opaque");
1285
1286 if ((ntohs(opaque->hdr.type) & EAP_FAST_TLV_TYPE) != attr_eap_fast_pac_opaque_tlv->attr) {
1287 errmsg = "PAC is not of type Opaque";
1288error:
1289 RERROR("%s, sending alert to client", errmsg);
1290 if (fr_tls_session_alert(request, tls_session, SSL3_AL_FATAL, SSL_AD_BAD_CERTIFICATE)) {
1291 RERROR("too many alerts");
1292 return 0;
1293 }
1294 if (t->pac.key) talloc_free(t->pac.key);
1295
1296 memset(&t->pac, 0, sizeof(t->pac));
1297 if (!fr_pair_list_empty(&fast_vps)) fr_pair_list_free(&fast_vps);
1298 return 1;
1299 }
1300
1301 /*
1302 * we would like to use the length of the SessionTicket
1303 * but Cisco hates everyone and sends a zero padding payload
1304 * so we have to use the length in the PAC-Opaque header
1305 */
1306 length = ntohs(opaque->hdr.length);
1307 if (len - sizeof(opaque->hdr) < length) {
1308 errmsg = "PAC has bad length in header";
1309 goto error;
1310 }
1311
1312 if (length < PAC_A_ID_LENGTH + EVP_MAX_IV_LENGTH + EVP_GCM_TLS_TAG_LEN + 1) {
1313 errmsg = "PAC file too short";
1314 goto error;
1315 }
1316
1317 if (memcmp(opaque->aad, t->a_id, PAC_A_ID_LENGTH)) {
1318 errmsg = "PAC has incorrect A_ID";
1319 goto error;
1320 }
1321
1322 dlen = length - sizeof(opaque->aad) - sizeof(opaque->iv) - sizeof(opaque->tag);
1323 plen = eap_fast_decrypt(opaque->data, dlen, opaque->aad, PAC_A_ID_LENGTH,
1324 (uint8_t const *) opaque->tag, t->pac_opaque_key, opaque->iv,
1325 (uint8_t *)&opaque_plaintext);
1326 if (plen == -1) {
1327 errmsg = "PAC failed to decrypt";
1328 goto error;
1329 }
1330
1331 RHEXDUMP3((uint8_t const *)&opaque_plaintext, plen, "PAC-Opaque plaintext data section");
1332
1333 if (eap_fast_decode_pair(tls_session, &fast_vps, attr_eap_fast_pac_opaque_tlv, (uint8_t *)&opaque_plaintext, plen, NULL) < 0) {
1334 errmsg = fr_strerror();
1335 goto error;
1336 }
1337
1338 for (vp = fr_pair_list_head(&fast_vps);
1339 vp;
1340 vp = fr_pair_list_next(&fast_vps, vp)) {
1342 fr_assert(t->pac.type == 0);
1343 t->pac.type = vp->vp_uint16;
1344 } else if (vp->da == attr_eap_fast_pac_info_pac_lifetime) {
1345 fr_assert(fr_time_eq(t->pac.expires, fr_time_wrap(0)));
1346 t->pac.expires = fr_time_add(request->packet->timestamp, vp->vp_time_delta);
1347 t->pac.expired = false;
1348 /*
1349 * Not sure if this is the correct attr
1350 * The original enum didn't match a specific TLV nesting level
1351 */
1352 } else if (vp->da == attr_eap_fast_pac_key) {
1353 fr_assert(t->pac.key == NULL);
1354 fr_assert(vp->vp_length == PAC_KEY_LENGTH);
1355 t->pac.key = talloc_array(t, uint8_t, PAC_KEY_LENGTH);
1356 fr_assert(t->pac.key != NULL);
1357 memcpy(t->pac.key, vp->vp_octets, PAC_KEY_LENGTH);
1358 } else {
1359 RERROR("unknown TLV: %pP", vp);
1360 errmsg = "unknown TLV";
1361 goto error;
1362 }
1363 }
1364
1365 fr_pair_list_free(&fast_vps);
1366
1367 if (!t->pac.type) {
1368 errmsg = "PAC missing type TLV";
1369 goto error;
1370 }
1371
1372 if (t->pac.type != PAC_TYPE_TUNNEL) {
1373 errmsg = "PAC is of not of tunnel type";
1374 goto error;
1375 }
1376
1377 if (fr_time_eq(t->pac.expires, fr_time_wrap(0))) {
1378 errmsg = "PAC missing lifetime TLV";
1379 goto error;
1380 }
1381
1382 if (!t->pac.key) {
1383 errmsg = "PAC missing key TLV";
1384 goto error;
1385 }
1386
1387 if (!SSL_set_session_secret_cb(tls_session->ssl, _session_secret, tls_session)) {
1388 RERROR("Failed setting SSL session secret callback");
1389 return 0;
1390 }
1391
1392 return 1;
1393}
1394
1396{
1397 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
1398 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
1399 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
1400
1401 if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
1402 REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
1403 } else {
1404 RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
1405 }
1406
1407 switch (eap_tls_session->state) {
1408 /*
1409 * EAP-TLS handshake was successful, tell the
1410 * client to keep talking.
1411 *
1412 * If this was EAP-TLS, we would just return
1413 * an EAP-TLS-Success packet here.
1414 */
1416 fr_tls_session_send(request, tls_session);
1417 fr_assert(tls_session->opaque != NULL);
1418 break;
1419
1420 /*
1421 * The TLS code is still working on the TLS
1422 * exchange, and it's a valid TLS request.
1423 * do nothing.
1424 */
1425 case EAP_TLS_HANDLED:
1427
1428 /*
1429 * Handshake is done, proceed with decoding tunneled
1430 * data.
1431 */
1433 break;
1434
1435 /*
1436 * Anything else: fail.
1437 */
1438 default:
1440 }
1441
1442 /*
1443 * Session is established, proceed with decoding
1444 * tunneled data.
1445 */
1446 RDEBUG2("Session established. Proceeding to decode tunneled attributes");
1447
1448 /*
1449 * Process the FAST portion of the request.
1450 */
1451 switch (eap_fast_process(request, mctx, eap_session, tls_session)) {
1453 eap_tls_fail(request, eap_session);
1455
1456 /*
1457 * Access-Challenge, continue tunneled conversation.
1458 */
1460 fr_tls_session_send(request, tls_session);
1461 eap_tls_request(request, eap_session);
1463
1464 /*
1465 * Success.
1466 */
1468 if (eap_tls_success(request, eap_session, NULL) < 0) RETURN_UNLANG_FAIL;
1469
1470 /*
1471 * @todo - generate MPPE keys, which have their own magical deriviation.
1472 */
1473
1474 /*
1475 * Result is always OK, even if we fail to persist the
1476 * session data.
1477 */
1478 p_result->rcode = RLM_MODULE_OK;
1479
1480 /*
1481 * Write the session to the session cache
1482 *
1483 * We do this here (instead of relying on OpenSSL to call the
1484 * session caching callback), because we only want to write
1485 * session data to the cache if all phases were successful.
1486 *
1487 * If we wrote out the cache data earlier, and the server
1488 * exited whilst the session was in progress, the supplicant
1489 * could resume the session (and get access) even if phase2
1490 * never completed.
1491 */
1492 return fr_tls_cache_pending_push(request, tls_session);
1493
1494 /*
1495 * No response packet, MUST be proxying it.
1496 * The main EAP module will take care of discovering
1497 * that the request now has a "proxy" packet, and
1498 * will proxy it, rather than returning an EAP packet.
1499 */
1502
1503 default:
1504 break;
1505 }
1506
1507 /*
1508 * Something we don't understand: Reject it.
1509 */
1510 eap_tls_fail(request, eap_session);
1512}
1513
1514/*
1515 * Do authentication, by letting EAP-TLS do most of the work.
1516 */
1518 request_t *request)
1519{
1520 eap_session_t *eap_session = eap_session_get(request->parent);
1521
1522 /*
1523 * Setup the resumption frame to process the result
1524 */
1525 (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
1526
1527 /*
1528 * Process TLS layer until done.
1529 */
1530 return eap_tls_process(request, eap_session);
1531}
1532
1533/*
1534 * Send an initial eap-tls request to the peer, using the libeap functions.
1535 */
1537{
1539 rlm_eap_fast_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
1540 eap_session_t *eap_session = eap_session_get(request->parent);
1541 eap_tls_session_t *eap_tls_session;
1542 fr_tls_session_t *tls_session;
1543
1544 fr_pair_t *vp;
1545 bool client_cert;
1546
1547 eap_session->tls = true;
1548
1549 /*
1550 * EAP-TLS-Require-Client-Cert attribute will override
1551 * the require_client_cert configuration option.
1552 */
1553 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
1554 if (vp) {
1555 client_cert = vp->vp_uint32 ? true : false;
1556 } else {
1557 client_cert = inst->req_client_cert;
1558 }
1559
1560 eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, thread->ssl_ctx, client_cert);
1561 if (!eap_tls_session) RETURN_UNLANG_FAIL;
1562
1563 tls_session = eap_tls_session->tls_session;
1564
1565 if (inst->cipher_list) {
1566 RDEBUG2("Over-riding main cipher list with '%s'", inst->cipher_list);
1567
1568 if (!SSL_set_cipher_list(tls_session->ssl, inst->cipher_list)) {
1569 REDEBUG("Failed over-riding cipher list to '%s'. EAP-FAST will likely not work",
1570 inst->cipher_list);
1571 }
1572 }
1573
1574#ifdef SSL_OP_NO_TLSv1_2
1575 /*
1576 * Forcibly disable TLSv1.2
1577 */
1578 SSL_set_options(tls_session->ssl, SSL_OP_NO_TLSv1_2);
1579#endif
1580
1581 /*
1582 * Push TLV of authority_identity into tls_record
1583 * call eap_tls_compose() with args
1584 *
1585 * RFC 4851 section 4.1.1
1586 * N.B. mandatory/reserved flags are not applicable here
1587 */
1589
1590 /*
1591 * TLS session initialization is over. Now handle TLS
1592 * related handshaking or application data.
1593 */
1594 if (eap_tls_compose(request, eap_session, EAP_TLS_START_SEND,
1595 SET_START(eap_tls_session->base_flags) | EAP_FAST_VERSION,
1596 &tls_session->clean_in, tls_session->clean_in.used,
1597 tls_session->clean_in.used) < 0) {
1598 talloc_free(tls_session);
1600 }
1601
1602 tls_session->record_init(&tls_session->clean_in);
1603 tls_session->opaque = eap_fast_alloc(tls_session, inst);
1604 eap_session->process = mod_handshake_process;
1605
1606 if (!SSL_set_session_ticket_ext_cb(tls_session->ssl, _session_ticket, tls_session)) {
1607 RERROR("Failed setting SSL session ticket callback");
1609 }
1610
1612}
1613
1615{
1616 rlm_eap_fast_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_fast_t);
1617 rlm_eap_fast_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
1618
1619 t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
1620 if (!t->ssl_ctx) return -1;
1621
1622 return 0;
1623}
1624
1626{
1627 rlm_eap_fast_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
1628
1629 if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
1630 t->ssl_ctx = NULL;
1631
1632 return 0;
1633}
1634
1635/*
1636 * Attach the module.
1637 */
1638static int mod_instantiate(module_inst_ctx_t const *mctx)
1639{
1640 rlm_eap_fast_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_fast_t);
1641 CONF_SECTION *conf = mctx->mi->conf;
1642
1643 inst->default_provisioning_method = eap_name2type(inst->default_provisioning_method_name);
1644 if (!inst->default_provisioning_method) {
1645 cf_log_err_by_child(conf, "default_provisioning_eap_type", "Unknown EAP type %s",
1646 inst->default_provisioning_method_name);
1647 return -1;
1648 }
1649
1650 /*
1651 * Read tls configuration, either from group given by 'tls'
1652 * option, or from the eap-tls configuration.
1653 */
1654 inst->tls_conf = eap_tls_conf_parse(conf);
1655
1656 if (!inst->tls_conf) {
1657 cf_log_err_by_child(conf, "tls", "Failed initializing SSL context");
1658 return -1;
1659 }
1660
1661 if (talloc_array_length(inst->pac_opaque_key) - 1 != 32) {
1662 cf_log_err_by_child(conf, "pac_opaque_key", "Must be 32 bytes long");
1663 return -1;
1664 }
1665
1666 /*
1667 * Allow anything for the TLS version, we try to forcibly
1668 * disable TLSv1.2 later.
1669 */
1670 if (inst->tls_conf->tls_min_version > (float) 1.1) {
1671 cf_log_err_by_child(conf, "tls_min_version", "require tls_min_version <= 1.1");
1672 return -1;
1673 }
1674
1675 if (!fr_time_delta_ispos(inst->pac_lifetime)) {
1676 cf_log_err_by_child(conf, "pac_lifetime", "must be non-zero");
1677 return -1;
1678 }
1679
1681
1682 fr_md5_calc(inst->a_id, (uint8_t const *)inst->authority_identity,
1683 talloc_array_length(inst->authority_identity) - 1);
1684
1685 return 0;
1686}
1687
1688/*
1689 * The module name should be the only globally exported symbol.
1690 * That is, everything else should be 'static'.
1691 */
1694 .common = {
1695 .magic = MODULE_MAGIC_INIT,
1696 .name = "eap_fast",
1697
1698 .inst_size = sizeof(rlm_eap_fast_t),
1700 .instantiate = mod_instantiate, /* Create new submodule instance */
1701
1702 .thread_inst_size = sizeof(rlm_eap_fast_thread_t),
1703 .thread_instantiate = mod_thread_instantiate,
1704 .thread_detach = mod_thread_detach,
1705 },
1706 .provides = { FR_EAP_METHOD_FAST },
1707 .session_init = mod_session_init, /* Initialise a new EAP session */
1708};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define USES_APPLE_DEPRECATED_API
Definition build.h:472
#define RCSID(id)
Definition build.h:485
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define UNUSED
Definition build.h:317
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:662
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:616
#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:284
#define FR_CONF_OFFSET_FLAGS(_name, _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:272
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:434
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:452
#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:241
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:599
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define cf_log_err_by_child(_parent, _child, _fmt,...)
Log an error message against a specified child.
Definition cf_util.h:316
eap_packet_t * response
Packet we received from the peer.
Definition compose.h:49
uint8_t id
Definition compose.h:37
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
#define MEM(x)
Definition debug.h:36
#define FR_MSCHAP_MPPE_RECV_KEY
Definition defs.h:162
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_STATUS_CLIENT
RFC2865/RFC5997 - Status Server (response)
Definition defs.h:45
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition defs.h:34
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
Definition defs.h:35
#define VENDORPEC_MICROSOFT
Definition defs.h:145
#define FR_MSCHAP_MPPE_SEND_KEY
Definition defs.h:161
#define FR_MSCHAP2_SUCCESS
Definition defs.h:164
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2403
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:274
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:287
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:3331
Specifies an attribute which must be present for the module to function.
Definition dict.h:273
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:286
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:212
Test enumeration values.
Definition dict_test.h:92
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK
Definition base.h:46
#define REQUEST_DATA_EAP_TUNNEL_CALLBACK
Definition base.h:45
void * tls_session
Definition base.h:54
eap_type_t eap_name2type(char const *name)
Return an EAP-Type for a particular name.
Definition types.c:38
@ FR_EAP_CODE_RESPONSE
Definition types.h:38
@ FR_EAP_CODE_REQUEST
Definition types.h:37
uint8_t data[1]
Definition types.h:125
uint8_t code
Definition types.h:122
#define EAP_HEADER_LEN
Definition types.h:34
uint8_t length[2]
Definition types.h:124
uint8_t id
Definition types.h:123
@ FR_EAP_METHOD_IDENTITY
Definition types.h:46
@ FR_EAP_METHOD_FAST
Definition types.h:89
Structure to represent packet format of eap on wire
Definition types.h:121
Function declarations and packet structures.
#define EAP_FAST_TLV_MANDATORY
Definition eap_fast.h:42
uint8_t const * a_id
Definition eap_fast.h:189
#define EAP_FAST_SKS_LEN
Definition eap_fast.h:38
unsigned char aad[PAC_A_ID_LENGTH]
Definition eap_fast.h:122
eap_fast_pac_attr_lifetime_t lifetime
Definition eap_fast.h:116
eap_fast_pac_attr_hdr_t hdr
Definition eap_fast.h:100
uint8_t client_challenge[MD5_DIGEST_LENGTH]
Definition eap_fast.h:163
eap_fast_pac_attr_lifetime_t lifetime
Definition eap_fast.h:130
eap_fast_stage_t stage
Definition eap_fast.h:172
#define EAP_FAST_KEY_LEN
Definition eap_fast.h:36
#define PAC_A_ID_LENGTH
Definition eap_fast.h:75
eap_fast_pac_attr_pac_key_t key
Definition eap_fast.h:137
#define EAP_FAST_VERSION
Definition eap_fast.h:34
eap_fast_keyblock_t * keyblock
Definition eap_fast.h:173
eap_fast_pac_attr_hdr_t hdr
Definition eap_fast.h:85
fr_time_delta_t pac_lifetime
Definition eap_fast.h:187
uint8_t * s_imck
Definition eap_fast.h:174
@ EAP_FAST_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST
Definition eap_fast.h:155
#define EAP_FAST_SIMCK_LEN
Definition eap_fast.h:39
eap_fast_pac_attr_a_id_info_t a_id_info
Definition eap_fast.h:132
struct eap_fast_tunnel_t::@171 isk
#define EAP_FAST_TLV_TYPE
Definition eap_fast.h:43
uint8_t data[PAC_A_ID_INFO_LENGTH]
Definition eap_fast.h:101
int default_provisioning_method
Definition eap_fast.h:185
eap_fast_pac_attr_hdr_t hdr
Definition eap_fast.h:129
unsigned char iv[EVP_MAX_IV_LENGTH]
Definition eap_fast.h:123
struct eap_fast_tunnel_t::@172 pac
uint8_t data[PAC_KEY_LENGTH]
Definition eap_fast.h:111
fr_pair_t * username
Definition eap_fast.h:167
eap_fast_pac_attr_hdr_t hdr
Definition eap_fast.h:121
unsigned char tag[EVP_GCM_TLS_TAG_LEN]
Definition eap_fast.h:124
uint8_t * emsk
Definition eap_fast.h:182
eap_fast_pac_attr_hdr_t hdr
Definition eap_fast.h:110
eap_fast_attr_pac_opaque_t opaque
Definition eap_fast.h:139
#define EAP_FAST_TLV_RESULT_SUCCESS
Definition eap_fast.h:49
eap_fast_pac_attr_pac_type_t type
Definition eap_fast.h:115
#define EAP_FAST_ERR_UNEXPECTED_TLV
Definition eap_fast.h:47
eap_fast_pac_attr_hdr_t hdr
Definition eap_fast.h:90
uint8_t data[PAC_A_ID_LENGTH]
Definition eap_fast.h:91
char const * authority_identity
Definition eap_fast.h:188
eap_fast_attr_pac_info_t info
Definition eap_fast.h:138
eap_fast_pac_attr_a_id_t a_id
Definition eap_fast.h:131
eap_fast_pac_attr_hdr_t hdr
Definition eap_fast.h:105
uint8_t * cmk
Definition eap_fast.h:175
uint8_t server_challenge[MD5_DIGEST_LENGTH]
Definition eap_fast.h:162
uint8_t data[sizeof(eap_fast_attr_pac_opaque_plaintext_t) *2]
Definition eap_fast.h:125
eap_fast_pac_attr_pac_type_t type
Definition eap_fast.h:133
@ EAP_FAST_COMPLETE
Definition eap_fast.h:57
@ EAP_FAST_AUTHENTICATION
Definition eap_fast.h:54
@ EAP_FAST_CRYPTOBIND_CHECK
Definition eap_fast.h:55
@ EAP_FAST_PROVISIONING
Definition eap_fast.h:56
@ EAP_FAST_TLS_SESSION_HANDSHAKE
Definition eap_fast.h:53
#define PAC_KEY_LENGTH
Definition eap_fast.h:74
@ EAP_FAST_UNKNOWN
Definition eap_fast.h:61
@ EAP_FAST_NORMAL_AUTH
Definition eap_fast.h:64
@ EAP_FAST_PROVISIONING_ANON
Definition eap_fast.h:62
@ EAP_FAST_PROVISIONING_AUTH
Definition eap_fast.h:63
eap_fast_pac_attr_pac_key_t key
Definition eap_fast.h:117
#define EAP_EMSK_LEN
Definition eap_fast.h:37
#define EAP_FAST_TLV_RESULT_FAILURE
Definition eap_fast.h:50
@ PAC_TYPE_TUNNEL
Definition eap_fast.h:68
uint8_t const * pac_opaque_key
Definition eap_fast.h:190
#define EAP_FAST_CMK_LEN
Definition eap_fast.h:40
uint8_t * msk
Definition eap_fast.h:181
int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len, uint8_t const *aad, size_t aad_len, uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext)
void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len, uint8_t const *aad, size_t aad_len, uint8_t const *key, uint8_t *iv, unsigned char *ciphertext, uint8_t *tag)
USES_APPLE_DEPRECATED_API void T_PRF(unsigned char const *secret, unsigned int secret_len, char const *prf_label, unsigned char const *seed, unsigned int seed_len, unsigned char *out, unsigned int out_len)
Crypto function declarations.
int fr_hmac_sha1(uint8_t digest[static SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len)
Calculate HMAC using internal SHA1 implementation.
Definition hmac_sha1.c:124
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:427
void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
Definition base.c:387
static eap_session_t * eap_session_get(request_t *request)
Definition session.h:83
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
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
Definition session.h:60
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:828
#define RWDEBUG2(fmt,...)
Definition log.h:362
#define RERROR(fmt,...)
Definition log.h:298
#define RHEXDUMP3(_data, _len, _fmt,...)
Definition log.h:705
talloc_free(reap)
@ L_DBG_LVL_1
Highest priority debug messages (-x).
Definition log.h:70
void fr_packet_free(fr_packet_t **packet_p)
Free a fr_packet_t.
Definition packet.c:89
#define MD5_DIGEST_LENGTH
unsigned short uint16_t
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Perform a single digest operation on a single input buffer.
unsigned char uint8_t
unsigned long int size_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 uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
int fr_pair_list_copy_by_da(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from, fr_dict_attr_t const *da, unsigned int count)
Duplicate pairs in a list matching the specified da.
Definition pair.c:2409
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2938
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, UNUSED bool tainted)
Convert string value to native attribute value.
Definition pair.c:2592
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:698
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:1343
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:287
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:2788
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:493
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:598
int fr_pair_prepend_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and prepend)
Definition pair.c:1489
fr_pair_t * fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Create a new valuepair.
Definition pair.c:375
static const conf_parser_t config[]
Definition base.c:186
#define fr_assert(_expr)
Definition rad_assert.h:38
static char * secret
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
static rs_t * conf
Definition radsniff.c:53
#define RETURN_UNLANG_HANDLED
Definition rcode.h:61
#define RETURN_UNLANG_FAIL
Definition rcode.h:59
#define RETURN_UNLANG_OK
Definition rcode.h:60
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:47
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:45
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:43
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:46
#define request_local_alloc_internal(_ctx, _args)
Allocate a new internal request outside of the request pool.
Definition request.h:343
Optional arguments for initialising requests.
Definition request.h:287
#define request_data_add(_request, _unique_ptr, _unique_int, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
static unlang_action_t mod_handshake_process(UNUSED unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
int stage
Processing stage.
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_eap_fast_pac_a_id_info
static fr_dict_attr_t const * attr_eap_fast_pac_lifetime
fr_dict_autoload_t rlm_eap_fast_dict[]
static fr_dict_attr_t const * attr_eap_fast_pac_i_id
static fr_dict_attr_t const * attr_user_password
static int eap_fast_verify(request_t *request, fr_tls_session_t *tls_session, uint8_t const *data, unsigned int data_len)
static fr_dict_attr_t const * attr_eap_fast_pac_type
#define RANDFILL(x)
static fr_radius_packet_code_t eap_fast_process_tlvs(request_t *request, module_ctx_t const *mctx, eap_session_t *eap_session, fr_tls_session_t *tls_session, fr_pair_list_t *fast_vps)
static fr_dict_attr_t const * attr_freeradius_proxied_to
static fr_dict_attr_t const * attr_eap_fast_pac_opaque_tlv
char const * cipher_list
cipher list specific to EAP-FAST
static fr_dict_attr_t const * attr_eap_fast_intermediate_result
virtual_server_t * virtual_server
Virtual server to use for processing inner EAP method.
static fr_dict_attr_t const * attr_eap_message
static fr_dict_attr_t const * attr_eap_type
static fr_dict_attr_t const * attr_eap_msk
static fr_dict_attr_t const * attr_eap_fast_pac_opaque_pac_key
#define MIN(a, b)
static fr_dict_attr_t const * attr_eap_fast_pac_info_i_id
static void eap_fast_send_identity_request(request_t *request, fr_tls_session_t *tls_session, eap_session_t *eap_session)
static fr_dict_attr_t const * attr_eap_fast_pac_info_a_id_info
static fr_dict_attr_t const * attr_eap_fast_pac_info_pac_lifetime
#define EAPTLS_MPPE_KEY_LEN
fr_dict_attr_autoload_t rlm_eap_fast_dict_attr[]
static fr_dict_t const * dict_freeradius
static fr_dict_attr_t const * attr_eap_tls_require_client_cert
static fr_dict_attr_t const * attr_eap_fast_pac_tlv
char const * tls_conf_name
Name of shared TLS config.
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
static fr_dict_attr_t const * attr_eap_fast_eap_payload
static fr_dict_t const * dict_radius
static fr_dict_attr_t const * attr_ms_chap_challenge
static fr_dict_attr_t const * attr_eap_fast_pac_key
static fr_dict_attr_t const * attr_eap_fast_crypto_binding
rlm_eap_submodule_t rlm_eap_fast
static int _session_secret(SSL *s, void *secret, int *secret_len, UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers, UNUSED SSL_CIPHER const **cipher, void *arg)
static fr_dict_attr_t const * attr_eap_fast_pac_acknowledge
fr_time_delta_t pac_lifetime
seconds to add to current time to describe PAC lifetime
static fr_radius_packet_code_t eap_fast_process(request_t *request, module_ctx_t const *mctx, eap_session_t *eap_session, fr_tls_session_t *tls_session)
static void eap_fast_append_result(fr_tls_session_t *tls_session, fr_radius_packet_code_t code)
static void eap_fast_session_ticket(fr_tls_session_t *tls_session, const SSL *s, uint8_t *secret, int *secret_len)
static void eap_fast_send_error(fr_tls_session_t *tls_session, int error)
char const * pac_opaque_key
The key used to encrypt PAC-Opaque.
static fr_radius_packet_code_t eap_fast_crypto_binding(request_t *request, UNUSED eap_session_t *eap_session, fr_tls_session_t *tls_session, eap_tlv_crypto_binding_tlv_t *binding)
static fr_dict_attr_t const * attr_eap_fast_pac_info_tlv
static fr_dict_attr_t const * attr_eap_emsk
static void eap_fast_init_keys(request_t *request, fr_tls_session_t *tls_session)
RFC 4851 section 5.1 - EAP-FAST Authentication Phase 1: Key Derivations.
char const * default_provisioning_method_name
static fr_dict_attr_t const * attr_ms_mppe_send_key
static fr_dict_attr_t const * attr_eap_fast_pac_info_a_id
char const * authority_identity
The identity we present in the EAP-TLS.
fr_dict_t const * dict_eap_fast
#define EAP_FAST_TLV_MAX
int default_provisioning_method
static fr_dict_attr_t const * attr_eap_fast_pac_info_pac_type
static fr_dict_attr_t const * attr_eap_fast_pac_a_id
static rlm_rcode_t process_reply(UNUSED eap_session_t *eap_session, fr_tls_session_t *tls_session, request_t *request, fr_packet_t *reply, fr_pair_list_t *reply_list)
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static fr_dict_attr_t const * attr_eap_fast_nak
static void eap_fast_send_pac_tunnel(request_t *request, fr_tls_session_t *tls_session)
static fr_dict_attr_t const * attr_eap_fast_pac_opaque_pac_type
static fr_radius_packet_code_t eap_fast_eap_payload(request_t *request, module_ctx_t const *mctx, eap_session_t *eap_session, fr_tls_session_t *tls_session, fr_pair_t *tlv_eap_payload)
static fr_dict_attr_t const * attr_eap_fast_error
static fr_dict_attr_t const * attr_eap_fast_pac_opaque_pac_lifetime
static void eap_fast_append_crypto_binding(request_t *request, fr_tls_session_t *tls_session)
static fr_dict_attr_t const * attr_user_name
static eap_fast_tunnel_t * eap_fast_alloc(TALLOC_CTX *ctx, rlm_eap_fast_t const *inst)
Allocate the FAST per-session data.
static fr_dict_attr_t const * attr_proxy_to_realm
static fr_dict_attr_t const * attr_ms_mppe_recv_key
static conf_parser_t submodule_config[]
static fr_dict_attr_t const * attr_eap_fast_result
fr_tls_conf_t * tls_conf
TLS config pointer.
bool req_client_cert
Whether we require a client cert in the outer tunnel.
static fr_dict_attr_t const * attr_eap_fast_pac_opaque_i_id
static ssize_t eap_fast_decode_pair(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)
FIXME do something with mandatory.
static fr_dict_attr_t const * attr_ms_chap_peer_challenge
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static unlang_action_t mod_session_init(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_attr_t const * attr_eap_fast_vendor_specific
static int mod_instantiate(module_inst_ctx_t const *mctx)
static void eap_fast_tlv_append(fr_tls_session_t *tls_session, fr_dict_attr_t const *tlv, bool mandatory, int length, void const *data)
static int _session_ticket(SSL *s, uint8_t const *data, int len, void *arg)
static void eap_fast_update_icmk(request_t *request, fr_tls_session_t *tls_session, uint8_t *msk)
RFC 4851 section 5.2 - Intermediate Compound Key Derivations.
static const void * fake
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:349
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:291
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:429
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
#define talloc_get_type_abort_const
Definition talloc.h:287
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
Definition time.h:731
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_lteq(_a, _b)
Definition time.h:240
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_eq(_a, _b)
Definition time.h:241
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
#define fr_time_max()
Definition time.h:143
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
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:264
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:1134
int eap_tls_compose(request_t *request, eap_session_t *eap_session, eap_tls_status_t status, uint8_t flags, fr_tls_record_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_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:372
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition tls.c:322
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
Definition tls.c:80
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs)
Parse TLS configuration.
Definition tls.c:1266
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
Definition tls.c:966
int base_flags
Some protocols use the reserved bits of the EAP-TLS flags (such as PEAP).
Definition tls.h:132
eap_tls_status_t state
The state of the EAP-TLS session.
Definition tls.h:127
@ EAP_TLS_INVALID
Invalid, don't reply.
Definition tls.h:91
@ EAP_TLS_HANDLED
TLS code has handled it.
Definition tls.h:94
@ EAP_TLS_RECORD_RECV_COMPLETE
Received final fragment of a record.
Definition tls.h:111
@ EAP_TLS_START_SEND
We're starting a new TLS session.
Definition tls.h:100
@ EAP_TLS_FAIL
Fail, send fail.
Definition tls.h:93
@ EAP_TLS_ESTABLISHED
Session established, send success (or start phase2).
Definition tls.h:92
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
Definition tls.h:129
#define SET_START(x)
Definition tls.h:86
Tracks the state of an EAP-TLS session.
Definition tls.h:126
unsigned int code
Packet code (type).
Definition packet.h:61
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
Definition pair.h:624
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:841
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
int fr_tls_utils_keyblock_size_get(request_t *request, SSL *ssl)
Returns the OpenSSL keyblock size.
Definition utils.c:80
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:1917
static fr_slen_t data
Definition value.h:1291
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1023
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.
Additional validation rules for virtual server lookup.