Turn on super pedantic warnings in CLANG
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_ikev2 / rlm_eap_ikev2.c
1 /*
2  *  rlm_eap_ikev2.c - Handles that are called from eap
3  *
4  *  This file is part of rlm_eap_ikev2 freeRADIUS module which implements
5  *  EAP-IKEv2 protocol functionality.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  *  Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl>
22  *  Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl>
23  *  Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl>
24  *  Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl>
25  *  Copyright 1999-2007 The FreeRADIUS server project
26  *
27  */
28
29 #include <freeradius-devel/radiusd.h>
30 #include "eap.h"
31
32 #include <assert.h>
33 #include <freeradius-devel/rad_assert.h>
34
35 #include "logging_impl.h"
36 #include <EAPIKEv2/connector.h>
37 #include "ike_conf.h"
38
39 typedef enum {
40         PW_IKEV2_CHALLENGE = 1,
41         PW_IKEV2_RESPONSE,
42         PW_IKEV2_SUCCESS,
43         PW_IKEV2_FAILURE,
44         PW_IKEV2_MAX_CODES
45 } pw_ikev2_code;
46
47 #define IKEV2_HEADER_LEN        4
48 #define IKEV2_MPPE_KEY_LEN     32
49
50 typedef struct rlm_eap_ikev2 {
51         char const      *tls_ca_file;                   //!< Sets the full path to a CA certificate (used to validate
52                                                         //!< the certificate the server presents).
53
54         char const      *tls_private_key_file;          //!< Sets the path to the private key for our public
55                                                         //!< certificate.
56         char const      *tls_private_key_password;      //!< Sets the path to the private key for our public
57                                                         //!< certificate.
58
59         char const      *tls_certificate_file;          //!< Sets the path to the public certificate file we present
60                                                         //!< to the servers.
61         char const      *tls_crl;
62
63         char const      *id;
64         uint32_t        max_fragment_size;
65         uint32_t        dh_counter_max;
66
67         char const      *default_auth_type;
68         char const      *users_file_name;
69         char const      *server_auth_type;
70         char const      *server_id_type;
71         bool            send_cert_request;
72
73         uint32_t        fast_expire;
74
75         bool            enable_fast_dhex;
76         bool            enable_fast_reconnect;
77 } rlm_eap_ikev2_t;
78
79 CONF_PARSER module_config[] = {
80         { "ca_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_ca_file), NULL  },
81         { "private_key_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_private_key_file), NULL  },
82         { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_private_key_password), NULL  },
83         { "certificate_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_certificate_file), NULL  },
84         { "crl_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_crl), NULL  },
85
86         { "id", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, id), NULL  },
87         { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, max_fragment_size), IKEv2_DEFAULT_MAX_FRAGMENT_SIZE_STR },
88         { "dh_counter_max", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, dh_counter_max), IKEv2_DEFAULT_DH_COUNTER_MAX_STR },
89         { "default_authtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, default_auth_type), "both" },
90         { "usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_eap_ikev2_t, users_file_name),"${confdir}/users" },
91         { "server_authtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, server_auth_type), "secret" },
92         { "idtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, server_id_type), IKEv2_DEFAULT_IDTYPE_STR },
93         { "certreq", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, send_cert_request), "no" },
94         { "fast_timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, fast_expire), "900" },
95
96         { "fast_dh_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, enable_fast_dhex), "no" },
97         { "enable_fast_reauth", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, enable_fast_reconnect), "yes" },
98
99         { NULL, -1, 0, NULL, NULL }        /* end the list */
100 };
101
102 static int set_mppe_keys(eap_handler_t *handler)
103 {
104         uint8_t const *p;
105         struct IKEv2Session *session;
106
107         session = ((struct IKEv2Data*)handler->opaque)->session;
108
109         if (session->eapKeyData==NULL){
110                 INFO(IKEv2_LOG_PREFIX "Key session not available!!!");
111                 return 1;
112         }
113
114         p = session->eapKeyData;
115         eap_add_reply(handler->request, "MS-MPPE-Recv-Key", p, IKEV2_MPPE_KEY_LEN);
116         p += IKEV2_MPPE_KEY_LEN;
117         eap_add_reply(handler->request, "MS-MPPE-Send-Key", p, IKEV2_MPPE_KEY_LEN);
118         return 0;
119 }
120
121 /** Compose Radius like message from table of output bytes
122  *
123  */
124 static int compose_rad_message(uint8_t *out,u_int32_t olen, EAP_DS *eap_ds) {
125         int len;
126
127         eap_ds->request->type.num = PW_EAP_IKEV2;
128         eap_ds->request->code = ((struct EAPHeader *)out)->Code;
129
130         if (eap_ds->request->code > PW_EAP_REQUEST || (olen <= 4)) {
131             eap_ds->request->type.data = NULL;
132             eap_ds->request->type.length = 0;
133
134             return 0;
135         }
136
137         len = ntohs(((struct EAPHeader *)out)->Length);
138
139         eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, len);
140         if (!eap_ds->request->type.data) return 1;
141
142         memcpy(eap_ds->request->type.data, out + 5, len - 5);
143         eap_ds->request->type.length = len - 5;
144
145         return 0;
146 }
147
148 /** Free memory after EAP-IKEv2 module usage
149  *
150  */
151 static int ikev2_detach(void *instance)
152 {
153         struct ikev2_ctx *data = (struct ikev2_ctx *) instance;
154
155         if (data) {
156                 Free_ikev2_ctx(data);
157                 data = NULL;
158         }
159         return 0;
160 }
161
162 /** Free memory after finished IKEv2 session
163  *
164  */
165 static void ikev2_free_opaque(void *opaque)
166 {
167
168         int fast_deleted;
169         struct IKEv2Data *ikev2_data=(struct IKEv2Data*)opaque;
170
171         DEBUG(IKEv2_LOG_PREFIX "Free session data");
172
173         if (ikev2_data->session) {
174                 if (ikev2_data->session->Status != IKEv2_SST_ESTABLISHED) {
175                         DEBUG(IKEv2_LOG_PREFIX "Unfinished IKEv2 session - cleanup!!!");
176                         IKEv2EndSession(ikev2_data->i2, ikev2_data->session);
177                         ikev2_data->session = NULL;
178                 } else {
179                         DEBUG(IKEv2_LOG_PREFIX "Unfinished IKEv2 session - keep it!!!");
180                         ikev2_data->session = NULL;
181                 }
182         }
183
184         fast_deleted = FreeSessionIfExpired(ikev2_data->i2, time(NULL));
185         if (fast_deleted) {
186                 DEBUG(IKEv2_LOG_PREFIX "Deleted %d expired IKEv2 sessions", fast_deleted);
187         }
188
189         free(ikev2_data);
190 }
191
192 /** Configure EAP-ikev2 handler
193  *
194  */
195 static int ikev2_attach(CONF_SECTION *conf, void **instance)
196 {
197         int ret;
198
199         struct ikev2_ctx *i2;
200         rlm_eap_ikev2_t *inst;
201
202         char *server_auth_type, *default_auth_type, *users_file_name;
203
204         ikev2_set_log_callback(vxlogf);
205
206         inst = talloc_zero(conf, rlm_eap_ikev2_t);
207         if (cf_section_parse(conf, &inst, module_config) < 0) return -1;
208
209         i2 = Create_ikev2_ctx();
210         if (!i2) return -1;
211         *instance = i2;
212
213         /*
214          *      Map our config structure onto the IKEv2 context
215          */
216         memcpy(&i2->trusted, &inst->tls_ca_file, sizeof(i2->trusted));
217         memcpy(&i2->pkfile, &inst->tls_private_key_file, sizeof(i2->pkfile));
218         memcpy(&i2->pkfile_pwd, &inst->tls_private_key_password, sizeof(i2->pkfile_pwd));
219         memcpy(&i2->certfile, &inst->tls_certificate_file, sizeof(i2->certfile));
220         memcpy(&i2->id, &inst->id, sizeof(i2->id));
221         i2->max_fragment_size = inst->max_fragment_size;
222         i2->DHCounterMax = inst->dh_counter_max;
223         i2->sendCertReq = (uint8_t) inst->send_cert_request;
224         i2->fastExpire = inst->fast_expire;
225         i2->enableFastDHEx = inst->enable_fast_dhex;
226         i2->enableFastReconnect = inst->enable_fast_reconnect;
227
228         memcpy(&server_auth_type, &inst->server_auth_type, sizeof(server_auth_type));
229         memcpy(&default_auth_type, &inst->default_auth_type, sizeof(default_auth_type));
230         memcpy(&users_file_name, &inst->users_file_name, sizeof(users_file_name));
231         hexalize(&i2->id, &i2->idlen);
232
233         i2->authtype = rad_get_authtype(server_auth_type);
234         if (!i2->id) {
235                 ERROR(IKEv2_LOG_PREFIX "'id' configuration option is required!!!");
236                 return -1;
237         }
238
239         switch (i2->authtype) {
240         default:
241         case IKEv2_AUTH_SK:
242                 break;
243
244         case IKEv2_AUTH_CERT:
245                 if (!i2->certfile || !i2->pkfile) {
246                         ERROR(IKEv2_LOG_PREFIX "'certificate_file' and 'private_key_file' items are required "
247                               "for 'cert' auth type");
248                         return -1;
249                 }
250
251                 if (!file_exists(i2->certfile)) {
252                         ERROR(IKEv2_LOG_PREFIX "Can not open 'certificate_file' %s", i2->certfile);
253                         return -1;
254                 }
255
256                 if (!file_exists(i2->pkfile)) {
257                         ERROR(IKEv2_LOG_PREFIX "Can not open 'private_key_file' %s",i2->pkfile);
258                         return -1;
259                 }
260                 break;
261         }
262
263         if (!i2->trusted) {
264                 AUTH(IKEv2_LOG_PREFIX "'ca_file' item not set, client cert based authentication will fail");
265         } else {
266                 if (!file_exists(i2->trusted)) {
267                         ERROR(IKEv2_LOG_PREFIX "Can not open 'ca_file' %s", i2->trusted);
268                         return -1;
269                 }
270         }
271
272         if (i2->crl_file) {
273                 if (!file_exists(i2->crl_file)) {
274                         ERROR(IKEv2_LOG_PREFIX "Can not open 'crl_file' %s", i2->crl_file);
275                         return -1;
276                 }
277         }
278
279         i2->idtype = IdTypeFromName(inst->server_id_type);
280         if (i2->idtype <= 0) {
281                 ERROR(IKEv2_LOG_PREFIX "Unsupported 'idtype': %s", inst->server_id_type);
282                 return -1;
283         }
284
285         if (rad_load_proposals(i2, conf)) {
286                 ERROR(IKEv2_LOG_PREFIX "Failed to load proposals");
287                 return -1;
288         }
289
290         ret = rad_load_credentials(instance, i2, users_file_name, default_auth_type);
291         if (ret == -1) {
292                 ERROR(IKEv2_LOG_PREFIX "Error while loading users credentials");
293                 return -1;
294         }
295
296         i2->x509_store = NULL;
297         if(CertInit(i2)){
298                 ERROR(IKEv2_LOG_PREFIX "Error while loading certs/crl");
299                 return -1;
300         }
301
302         return 0;
303 }
304
305 /** Initiate the EAP-ikev2 session by sending a challenge to the peer.
306  *
307  */
308 static int ikev2_initiate(void *instance, eap_handler_t *handler)
309 {
310         INFO(IKEv2_LOG_PREFIX "Initiate connection!");
311
312         struct IKEv2Data *ikev2_data;
313         struct ikev2_ctx *i2=(struct ikev2_ctx*)instance;
314
315         uint8_t *sikemsg = NULL;
316         u_int32_t slen = 0;
317
318         uint8_t *out = NULL;
319         u_int32_t olen = 0;
320
321         struct IKEv2Session *session;
322         handler->free_opaque = ikev2_free_opaque;
323
324         /* try get respondent FASTID */
325         uint8_t const *eap_username;
326
327         eap_username = handler->request->username->vp_octets;
328         session = FindSessionByFastid(i2, (char const *)eap_username);
329         if (!session) {
330                 if (IKEv2BeginSession( i2, &session, IKEv2_STY_INITIATOR ) != IKEv2_RET_OK) {
331                         ERROR(IKEv2_LOG_PREFIX "Can't initialize IKEv2 session");
332                         return 1;
333                 }
334         } else {
335                 DEBUG(IKEv2_LOG_PREFIX "Fast reconnect procedure start");
336         }
337         session->timestamp=time(NULL);
338
339         ikev2_data = IKEv2Data_new(i2,session);
340         handler->opaque = ikev2_data;
341
342         if (IKEv2ProcessMsg(i2, NULL , &sikemsg, &slen, session) != IKEv2_RET_OK) {
343                 ERROR(IKEv2_LOG_PREFIX "Error while processing IKEv2 message");
344                 return 1;
345         }
346
347         if (slen != 0) {
348                 session->eapMsgID++;
349                 olen = CreateIKEv2Message(i2, sikemsg, slen, false, 0, session, &out );
350                 if (session->fragdata) {
351                         session->sendfrag = true;
352                 }
353         }
354
355         if ((olen > 0) && (out!=NULL)) {
356                 if (compose_rad_message(out, olen, handler->eap_ds)) {
357                         free(out);
358                         return 0;
359                 }
360                 free(out);
361         }
362
363         /*
364          *      We don't need to authorize the user at this point.
365          *
366          *      We also don't need to keep the challenge, as it's
367          *      stored in 'handler->eap_ds', which will be given back
368          *      to us...
369          */
370         handler->stage = AUTHENTICATE;
371         return 1;
372 }
373
374 /** Authenticate a previously sent challenge
375  *
376  */
377 static int ikev2_authenticate(void *instance, eap_handler_t *handler)
378 {
379         uint8_t *in;
380         uint8_t *out = NULL;
381
382         uint8_t *ikemsg;
383         u_int32_t len;
384
385         uint8_t *sikemsg = NULL;   //out message
386         u_int32_t slen = 0;
387
388         u_int32_t olen = 0;
389         struct ikev2_ctx *i2 = (struct ikev2_ctx*)instance;
390         struct EAPHeader *hdr;
391
392         struct IKEv2Data *ikev2_data;
393         struct IKEv2Session *session;
394
395         INFO(IKEv2_LOG_PREFIX "authenticate" );
396
397         rad_assert(handler->request != NULL);
398         rad_assert(handler->stage == AUTHENTICATE);
399
400         EAP_DS *eap_ds=handler->eap_ds;
401         if (!eap_ds ||
402             !eap_ds->response ||
403             (eap_ds->response->code != PW_IKEV2_RESPONSE) ||
404             eap_ds->response->type.num != PW_EAP_IKEV2 ||
405             !eap_ds->response->type.data) {
406                 ERROR(IKEv2_LOG_PREFIX "corrupted data");
407                 return -1;
408         }
409
410         in = talloc_array(eap_ds, uint8_t, eap_ds->response->length);
411         if (in){
412                 ERROR(IKEv2_LOG_PREFIX "alloc error");
413                 return -1;
414         }
415
416         rad_assert(in != NULL);
417         hdr = (struct EAPHeader *)in;
418
419         hdr->Code = eap_ds->response->code;
420         hdr->Id = eap_ds->response->id;
421         hdr->Length = htons(eap_ds->response->length);
422         hdr->Type = eap_ds->response->type.num;
423         memcpy(in + 5, eap_ds->response->type.data, eap_ds->response->length - 5);
424
425         ikev2_data = (struct IKEv2Data*)handler->opaque;
426         session = ikev2_data->session;
427         session->timestamp = time(NULL);
428
429         if (!session->fragdata) session->sendfrag = false;
430
431         if (session->sendfrag && !ParseFragmentAck(in, session)){
432                 session->eapMsgID = eap_ds->response->id + 1;
433
434                 olen = CreateIKEv2Message(i2, NULL, 0, false, hdr->Id, session, (uint8_t **)&out);
435                 talloc_free(in);
436
437                 if (compose_rad_message(out,olen,handler->eap_ds)) {
438                         free(out);
439                         return 0;
440                 }
441
442                 free(out);
443                 return 1;
444         }
445
446         session->eapMsgID = eap_ds->response->id + 1;
447
448         if (ParseIKEv2Message(in, &ikemsg, &len, session)){
449                 if (ikemsg != NULL) free(ikemsg);
450
451                 handler->eap_ds->request->code=PW_EAP_FAILURE;
452                 INFO(IKEv2_LOG_PREFIX "Discarded packet");
453
454                 return 1;
455         }
456
457         /* Send fragment ack */
458         if (!ikemsg || !len) {
459                 if (session->SK_ready) session->include_integ = 1;
460
461                 olen = CreateFragmentAck(in, &out, session); // confirm fragment
462                 TALLOC_FREE(in);
463
464                 if (compose_rad_message(out,olen,handler->eap_ds)) {
465                         free(out);
466                         return 0;
467                 }
468
469                 free(out);
470                 return 1;
471         }
472         TALLOC_FREE(in);
473
474         if (IKEv2ProcessMsg(i2, ikemsg, &sikemsg, &slen, session) != IKEv2_RET_OK) {
475                 INFO(IKEv2_LOG_PREFIX "EAP_STATE_DISCARD");
476                 //session->State = EAP_STATE_DISCARD;
477                 free(out);
478                 return 1;
479         }
480
481         free(ikemsg);
482
483         /* If there is there is something to send */
484         if (slen != 0){
485                 olen = CreateIKEv2Message(i2, sikemsg, slen, false, 0, session, &out);
486                 if (session->fragdata) session->sendfrag = true;
487         } else {
488                 if (session->Status == IKEv2_SST_FAILED ) {
489                         INFO(IKEv2_LOG_PREFIX "FAILED");
490                         olen = CreateResultMessage( false, session, &out );
491                 }
492
493                 if(session->Status == IKEv2_SST_ESTABLISHED) {
494                         INFO(IKEv2_LOG_PREFIX "SUCCESS");
495                         olen = CreateResultMessage(true, session, &out);
496                         session->fFastReconnect = i2->enableFastReconnect;
497
498                         GenEapKeys(session ,EAP_IKEv2_KEY_LEN);
499                         set_mppe_keys(handler);
500                 }
501
502                 // keep sessions in memory, only reference cleared
503                 ikev2_data->session = NULL;
504         }
505         if ((olen > 0) && (out != NULL)){
506                 if (compose_rad_message(out, olen, handler->eap_ds)){
507                         free(out);
508                         return 0;
509                 }
510         }
511
512         free(out);
513         return 1;
514 }
515
516 /*
517  *      The module name should be the only globally exported symbol.
518  *      That is, everything else should be 'static'.
519  */
520 extern rlm_eap_module_t rlm_eap_ikev2;
521 rlm_eap_module_t rlm_eap_ikev2 = {
522         "eap_ikev2",
523         ikev2_attach,                   /* attach */
524         ikev2_initiate,                 /* Start the initial request */
525         NULL,                           /* authorization */
526         ikev2_authenticate,             /* authentication */
527         ikev2_detach                    /* detach */
528 };