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