9911ce41a1e2ef8313f3bf605e5cf4da5c9f4ed3
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_fast / rlm_eap_fast.c
1 /*
2  * rlm_eap_fast.c  contains the interfaces that are called from eap
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2016 Alan DeKok <aland@freeradius.org>
21  * Copyright 2016 The FreeRADIUS server project
22  */
23
24 RCSID("$Id$")
25 USES_APPLE_DEPRECATED_API       /* OpenSSL API has been deprecated by Apple */
26
27
28 #include "eap_fast.h"
29 #include "eap_fast_crypto.h"
30
31
32 #include <freeradius-devel/md5.h>
33
34 /*
35  *      An instance of EAP-FAST
36  */
37 typedef struct rlm_eap_fast_t {
38         char const              *tls_conf_name;                         //!< Name of shared TLS config.
39         fr_tls_server_conf_t *tls_conf;
40
41         char const              *default_method_name;
42         int                     default_method;
43
44         char const              *virtual_server;                        //!< Virtual server to use for processing
45                                                                         //!< inner EAP method.
46         bool                    req_client_cert;                        //!< Whether we require a client cert
47                                                                         //!< in the outer tunnel.
48
49         int                     stage;                                  //!< Processing stage.
50
51         uint32_t pac_lifetime;                          //!< seconds to add to current time to describe PAC lifetime
52         char const              *authority_identity;                    //!< The identity we present in the EAP-TLS
53         uint8_t                 a_id[PAC_A_ID_LENGTH];                  //!< The identity we present in the EAP-TLS
54         char const              *pac_opaque_key;                        //!< The key used to encrypt PAC-Opaque
55         bool use_tunneled_reply;                //!< Use the reply attributes from the tunneled session in
56                                                 //!< the non-tunneled reply to the client.
57
58         bool copy_request_to_tunnel;            //!< Use SOME of the request attributes from outside of the
59 } rlm_eap_fast_t;
60
61
62 static CONF_PARSER module_config[] = {
63         { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_fast_t, tls_conf_name), NULL },
64
65         { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_fast_t, default_method_name), "mschapv2" },
66
67         { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_NOT_EMPTY, rlm_eap_fast_t, virtual_server) , NULL},
68
69         { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, req_client_cert), "no" },
70
71         { "pac_lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_fast_t, pac_lifetime), "604800" },
72         { "authority_identity", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_eap_fast_t, authority_identity), NULL },
73         { "pac_opaque_key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_eap_fast_t, pac_opaque_key), NULL },
74         { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, copy_request_to_tunnel), "no" },
75
76         { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, use_tunneled_reply), "no" },
77
78         CONF_PARSER_TERMINATOR
79 };
80
81 /*
82  *      Attach the module.
83  */
84 static int mod_instantiate(CONF_SECTION *cs, void **instance)
85 {
86         rlm_eap_fast_t *inst;
87
88         *instance = inst = talloc_zero(cs, rlm_eap_fast_t);
89         if (!inst) return -1;
90
91         /*
92          *      Parse the configuration attributes.
93          */
94         if (cf_section_parse(cs, inst, module_config) < 0) {
95                 return -1;
96         }
97
98         if (!cf_section_sub_find_name2(main_config.config, "server", inst->virtual_server)) {
99                 ERROR("rlm_eap_fast.virtual_server: Unknown virtual server '%s'", inst->virtual_server);
100                 return -1;
101         }
102
103         inst->default_method = eap_name2type(inst->default_method_name);
104         if (!inst->default_method) {
105                 ERROR("rlm_eap_fast.default_provisioning_eap_type: "
106                           "Unknown EAP type %s",
107                                    inst->default_method_name);
108                 return -1;
109         }
110
111         /*
112          *      Read tls configuration, either from group given by 'tls'
113          *      option, or from the eap-tls configuration.
114          */
115         inst->tls_conf = eaptls_conf_parse(cs, "tls");
116
117         if (!inst->tls_conf) {
118                 ERROR("rlm_eap_fast.tls: Failed initializing SSL context");
119                 return -1;
120         }
121
122         if (talloc_array_length(inst->pac_opaque_key) - 1 != 32) {
123                 ERROR("rlm_eap_fast.pac_opaque_key: Must be 32 bytes long");
124                 return -1;
125         }
126
127         // FIXME TLSv1.2 uses a different PRF and SSL_export_keying_material("key expansion") is forbidden
128         if (!inst->tls_conf->disable_tlsv1_2) {
129                 ERROR("rlm_eap_fast.disable_tlsv1_2: require disable_tlsv1_2=yes");
130                 return -1;
131         }
132
133         if (!inst->pac_lifetime) {
134                 ERROR("rlm_eap_fast.pac_lifetime: must be non-zero");
135                 return -1;
136         }
137
138         rad_assert(PAC_A_ID_LENGTH == MD5_DIGEST_LENGTH);
139         FR_MD5_CTX ctx;
140         fr_md5_init(&ctx);
141         fr_md5_update(&ctx, inst->authority_identity, talloc_array_length(inst->authority_identity) - 1);
142         fr_md5_final(inst->a_id, &ctx);
143
144         return 0;
145 }
146
147 /** Allocate the FAST per-session data
148  *
149  */
150 static eap_fast_tunnel_t *eap_fast_alloc(TALLOC_CTX *ctx, rlm_eap_fast_t *inst)
151 {
152         eap_fast_tunnel_t *t = talloc_zero(ctx, eap_fast_tunnel_t);
153
154         t->mode = EAP_FAST_UNKNOWN;
155         t->stage = TLS_SESSION_HANDSHAKE;
156
157         t->default_method = inst->default_method;
158         t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
159         t->use_tunneled_reply = inst->use_tunneled_reply;
160
161         t->pac_lifetime = inst->pac_lifetime;
162         t->authority_identity = inst->authority_identity;
163         t->a_id = inst->a_id;
164         t->pac_opaque_key = (const uint8_t *)inst->pac_opaque_key;
165
166         t->virtual_server = inst->virtual_server;
167
168         return t;
169 }
170
171 static void eap_fast_session_ticket(tls_session_t *tls_session, uint8_t *client_random,
172                                         uint8_t *server_random, uint8_t *secret, int *secret_len)
173 {
174         eap_fast_tunnel_t       *t = (eap_fast_tunnel_t *) tls_session->opaque;
175         uint8_t                 seed[2 * SSL3_RANDOM_SIZE];
176
177         rad_assert(t->pac.key);
178
179         memcpy(seed, server_random, SSL3_RANDOM_SIZE);
180         memcpy(&seed[SSL3_RANDOM_SIZE], client_random, SSL3_RANDOM_SIZE);
181
182         T_PRF(t->pac.key, PAC_KEY_LENGTH, "PAC to master secret label hash",
183                   seed, sizeof(seed), secret, SSL_MAX_MASTER_KEY_LENGTH);
184         *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
185 }
186
187 // hostap:src/crypto/tls_openssl.c:tls_sess_sec_cb()
188 static int _session_secret(SSL *s, void *secret, int *secret_len,
189                            UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers,
190                            UNUSED SSL_CIPHER **cipher, void *arg)
191 {
192         // FIXME enforce non-anon cipher
193
194         REQUEST         *request = (REQUEST *)SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
195         tls_session_t   *tls_session = arg;
196         eap_fast_tunnel_t       *t;
197
198         if (!tls_session) return 0;
199
200         t = (eap_fast_tunnel_t *) tls_session->opaque;
201
202         if (!t->pac.key) return 0;
203
204         RDEBUG("processing PAC-Opaque");
205
206 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
207         eap_fast_session_ticket(tls_session, s->s3->client_random, s->s3->server_random, secret, secret_len);
208 #else
209         uint8_t const client_random[SSL3_RANDOM_SIZE];
210         uint8_t const server_random[SSL3_RANDOM_SIZE];
211
212         SSL_get_client_random(s, client_random, sizeof(client_random));
213         SSL_get_server_random(s, server_random, sizeof(server_random));
214
215         eap_fast_session_ticket(tls_session, client_random, server_random, secret, secret_len);
216 #endif
217
218         memset(t->pac.key, 0, PAC_KEY_LENGTH);
219         talloc_free(t->pac.key);
220         t->pac.key = NULL;
221
222         return 1;
223 }
224
225 /*
226  * hints from hostap:src/crypto/tls_openssl.c:tls_session_ticket_ext_cb()
227  *
228  * N.B. we actually always tell OpenSSL we have digested the ticket so that
229  *      it does not cause a fail loop and enables us to update the PAC easily
230  *
231  */
232 static int _session_ticket(SSL *s, uint8_t const *data, int len, void *arg)
233 {
234         tls_session_t           *tls_session = arg;
235         REQUEST                 *request = (REQUEST *)SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
236         eap_fast_tunnel_t       *t;
237         VALUE_PAIR              *fast_vps = NULL;
238         vp_cursor_t             cursor;
239         DICT_ATTR const *fast_da;
240         char const              *errmsg;
241         int                     dlen, plen;
242         uint16_t                length;
243         eap_fast_attr_pac_opaque_t const        *opaque = (eap_fast_attr_pac_opaque_t const *) data;
244         eap_fast_attr_pac_opaque_t              opaque_plaintext;
245
246         if (!tls_session) return 0;
247
248         t = (eap_fast_tunnel_t *) tls_session->opaque;
249
250         RDEBUG("PAC provided via ClientHello SessionTicket extension");
251
252         if ((ntohs(opaque->hdr.type) & EAP_FAST_TLV_TYPE) != PAC_INFO_PAC_OPAQUE) {
253                 errmsg = "PAC is not of type Opaque";
254 error:
255                 RERROR("%s, sending alert to client", errmsg);
256                 /*
257                 if (tls_session_handshake_alert(request, tls_session, SSL3_AL_FATAL, SSL_AD_BAD_CERTIFICATE)) {
258                         RERROR("too many alerts");
259                         return 0;
260                 }
261                 */
262                 if (t->pac.key) talloc_free(t->pac.key);
263
264                 memset(&t->pac, 0, sizeof(t->pac));
265                 if (fast_vps) fr_pair_list_free(&fast_vps);
266                 return 1;
267         }
268
269         /*
270          * we would like to use the length of the SessionTicket
271          * but Cisco hates everyone and sends a zero padding payload
272          * so we have to use the length in the PAC-Opaque header
273          */
274         length = ntohs(opaque->hdr.length);
275         if (len - sizeof(opaque->hdr) < length) {
276                 errmsg = "PAC has bad length in header";
277                 goto error;
278         }
279
280         if (length < PAC_A_ID_LENGTH + EVP_MAX_IV_LENGTH + EVP_GCM_TLS_TAG_LEN + 1) {
281                 errmsg = "PAC file too short";
282                 goto error;
283         }
284
285         if (memcmp(opaque->aad, t->a_id, PAC_A_ID_LENGTH)) {
286                 errmsg = "PAC has incorrect A_ID";
287                 goto error;
288         }
289
290         dlen = length - sizeof(opaque->aad) - sizeof(opaque->iv) - sizeof(opaque->tag);
291         plen = eap_fast_decrypt(opaque->data, dlen, opaque->aad, PAC_A_ID_LENGTH,
292                                         (uint8_t const *) opaque->tag, t->pac_opaque_key, opaque->iv,
293                                         (uint8_t *)&opaque_plaintext);
294         if (plen == -1) {
295                 errmsg = "PAC failed to decrypt";
296                 goto error;
297         }
298
299         fast_da = dict_attrbyname("FreeRADIUS-EAP-FAST-PAC-Opaque-TLV");
300         rad_assert(fast_da != NULL);
301
302         fast_vps = eap_fast_fast2vp((REQUEST *)tls_session, s, (uint8_t *)&opaque_plaintext, plen, fast_da, NULL);
303         if (!fast_vps) return 0;
304
305         for (VALUE_PAIR *vp = fr_cursor_init(&cursor, &fast_vps); vp; vp = fr_cursor_next(&cursor)) {
306                 char *value;
307
308                 switch ((vp->da->attr >> fr_attr_shift[3]) & fr_attr_mask[3]) {
309                 case PAC_INFO_PAC_TYPE:
310                         rad_assert(t->pac.type == 0);
311                         t->pac.type = vp->vp_integer;
312                         break;
313                 case PAC_INFO_PAC_LIFETIME:
314                         rad_assert(t->pac.expires == 0);
315                         t->pac.expires = vp->vp_integer;
316                         t->pac.expired = (vp->vp_integer <= time(NULL));
317                         break;
318                 case PAC_INFO_PAC_KEY:
319                         rad_assert(t->pac.key == NULL);
320                         rad_assert(vp->vp_length == PAC_KEY_LENGTH);
321                         t->pac.key = talloc_size(t, PAC_KEY_LENGTH);
322                         rad_assert(t->pac.key != NULL);
323                         memcpy(t->pac.key, vp->vp_octets, PAC_KEY_LENGTH);
324                         break;
325                 default:
326                         value = vp_aprints(tls_session, vp, '"');
327                         RERROR("unknown TLV: %s", value);
328                         talloc_free(value);
329                         errmsg = "unknown TLV";
330                         goto error;
331                 }
332         }
333
334         fr_pair_list_free(&fast_vps);
335
336         if (!t->pac.type) {
337                 errmsg = "PAC missing type TLV";
338                 goto error;
339         }
340
341         if (t->pac.type != PAC_TYPE_TUNNEL) {
342                 errmsg = "PAC is of not of tunnel type";
343                 goto error;
344         }
345
346         if (!t->pac.expires) {
347                 errmsg = "PAC missing lifetime TLV";
348                 goto error;
349         }
350
351         if (!t->pac.key) {
352                 errmsg = "PAC missing key TLV";
353                 goto error;
354         }
355
356         if (!SSL_set_session_secret_cb(tls_session->ssl, _session_secret, tls_session)) {
357                 RERROR("Failed setting SSL session secret callback");
358                 return 0;
359         }
360
361         return 1;
362 }
363
364
365 /*
366  *      Do authentication, by letting EAP-TLS do most of the work.
367  */
368 static int mod_process(void *arg, eap_handler_t *handler)
369 {
370         int rcode;
371         fr_tls_status_t status;
372         rlm_eap_fast_t *inst = (rlm_eap_fast_t *) arg;
373         tls_session_t *tls_session = (tls_session_t *) handler->opaque;
374         eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
375         REQUEST *request = handler->request;
376
377         RDEBUG2("Authenticate");
378
379         /*
380          *      We need FAST data associated with the session, so
381          *      allocate it here, if it wasn't already alloacted.
382          */
383         if (!t) t = tls_session->opaque = eap_fast_alloc(tls_session, inst);
384
385         /*
386          *      Process TLS layer until done.
387          */
388         status = eaptls_process(handler);
389         if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
390                 REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
391         } else {
392                 RDEBUG2("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
393         }
394
395         switch (status) {
396         /*
397          *      EAP-TLS handshake was successful, tell the
398          *      client to keep talking.
399          *
400          *      If this was EAP-TLS, we would just return
401          *      an EAP-TLS-Success packet here.
402          */
403         case FR_TLS_SUCCESS:
404                 tls_handshake_send(request, tls_session);
405                 rad_assert(t != NULL);
406                 break;
407
408         /*
409          *      The TLS code is still working on the TLS
410          *      exchange, and it's a valid TLS request.
411          *      do nothing.
412          */
413         case FR_TLS_HANDLED:
414                 return 1;
415
416         /*
417          *      Handshake is done, proceed with decoding tunneled
418          *      data.
419          */
420         case FR_TLS_OK:
421                 break;
422
423         /*
424          *      Anything else: fail.
425          */
426         default:
427                 return 0;
428         }
429
430         /*
431          *      Session is established, proceed with decoding
432          *      tunneled data.
433          */
434         RDEBUG2("Session established.  Proceeding to decode tunneled attributes");
435
436         /*
437          *      Process the FAST portion of the request.
438          */
439         rcode = eap_fast_process(handler, tls_session);
440
441         switch (rcode) {
442         case PW_CODE_ACCESS_REJECT:
443                 RDEBUG("Reject");
444                 eaptls_fail(handler, EAP_FAST_VERSION);
445                 return 0;
446
447                 /*
448                  *      Access-Challenge, continue tunneled conversation.
449                  */
450         case PW_CODE_ACCESS_CHALLENGE:
451                 RDEBUG("Challenge");
452                 tls_handshake_send(request, tls_session);
453                 eaptls_request(handler->eap_ds, tls_session);
454                 return 1;
455
456                 /*
457                  *      Success: Automatically return MPPE keys.
458                  */
459         case PW_CODE_ACCESS_ACCEPT:
460                 RDEBUG("Note the missing PRF label warning below is harmless, ignore it");
461                 if (t->accept_vps) {
462                         RDEBUG2("Using saved attributes from the original Access-Accept");
463                         rdebug_pair_list(L_DBG_LVL_2, request, t->accept_vps, NULL);
464                         fr_pair_list_mcopy_by_num(handler->request->reply,
465                                   &handler->request->reply->vps,
466                                   &t->accept_vps, 0, 0, TAG_ANY);
467                 } else if (t->use_tunneled_reply) {
468                         RDEBUG2("No saved attributes in the original Access-Accept");
469                 }
470                 return eaptls_success(handler, EAP_FAST_VERSION);
471
472                 /*
473                  *      No response packet, MUST be proxying it.
474                  *      The main EAP module will take care of discovering
475                  *      that the request now has a "proxy" packet, and
476                  *      will proxy it, rather than returning an EAP packet.
477                  */
478         case PW_CODE_STATUS_CLIENT:
479 #ifdef WITH_PROXY
480                 rad_assert(handler->request->proxy != NULL);
481 #endif
482                 return 1;
483
484         default:
485                 break;
486         }
487
488         /*
489          *      Something we don't understand: Reject it.
490          */
491         eaptls_fail(handler, EAP_FAST_VERSION);
492         return 0;
493 }
494
495 static int eap_fast_tls_start(EAP_DS * eap_ds,tls_session_t *tls_session)
496 {
497         EAPTLS_PACKET   reply;
498
499         reply.code = FR_TLS_START;
500         reply.length = TLS_HEADER_LEN + 1 + tls_session->clean_in.used;/*flags*/
501
502         reply.flags = tls_session->peap_flag;
503         reply.flags = SET_START(reply.flags);
504
505         reply.data = tls_session->clean_in.data;
506         reply.dlen = tls_session->clean_in.used;
507
508         eaptls_compose(eap_ds, &reply);
509
510         return 1;
511 }
512
513
514 /*
515  *      Send an initial eap-tls request to the peer, using the libeap functions.
516  */
517 static int mod_session_init(void *type_arg, eap_handler_t *handler)
518 {
519         int                     rcode;
520         tls_session_t           *tls_session;
521         rlm_eap_fast_t          *inst;
522         VALUE_PAIR              *vp;
523         bool                    client_cert;
524         REQUEST                 *request = handler->request;
525
526         inst = type_arg;
527
528         handler->tls = true;
529
530         /*
531          *      EAP-TLS-Require-Client-Cert attribute will override
532          *      the require_client_cert configuration option.
533          */
534         vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
535         if (vp) {
536                 client_cert = vp->vp_integer ? true : false;
537         } else {
538                 client_cert = inst->req_client_cert;
539         }
540         handler->opaque = tls_session = eaptls_session(handler, inst->tls_conf, client_cert);
541
542         if (!tls_session) return 0;
543
544         /*
545          *      Push TLV of authority_identity into tls_record
546          *      call eap_tls_compose() with args
547          *
548          *      RFC 4851 section 4.1.1
549          *      N.B. mandatory/reserved flags are not applicable here
550          */
551         eap_fast_tlv_append(tls_session, PAC_INFO_A_ID, false, PAC_A_ID_LENGTH, inst->a_id);
552         tls_session->peap_flag = EAP_FAST_VERSION;
553         tls_session->length_flag = false;
554         rcode = eap_fast_tls_start(handler->eap_ds, tls_session);
555
556         if (rcode < 0) {
557                 talloc_free(tls_session);
558                 return 0;
559         }
560
561         tls_session->record_init(&tls_session->clean_in);
562
563         if (!SSL_set_session_ticket_ext_cb(tls_session->ssl, _session_ticket, tls_session)) {
564                 RERROR("Failed setting SSL session ticket callback");
565                 return 0;
566         }
567
568         handler->stage = PROCESS;
569
570         return 1;
571 }
572
573
574 /*
575  *      The module name should be the only globally exported symbol.
576  *      That is, everything else should be 'static'.
577  */
578 extern rlm_eap_module_t rlm_eap_fast;
579 rlm_eap_module_t rlm_eap_fast = {
580         .name           = "eap_fast",
581         .instantiate    = mod_instantiate,      /* Create new submodule instance */
582         .session_init   = mod_session_init,     /* Initialise a new EAP session */
583         .process        = mod_process           /* Process next round of EAP method */
584 };