The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: e4e69ff87b6d4a86f9bd4e351bf69c5648d12b0b $
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: e4e69ff87b6d4a86f9bd4e351bf69c5648d12b0b $")
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 rcode = RLM_MODULE_OK;
642
643 /*
644 * Copy what we need into the TTLS tunnel and leave
645 * the rest to be cleaned up.
646 */
647 for (vp = fr_pair_list_head(reply_list); vp; vp = fr_pair_list_next(reply_list, vp)) {
649
650 /* FIXME must be a better way to capture/re-derive this later for ISK */
651 switch (vp->da->attr) {
653 if (vp->vp_length != MD5_DIGEST_LENGTH) {
654 wrong_length:
655 REDEBUG("Found %s with incorrect length. Expected %u, got %zu",
656 vp->da->name, MD5_DIGEST_LENGTH, vp->vp_length);
657 rcode = RLM_MODULE_INVALID;
658 break;
659 }
660
661 memcpy(t->isk.mppe_send, vp->vp_octets, MD5_DIGEST_LENGTH);
662 break;
663
665 if (vp->vp_length != MD5_DIGEST_LENGTH) goto wrong_length;
666 memcpy(t->isk.mppe_recv, vp->vp_octets, MD5_DIGEST_LENGTH);
667 break;
668
670 RDEBUG2("Got %s, tunneling it to the client in a challenge", vp->da->name);
671 rcode = RLM_MODULE_HANDLED;
672 t->authenticated = true;
673 break;
674
675 default:
676 break;
677 }
678 }
679 RHEXDUMP3((uint8_t *)&t->isk, 2 * MD5_DIGEST_LENGTH, "ISK[j]"); /* FIXME (part of above) */
680 break;
681
683 rcode = RLM_MODULE_REJECT;
684 break;
685
687 /*
688 * Copy the EAP-Message back to the tunnel.
689 */
690
691 for (vp = fr_pair_dcursor_by_da_init(&cursor, reply_list, attr_eap_message);
692 vp;
693 vp = fr_dcursor_next(&cursor)) {
694 eap_fast_tlv_append(tls_session, attr_eap_fast_eap_payload, true, vp->vp_length, vp->vp_octets);
695 }
696
697 rcode = RLM_MODULE_HANDLED;
698 break;
699
700 default:
701 REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
702 rcode = RLM_MODULE_INVALID;
703 break;
704 }
705
706 return rcode;
707}
708
710 fr_tls_session_t *tls_session, fr_pair_t *tlv_eap_payload)
711{
713 rlm_rcode_t rcode;
714 fr_pair_t *vp;
717 rlm_eap_fast_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_fast_t);
718
719 RDEBUG2("Processing received EAP Payload");
720
721 /*
722 * Allocate a fake request_t structure.
723 */
724 fake = request_local_alloc_internal(request, &(request_init_args_t){ .parent = request });
725 fr_assert(fr_pair_list_empty(&fake->request_pairs));
726
727 t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
728
729 /*
730 * Add the tunneled attributes to the fake request.
731 */
732
733 /*
734 * Tell the request that it's a fake one.
735 */
736 MEM(fr_pair_prepend_by_da(fake->request_ctx, &vp, &fake->request_pairs, attr_freeradius_proxied_to) >= 0);
737 (void)fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1") - 1, NULL, false);
738
739 /*
740 * Add EAP-Message after other attributes, as VP is used below.
741 */
742 MEM(vp = fr_pair_afrom_da(fake->request_ctx, attr_eap_message));
743 fr_pair_append(&fake->request_pairs, vp);
744 fr_pair_value_memdup(vp, tlv_eap_payload->vp_octets, tlv_eap_payload->vp_length, false);
745
746 RDEBUG2("Got tunneled request");
747 log_request_pair_list(L_DBG_LVL_1, fake, NULL, &fake->request_pairs, NULL);
748
749 /*
750 * If there's no User-Name in the stored data, look for
751 * an EAP-Identity, and pull it out of there.
752 */
753 if (!t->username) {
754 fr_assert(vp->da == attr_eap_message); /* cached from above */
755
756 if ((vp->vp_length >= EAP_HEADER_LEN + 2) &&
757 (vp->vp_strvalue[0] == FR_EAP_CODE_RESPONSE) &&
758 (vp->vp_strvalue[EAP_HEADER_LEN] == FR_EAP_METHOD_IDENTITY) &&
759 (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
760 /*
761 * Create and remember a User-Name
762 */
764 t->username->vp_tainted = true;
765 fr_pair_value_bstrndup(t->username, (char const *)vp->vp_octets + 5, vp->vp_length - 5, true);
766
767 RDEBUG2("Got tunneled identity of %pV", &t->username->data);
768 } else {
769 /*
770 * Don't reject the request outright,
771 * as it's permitted to do EAP without
772 * user-name.
773 */
774 RWDEBUG2("No EAP-Identity found to start EAP conversation");
775 }
776 } /* else there WAS a t->username */
777
778 if (t->username) {
779 MEM(vp = fr_pair_copy(fake->request_ctx, t->username));
780 fr_pair_append(&fake->request_pairs, vp);
781 }
782
783 if (t->stage == EAP_FAST_AUTHENTICATION) { /* FIXME do this only for MSCHAPv2 */
784 fr_pair_t *tvp;
785
787 tvp->vp_uint32 = t->default_provisioning_method;
788 fr_pair_append(&fake->control_pairs, tvp);
789
790 /*
791 * RFC 5422 section 3.2.3 - Authenticating Using EAP-FAST-MSCHAPv2
792 */
796 fr_pair_append(&fake->control_pairs, tvp);
797 RHEXDUMP3(t->keyblock->server_challenge, MD5_DIGEST_LENGTH, "MSCHAPv2 auth_challenge");
798
801 fr_pair_append(&fake->control_pairs, tvp);
802 RHEXDUMP3(t->keyblock->client_challenge, MD5_DIGEST_LENGTH, "MSCHAPv2 peer_challenge");
803 }
804 }
805
806 /*
807 * Call authentication recursively, which will
808 * do PAP, CHAP, MS-CHAP, etc.
809 */
810 eap_virtual_server(request, eap_session, inst->virtual_server);
811
812 /*
813 * Decide what to do with the reply.
814 */
815 switch (fake->reply->code) {
816 case 0: /* No reply code, must be proxied... */
817#ifdef WITH_PROXY
818 vp = fr_pair_find_by_da(&fake->control, NULL, attr_proxy_to_realm);
819 if (vp) {
820 int ret;
821 eap_tunnel_data_t *tunnel;
822
823 RDEBUG2("Tunneled authentication will be proxied to %pV", &vp->data);
824
825 /*
826 * Tell the original request that it's going to be proxied.
827 */
828 fr_pair_list_copy_by_da(request->control_ctx, &request->control_pairs,
829 &fake->control_pairs, attr_proxy_to_realm, 0);
830
831 /*
832 * Seed the proxy packet with the tunneled request.
833 */
834 fr_assert(!request->proxy);
835
836 /*
837 * FIXME: Actually proxy stuff
838 */
839 request->proxy = request_alloc_internal(request, &(request_init_args_t){ .parent = request });
840
841 request->proxy->packet = talloc_steal(request->proxy, fake->packet);
842 memset(&request->proxy->packet->src_ipaddr, 0,
843 sizeof(request->proxy->packet->src_ipaddr));
844 memset(&request->proxy->packet->src_ipaddr, 0,
845 sizeof(request->proxy->packet->src_ipaddr));
846 request->proxy->packet->src_port = 0;
847 request->proxy->packet->dst_port = 0;
848 fake->packet = NULL;
849 fr_packet_free(&fake->reply);
850 fake->reply = NULL;
851
852 /*
853 * Set up the callbacks for the tunnel
854 */
855 tunnel = talloc_zero(request, eap_tunnel_data_t);
856 tunnel->tls_session = tls_session;
857
858 /*
859 * Associate the callback with the request.
860 */
861 ret = request_data_add(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK,
862 tunnel, false, false, false);
863 fr_cond_assert(ret == 0);
864
865 /*
866 * rlm_eap.c has taken care of associating the eap_session
867 * with the fake request.
868 *
869 * So we associate the fake request with this request.
870 */
871 ret = request_data_add(request, request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
872 fake, true, false, false);
873 fr_cond_assert(ret == 0);
874
875 fake = NULL;
876
877 /*
878 * Didn't authenticate the packet, but we're proxying it.
879 */
881
882 } else
883#endif /* WITH_PROXY */
884 {
885 REDEBUG("No tunneled reply was found, and the request was not proxied: rejecting the user");
887 }
888 break;
889
890 default:
891 /*
892 * Returns RLM_MODULE_FOO, and we want to return FR_FOO
893 */
894 rcode = process_reply(eap_session, tls_session, request, fake->reply, &fake->reply_pairs);
895 switch (rcode) {
898 break;
899
902 break;
903
904 case RLM_MODULE_OK:
906 break;
907
908 default:
910 break;
911 }
912 break;
913 }
914
916
917 return code;
918}
919
921 fr_tls_session_t *tls_session, eap_tlv_crypto_binding_tlv_t *binding)
922{
923 uint8_t cmac[sizeof(binding->compound_mac)];
924 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
925
926 memcpy(cmac, binding->compound_mac, sizeof(cmac));
927 memset(binding->compound_mac, 0, sizeof(binding->compound_mac));
928
929 RHEXDUMP3((uint8_t const *) binding, sizeof(*binding), "Crypto-Binding TLV for Compound MAC calculation");
930 RHEXDUMP3(cmac, sizeof(cmac), "Received Compound MAC");
931
932 fr_hmac_sha1(binding->compound_mac, (uint8_t *)binding, sizeof(*binding), t->cmk, EAP_FAST_CMK_LEN);
933 if (memcmp(binding->compound_mac, cmac, sizeof(cmac))) {
934 RDEBUG2("Crypto-Binding TLV mismatch");
935 RHEXDUMP3((uint8_t const *) binding->compound_mac,
936 sizeof(binding->compound_mac), "Calculated Compound MAC");
938 }
939
941}
942
944 fr_tls_session_t *tls_session, fr_pair_list_t *fast_vps)
945{
946 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
947 fr_pair_t *vp;
948 eap_tlv_crypto_binding_tlv_t my_binding, *binding = NULL;
949
950 memset(&my_binding, 0, sizeof(my_binding));
951
952 for (vp = fr_pair_list_head(fast_vps);
953 vp;
954 vp = fr_pair_list_next(fast_vps, vp)) {
956 if (vp->da->parent == fr_dict_root(dict_eap_fast)) {
958 code = eap_fast_eap_payload(request, mctx, eap_session, tls_session, vp);
960 } else if ((vp->da == attr_eap_fast_result) ||
964 } else {
965 RDEBUG2("ignoring unknown %pP", vp);
966 continue;
967 }
968 } else if (vp->da->parent == attr_eap_fast_crypto_binding) {
969 binding = &my_binding;
970
971 /*
972 * fr_radius_encode_pair() does not work for structures
973 */
974 switch (vp->da->attr) {
975 case 1: /* FR_EAP_FAST_CRYPTO_BINDING_RESERVED */
976 binding->reserved = vp->vp_uint8;
977 break;
978 case 2: /* FR_EAP_FAST_CRYPTO_BINDING_VERSION */
979 binding->version = vp->vp_uint8;
980 break;
981 case 3: /* FR_EAP_FAST_CRYPTO_BINDING_RECV_VERSION */
982 binding->received_version = vp->vp_uint8;
983 break;
984 case 4: /* FR_EAP_FAST_CRYPTO_BINDING_SUB_TYPE */
985 binding->subtype = vp->vp_uint8;
986 break;
987 case 5: /* FR_EAP_FAST_CRYPTO_BINDING_NONCE */
988 if (vp->vp_length >= sizeof(binding->nonce)) {
989 memcpy(binding->nonce, vp->vp_octets, vp->vp_length);
990 }
991 break;
992 case 6: /* FR_EAP_FAST_CRYPTO_BINDING_COMPOUND_MAC */
993 if (vp->vp_length >= sizeof(binding->compound_mac)) {
994 memcpy(binding->compound_mac, vp->vp_octets, sizeof(binding->compound_mac));
995 }
996 break;
997 }
998 continue;
999 } else if (vp->da->parent == attr_eap_fast_pac_tlv) {
1001 if (vp->vp_uint32 == EAP_FAST_TLV_RESULT_SUCCESS) {
1003 t->pac.expires = fr_time_max();
1004 t->pac.expired = false;
1006 }
1007 } else if (vp->da == attr_eap_fast_pac_info_pac_type) {
1008 if (vp->vp_uint32 != PAC_TYPE_TUNNEL) {
1009 RDEBUG2("only able to serve Tunnel PAC's, ignoring request");
1010 continue;
1011 }
1012 t->pac.send = true;
1013 continue;
1014 } else {
1015 RDEBUG2("ignoring unknown EAP-FAST-PAC-TLV %pP", vp);
1016 continue;
1017 }
1018 } else {
1019 RDEBUG2("ignoring non-EAP-FAST TLV %pP", vp);
1020 continue;
1021 }
1022
1024 }
1025
1026 if (binding) {
1027 fr_radius_packet_code_t code = eap_fast_crypto_binding(request, eap_session, tls_session, binding);
1028 if (code == FR_RADIUS_CODE_ACCESS_ACCEPT) {
1030 }
1031 return code;
1032 }
1033
1035}
1036
1037
1038/*
1039 * Process the inner tunnel data
1040 */
1041static 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)
1042{
1044 fr_pair_list_t fast_vps;
1045 uint8_t const *data;
1046 size_t data_len;
1048
1049 fr_pair_list_init(&fast_vps);
1050 /*
1051 * Just look at the buffer directly, without doing
1052 * record_to_buff.
1053 */
1054 data_len = tls_session->clean_out.used;
1055 tls_session->clean_out.used = 0;
1056 data = tls_session->clean_out.data;
1057
1058 t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
1059
1060 /*
1061 * See if the tunneled data is well formed.
1062 */
1063 if (!eap_fast_verify(request, tls_session, data, data_len)) return FR_RADIUS_CODE_ACCESS_REJECT;
1064
1066 char buf[256];
1067
1069
1070 if (strstr(SSL_CIPHER_description(SSL_get_current_cipher(tls_session->ssl),
1071 buf, sizeof(buf)), "Au=None")) {
1072 /* FIXME enforce MSCHAPv2 - RFC 5422 section 3.2.2 */
1073 RDEBUG2("Using anonymous provisioning");
1075 t->pac.send = true;
1076 } else {
1077 fr_time_t renew;
1078
1079 if (SSL_session_reused(tls_session->ssl)) {
1080 RDEBUG2("Session Resumed from PAC");
1082 } else {
1083 RDEBUG2("Using authenticated provisioning");
1085 }
1086
1087 /*
1088 * Send a new pac at 60% of the lifetime,
1089 * or if the PAC has expired, or if no lifetime was set.
1090 */
1091 renew = fr_time_add(request->packet->timestamp,
1093
1094 if (t->pac.expired || fr_time_eq(t->pac.expires, fr_time_wrap(0)) ||
1095 fr_time_lteq(t->pac.expires, renew)) {
1096 t->pac.send = true;
1097 }
1098 }
1099
1100 eap_fast_init_keys(request, tls_session);
1101
1102 eap_fast_send_identity_request(request, tls_session, eap_session);
1103
1106 }
1107
1108 if (eap_fast_decode_pair(request, &fast_vps, fr_dict_root(dict_eap_fast),
1109 data, data_len, NULL) < 0) return FR_RADIUS_CODE_ACCESS_REJECT;
1110
1111 RDEBUG2("Got Tunneled FAST TLVs");
1112 log_request_pair_list(L_DBG_LVL_1, request, NULL, &fast_vps, NULL);
1113 code = eap_fast_process_tlvs(request, mctx, eap_session, tls_session, &fast_vps);
1114 fr_pair_list_free(&fast_vps);
1115
1117
1118 switch (t->stage) {
1121 break;
1122
1124 {
1125 if (t->mode != EAP_FAST_PROVISIONING_ANON && !t->pac.send)
1126 t->result_final = true;
1127
1128 eap_fast_append_result(tls_session, code);
1129
1130 eap_fast_update_icmk(request, tls_session, (uint8_t *)&t->isk);
1131 eap_fast_append_crypto_binding(request, tls_session);
1132
1134 break;
1135 }
1137 t->result_final = true;
1138
1139 eap_fast_append_result(tls_session, code);
1140
1141 if (t->pac.send) {
1142 RDEBUG2("Peer requires new PAC");
1143 eap_fast_send_pac_tunnel(request, tls_session);
1145 break;
1146 }
1147
1150
1151 case EAP_FAST_COMPLETE:
1152 /*
1153 * RFC 5422 section 3.5 - Network Access after EAP-FAST Provisioning
1154 */
1155 if (t->pac.type && t->pac.expired) {
1156 REDEBUG("Rejecting expired PAC.");
1158 break;
1159 }
1160
1161 if (t->mode == EAP_FAST_PROVISIONING_ANON) {
1162 REDEBUG("Rejecting unauthenticated provisioning");
1164 break;
1165 }
1166
1167 /*
1168 * eap_crypto_mppe_keys() is unsuitable for EAP-FAST as Cisco decided
1169 * it would be a great idea to flip the recv/send keys around
1170 */
1171 #define EAPTLS_MPPE_KEY_LEN 32
1176
1177 break;
1178
1179 default:
1180 RERROR("Internal sanity check failed in EAP-FAST at %d", t->stage);
1182 }
1183
1184 return code;
1185}
1186
1187/** Allocate the FAST per-session data
1188 *
1189 */
1190static eap_fast_tunnel_t *eap_fast_alloc(TALLOC_CTX *ctx, rlm_eap_fast_t const *inst)
1191{
1192 eap_fast_tunnel_t *t = talloc_zero(ctx, eap_fast_tunnel_t);
1193
1196
1197 t->default_provisioning_method = inst->default_provisioning_method;
1198
1199 t->pac_lifetime = inst->pac_lifetime;
1200 t->authority_identity = inst->authority_identity;
1201 t->a_id = inst->a_id;
1202 t->pac_opaque_key = (uint8_t const *)inst->pac_opaque_key;
1203
1204 return t;
1205}
1206
1207static void eap_fast_session_ticket(fr_tls_session_t *tls_session, const SSL *s,
1208 uint8_t *secret, int *secret_len)
1209{
1210 eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
1211 uint8_t seed[2 * SSL3_RANDOM_SIZE];
1212
1213 fr_assert(t->pac.key);
1214
1215 SSL_get_server_random(s, seed, SSL3_RANDOM_SIZE);
1216 SSL_get_client_random(s, &seed[SSL3_RANDOM_SIZE], SSL3_RANDOM_SIZE);
1217
1218 T_PRF(t->pac.key, PAC_KEY_LENGTH, "PAC to master secret label hash",
1219 seed, sizeof(seed), secret, SSL_MAX_MASTER_KEY_LENGTH);
1220 *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
1221}
1222
1223static int _session_secret(SSL *s, void *secret, int *secret_len,
1224 UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers,
1225 UNUSED SSL_CIPHER const **cipher, void *arg)
1226{
1227 // FIXME enforce non-anon cipher
1228
1229 request_t *request = fr_tls_session_request(s);
1230 fr_tls_session_t *tls_session = arg;
1232
1233 if (!tls_session) return 0;
1234
1235 t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
1236
1237 if (!t->pac.key) return 0;
1238
1239 RDEBUG2("processing PAC-Opaque");
1240
1241 eap_fast_session_ticket(tls_session, s, secret, secret_len);
1242
1243 memset(t->pac.key, 0, PAC_KEY_LENGTH);
1244 talloc_free(t->pac.key);
1245 t->pac.key = NULL;
1246
1247 return 1;
1248}
1249
1250/*
1251 * hints from hostap:src/crypto/tls_openssl.c:fr_tls_session_ticket_ext_cb()
1252 *
1253 * N.B. we actually always tell OpenSSL we have digested the ticket so that
1254 * it does not cause a fail loop and enables us to update the PAC easily
1255 *
1256 */
1257static int _session_ticket(SSL *s, uint8_t const *data, int len, void *arg)
1258{
1259 fr_tls_session_t *tls_session = talloc_get_type_abort(arg, fr_tls_session_t);
1260 request_t *request = fr_tls_session_request(s);
1262 fr_pair_list_t fast_vps;
1263 fr_pair_t *vp;
1264 char const *errmsg;
1265 int dlen, plen;
1266 uint16_t length;
1268 eap_fast_attr_pac_opaque_t opaque_plaintext;
1269
1270 if (!tls_session) return 0;
1271
1272 fr_pair_list_init(&fast_vps);
1273 t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
1274
1275 RDEBUG2("PAC provided via ClientHello SessionTicket extension");
1276 RHEXDUMP3(data, len, "PAC-Opaque");
1277
1278 if ((ntohs(opaque->hdr.type) & EAP_FAST_TLV_TYPE) != attr_eap_fast_pac_opaque_tlv->attr) {
1279 errmsg = "PAC is not of type Opaque";
1280error:
1281 RERROR("%s, sending alert to client", errmsg);
1282 if (fr_tls_session_alert(request, tls_session, SSL3_AL_FATAL, SSL_AD_BAD_CERTIFICATE)) {
1283 RERROR("too many alerts");
1284 return 0;
1285 }
1286 if (t->pac.key) talloc_free(t->pac.key);
1287
1288 memset(&t->pac, 0, sizeof(t->pac));
1289 if (!fr_pair_list_empty(&fast_vps)) fr_pair_list_free(&fast_vps);
1290 return 1;
1291 }
1292
1293 /*
1294 * we would like to use the length of the SessionTicket
1295 * but Cisco hates everyone and sends a zero padding payload
1296 * so we have to use the length in the PAC-Opaque header
1297 */
1298 length = ntohs(opaque->hdr.length);
1299 if (len - sizeof(opaque->hdr) < length) {
1300 errmsg = "PAC has bad length in header";
1301 goto error;
1302 }
1303
1304 if (length < PAC_A_ID_LENGTH + EVP_MAX_IV_LENGTH + EVP_GCM_TLS_TAG_LEN + 1) {
1305 errmsg = "PAC file too short";
1306 goto error;
1307 }
1308
1309 if (memcmp(opaque->aad, t->a_id, PAC_A_ID_LENGTH)) {
1310 errmsg = "PAC has incorrect A_ID";
1311 goto error;
1312 }
1313
1314 dlen = length - sizeof(opaque->aad) - sizeof(opaque->iv) - sizeof(opaque->tag);
1315 plen = eap_fast_decrypt(opaque->data, dlen, opaque->aad, PAC_A_ID_LENGTH,
1316 (uint8_t const *) opaque->tag, t->pac_opaque_key, opaque->iv,
1317 (uint8_t *)&opaque_plaintext);
1318 if (plen == -1) {
1319 errmsg = "PAC failed to decrypt";
1320 goto error;
1321 }
1322
1323 RHEXDUMP3((uint8_t const *)&opaque_plaintext, plen, "PAC-Opaque plaintext data section");
1324
1325 if (eap_fast_decode_pair(tls_session, &fast_vps, attr_eap_fast_pac_opaque_tlv, (uint8_t *)&opaque_plaintext, plen, NULL) < 0) {
1326 errmsg = fr_strerror();
1327 goto error;
1328 }
1329
1330 for (vp = fr_pair_list_head(&fast_vps);
1331 vp;
1332 vp = fr_pair_list_next(&fast_vps, vp)) {
1334 fr_assert(t->pac.type == 0);
1335 t->pac.type = vp->vp_uint16;
1336 } else if (vp->da == attr_eap_fast_pac_info_pac_lifetime) {
1337 fr_assert(fr_time_eq(t->pac.expires, fr_time_wrap(0)));
1338 t->pac.expires = fr_time_add(request->packet->timestamp, vp->vp_time_delta);
1339 t->pac.expired = false;
1340 /*
1341 * Not sure if this is the correct attr
1342 * The original enum didn't match a specific TLV nesting level
1343 */
1344 } else if (vp->da == attr_eap_fast_pac_key) {
1345 fr_assert(t->pac.key == NULL);
1346 fr_assert(vp->vp_length == PAC_KEY_LENGTH);
1347 t->pac.key = talloc_array(t, uint8_t, PAC_KEY_LENGTH);
1348 fr_assert(t->pac.key != NULL);
1349 memcpy(t->pac.key, vp->vp_octets, PAC_KEY_LENGTH);
1350 } else {
1351 RERROR("unknown TLV: %pP", vp);
1352 errmsg = "unknown TLV";
1353 goto error;
1354 }
1355 }
1356
1357 fr_pair_list_free(&fast_vps);
1358
1359 if (!t->pac.type) {
1360 errmsg = "PAC missing type TLV";
1361 goto error;
1362 }
1363
1364 if (t->pac.type != PAC_TYPE_TUNNEL) {
1365 errmsg = "PAC is of not of tunnel type";
1366 goto error;
1367 }
1368
1369 if (fr_time_eq(t->pac.expires, fr_time_wrap(0))) {
1370 errmsg = "PAC missing lifetime TLV";
1371 goto error;
1372 }
1373
1374 if (!t->pac.key) {
1375 errmsg = "PAC missing key TLV";
1376 goto error;
1377 }
1378
1379 if (!SSL_set_session_secret_cb(tls_session->ssl, _session_secret, tls_session)) {
1380 RERROR("Failed setting SSL session secret callback");
1381 return 0;
1382 }
1383
1384 return 1;
1385}
1386
1388{
1389 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
1390 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
1391 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
1392
1393 if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
1394 REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
1395 } else {
1396 RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
1397 }
1398
1399 switch (eap_tls_session->state) {
1400 /*
1401 * EAP-TLS handshake was successful, tell the
1402 * client to keep talking.
1403 *
1404 * If this was EAP-TLS, we would just return
1405 * an EAP-TLS-Success packet here.
1406 */
1408 fr_tls_session_send(request, tls_session);
1409 fr_assert(tls_session->opaque != NULL);
1410 break;
1411
1412 /*
1413 * The TLS code is still working on the TLS
1414 * exchange, and it's a valid TLS request.
1415 * do nothing.
1416 */
1417 case EAP_TLS_HANDLED:
1419
1420 /*
1421 * Handshake is done, proceed with decoding tunneled
1422 * data.
1423 */
1425 break;
1426
1427 /*
1428 * Anything else: fail.
1429 */
1430 default:
1432 }
1433
1434 /*
1435 * Session is established, proceed with decoding
1436 * tunneled data.
1437 */
1438 RDEBUG2("Session established. Proceeding to decode tunneled attributes");
1439
1440 /*
1441 * Process the FAST portion of the request.
1442 */
1443 switch (eap_fast_process(request, mctx, eap_session, tls_session)) {
1445 eap_tls_fail(request, eap_session);
1447
1448 /*
1449 * Access-Challenge, continue tunneled conversation.
1450 */
1452 fr_tls_session_send(request, tls_session);
1453 eap_tls_request(request, eap_session);
1455
1456 /*
1457 * Success.
1458 */
1460 if (eap_tls_success(request, eap_session, NULL) < 0) RETURN_UNLANG_FAIL;
1461
1462 /*
1463 * @todo - generate MPPE keys, which have their own magical deriviation.
1464 */
1465
1466 /*
1467 * Result is always OK, even if we fail to persist the
1468 * session data.
1469 */
1470 p_result->rcode = RLM_MODULE_OK;
1471
1472 /*
1473 * Write the session to the session cache
1474 *
1475 * We do this here (instead of relying on OpenSSL to call the
1476 * session caching callback), because we only want to write
1477 * session data to the cache if all phases were successful.
1478 *
1479 * If we wrote out the cache data earlier, and the server
1480 * exited whilst the session was in progress, the supplicant
1481 * could resume the session (and get access) even if phase2
1482 * never completed.
1483 */
1484 return fr_tls_cache_pending_push(request, tls_session);
1485
1486 /*
1487 * No response packet, MUST be proxying it.
1488 * The main EAP module will take care of discovering
1489 * that the request now has a "proxy" packet, and
1490 * will proxy it, rather than returning an EAP packet.
1491 */
1494
1495 default:
1496 break;
1497 }
1498
1499 /*
1500 * Something we don't understand: Reject it.
1501 */
1502 eap_tls_fail(request, eap_session);
1504}
1505
1506/*
1507 * Do authentication, by letting EAP-TLS do most of the work.
1508 */
1510 request_t *request)
1511{
1512 eap_session_t *eap_session = eap_session_get(request->parent);
1513
1514 /*
1515 * Setup the resumption frame to process the result
1516 */
1517 (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
1518
1519 /*
1520 * Process TLS layer until done.
1521 */
1522 return eap_tls_process(request, eap_session);
1523}
1524
1525/*
1526 * Send an initial eap-tls request to the peer, using the libeap functions.
1527 */
1529{
1531 rlm_eap_fast_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
1532 eap_session_t *eap_session = eap_session_get(request->parent);
1533 eap_tls_session_t *eap_tls_session;
1534 fr_tls_session_t *tls_session;
1535
1536 fr_pair_t *vp;
1537 bool client_cert;
1538
1539 eap_session->tls = true;
1540
1541 /*
1542 * EAP-TLS-Require-Client-Cert attribute will override
1543 * the require_client_cert configuration option.
1544 */
1545 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
1546 if (vp) {
1547 client_cert = vp->vp_uint32 ? true : false;
1548 } else {
1549 client_cert = inst->req_client_cert;
1550 }
1551
1552 eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, thread->ssl_ctx, client_cert);
1553 if (!eap_tls_session) RETURN_UNLANG_FAIL;
1554
1555 tls_session = eap_tls_session->tls_session;
1556
1557 if (inst->cipher_list) {
1558 RDEBUG2("Over-riding main cipher list with '%s'", inst->cipher_list);
1559
1560 if (!SSL_set_cipher_list(tls_session->ssl, inst->cipher_list)) {
1561 REDEBUG("Failed over-riding cipher list to '%s'. EAP-FAST will likely not work",
1562 inst->cipher_list);
1563 }
1564 }
1565
1566#ifdef SSL_OP_NO_TLSv1_2
1567 /*
1568 * Forcibly disable TLSv1.2
1569 */
1570 SSL_set_options(tls_session->ssl, SSL_OP_NO_TLSv1_2);
1571#endif
1572
1573 /*
1574 * Push TLV of authority_identity into tls_record
1575 * call eap_tls_compose() with args
1576 *
1577 * RFC 4851 section 4.1.1
1578 * N.B. mandatory/reserved flags are not applicable here
1579 */
1581
1582 /*
1583 * TLS session initialization is over. Now handle TLS
1584 * related handshaking or application data.
1585 */
1586 if (eap_tls_compose(request, eap_session, EAP_TLS_START_SEND,
1587 SET_START(eap_tls_session->base_flags) | EAP_FAST_VERSION,
1588 &tls_session->clean_in, tls_session->clean_in.used,
1589 tls_session->clean_in.used) < 0) {
1590 talloc_free(tls_session);
1592 }
1593
1594 tls_session->record_init(&tls_session->clean_in);
1595 tls_session->opaque = eap_fast_alloc(tls_session, inst);
1596 eap_session->process = mod_handshake_process;
1597
1598 if (!SSL_set_session_ticket_ext_cb(tls_session->ssl, _session_ticket, tls_session)) {
1599 RERROR("Failed setting SSL session ticket callback");
1601 }
1602
1604}
1605
1607{
1608 rlm_eap_fast_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_fast_t);
1609 rlm_eap_fast_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
1610
1611 t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
1612 if (!t->ssl_ctx) return -1;
1613
1614 return 0;
1615}
1616
1618{
1619 rlm_eap_fast_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
1620
1621 if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
1622 t->ssl_ctx = NULL;
1623
1624 return 0;
1625}
1626
1627/*
1628 * Attach the module.
1629 */
1630static int mod_instantiate(module_inst_ctx_t const *mctx)
1631{
1632 rlm_eap_fast_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_fast_t);
1633 CONF_SECTION *conf = mctx->mi->conf;
1634
1635 inst->default_provisioning_method = eap_name2type(inst->default_provisioning_method_name);
1636 if (!inst->default_provisioning_method) {
1637 cf_log_err_by_child(conf, "default_provisioning_eap_type", "Unknown EAP type %s",
1638 inst->default_provisioning_method_name);
1639 return -1;
1640 }
1641
1642 /*
1643 * Read tls configuration, either from group given by 'tls'
1644 * option, or from the eap-tls configuration.
1645 */
1646 inst->tls_conf = eap_tls_conf_parse(conf);
1647
1648 if (!inst->tls_conf) {
1649 cf_log_err_by_child(conf, "tls", "Failed initializing SSL context");
1650 return -1;
1651 }
1652
1653 if (talloc_strlen(inst->pac_opaque_key) != 32) {
1654 cf_log_err_by_child(conf, "pac_opaque_key", "Must be 32 bytes long");
1655 return -1;
1656 }
1657
1658 /*
1659 * Allow anything for the TLS version, we try to forcibly
1660 * disable TLSv1.2 later.
1661 */
1662 if (inst->tls_conf->tls_min_version > (float) 1.1) {
1663 cf_log_err_by_child(conf, "tls_min_version", "require tls_min_version <= 1.1");
1664 return -1;
1665 }
1666
1667 if (!fr_time_delta_ispos(inst->pac_lifetime)) {
1668 cf_log_err_by_child(conf, "pac_lifetime", "must be non-zero");
1669 return -1;
1670 }
1671
1673
1674 fr_md5_calc(inst->a_id, (uint8_t const *)inst->authority_identity,
1675 talloc_strlen(inst->authority_identity));
1676
1677 return 0;
1678}
1679
1680/*
1681 * The module name should be the only globally exported symbol.
1682 * That is, everything else should be 'static'.
1683 */
1686 .common = {
1687 .magic = MODULE_MAGIC_INIT,
1688 .name = "eap_fast",
1689
1690 .inst_size = sizeof(rlm_eap_fast_t),
1692 .instantiate = mod_instantiate, /* Create new submodule instance */
1693
1694 .thread_inst_size = sizeof(rlm_eap_fast_thread_t),
1695 .thread_instantiate = mod_thread_instantiate,
1696 .thread_detach = mod_thread_detach,
1697 },
1698 .provides = { FR_EAP_METHOD_FAST },
1699 .session_init = mod_session_init, /* Initialise a new EAP session */
1700};
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:547
#define RCSID(id)
Definition build.h:560
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:391
#define UNUSED
Definition build.h:384
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:669
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:623
#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:606
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
#define cf_log_err_by_child(_parent, _child, _fmt,...)
Log an error message against a specified child.
Definition cf_util.h:372
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: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:2639
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:3570
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:43
#define REQUEST_DATA_EAP_TUNNEL_CALLBACK
Definition base.h:42
void * tls_session
Definition base.h:51
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.
struct eap_fast_tunnel_t::@177 isk
#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
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
struct eap_fast_tunnel_t::@178 pac
@ 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.
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:140
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:385
void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
Definition base.c:345
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:828
#define RWDEBUG2(fmt,...)
Definition log.h:379
#define RERROR(fmt,...)
Definition log.h:315
#define RHEXDUMP3(_data, _len, _fmt,...)
Definition log.h:722
@ 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:162
#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:344
Optional arguments for initialising requests.
Definition request.h:288
#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:804
#define talloc_get_type_abort_const
Definition talloc.h:117
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
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:558
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.