proper notification handling
[strongswan.git] / src / charon / sa / authenticators / eap / eap_sim.c
1 /**
2 * @file eap_sim.c
3 *
4 * @brief Implementation of eap_sim_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "eap_sim.h"
24
25 #include <dlfcn.h>
26
27 #include <daemon.h>
28 #include <library.h>
29
30 #define MAX_TRIES 3
31
32 ENUM(sim_subtype_names, SIM_START, SIM_CLIENT_ERROR,
33 "SIM_START",
34 "SIM_CHALLENGE",
35 "SIM_NOTIFICATION",
36 "SIM_13",
37 "SIM_CLIENT_ERROR",
38 );
39
40 ENUM_BEGIN(sim_attribute_names, AT_END, AT_CLIENT_ERROR_CODE,
41 "AT_END",
42 "AT_0",
43 "AT_RAND",
44 "AT_AUTN",
45 "AT_RES",
46 "AT_AUTS",
47 "AT_5",
48 "AT_PADDING",
49 "AT_NONCE_MT",
50 "AT_8",
51 "AT_9",
52 "AT_PERMANENT_ID_REQ",
53 "AT_MAC",
54 "AT_NOTIFICATION",
55 "AT_ANY_ID_REQ",
56 "AT_IDENTITY",
57 "AT_VERSION_LIST",
58 "AT_SELECTED_VERSION",
59 "AT_FULLAUTH_ID_REQ",
60 "AT_18",
61 "AT_COUNTER",
62 "AT_COUNTER_TOO_SMALL",
63 "AT_NONCE_S",
64 "AT_CLIENT_ERROR_CODE");
65 ENUM_NEXT(sim_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
66 "AT_IV",
67 "AT_ENCR_DATA",
68 "AT_131",
69 "AT_NEXT_PSEUDONYM",
70 "AT_NEXT_REAUTH_ID",
71 "AT_CHECKCODE",
72 "AT_RESULT_IND");
73 ENUM_END(sim_attribute_names, AT_RESULT_IND);
74
75
76 typedef struct private_eap_sim_t private_eap_sim_t;
77
78 /**
79 * Private data of an eap_sim_t object.
80 */
81 struct private_eap_sim_t {
82
83 /**
84 * Public authenticator_t interface.
85 */
86 eap_sim_t public;
87
88 /**
89 * ID of ourself
90 */
91 identification_t *peer;
92
93 /**
94 * SIM cardreader function loaded from library
95 */
96 sim_algo_t alg;
97
98 /**
99 * handle of the loaded library
100 */
101 void *handle;
102
103 /**
104 * how many times we try to authenticate
105 */
106 int tries;
107
108 /**
109 * version this implementation uses
110 */
111 chunk_t version;
112
113 /**
114 * version list received from server
115 */
116 chunk_t version_list;
117
118 /**
119 * Nonce value used in AT_NONCE_MT
120 */
121 chunk_t nonce;
122
123 /**
124 * k_encr key derived from MK
125 */
126 chunk_t k_encr;
127
128 /**
129 * k_auth key derived from MK, used for AT_MAC verification
130 */
131 chunk_t k_auth;
132
133 /**
134 * MSK, used for EAP-SIM based IKEv2 authentication
135 */
136 chunk_t msk;
137
138 /**
139 * EMSK, extendes MSK for further uses
140 */
141 chunk_t emsk;
142 };
143
144 /** length of the AT_NONCE_MT nonce value */
145 #define NONCE_LEN 16
146 /** length of the AT_MAC value */
147 #define MAC_LEN 16
148 /** length of the AT_RAND value */
149 #define RAND_LEN 16
150 /** length of the k_encr key */
151 #define KENCR_LEN 16
152 /** length of the k_auth key */
153 #define KAUTH_LEN 16
154 /** length of the MSK */
155 #define MSK_LEN 64
156 /** length of the EMSK */
157 #define EMSK_LEN 64
158
159 /* client error codes used in AT_CLIENT_ERROR_CODE */
160 char client_error_general_buf[] = {0x00, 0x01};
161 char client_error_unsupported_buf[] = {0x00, 0x02};
162 char client_error_insufficient_buf[] = {0x00, 0x03};
163 char client_error_notfresh_buf[] = {0x00, 0x04};
164 chunk_t client_error_general = chunk_from_buf(client_error_general_buf);
165 chunk_t client_error_unsupported = chunk_from_buf(client_error_unsupported_buf);
166 chunk_t client_error_insufficient = chunk_from_buf(client_error_insufficient_buf);
167 chunk_t client_error_notfresh = chunk_from_buf(client_error_notfresh_buf);
168
169 /**
170 * Read EAP and EAP-SIM header, return SIM type
171 */
172 static sim_subtype_t read_header(chunk_t *message)
173 {
174 sim_subtype_t type;
175
176 if (message->len < 8)
177 {
178 *message = chunk_empty;
179 return 0;
180 }
181 type = *(message->ptr + 5);
182 *message = chunk_skip(*message, 8);
183 return type;
184 }
185
186 /**
187 * read the next attribute from the chunk data
188 */
189 static sim_attribute_t read_attribute(chunk_t *message, chunk_t *data)
190 {
191 sim_attribute_t attribute;
192 size_t length;
193
194 DBG3(DBG_IKE, "reading attribute from %B", message);
195
196 if (message->len < 2)
197 {
198 return AT_END;
199 }
200 attribute = *message->ptr++;
201 length = *message->ptr++ * 4 - 2;
202 message->len -= 2;
203 DBG3(DBG_IKE, "found attribute %N with length %d",
204 sim_attribute_names, attribute, length);
205
206 if (length > message->len)
207 {
208 return AT_END;
209 }
210 data->len = length;
211 data->ptr = message->ptr;
212 *message = chunk_skip(*message, length);
213 return attribute;
214 }
215
216 /**
217 * Build an EAP-SIM payload using a variable length attribute list.
218 * The variable argument takes a sim_attribute_t followed by its data in a chunk.
219 */
220 static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier,
221 sim_subtype_t type, ...)
222 {
223 chunk_t message = chunk_alloca(512);
224 chunk_t pos = message;
225 eap_payload_t *payload;
226 va_list args;
227 sim_attribute_t attr;
228 u_int8_t *mac_pos = NULL;
229 chunk_t mac_data = chunk_empty;
230
231 /* write EAP header, skip length bytes */
232 *pos.ptr++ = EAP_RESPONSE;
233 *pos.ptr++ = identifier;
234 pos.ptr += 2;
235 pos.len -= 4;
236 /* write SIM header with type and subtype, zero reserved bytes */
237 *pos.ptr++ = EAP_SIM;
238 *pos.ptr++ = type;
239 *pos.ptr++ = 0;
240 *pos.ptr++ = 0;
241 pos.len -= 4;
242
243 va_start(args, type);
244 while ((attr = va_arg(args, sim_attribute_t)) != AT_END)
245 {
246 chunk_t data = va_arg(args, chunk_t);
247
248 DBG3(DBG_IKE, "building %N %B", sim_attribute_names, attr, &data);
249
250 /* write attribute header */
251 *pos.ptr++ = attr;
252 pos.len--;
253
254 switch (attr)
255 {
256 case AT_CLIENT_ERROR_CODE:
257 case AT_SELECTED_VERSION:
258 {
259 *pos.ptr = data.len/4 + 1;
260 pos = chunk_skip(pos, 1);
261 memcpy(pos.ptr, data.ptr, data.len);
262 pos = chunk_skip(pos, data.len);
263 break;
264 }
265 case AT_IDENTITY:
266 {
267 /* align up to four byte */
268 if (data.len % 4)
269 {
270 chunk_t tmp = chunk_alloca((data.len/4)*4 + 4);
271 memset(tmp.ptr, 0, tmp.len);
272 memcpy(tmp.ptr, data.ptr, data.len);
273 data = tmp;
274 }
275 *pos.ptr = data.len/4 + 1;
276 pos = chunk_skip(pos, 1);
277 /* actual length in bytes */
278 *(u_int16_t*)pos.ptr = htons(data.len);
279 pos = chunk_skip(pos, sizeof(u_int16_t));
280 memcpy(pos.ptr, data.ptr, data.len);
281 pos = chunk_skip(pos, data.len);
282 break;
283 }
284 case AT_NONCE_MT:
285 {
286 *pos.ptr = data.len/4 + 1;
287 pos = chunk_skip(pos, 1);
288 memset(pos.ptr, 0, 2);
289 pos = chunk_skip(pos, 2);
290 memcpy(pos.ptr, data.ptr, data.len);
291 pos = chunk_skip(pos, data.len);
292 break;
293 }
294 case AT_MAC:
295 {
296 *pos.ptr++ = 5; pos.len--;
297 *pos.ptr++ = 0; pos.len--;
298 *pos.ptr++ = 0; pos.len--;
299 mac_pos = pos.ptr;
300 memset(mac_pos, 0, MAC_LEN);
301 pos = chunk_skip(pos, MAC_LEN);
302 mac_data = data;
303 break;
304 }
305 case AT_RAND:
306 {
307 *pos.ptr++ = data.len/4 + 1; pos.len--;
308 *pos.ptr++ = 0; pos.len--;
309 *pos.ptr++ = 0; pos.len--;
310 memcpy(pos.ptr, data.ptr, data.len);
311 pos = chunk_skip(pos, data.len);
312 break;
313 }
314 default:
315 DBG1(DBG_IKE, "no rule to build EAP_SIM attribute %N, skipped",
316 sim_attribute_names, attr);
317 break;
318 }
319 }
320 va_end(args);
321
322 /* calculate message length, write into header */
323 message.len = pos.ptr - message.ptr;
324 *(u_int16_t*)(message.ptr + 2) = htons(message.len);
325
326 /* create MAC if AT_MAC attribte was included. Append supplied va_arg
327 * chunk mac_data to "to-sign" chunk */
328 if (mac_pos)
329 {
330 signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
331 signer->set_key(signer, this->k_auth);
332 mac_data = chunk_cata("cc", message, mac_data);
333 signer->get_signature(signer, mac_data, mac_pos);
334 DBG3(DBG_IKE, "AT_MAC signature of %B\n is %b",
335 &mac_data, mac_pos, MAC_LEN);
336 signer->destroy(signer);
337 }
338
339 payload = eap_payload_create_data(message);
340
341 DBG3(DBG_IKE, "created EAP message %B", &message);
342 return payload;
343 }
344
345 /**
346 * process an EAP-SIM/Request/Start message
347 */
348 static status_t process_start(private_eap_sim_t *this, eap_payload_t *in,
349 eap_payload_t **out)
350 {
351 chunk_t message, data;
352 sim_attribute_t attribute, include_id = AT_END;
353 u_int8_t identifier;
354
355 identifier = in->get_identifier(in);
356 message = in->get_data(in);
357 read_header(&message);
358
359 while ((attribute = read_attribute(&message, &data)) != AT_END)
360 {
361 switch (attribute)
362 {
363 case AT_VERSION_LIST:
364 {
365 /* check if server supports our implementation */
366 bool found = FALSE;
367 if (data.len > 2)
368 {
369 /* read actual length first */
370 data.len = min(data.len, ntohs(*(u_int16_t*)data.ptr) + 2);
371 data = chunk_skip(data, 2);
372 chunk_free(&this->version_list);
373 this->version_list = chunk_clone(data);
374 while (data.len >= this->version.len)
375 {
376 if (memeq(data.ptr, this->version.ptr, this->version.len))
377 {
378 found = TRUE;
379 break;
380 }
381 data = chunk_skip(data, this->version.len);
382 }
383 }
384 if (!found)
385 {
386 DBG1(DBG_IKE, "server does not support EAP_SIM "
387 "version number %#B", &this->version);
388 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
389 AT_CLIENT_ERROR_CODE, client_error_unsupported,
390 AT_END);
391 return NEED_MORE;
392 }
393 break;
394 }
395 case AT_PERMANENT_ID_REQ:
396 case AT_FULLAUTH_ID_REQ:
397 case AT_ANY_ID_REQ:
398 /* only include AT_IDENTITY if requested */
399 include_id = AT_IDENTITY;
400 break;
401 case AT_NOTIFICATION:
402 {
403 u_int16_t code = 0;
404 if (data.len == 2)
405 {
406 code = ntohs(*(u_int16_t*)data.ptr);
407 }
408 if (code <= 32767) /* no success bit */
409 {
410 DBG1(DBG_IKE, "received %N error %d",
411 sim_attribute_names, attribute, code);
412 *out = build_payload(this,
413 in->get_identifier(in), SIM_CLIENT_ERROR,
414 AT_CLIENT_ERROR_CODE, client_error_general,
415 AT_END);
416 return NEED_MORE;
417 }
418 else
419 {
420 DBG1(DBG_IKE, "received %N code %d",
421 sim_attribute_names, attribute, code);
422 }
423 break;
424 }
425 default:
426 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
427 sim_attribute_names, attribute);
428 break;
429 }
430 }
431
432 /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */
433 *out = build_payload(this, identifier, SIM_START,
434 AT_SELECTED_VERSION, this->version,
435 AT_NONCE_MT, this->nonce,
436 include_id, this->peer->get_encoding(this->peer),
437 AT_END);
438 return NEED_MORE;
439 }
440
441 /**
442 * process an EAP-SIM/Request/Challenge message
443 */
444 static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in,
445 eap_payload_t **out)
446 {
447 chunk_t message, data, tmp, kcs, kc, sreses, sres, mk;
448 sim_attribute_t attribute;
449 u_int8_t identifier, i;
450 chunk_t mac = chunk_empty, rands = chunk_empty;
451 signer_t *signer;
452 hasher_t *hasher;
453 prf_t *prf;
454
455 if (this->tries-- <= 0)
456 {
457 /* give up without notification. This hack is required as some buggy
458 * server implementations won't respect our client-error. */
459 return FAILED;
460 }
461
462 identifier = in->get_identifier(in);
463 message = in->get_data(in);
464 read_header(&message);
465
466 while ((attribute = read_attribute(&message, &data)) != AT_END)
467 {
468 switch (attribute)
469 {
470 case AT_RAND:
471 {
472 rands = chunk_skip(data, 2);
473 break;
474 }
475 case AT_MAC:
476 {
477 /* backup MAC, zero it inline for later verification */
478 data = chunk_skip(data, 2);
479 mac = chunk_clonea(data);
480 memset(data.ptr, 0, data.len);
481 break;
482 }
483 case AT_NOTIFICATION:
484 {
485 u_int16_t code = 0;
486 if (data.len == 2)
487 {
488 code = ntohs(*(u_int16_t*)data.ptr);
489 }
490 if (code <= 32767) /* no success bit */
491 {
492 DBG1(DBG_IKE, "received %N error %d",
493 sim_attribute_names, attribute, code);
494 *out = build_payload(this,
495 in->get_identifier(in), SIM_CLIENT_ERROR,
496 AT_CLIENT_ERROR_CODE, client_error_general,
497 AT_END);
498 return NEED_MORE;
499 }
500 else
501 {
502 DBG1(DBG_IKE, "received %N code %d",
503 sim_attribute_names, attribute, code);
504 }
505 break;
506 }
507 default:
508 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
509 sim_attribute_names, attribute);
510 break;
511 }
512 }
513
514 /* excepting two or three RAND, each 16 bytes. We require two valid
515 * and different RANDs */
516 if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) ||
517 memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN))
518 {
519 DBG1(DBG_IKE, "no valid AT_RAND received");
520 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
521 AT_CLIENT_ERROR_CODE, client_error_insufficient,
522 AT_END);
523 return NEED_MORE;
524 }
525 if (mac.len != MAC_LEN)
526 {
527 DBG1(DBG_IKE, "no valid AT_MAC received");
528 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
529 AT_CLIENT_ERROR_CODE, client_error_general,
530 AT_END);
531 return NEED_MORE;
532 }
533
534 /* get two or three KCs/SRESes from SIM using RANDs */
535 kcs = kc = chunk_alloca(rands.len / 2);
536 sreses = sres = chunk_alloca(rands.len / 4);
537 while (rands.len > 0)
538 {
539 int kc_len = kc.len, sres_len = sres.len;
540
541 if (this->alg(rands.ptr, RAND_LEN, sres.ptr, &sres_len, kc.ptr, &kc_len))
542 {
543 DBG1(DBG_IKE, "unable to get triplets from SIM");
544 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
545 AT_CLIENT_ERROR_CODE, client_error_general,
546 AT_END);
547 return NEED_MORE;
548 }
549 DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b",
550 rands.ptr, RAND_LEN, sres.ptr, sres_len, kc.ptr, kc_len);
551 kc = chunk_skip(kc, kc_len);
552 sres = chunk_skip(sres, sres_len);
553 rands = chunk_skip(rands, RAND_LEN);
554 }
555
556 /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
557 tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer), kcs,
558 this->nonce, this->version_list, this->version);
559 hasher = hasher_create(HASH_SHA1);
560 mk = chunk_alloca(hasher->get_hash_size(hasher));
561 hasher->get_hash(hasher, tmp, mk.ptr);
562 hasher->destroy(hasher);
563 DBG3(DBG_IKE, "MK = SHA1(%B\n) = %B", &tmp, &mk);
564
565 /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf()
566 * FIPS PRF has 320 bit block size, we need 160 byte for keys
567 * => run prf four times */
568 prf = prf_create(PRF_FIPS_SHA1_160);
569 prf->set_key(prf, mk);
570 tmp = chunk_alloca(prf->get_block_size(prf) * 4);
571 for (i = 0; i < 4; i++)
572 {
573 prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * i);
574 }
575 prf->destroy(prf);
576 chunk_free(&this->k_encr);
577 chunk_free(&this->k_auth);
578 chunk_free(&this->msk);
579 chunk_free(&this->emsk);
580 chunk_split(tmp, "aaaa", KENCR_LEN, &this->k_encr, KAUTH_LEN, &this->k_auth,
581 MSK_LEN, &this->msk, EMSK_LEN, &this->emsk);
582 DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B",
583 &this->k_encr, &this->k_auth, &this->msk, &this->emsk);
584
585 /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */
586 signer = signer_create(AUTH_HMAC_SHA1_128);
587 signer->set_key(signer, this->k_auth);
588 tmp = chunk_cata("cc", in->get_data(in), this->nonce);
589 if (!signer->verify_signature(signer, tmp, mac))
590 {
591 DBG1(DBG_IKE, "AT_MAC verification failed");
592 signer->destroy(signer);
593 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
594 AT_CLIENT_ERROR_CODE, client_error_general,
595 AT_END);
596 return NEED_MORE;
597 }
598 signer->destroy(signer);
599
600 /* build response, AT_MAC is built over "EAP packet | n*SRES" */
601 *out = build_payload(this, identifier, SIM_CHALLENGE,
602 AT_MAC, sreses,
603 AT_END);
604 return NEED_MORE;
605 }
606
607 /**
608 * process an EAP-SIM/Request/Notification message
609 */
610 static status_t process_notification(private_eap_sim_t *this, eap_payload_t *in,
611 eap_payload_t **out)
612 {
613 chunk_t message, data;
614 sim_attribute_t attribute;
615
616 message = in->get_data(in);
617 read_header(&message);
618
619 while ((attribute = read_attribute(&message, &data)) != AT_END)
620 {
621 switch (attribute)
622 {
623 case AT_NOTIFICATION:
624 {
625 u_int16_t code = 0;
626 if (data.len == 2)
627 {
628 code = ntohs(*(u_int16_t*)data.ptr);
629 }
630 if (code <= 32767) /* no success bit */
631 {
632 DBG1(DBG_IKE, "received %N error %d",
633 sim_attribute_names, attribute, code);
634 *out = build_payload(this,
635 in->get_identifier(in), SIM_CLIENT_ERROR,
636 AT_CLIENT_ERROR_CODE, client_error_general,
637 AT_END);
638 return NEED_MORE;
639 }
640 else
641 {
642 DBG1(DBG_IKE, "received %N code %d",
643 sim_attribute_names, attribute, code);
644 }
645 break;
646 }
647 default:
648 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
649 sim_attribute_names, attribute);
650 break;
651 }
652 }
653 /* reply with empty notification */
654 *out = build_payload(this, in->get_identifier(in), SIM_NOTIFICATION, AT_END);
655 return NEED_MORE;
656 }
657
658
659 /**
660 * Implementation of eap_method_t.process for the peer
661 */
662 static status_t process(private_eap_sim_t *this,
663 eap_payload_t *in, eap_payload_t **out)
664 {
665 sim_subtype_t type;
666 chunk_t message;
667
668 message = in->get_data(in);
669 type = read_header(&message);
670
671 switch (type)
672 {
673 case SIM_START:
674 return process_start(this, in, out);
675 case SIM_CHALLENGE:
676 return process_challenge(this, in, out);
677 case SIM_NOTIFICATION:
678 return process_notification(this, in, out);
679 default:
680 DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N",
681 sim_subtype_names, type);
682 *out = build_payload(this, in->get_identifier(in), SIM_CLIENT_ERROR,
683 AT_CLIENT_ERROR_CODE, client_error_general, AT_END);
684 return NEED_MORE;
685 }
686 }
687
688 /**
689 * Implementation of eap_method_t.initiate for the peer
690 */
691 static status_t initiate(private_eap_sim_t *this, eap_payload_t **out)
692 {
693 /* peer never initiates */
694 return FAILED;
695 }
696
697 /**
698 * Implementation of eap_method_t.get_type.
699 */
700 static eap_type_t get_type(private_eap_sim_t *this)
701 {
702 return EAP_SIM;
703 }
704
705 /**
706 * Implementation of eap_method_t.get_msk.
707 */
708 static status_t get_msk(private_eap_sim_t *this, chunk_t *msk)
709 {
710 if (this->msk.ptr)
711 {
712 *msk = this->msk;
713 return SUCCESS;
714 }
715 return FAILED;
716 }
717
718 /**
719 * Implementation of eap_method_t.is_mutual.
720 */
721 static bool is_mutual(private_eap_sim_t *this)
722 {
723 return TRUE;
724 }
725
726 /**
727 * Implementation of eap_method_t.destroy.
728 */
729 static void destroy(private_eap_sim_t *this)
730 {
731 dlclose(this->handle);
732 chunk_free(&this->nonce);
733 chunk_free(&this->version_list);
734 chunk_free(&this->k_auth);
735 chunk_free(&this->k_encr);
736 chunk_free(&this->msk);
737 chunk_free(&this->emsk);
738 free(this);
739 }
740
741 /*
742 * Described in header.
743 */
744 eap_sim_t *eap_create(eap_role_t role,
745 identification_t *server, identification_t *peer)
746 {
747 private_eap_sim_t *this;
748 randomizer_t *randomizer;
749 static char version[] = {0x00,0x01};
750
751 if (role != EAP_PEER)
752 {
753 return NULL;
754 }
755 this = malloc_thing(private_eap_sim_t);
756
757 this->handle = dlopen(SIM_READER_LIB, RTLD_LAZY);
758 if (this->handle == NULL)
759 {
760 DBG1(DBG_IKE, "unable to open SIM reader '%s'", SIM_READER_LIB);
761 free(this);
762 return NULL;
763 }
764 this->alg = dlsym(this->handle, SIM_READER_ALG);
765 if (this->alg == NULL)
766 {
767 DBG1(DBG_IKE, "unable to open SIM reader function '%s' in '%s'",
768 SIM_READER_ALG, SIM_READER_LIB);
769 dlclose(this->handle);
770 free(this);
771 return NULL;
772 }
773
774 randomizer = randomizer_create();
775 if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN,
776 &this->nonce))
777 {
778 DBG1(DBG_IKE, "unable to generate NONCE for EAP_SIM");
779 randomizer->destroy(randomizer);
780 free(this);
781 return NULL;
782 }
783 randomizer->destroy(randomizer);
784
785 /* public functions */
786 this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
787 this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
788 this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type;
789 this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
790 this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
791 this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
792
793 /* private data */
794 this->peer = peer;
795 this->tries = MAX_TRIES;
796 this->version.ptr = version;
797 this->version.len = sizeof(version);
798 this->version_list = chunk_empty;
799 this->k_auth = chunk_empty;
800 this->k_encr = chunk_empty;
801 this->msk = chunk_empty;
802 this->emsk = chunk_empty;
803
804 return &this->public;
805 }