All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_eap_sim.c
Go to the documentation of this file.
1 /*
2  * rlm_eap_sim.c Handles that are called from eap for SIM
3  *
4  * The development of the EAP/SIM support was funded by Internet Foundation
5  * Austria (http://www.nic.at/ipa).
6  *
7  * Version: $Id: b082b12e7b910d5dc3e5960d26de4ae5cfdb9f43 $
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  *
23  * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
24  * Copyright 2003,2006 The FreeRADIUS server project
25  *
26  */
27 
28 RCSID("$Id: b082b12e7b910d5dc3e5960d26de4ae5cfdb9f43 $")
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 
33 #include "../../eap.h"
34 #include "eap_types.h"
35 #include "eap_sim.h"
36 #include "comp128.h"
37 
38 #include <freeradius-devel/rad_assert.h>
39 
40 typedef struct eap_sim_server_state {
42  struct eapsim_keys keys;
43  int sim_id;
45 
46 /*
47  * build a reply to be sent.
48  */
49 static int eap_sim_compose(eap_session_t *eap_session)
50 {
51  /* we will set the ID on requests, since we have to HMAC it */
52  eap_session->this_round->set_request_id = true;
53 
54  return map_eapsim_basictypes(eap_session->request->reply,
55  eap_session->this_round->request);
56 }
57 
58 static int eap_sim_sendstart(eap_session_t *eap_session)
59 {
60  VALUE_PAIR **vps, *newvp;
61  uint16_t words[3];
62  eap_sim_state_t *ess;
63  RADIUS_PACKET *packet;
64  uint8_t *p;
65 
66  rad_assert(eap_session->request != NULL);
67  rad_assert(eap_session->request->reply);
68 
69  ess = (eap_sim_state_t *)eap_session->opaque;
70 
71  /* these are the outgoing attributes */
72  packet = eap_session->request->reply;
73  vps = &packet->vps;
74  rad_assert(vps != NULL);
75 
76 
77  /*
78  * Add appropriate TLVs for the EAP things we wish to send.
79  */
80 
81  /* the version list. We support only version 1. */
82  words[0] = htons(sizeof(words[1]));
83  words[1] = htons(EAP_SIM_VERSION);
84  words[2] = 0;
85 
86  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_SIM_VERSION_LIST);
87  fr_pair_value_memcpy(newvp, (uint8_t const *) words, sizeof(words));
88 
89  fr_pair_add(vps, newvp);
90 
91  /* set the EAP_ID - new value */
92  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_ID);
93  newvp->vp_integer = ess->sim_id++;
94  fr_pair_replace(vps, newvp);
95 
96  /* record it in the ess */
97  ess->keys.versionlistlen = 2;
98  memcpy(ess->keys.versionlist, words + 1, ess->keys.versionlistlen);
99 
100  /* the ANY_ID attribute. We do not support re-auth or pseudonym */
101  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_SIM_FULLAUTH_ID_REQ);
102  p = talloc_array(newvp, uint8_t, 2);
103  p[0] = 0;
104  p[0] = 1;
105  fr_pair_value_memsteal(newvp, p);
106  fr_pair_add(vps, newvp);
107 
108  /* the SUBTYPE, set to start. */
109  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_SIM_SUBTYPE);
110  newvp->vp_integer = EAPSIM_START;
111  fr_pair_replace(vps, newvp);
112 
113  return 1;
114 }
115 
116 static int eap_sim_get_challenge(eap_session_t *eap_session, VALUE_PAIR *vps, int idx, eap_sim_state_t *ess)
117 {
118  REQUEST *request = eap_session->request;
119  VALUE_PAIR *vp, *ki, *algo_version;
120 
121  rad_assert(idx >= 0 && idx < 3);
122 
123  /*
124  * Generate a new RAND value, and derive Kc and SRES from Ki
125  */
126  ki = fr_pair_find_by_num(vps, 0, PW_EAP_SIM_KI, TAG_ANY);
127  if (ki) {
128  int i;
129 
130  /*
131  * Check to see if have a Ki for the IMSI, this allows us to generate the rest
132  * of the triplets.
133  */
134  algo_version = fr_pair_find_by_num(vps, 0, PW_EAP_SIM_ALGO_VERSION, TAG_ANY);
135  if (!algo_version) {
136  REDEBUG("Found Ki, but missing EAP-Sim-Algo-Version");
137  return 0;
138  }
139 
140  for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
141  ess->keys.rand[idx][i] = fr_rand();
142  }
143 
144  switch (algo_version->vp_integer) {
145  case 1:
146  comp128v1(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx]);
147  break;
148 
149  case 2:
150  comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
151  true);
152  break;
153 
154  case 3:
155  comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
156  false);
157  break;
158 
159  case 4:
160  REDEBUG("Comp128-4 algorithm is not supported as details have not yet been published. "
161  "If you have details of this algorithm please contact the FreeRADIUS "
162  "maintainers");
163  return 0;
164 
165  default:
166  REDEBUG("Unknown/unsupported algorithm Comp128-%i", algo_version->vp_integer);
167  }
168 
169  if (RDEBUG_ENABLED2) {
170  char buffer[33]; /* 32 hexits (16 bytes) + 1 */
171  char *p;
172 
173  RDEBUG2("Generated following triplets for round %i:", idx);
174 
175  RINDENT();
176  p = buffer;
177  for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
178  p += sprintf(p, "%02x", ess->keys.rand[idx][i]);
179  }
180  RDEBUG2("RAND : 0x%s", buffer);
181 
182  p = buffer;
183  for (i = 0; i < EAPSIM_SRES_SIZE; i++) {
184  p += sprintf(p, "%02x", ess->keys.sres[idx][i]);
185  }
186  RDEBUG2("SRES : 0x%s", buffer);
187 
188  p = buffer;
189  for (i = 0; i < EAPSIM_KC_SIZE; i++) {
190  p += sprintf(p, "%02x", ess->keys.Kc[idx][i]);
191  }
192  RDEBUG2("Kc : 0x%s", buffer);
193  REXDENT();
194  }
195  return 1;
196  }
197 
198  /*
199  * Use known RAND, SRES, and Kc values, these may of been pulled in from an AuC,
200  * or created by sending challenges to the SIM directly.
201  */
202  vp = fr_pair_find_by_num(vps, 0, PW_EAP_SIM_RAND1 + idx, TAG_ANY);
203  if (!vp) {
204  /* bad, we can't find stuff! */
205  REDEBUG("control:EAP-SIM-RAND%i not found", idx + 1);
206  return 0;
207  }
208  if (vp->vp_length != EAPSIM_RAND_SIZE) {
209  REDEBUG("control:EAP-SIM-RAND%i is not " STRINGIFY(EAPSIM_RAND_SIZE) " bytes, got %zu bytes",
210  idx + 1, vp->vp_length);
211  return 0;
212  }
213  memcpy(ess->keys.rand[idx], vp->vp_octets, EAPSIM_RAND_SIZE);
214 
215  vp = fr_pair_find_by_num(vps, 0, PW_EAP_SIM_SRES1 + idx, TAG_ANY);
216  if (!vp) {
217  /* bad, we can't find stuff! */
218  REDEBUG("control:EAP-SIM-SRES%i not found", idx + 1);
219  return 0;
220  }
221  if (vp->vp_length != EAPSIM_SRES_SIZE) {
222  REDEBUG("control:EAP-SIM-SRES%i is not " STRINGIFY(EAPSIM_SRES_SIZE) " bytes, got %zu bytes",
223  idx + 1, vp->vp_length);
224  return 0;
225  }
226  memcpy(ess->keys.sres[idx], vp->vp_octets, EAPSIM_SRES_SIZE);
227 
228  vp = fr_pair_find_by_num(vps, 0, PW_EAP_SIM_KC1 + idx, TAG_ANY);
229  if (!vp) {
230  /* bad, we can't find stuff! */
231  REDEBUG("control:EAP-SIM-Kc%i not found", idx + 1);
232  return 0;
233  }
234  if (vp->vp_length != EAPSIM_KC_SIZE) {
235  REDEBUG("control:EAP-SIM-Kc%i is not 8 bytes, got %zu bytes", idx + 1, vp->vp_length);
236  return 0;
237  }
238  memcpy(ess->keys.Kc[idx], vp->vp_octets, EAPSIM_KC_SIZE);
239  if (vp->vp_length != EAPSIM_KC_SIZE) {
240  REDEBUG("control:EAP-SIM-Kc%i is not " STRINGIFY(EAPSIM_KC_SIZE) " bytes, got %zu bytes",
241  idx + 1, vp->vp_length);
242  return 0;
243  }
244  memcpy(ess->keys.Kc[idx], vp->vp_strvalue, EAPSIM_KC_SIZE);
245 
246  return 1;
247 }
248 
249 /** Send the challenge itself
250  *
251  * Challenges will come from one of three places eventually:
252  *
253  * 1 from attributes like PW_EAP_SIM_RANDx
254  * (these might be retrieved from a database)
255  *
256  * 2 from internally implemented SIM authenticators
257  * (a simple one based upon XOR will be provided)
258  *
259  * 3 from some kind of SS7 interface.
260  *
261  * For now, they only come from attributes.
262  * It might be that the best way to do 2/3 will be with a different
263  * module to generate/calculate things.
264  *
265  */
266 static int eap_sim_sendchallenge(eap_session_t *eap_session)
267 {
268  REQUEST *request = eap_session->request;
269  eap_sim_state_t *ess;
270  VALUE_PAIR **invps, **outvps, *newvp;
271  RADIUS_PACKET *packet;
272  uint8_t *p;
273 
274  ess = (eap_sim_state_t *)eap_session->opaque;
275  rad_assert(eap_session->request != NULL);
276  rad_assert(eap_session->request->reply);
277 
278  /*
279  * Invps is the data from the client but this is for non-protocol data here.
280  * We should already have consumed any client originated data.
281  */
282  invps = &eap_session->request->packet->vps;
283 
284  /*
285  * Outvps is the data to the client
286  */
287  packet = eap_session->request->reply;
288  outvps = &packet->vps;
289 
290  if (RDEBUG_ENABLED2) {
291  RDEBUG2("EAP-SIM decoded packet");
292  rdebug_pair_list(L_DBG_LVL_2, request, *invps, NULL);
293  }
294 
295  /*
296  * Okay, we got the challenges! Put them into an attribute.
297  */
298  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_SIM_RAND);
299  p = talloc_array(newvp, uint8_t, 2 + (EAPSIM_RAND_SIZE * 3));
300  memset(p, 0, 2); /* clear reserved bytes */
301  p += 2;
302  memcpy(p, ess->keys.rand[0], EAPSIM_RAND_SIZE);
303  p += EAPSIM_RAND_SIZE;
304  memcpy(p, ess->keys.rand[1], EAPSIM_RAND_SIZE);
305  p += EAPSIM_RAND_SIZE;
306  memcpy(p, ess->keys.rand[2], EAPSIM_RAND_SIZE);
307  fr_pair_value_memsteal(newvp, p);
308  fr_pair_add(outvps, newvp);
309 
310  /*
311  * Set the EAP_ID - new value
312  */
313  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_ID);
314  newvp->vp_integer = ess->sim_id++;
315  fr_pair_replace(outvps, newvp);
316 
317  /*
318  * Make a copy of the identity
319  */
320  ess->keys.identitylen = strlen(eap_session->identity);
321  memcpy(ess->keys.identity, eap_session->identity, ess->keys.identitylen);
322 
323  /*
324  * Use the SIM identity, if available
325  */
326  newvp = fr_pair_find_by_num(*invps, 0, PW_EAP_SIM_IDENTITY, TAG_ANY);
327  if (newvp && newvp->vp_length > 2) {
328  uint16_t len;
329 
330  memcpy(&len, newvp->vp_octets, sizeof(uint16_t));
331  len = ntohs(len);
332  if (len <= newvp->vp_length - 2 && len <= MAX_STRING_LEN) {
333  ess->keys.identitylen = len;
334  memcpy(ess->keys.identity, newvp->vp_octets + 2, ess->keys.identitylen);
335  }
336  }
337 
338  /*
339  * All set, calculate keys!
340  */
342 
343 #ifdef EAP_SIM_DEBUG_PRF
344  eapsim_dump_mk(&ess->keys);
345 #endif
346 
347  /*
348  * Need to include an AT_MAC attribute so that it will get
349  * calculated. The NONCE_MT and the MAC are both 16 bytes, so
350  * We store the NONCE_MT in the MAC for the encoder, which
351  * will pull it out before it does the operation.
352  */
353  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_SIM_MAC);
354  fr_pair_value_memcpy(newvp, ess->keys.nonce_mt, 16);
355  fr_pair_replace(outvps, newvp);
356 
357  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_SIM_KEY);
358  fr_pair_value_memcpy(newvp, ess->keys.K_aut, 16);
359  fr_pair_replace(outvps, newvp);
360 
361  /* the SUBTYPE, set to challenge. */
362  newvp = fr_pair_afrom_num(packet, 0, PW_EAP_SIM_SUBTYPE);
363  newvp->vp_integer = EAPSIM_CHALLENGE;
364  fr_pair_replace(outvps, newvp);
365 
366  return 1;
367 }
368 
369 #ifndef EAPTLS_MPPE_KEY_LEN
370 #define EAPTLS_MPPE_KEY_LEN 32
371 #endif
372 
373 /*
374  * this code sends the success message.
375  *
376  * the only work to be done is the add the appropriate SEND/RECV
377  * radius attributes derived from the MSK.
378  *
379  */
380 static int eap_sim_sendsuccess(eap_session_t *eap_session)
381 {
382  unsigned char *p;
383  eap_sim_state_t *ess;
384  VALUE_PAIR *vp;
385  RADIUS_PACKET *packet;
386 
387  /* outvps is the data to the client. */
388  packet = eap_session->request->reply;
389  ess = (eap_sim_state_t *)eap_session->opaque;
390 
391  /* set the EAP_ID - new value */
392  vp = fr_pair_afrom_num(packet, 0, PW_EAP_ID);
393  vp->vp_integer = ess->sim_id++;
394  fr_pair_replace(&eap_session->request->reply->vps, vp);
395 
396  p = ess->keys.msk;
397  eap_add_reply(eap_session->request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN);
398  p += EAPTLS_MPPE_KEY_LEN;
399  eap_add_reply(eap_session->request, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN);
400 
401  return 1;
402 }
403 
404 
405 /** Run the server state machine
406  *
407  */
408 static void eap_sim_stateenter(eap_session_t *eap_session,
409  eap_sim_state_t *ess,
410  enum eapsim_serverstates newstate)
411 {
412  switch (newstate) {
413  /*
414  * Send the EAP-SIM Start message, listing the versions that we support.
415  */
416  case EAPSIM_SERVER_START:
417  eap_sim_sendstart(eap_session);
418  break;
419  /*
420  * Send the EAP-SIM Challenge message.
421  */
423  eap_sim_sendchallenge(eap_session);
424  break;
425 
426  /*
427  * Send the EAP Success message
428  */
430  eap_sim_sendsuccess(eap_session);
431  eap_session->this_round->request->code = PW_EAP_SUCCESS;
432  break;
433  /*
434  * Nothing to do for this transition.
435  */
436  default:
437 
438  break;
439  }
440 
441  ess->state = newstate;
442 
443  /* build the target packet */
444  eap_sim_compose(eap_session);
445 }
446 
447 
448 static int CC_HINT(nonnull) mod_process(void *instance, eap_session_t *eap_session);
449 
450 /*
451  * Initiate the EAP-SIM session by starting the state machine
452  * and initiating the state.
453  */
454 static int mod_session_init(UNUSED void *instance, eap_session_t *eap_session)
455 {
456  REQUEST *request = eap_session->request;
457  eap_sim_state_t *ess;
458  time_t n;
459 
460  ess = talloc_zero(eap_session, eap_sim_state_t);
461  if (!ess) {
462  RDEBUG2("No space for EAP-SIM state");
463  return 0;
464  }
465 
466  eap_session->opaque = ess;
467 
468  /*
469  * Save the keying material, because it could change on a subsequent retrieval.
470  */
471  if (!eap_sim_get_challenge(eap_session, request->config, 0, ess) ||
472  !eap_sim_get_challenge(eap_session, request->config, 1, ess) ||
473  !eap_sim_get_challenge(eap_session, request->config, 2, ess)) {
474  return 0;
475  }
476 
477  /*
478  * This value doesn't have be strong, but it is good if it is different now and then.
479  */
480  time(&n);
481  ess->sim_id = (n & 0xff);
482 
483  eap_sim_stateenter(eap_session, ess, EAPSIM_SERVER_START);
484 
485  eap_session->process = mod_process;
486 
487  return 1;
488 }
489 
490 
491 /** Process an EAP-Sim/Response/Start
492  *
493  * Verify that client chose a version, and provided a NONCE_MT,
494  * and if so, then change states to challenge, and send the new
495  * challenge, else, resend the Request/Start.
496  */
497 static int process_eap_sim_start(eap_session_t *eap_session, VALUE_PAIR *vps)
498 {
499  REQUEST *request = eap_session->request;
500  VALUE_PAIR *nonce_vp, *selectedversion_vp;
501  eap_sim_state_t *ess;
502  uint16_t simversion;
503  ess = (eap_sim_state_t *)eap_session->opaque;
504 
505  nonce_vp = fr_pair_find_by_num(vps, 0, PW_EAP_SIM_NONCE_MT, TAG_ANY);
506  selectedversion_vp = fr_pair_find_by_num(vps, 0, PW_EAP_SIM_SELECTED_VERSION, TAG_ANY);
507  if (!nonce_vp || !selectedversion_vp) {
508  RDEBUG2("Client did not select a version and send a NONCE");
509  eap_sim_stateenter(eap_session, ess, EAPSIM_SERVER_START);
510 
511  return 1;
512  }
513 
514  /*
515  * Okay, good got stuff that we need. Check the version we found.
516  */
517  if (selectedversion_vp->vp_length < 2) {
518  REDEBUG("EAP-SIM version field is too short");
519  return 0;
520  }
521  memcpy(&simversion, selectedversion_vp->vp_strvalue, sizeof(simversion));
522  simversion = ntohs(simversion);
523  if (simversion != EAP_SIM_VERSION) {
524  REDEBUG("EAP-SIM version %i is unknown", simversion);
525  return 0;
526  }
527 
528  /*
529  * Record it for later keying
530  */
531  memcpy(ess->keys.versionselect, selectedversion_vp->vp_strvalue, sizeof(ess->keys.versionselect));
532 
533  /*
534  * Double check the nonce size.
535  */
536  if(nonce_vp->vp_length != 18) {
537  REDEBUG("EAP-SIM nonce_mt must be 16 bytes (+2 bytes padding), not %zu", nonce_vp->vp_length);
538  return 0;
539  }
540  memcpy(ess->keys.nonce_mt, nonce_vp->vp_strvalue + 2, 16);
541 
542  /*
543  * Everything looks good, change states
544  */
545  eap_sim_stateenter(eap_session, ess, EAPSIM_SERVER_CHALLENGE);
546 
547  return 1;
548 }
549 
550 
551 /** Process an EAP-Sim/Response/Challenge
552  *
553  * Verify that MAC that we received matches what we would have
554  * calculated from the packet with the SRESx appended.
555  *
556  */
557 static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps)
558 {
559  REQUEST *request = eap_session->request;
560  eap_sim_state_t *ess = eap_session->opaque;
561 
562  uint8_t srescat[EAPSIM_SRES_SIZE * 3];
563  uint8_t *p = srescat;
564 
565  uint8_t calcmac[EAPSIM_CALCMAC_SIZE];
566 
567  memcpy(p, ess->keys.sres[0], EAPSIM_SRES_SIZE);
568  p += EAPSIM_SRES_SIZE;
569  memcpy(p, ess->keys.sres[1], EAPSIM_SRES_SIZE);
570  p += EAPSIM_SRES_SIZE;
571  memcpy(p, ess->keys.sres[2], EAPSIM_SRES_SIZE);
572 
573  /*
574  * Verify the MAC, now that we have all the keys
575  */
576  if (eapsim_checkmac(eap_session, vps, ess->keys.K_aut, srescat, sizeof(srescat), calcmac)) {
577  RDEBUG2("MAC check succeed");
578  } else {
579  int i, j;
580  char macline[20*3];
581  char *m = macline;
582 
583  j=0;
584  for (i = 0; i < EAPSIM_CALCMAC_SIZE; i++) {
585  if(j==4) {
586  *m++ = '_';
587  j=0;
588  }
589  j++;
590 
591  sprintf(m, "%02x", calcmac[i]);
592  m = m + strlen(m);
593  }
594  REDEBUG("Calculated MAC (%s) did not match", macline);
595  return 0;
596  }
597 
598  /* everything looks good, change states */
599  eap_sim_stateenter(eap_session, ess, EAPSIM_SERVER_SUCCESS);
600  return 1;
601 }
602 
603 
604 /** Authenticate a previously sent challenge
605  *
606  */
607 static int mod_process(UNUSED void *arg, eap_session_t *eap_session)
608 {
609  REQUEST *request = eap_session->request;
610  eap_sim_state_t *ess = eap_session->opaque;
611 
612  VALUE_PAIR *vp, *vps;
613 
614  enum eapsim_subtype subtype;
615 
616  int success;
617 
618  /*
619  * VPS is the data from the client
620  */
621  vps = eap_session->request->packet->vps;
622 
623  success = unmap_eapsim_basictypes(eap_session->request->packet,
624  eap_session->this_round->response->type.data,
625  eap_session->this_round->response->type.length);
626 
627  if (!success) return 0;
628 
629  /*
630  * See what kind of message we have gotten
631  */
632  vp = fr_pair_find_by_num(vps, 0, PW_EAP_SIM_SUBTYPE, TAG_ANY);
633  if (!vp) {
634  REDEBUG2("No subtype attribute was created, message dropped");
635  return 0;
636  }
637  subtype = vp->vp_integer;
638 
639  /*
640  * Client error supersedes anything else.
641  */
642  if (subtype == EAPSIM_CLIENT_ERROR) {
643  return 0;
644  }
645 
646  switch (ess->state) {
647  case EAPSIM_SERVER_START:
648  switch (subtype) {
649  /*
650  * Pretty much anything else here is illegal, so we will retransmit the request.
651  */
652  default:
653 
654  eap_sim_stateenter(eap_session, ess, EAPSIM_SERVER_START);
655  return 1;
656  /*
657  * A response to our EAP-Sim/Request/Start!
658  */
659  case EAPSIM_START:
660  return process_eap_sim_start(eap_session, vps);
661  }
662 
664  switch (subtype) {
665  /*
666  * Pretty much anything else here is illegal, so we will retransmit the request.
667  */
668  default:
669  eap_sim_stateenter(eap_session, ess, EAPSIM_SERVER_CHALLENGE);
670  return 1;
671  /*
672  * A response to our EAP-Sim/Request/Challenge!
673  */
674  case EAPSIM_CHALLENGE:
675  return process_eap_sim_challenge(eap_session, vps);
676  }
677 
678  default:
679  rad_assert(0 == 1);
680  }
681 
682  return 0;
683 }
684 
685 /*
686  * The module name should be the only globally exported symbol.
687  * That is, everything else should be 'static'.
688  */
690 rlm_eap_module_t rlm_eap_sim = {
691  .name = "eap_sim",
692  .session_init = mod_session_init, /* Initialise a new EAP session */
693  .process = mod_process, /* Process next round of EAP method */
694 };
2nd highest priority debug messages (-xx | -X).
Definition: log.h:52
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:265
void comp128v1(uint8_t *sres, uint8_t *kc, uint8_t const *ki, uint8_t const *rand)
Calculate comp128v1 sres and kc from ki and rand.
Definition: comp128.c:239
uint8_t msk[64]
Definition: eap_sim.h:102
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
#define RDEBUG_ENABLED2
True if request debug level 1-2 messages are enabled.
Definition: log.h:238
struct eapsim_keys keys
Definition: rlm_eap_sim.c:42
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
static int eap_sim_get_challenge(eap_session_t *eap_session, VALUE_PAIR *vps, int idx, eap_sim_state_t *ess)
Definition: rlm_eap_sim.c:116
uint8_t sres[3][EAPSIM_SRES_SIZE]
Definition: eap_sim.h:92
#define UNUSED
Definition: libradius.h:134
#define REDEBUG2(fmt,...)
Definition: log.h:255
static int process_eap_sim_start(eap_session_t *eap_session, VALUE_PAIR *vps)
Process an EAP-Sim/Response/Start.
Definition: rlm_eap_sim.c:497
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
uint8_t versionselect[2]
Definition: eap_sim.h:96
void comp128v23(uint8_t *sres, uint8_t *kc, uint8_t const *ki, uint8_t const *rand, bool v2)
Calculate comp128v2 or comp128v3 sres and kc from ki and rand.
Definition: comp128.c:335
eap_packet_t * request
Packet we will send to the peer.
Definition: eap.h:45
void * opaque
Opaque data used by EAP methods.
Definition: eap.h:80
static void eap_sim_stateenter(eap_session_t *eap_session, eap_sim_state_t *ess, enum eapsim_serverstates newstate)
Run the server state machine.
Definition: rlm_eap_sim.c:408
eap_type_data_t type
Definition: eap_types.h:136
REQUEST * request
Request that contains the response we're processing.
Definition: eap.h:71
enum eapsim_serverstates state
Definition: rlm_eap_sim.c:41
#define EAPSIM_KC_SIZE
Definition: eap_sim.h:81
static int eap_sim_sendchallenge(eap_session_t *eap_session)
Send the challenge itself.
Definition: rlm_eap_sim.c:266
static int mod_session_init(void *instance, eap_session_t *eap_session)
Definition: rlm_eap_gtc.c:89
uint8_t rand[3][EAPSIM_RAND_SIZE]
Definition: eap_sim.h:91
static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps)
Process an EAP-Sim/Response/Challenge.
Definition: rlm_eap_sim.c:557
#define rad_assert(expr)
Definition: rad_assert.h:38
static int eap_sim_sendstart(eap_session_t *eap_session)
Definition: rlm_eap_sim.c:58
#define EAP_SIM_VERSION
Definition: eap_sim.h:31
int unmap_eapsim_basictypes(RADIUS_PACKET *r, uint8_t *attr, unsigned int attrlen)
Definition: eapsimlib.c:284
static int eap_sim_sendsuccess(eap_session_t *eap_session)
Definition: rlm_eap_sim.c:380
struct eap_sim_server_state eap_sim_state_t
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
Tracks the progress of a single session of any EAP method.
Definition: eap.h:60
#define STRINGIFY(x)
Definition: build.h:34
int eapsim_checkmac(TALLOC_CTX *ctx, VALUE_PAIR *rvps, uint8_t key[8], uint8_t *extra, int extralen, uint8_t calcmac[20])
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
Definition: eap.h:77
int map_eapsim_basictypes(RADIUS_PACKET *r, eap_packet_t *ep)
Definition: eapsimlib.c:63
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
size_t length
Definition: eap_types.h:123
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
static int eap_sim_compose(eap_session_t *eap_session)
Definition: rlm_eap_sim.c:49
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:272
char const * name
The name of the sub-module (without rlm_ prefix).
Definition: eap.h:96
void eapsim_dump_mk(struct eapsim_keys *ek)
Definition: eapcrypto.c:103
void rdebug_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a list of VALUE_PAIRs.
Definition: pair.c:757
rlm_eap_module_t rlm_eap_sim
Definition: rlm_eap_sim.c:690
char * identity
NAI (User-Name) from EAP-Identity.
Definition: eap.h:73
uint8_t identity[MAX_STRING_LEN]
Definition: eap_sim.h:88
#define RDEBUG2(fmt,...)
Definition: log.h:244
static int CC_HINT(nonnull)
Definition: rlm_eap_sim.c:448
uint8_t K_aut[EAPSIM_AUTH_SIZE]
Definition: eap_sim.h:100
void fr_pair_value_memsteal(VALUE_PAIR *vp, uint8_t const *src)
Reparent an allocated octet buffer to a VALUE_PAIR.
Definition: pair.c:1933
#define TAG_ANY
Definition: pair.h:191
Interface to call EAP sub mdoules.
Definition: eap.h:95
uint8_t Kc[3][EAPSIM_KC_SIZE]
Definition: eap_sim.h:93
uint8_t versionlist[MAX_STRING_LEN]
Definition: eap_sim.h:94
static int mod_process(UNUSED void *arg, eap_session_t *eap_session)
Authenticate a previously sent challenge.
Definition: rlm_eap_sim.c:607
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
void eapsim_calculate_keys(struct eapsim_keys *ek)
Definition: eapcrypto.c:37
#define EAPSIM_SRES_SIZE
Definition: eap_sim.h:79
#define EAPSIM_CALCMAC_SIZE
Definition: eap_sim.h:82
#define REDEBUG(fmt,...)
Definition: log.h:254
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
uint8_t versionlistlen
Definition: eap_sim.h:95
eap_packet_t * response
Packet we received from the peer.
Definition: eap.h:44
eapsim_subtype
Definition: eap_sim.h:33
uint8_t nonce_mt[EAPSIM_NONCEMT_SIZE]
Definition: eap_sim.h:90
#define MAX_STRING_LEN
Definition: libradius.h:120
void fr_pair_replace(VALUE_PAIR **head, VALUE_PAIR *add)
Replace all matching VPs.
Definition: pair.c:696
#define vp_length
Definition: pair.h:182
#define RCSID(id)
Definition: build.h:135
bool set_request_id
Definition: eap.h:46
#define EAPSIM_RAND_SIZE
Definition: eap_sim.h:80
eapsim_serverstates
Definition: eap_sim.h:53
eap_code_t code
Definition: eap_types.h:133
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
void eap_add_reply(REQUEST *request, char const *name, uint8_t const *value, int len)
Definition: eapcommon.c:388
uint8_t * data
Definition: eap_types.h:124
unsigned int identitylen
Definition: eap_sim.h:89
#define EAPTLS_MPPE_KEY_LEN
Definition: rlm_eap_sim.c:370