reintegrated two-sim branch providing SIM card plugin API
[strongswan.git] / src / charon / plugins / eap_sim / eap_sim.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "eap_sim.h"
19
20 #include <dlfcn.h>
21
22 #include <daemon.h>
23 #include <library.h>
24
25 #define MAX_TRIES 3
26
27 /* number of triplets for one authentication */
28 #define TRIPLET_COUNT 3
29
30 typedef enum sim_subtype_t sim_subtype_t;
31
32 /**
33 * Subtypes of SIM messages
34 */
35 enum sim_subtype_t {
36 SIM_START = 10,
37 SIM_CHALLENGE = 11,
38 SIM_NOTIFICATION = 12,
39 SIM_CLIENT_ERROR = 14,
40 };
41
42 ENUM(sim_subtype_names, SIM_START, SIM_CLIENT_ERROR,
43 "SIM_START",
44 "SIM_CHALLENGE",
45 "SIM_NOTIFICATION",
46 "SIM_13",
47 "SIM_CLIENT_ERROR",
48 );
49
50 typedef enum sim_attribute_t sim_attribute_t;
51
52 /**
53 * Attributes in SIM messages
54 */
55 enum sim_attribute_t {
56 /** defines the end of attribute list */
57 AT_END = -1,
58 AT_RAND = 1,
59 AT_AUTN = 2,
60 AT_RES = 3,
61 AT_AUTS = 4,
62 AT_PADDING = 6,
63 AT_NONCE_MT = 7,
64 AT_PERMANENT_ID_REQ = 10,
65 AT_MAC = 11,
66 AT_NOTIFICATION = 12,
67 AT_ANY_ID_REQ = 13,
68 AT_IDENTITY = 14,
69 AT_VERSION_LIST = 15,
70 AT_SELECTED_VERSION = 16,
71 AT_FULLAUTH_ID_REQ = 17,
72 AT_COUNTER = 19,
73 AT_COUNTER_TOO_SMALL = 20,
74 AT_NONCE_S = 21,
75 AT_CLIENT_ERROR_CODE = 22,
76 AT_IV = 129,
77 AT_ENCR_DATA = 130,
78 AT_NEXT_PSEUDONYM = 132,
79 AT_NEXT_REAUTH_ID = 133,
80 AT_CHECKCODE = 134,
81 AT_RESULT_IND = 135,
82 };
83
84 ENUM_BEGIN(sim_attribute_names, AT_END, AT_CLIENT_ERROR_CODE,
85 "AT_END",
86 "AT_0",
87 "AT_RAND",
88 "AT_AUTN",
89 "AT_RES",
90 "AT_AUTS",
91 "AT_5",
92 "AT_PADDING",
93 "AT_NONCE_MT",
94 "AT_8",
95 "AT_9",
96 "AT_PERMANENT_ID_REQ",
97 "AT_MAC",
98 "AT_NOTIFICATION",
99 "AT_ANY_ID_REQ",
100 "AT_IDENTITY",
101 "AT_VERSION_LIST",
102 "AT_SELECTED_VERSION",
103 "AT_FULLAUTH_ID_REQ",
104 "AT_18",
105 "AT_COUNTER",
106 "AT_COUNTER_TOO_SMALL",
107 "AT_NONCE_S",
108 "AT_CLIENT_ERROR_CODE");
109 ENUM_NEXT(sim_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
110 "AT_IV",
111 "AT_ENCR_DATA",
112 "AT_131",
113 "AT_NEXT_PSEUDONYM",
114 "AT_NEXT_REAUTH_ID",
115 "AT_CHECKCODE",
116 "AT_RESULT_IND");
117 ENUM_END(sim_attribute_names, AT_RESULT_IND);
118
119
120 typedef struct private_eap_sim_t private_eap_sim_t;
121
122 /**
123 * Private data of an eap_sim_t object.
124 */
125 struct private_eap_sim_t {
126
127 /**
128 * Public authenticator_t interface.
129 */
130 eap_sim_t public;
131
132 /**
133 * ID of ourself
134 */
135 identification_t *peer;
136
137 /**
138 * hashing function
139 */
140 hasher_t *hasher;
141
142 /**
143 * prf
144 */
145 prf_t *prf;
146
147 /**
148 * MAC function
149 */
150 signer_t *signer;
151
152 /**
153 * how many times we try to authenticate
154 */
155 int tries;
156
157 /**
158 * unique EAP identifier
159 */
160 u_int8_t identifier;
161
162 /**
163 * EAP message type this role sends
164 */
165 u_int8_t type;
166
167 /**
168 * version this implementation uses
169 */
170 chunk_t version;
171
172 /**
173 * version list received from server
174 */
175 chunk_t version_list;
176
177 /**
178 * Nonce value used in AT_NONCE_MT
179 */
180 chunk_t nonce;
181
182 /**
183 * concatenated SRES values
184 */
185 chunk_t sreses;
186
187 /**
188 * k_encr key derived from MK
189 */
190 chunk_t k_encr;
191
192 /**
193 * k_auth key derived from MK, used for AT_MAC verification
194 */
195 chunk_t k_auth;
196
197 /**
198 * MSK, used for EAP-SIM based IKEv2 authentication
199 */
200 chunk_t msk;
201
202 /**
203 * EMSK, extended MSK for further uses
204 */
205 chunk_t emsk;
206 };
207
208 /** length of the AT_NONCE_MT nonce value */
209 #define NONCE_LEN 16
210 /** length of the AT_MAC value */
211 #define MAC_LEN 16
212 /** length of the AT_RAND value */
213 #define RAND_LEN 16
214 /** length of Kc */
215 #define KC_LEN 8
216 /** length of SRES */
217 #define SRES_LEN 4
218 /** length of the k_encr key */
219 #define KENCR_LEN 16
220 /** length of the k_auth key */
221 #define KAUTH_LEN 16
222 /** length of the MSK */
223 #define MSK_LEN 64
224 /** length of the EMSK */
225 #define EMSK_LEN 64
226
227 static char version[] = {0x00,0x01};
228 /* client error codes used in AT_CLIENT_ERROR_CODE */
229 char client_error_general_buf[] = {0x00, 0x01};
230 char client_error_unsupported_buf[] = {0x00, 0x02};
231 char client_error_insufficient_buf[] = {0x00, 0x03};
232 char client_error_notfresh_buf[] = {0x00, 0x04};
233 chunk_t client_error_general = chunk_from_buf(client_error_general_buf);
234 chunk_t client_error_unsupported = chunk_from_buf(client_error_unsupported_buf);
235 chunk_t client_error_insufficient = chunk_from_buf(client_error_insufficient_buf);
236 chunk_t client_error_notfresh = chunk_from_buf(client_error_notfresh_buf);
237
238 /**
239 * Read EAP and EAP-SIM header, return SIM type
240 */
241 static sim_subtype_t read_header(chunk_t *message)
242 {
243 sim_subtype_t type;
244
245 if (message->len < 8)
246 {
247 *message = chunk_empty;
248 return 0;
249 }
250 type = *(message->ptr + 5);
251 *message = chunk_skip(*message, 8);
252 return type;
253 }
254
255 /**
256 * read the next attribute from the chunk data
257 */
258 static sim_attribute_t read_attribute(chunk_t *message, chunk_t *data)
259 {
260 sim_attribute_t attribute;
261 size_t length;
262
263 DBG3(DBG_IKE, "reading attribute from %B", message);
264
265 if (message->len < 2)
266 {
267 return AT_END;
268 }
269 attribute = *message->ptr++;
270 length = *message->ptr++ * 4 - 2;
271 message->len -= 2;
272 DBG3(DBG_IKE, "found attribute %N with length %d",
273 sim_attribute_names, attribute, length);
274
275 if (length > message->len)
276 {
277 return AT_END;
278 }
279 data->len = length;
280 data->ptr = message->ptr;
281 *message = chunk_skip(*message, length);
282 return attribute;
283 }
284
285 /**
286 * Build an EAP-SIM payload using a variable length attribute list.
287 * The variable argument takes a sim_attribute_t followed by its data in a chunk.
288 */
289 static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier,
290 sim_subtype_t type, ...)
291 {
292 chunk_t message = chunk_alloca(512);
293 chunk_t pos = message;
294 eap_payload_t *payload;
295 va_list args;
296 sim_attribute_t attr;
297 u_int8_t *mac_pos = NULL;
298 chunk_t mac_data = chunk_empty;
299
300 /* write EAP header, skip length bytes */
301 *pos.ptr++ = this->type;
302 *pos.ptr++ = identifier;
303 pos.ptr += 2;
304 pos.len -= 4;
305 /* write SIM header with type and subtype, zero reserved bytes */
306 *pos.ptr++ = EAP_SIM;
307 *pos.ptr++ = type;
308 *pos.ptr++ = 0;
309 *pos.ptr++ = 0;
310 pos.len -= 4;
311
312 va_start(args, type);
313 while ((attr = va_arg(args, sim_attribute_t)) != AT_END)
314 {
315 chunk_t data = va_arg(args, chunk_t);
316
317 DBG3(DBG_IKE, "building %N %B", sim_attribute_names, attr, &data);
318
319 /* write attribute header */
320 *pos.ptr++ = attr;
321 pos.len--;
322
323 switch (attr)
324 {
325 case AT_CLIENT_ERROR_CODE:
326 case AT_SELECTED_VERSION:
327 {
328 *pos.ptr = data.len/4 + 1;
329 pos = chunk_skip(pos, 1);
330 memcpy(pos.ptr, data.ptr, data.len);
331 pos = chunk_skip(pos, data.len);
332 break;
333 }
334 case AT_IDENTITY:
335 case AT_VERSION_LIST:
336 {
337 u_int16_t act_len = data.len;
338 /* align up to four byte */
339 if (data.len % 4)
340 {
341 chunk_t tmp = chunk_alloca((data.len/4)*4 + 4);
342 memset(tmp.ptr, 0, tmp.len);
343 memcpy(tmp.ptr, data.ptr, data.len);
344 data = tmp;
345 }
346 *pos.ptr = data.len/4 + 1;
347 pos = chunk_skip(pos, 1);
348 /* actual length in bytes */
349 *(u_int16_t*)pos.ptr = htons(act_len);
350 pos = chunk_skip(pos, sizeof(u_int16_t));
351 memcpy(pos.ptr, data.ptr, data.len);
352 pos = chunk_skip(pos, data.len);
353 break;
354 }
355 case AT_NONCE_MT:
356 {
357 *pos.ptr = data.len/4 + 1;
358 pos = chunk_skip(pos, 1);
359 memset(pos.ptr, 0, 2);
360 pos = chunk_skip(pos, 2);
361 memcpy(pos.ptr, data.ptr, data.len);
362 pos = chunk_skip(pos, data.len);
363 break;
364 }
365 case AT_MAC:
366 {
367 *pos.ptr++ = 5; pos.len--;
368 *pos.ptr++ = 0; pos.len--;
369 *pos.ptr++ = 0; pos.len--;
370 mac_pos = pos.ptr;
371 memset(mac_pos, 0, MAC_LEN);
372 pos = chunk_skip(pos, MAC_LEN);
373 mac_data = data;
374 break;
375 }
376 case AT_RAND:
377 {
378 *pos.ptr++ = data.len/4 + 1; pos.len--;
379 *pos.ptr++ = 0; pos.len--;
380 *pos.ptr++ = 0; pos.len--;
381 memcpy(pos.ptr, data.ptr, data.len);
382 pos = chunk_skip(pos, data.len);
383 break;
384 }
385 default:
386 DBG1(DBG_IKE, "no rule to build EAP_SIM attribute %N, skipped",
387 sim_attribute_names, attr);
388 break;
389 }
390 }
391 va_end(args);
392
393 /* calculate message length, write into header */
394 message.len = pos.ptr - message.ptr;
395 *(u_int16_t*)(message.ptr + 2) = htons(message.len);
396
397 /* create MAC if AT_MAC attribte was included. Append supplied va_arg
398 * chunk mac_data to "to-sign" chunk */
399 if (mac_pos)
400 {
401 this->signer->set_key(this->signer, this->k_auth);
402 mac_data = chunk_cata("cc", message, mac_data);
403 this->signer->get_signature(this->signer, mac_data, mac_pos);
404 DBG3(DBG_IKE, "AT_MAC signature of %B\n is %b",
405 &mac_data, mac_pos, MAC_LEN);
406 }
407
408 payload = eap_payload_create_data(message);
409
410 DBG3(DBG_IKE, "created EAP message %B", &message);
411 return payload;
412 }
413
414 /**
415 * process an EAP-SIM/Request/Start message
416 */
417 static status_t peer_process_start(private_eap_sim_t *this, eap_payload_t *in,
418 eap_payload_t **out)
419 {
420 chunk_t message, data;
421 sim_attribute_t attribute, include_id = AT_END;
422 u_int8_t identifier;
423
424 identifier = in->get_identifier(in);
425 message = in->get_data(in);
426 read_header(&message);
427
428 while ((attribute = read_attribute(&message, &data)) != AT_END)
429 {
430 switch (attribute)
431 {
432 case AT_VERSION_LIST:
433 {
434 /* check if server supports our implementation */
435 bool found = FALSE;
436 if (data.len > 2)
437 {
438 /* read actual length first */
439 data.len = min(data.len, ntohs(*(u_int16_t*)data.ptr) + 2);
440 data = chunk_skip(data, 2);
441 chunk_free(&this->version_list);
442 this->version_list = chunk_clone(data);
443 while (data.len >= this->version.len)
444 {
445 if (memeq(data.ptr, this->version.ptr, this->version.len))
446 {
447 found = TRUE;
448 break;
449 }
450 data = chunk_skip(data, this->version.len);
451 }
452 }
453 if (!found)
454 {
455 DBG1(DBG_IKE, "server does not support EAP_SIM "
456 "version number %#B", &this->version);
457 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
458 AT_CLIENT_ERROR_CODE, client_error_unsupported,
459 AT_END);
460 return NEED_MORE;
461 }
462 break;
463 }
464 case AT_PERMANENT_ID_REQ:
465 case AT_FULLAUTH_ID_REQ:
466 case AT_ANY_ID_REQ:
467 /* only include AT_IDENTITY if requested */
468 include_id = AT_IDENTITY;
469 break;
470 case AT_NOTIFICATION:
471 {
472 u_int16_t code = 0;
473 if (data.len == 2)
474 {
475 code = ntohs(*(u_int16_t*)data.ptr);
476 }
477 if (code <= 32767) /* no success bit */
478 {
479 DBG1(DBG_IKE, "received %N error %d",
480 sim_attribute_names, attribute, code);
481 *out = build_payload(this,
482 in->get_identifier(in), SIM_CLIENT_ERROR,
483 AT_CLIENT_ERROR_CODE, client_error_general,
484 AT_END);
485 return NEED_MORE;
486 }
487 else
488 {
489 DBG1(DBG_IKE, "received %N code %d",
490 sim_attribute_names, attribute, code);
491 }
492 break;
493 }
494 default:
495 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
496 sim_attribute_names, attribute);
497 break;
498 }
499 }
500
501 /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */
502 *out = build_payload(this, identifier, SIM_START,
503 AT_SELECTED_VERSION, this->version,
504 AT_NONCE_MT, this->nonce,
505 include_id, this->peer->get_encoding(this->peer),
506 AT_END);
507 return NEED_MORE;
508 }
509
510 /**
511 * derive EAP keys from kc
512 */
513 static void derive_keys(private_eap_sim_t *this, chunk_t kcs)
514 {
515 chunk_t tmp, mk;
516 int i;
517
518 /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
519 tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer), kcs,
520 this->nonce, this->version_list, this->version);
521 mk = chunk_alloca(this->hasher->get_hash_size(this->hasher));
522 this->hasher->get_hash(this->hasher, tmp, mk.ptr);
523 DBG3(DBG_IKE, "MK = SHA1(%B\n) = %B", &tmp, &mk);
524
525 /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf()
526 * FIPS PRF has 320 bit block size, we need 160 byte for keys
527 * => run prf four times */
528 this->prf->set_key(this->prf, mk);
529 tmp = chunk_alloca(this->prf->get_block_size(this->prf) * 4);
530 for (i = 0; i < 4; i++)
531 {
532 this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * i);
533 }
534 chunk_free(&this->k_encr);
535 chunk_free(&this->k_auth);
536 chunk_free(&this->msk);
537 chunk_free(&this->emsk);
538 chunk_split(tmp, "aaaa", KENCR_LEN, &this->k_encr, KAUTH_LEN, &this->k_auth,
539 MSK_LEN, &this->msk, EMSK_LEN, &this->emsk);
540 DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B",
541 &this->k_encr, &this->k_auth, &this->msk, &this->emsk);
542 }
543
544 /**
545 * Read a triplet from the SIM card
546 */
547 static bool get_card_triplet(private_eap_sim_t *this,
548 char *rand, char *sres, char *kc)
549 {
550 enumerator_t *enumerator;
551 sim_card_t *card = NULL, *current;
552 id_match_t match, best = ID_MATCH_NONE;
553 bool success = FALSE;
554
555 /* find the best matching SIM */
556 enumerator = charon->sim->create_card_enumerator(charon->sim);
557 while (enumerator->enumerate(enumerator, &current))
558 {
559 match = this->peer->matches(this->peer, current->get_imsi(current));
560 if (match > best)
561 {
562 card = current;
563 best = match;
564 break;
565 }
566 }
567 if (card)
568 {
569 success = card->get_triplet(card, rand, sres, kc);
570 }
571 enumerator->destroy(enumerator);
572 if (!card)
573 {
574 DBG1(DBG_IKE, "no SIM card found matching '%D'", this->peer);
575 }
576 return success;
577 }
578
579 /**
580 * process an EAP-SIM/Request/Challenge message
581 */
582 static status_t peer_process_challenge(private_eap_sim_t *this,
583 eap_payload_t *in, eap_payload_t **out)
584 {
585 chunk_t message, data, tmp, kcs, kc, sreses, sres;
586 sim_attribute_t attribute;
587 u_int8_t identifier;
588 chunk_t mac = chunk_empty, rands = chunk_empty;
589
590 if (this->tries-- <= 0)
591 {
592 /* give up without notification. This hack is required as some buggy
593 * server implementations won't respect our client-error. */
594 return FAILED;
595 }
596
597 identifier = in->get_identifier(in);
598 message = in->get_data(in);
599 read_header(&message);
600
601 while ((attribute = read_attribute(&message, &data)) != AT_END)
602 {
603 switch (attribute)
604 {
605 case AT_RAND:
606 {
607 rands = chunk_skip(data, 2);
608 break;
609 }
610 case AT_MAC:
611 {
612 /* backup MAC, zero it inline for later verification */
613 data = chunk_skip(data, 2);
614 mac = chunk_clonea(data);
615 memset(data.ptr, 0, data.len);
616 break;
617 }
618 case AT_NOTIFICATION:
619 {
620 u_int16_t code = 0;
621 if (data.len == 2)
622 {
623 code = ntohs(*(u_int16_t*)data.ptr);
624 }
625 if (code <= 32767) /* no success bit */
626 {
627 DBG1(DBG_IKE, "received %N error %d",
628 sim_attribute_names, attribute, code);
629 *out = build_payload(this,
630 in->get_identifier(in), SIM_CLIENT_ERROR,
631 AT_CLIENT_ERROR_CODE, client_error_general,
632 AT_END);
633 return NEED_MORE;
634 }
635 else
636 {
637 DBG1(DBG_IKE, "received %N code %d",
638 sim_attribute_names, attribute, code);
639 }
640 break;
641 }
642 default:
643 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
644 sim_attribute_names, attribute);
645 break;
646 }
647 }
648
649 /* excepting two or three RAND, each 16 bytes. We require two valid
650 * and different RANDs */
651 if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) ||
652 memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN))
653 {
654 DBG1(DBG_IKE, "no valid AT_RAND received");
655 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
656 AT_CLIENT_ERROR_CODE, client_error_insufficient,
657 AT_END);
658 return NEED_MORE;
659 }
660 if (mac.len != MAC_LEN)
661 {
662 DBG1(DBG_IKE, "no valid AT_MAC received");
663 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
664 AT_CLIENT_ERROR_CODE, client_error_general,
665 AT_END);
666 return NEED_MORE;
667 }
668
669 /* get two or three KCs/SRESes from SIM using RANDs */
670 kcs = kc = chunk_alloca(rands.len / 2);
671 sreses = sres = chunk_alloca(rands.len / 4);
672 while (rands.len >= RAND_LEN)
673 {
674 if (!get_card_triplet(this, rands.ptr, sres.ptr, kc.ptr))
675 {
676 DBG1(DBG_IKE, "unable to get EAP-SIM triplet");
677 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
678 AT_CLIENT_ERROR_CODE, client_error_general,
679 AT_END);
680 return NEED_MORE;
681 }
682 DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b",
683 rands.ptr, RAND_LEN, sres.ptr, SRES_LEN, kc.ptr, KC_LEN);
684 kc = chunk_skip(kc, KC_LEN);
685 sres = chunk_skip(sres, SRES_LEN);
686 rands = chunk_skip(rands, RAND_LEN);
687 }
688
689 derive_keys(this, kcs);
690
691 /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */
692 this->signer->set_key(this->signer, this->k_auth);
693 tmp = chunk_cata("cc", in->get_data(in), this->nonce);
694 if (!this->signer->verify_signature(this->signer, tmp, mac))
695 {
696 DBG1(DBG_IKE, "AT_MAC verification failed");
697 *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
698 AT_CLIENT_ERROR_CODE, client_error_general,
699 AT_END);
700 return NEED_MORE;
701 }
702
703 /* build response, AT_MAC is built over "EAP packet | n*SRES" */
704 *out = build_payload(this, identifier, SIM_CHALLENGE,
705 AT_MAC, sreses,
706 AT_END);
707 return NEED_MORE;
708 }
709
710 /**
711 * process an EAP-SIM/Response/Challenge message
712 */
713 static status_t server_process_challenge(private_eap_sim_t *this,
714 eap_payload_t *in, eap_payload_t **out)
715 {
716 chunk_t message, data;
717 sim_attribute_t attribute;
718 chunk_t mac = chunk_empty, tmp;
719
720 message = in->get_data(in);
721 read_header(&message);
722
723 while ((attribute = read_attribute(&message, &data)) != AT_END)
724 {
725 switch (attribute)
726 {
727 case AT_MAC:
728 /* MAC has two reserved bytes */
729 if (data.len == MAC_LEN + 2)
730 { /* clone and zero MAC for verification */
731 mac = chunk_clonea(chunk_skip(data, 2));
732 memset(data.ptr, 0, data.len);
733 }
734 break;
735 default:
736 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
737 sim_attribute_names, attribute);
738 break;
739 }
740 }
741 if (!mac.ptr)
742 {
743 DBG1(DBG_IKE, "no valid AT_MAC attribute received");
744 return FAILED;
745 }
746 /* verify AT_MAC attribute, signature is over "EAP packet | n*SRES" */
747 this->signer->set_key(this->signer, this->k_auth);
748 tmp = chunk_cata("cc", in->get_data(in), this->sreses);
749 if (!this->signer->verify_signature(this->signer, tmp, mac))
750 {
751 DBG1(DBG_IKE, "AT_MAC verification failed");
752 return FAILED;
753 }
754 return SUCCESS;
755 }
756
757 /**
758 * Fetch a triplet from a provider
759 */
760 static bool get_provider_triplet(private_eap_sim_t *this,
761 char *rand, char *sres, char *kc)
762 {
763 enumerator_t *enumerator;
764 sim_provider_t *provider;
765 int tried = 0;
766
767 enumerator = charon->sim->create_provider_enumerator(charon->sim);
768 while (enumerator->enumerate(enumerator, &provider))
769 {
770 if (provider->get_triplet(provider, this->peer, rand, sres, kc))
771 {
772 enumerator->destroy(enumerator);
773 return TRUE;
774 }
775 tried++;
776 }
777 enumerator->destroy(enumerator);
778 DBG1(DBG_IKE, "tried %d SIM providers, but none had a triplet for '%D'",
779 tried, this->peer);
780 return FALSE;
781 }
782
783 /**
784 * process an EAP-SIM/Response/Start message
785 */
786 static status_t server_process_start(private_eap_sim_t *this,
787 eap_payload_t *in, eap_payload_t **out)
788 {
789 chunk_t message, data;
790 sim_attribute_t attribute;
791 bool supported = FALSE;
792 chunk_t rands, rand, kcs, kc, sreses, sres;
793 int i;
794
795 message = in->get_data(in);
796 read_header(&message);
797
798 while ((attribute = read_attribute(&message, &data)) != AT_END)
799 {
800 switch (attribute)
801 {
802 case AT_NONCE_MT:
803 if (data.len == NONCE_LEN + 2)
804 {
805 this->nonce = chunk_clone(chunk_skip(data, 2));
806 }
807 break;
808 case AT_SELECTED_VERSION:
809 if (chunk_equals(data, this->version))
810 {
811 supported = TRUE;
812 }
813 break;
814 default:
815 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
816 sim_attribute_names, attribute);
817 break;
818 }
819 }
820 if (!supported || !this->nonce.ptr)
821 {
822 DBG1(DBG_IKE, "received incomplete EAP-SIM/Response/Start");
823 return FAILED;
824 }
825
826 /* read triplets from provider */
827 rand = rands = chunk_alloca(RAND_LEN * TRIPLET_COUNT);
828 kc = kcs = chunk_alloca(KC_LEN * TRIPLET_COUNT);
829 sres = sreses = chunk_alloca(SRES_LEN * TRIPLET_COUNT);
830 rands.len = 0;
831 kcs.len = 0;
832 sreses.len = 0;
833 for (i = 0; i < TRIPLET_COUNT; i++)
834 {
835 if (!get_provider_triplet(this, rand.ptr, sres.ptr, kc.ptr))
836 {
837 DBG1(DBG_IKE, "getting EAP-SIM triplet %d failed", i);
838 return FAILED;
839 }
840 rands.len += RAND_LEN;
841 sreses.len += SRES_LEN;
842 kcs.len += KC_LEN;
843 rand = chunk_skip(rand, RAND_LEN);
844 sres = chunk_skip(sres, SRES_LEN);
845 kc = chunk_skip(kc, KC_LEN);
846 }
847 derive_keys(this, kcs);
848
849 /* build MAC over "EAP packet | NONCE_MT" */
850 *out = build_payload(this, this->identifier++, SIM_CHALLENGE, AT_RAND,
851 rands, AT_MAC, this->nonce, AT_END);
852 this->sreses = chunk_clone(sreses);
853 return NEED_MORE;
854 }
855
856 /**
857 * process an EAP-SIM/Request/Notification message
858 */
859 static status_t peer_process_notification(private_eap_sim_t *this,
860 eap_payload_t *in, eap_payload_t **out)
861 {
862 chunk_t message, data;
863 sim_attribute_t attribute;
864
865 message = in->get_data(in);
866 read_header(&message);
867
868 while ((attribute = read_attribute(&message, &data)) != AT_END)
869 {
870 switch (attribute)
871 {
872 case AT_NOTIFICATION:
873 {
874 u_int16_t code = 0;
875 if (data.len == 2)
876 {
877 code = ntohs(*(u_int16_t*)data.ptr);
878 }
879 if (code <= 32767) /* no success bit */
880 {
881 DBG1(DBG_IKE, "received %N error %d",
882 sim_attribute_names, attribute, code);
883 *out = build_payload(this,
884 in->get_identifier(in), SIM_CLIENT_ERROR,
885 AT_CLIENT_ERROR_CODE, client_error_general,
886 AT_END);
887 return NEED_MORE;
888 }
889 else
890 {
891 DBG1(DBG_IKE, "received %N code %d",
892 sim_attribute_names, attribute, code);
893 }
894 break;
895 }
896 default:
897 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
898 sim_attribute_names, attribute);
899 break;
900 }
901 }
902 /* reply with empty notification */
903 *out = build_payload(this, in->get_identifier(in), SIM_NOTIFICATION, AT_END);
904 return NEED_MORE;
905 }
906
907 /**
908 * Process a client error
909 */
910 static status_t server_process_client_error(private_eap_sim_t *this,
911 eap_payload_t *in, eap_payload_t **out)
912 {
913 chunk_t message, data;
914 sim_attribute_t attribute;
915
916 message = in->get_data(in);
917 read_header(&message);
918
919 while ((attribute = read_attribute(&message, &data)) != AT_END)
920 {
921 if (attribute == AT_CLIENT_ERROR_CODE)
922 {
923 u_int16_t code = 0;
924 if (data.len == 2)
925 {
926 code = ntohs(*(u_int16_t*)data.ptr);
927 }
928 DBG1(DBG_IKE, "received %N error %d",
929 sim_attribute_names, attribute, code);
930 }
931 else
932 {
933 DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
934 sim_attribute_names, attribute);
935 }
936 }
937 return FAILED;
938 }
939
940 /**
941 * Implementation of eap_method_t.process for the peer
942 */
943 static status_t peer_process(private_eap_sim_t *this,
944 eap_payload_t *in, eap_payload_t **out)
945 {
946 sim_subtype_t type;
947 chunk_t message;
948
949 message = in->get_data(in);
950 type = read_header(&message);
951
952 switch (type)
953 {
954 case SIM_START:
955 return peer_process_start(this, in, out);
956 case SIM_CHALLENGE:
957 return peer_process_challenge(this, in, out);
958 case SIM_NOTIFICATION:
959 return peer_process_notification(this, in, out);
960 default:
961 DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N",
962 sim_subtype_names, type);
963 *out = build_payload(this, in->get_identifier(in), SIM_CLIENT_ERROR,
964 AT_CLIENT_ERROR_CODE, client_error_general, AT_END);
965 return NEED_MORE;
966 }
967 }
968
969 /**
970 * Implementation of eap_method_t.process for the server
971 */
972 static status_t server_process(private_eap_sim_t *this,
973 eap_payload_t *in, eap_payload_t **out)
974 {
975 sim_subtype_t type;
976 chunk_t message;
977
978 message = in->get_data(in);
979 type = read_header(&message);
980
981 switch (type)
982 {
983 case SIM_START:
984 return server_process_start(this, in, out);
985 case SIM_CHALLENGE:
986 return server_process_challenge(this, in, out);
987 case SIM_CLIENT_ERROR:
988 return server_process_client_error(this, in, out);
989 default:
990 DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N",
991 sim_subtype_names, type);
992 return FAILED;
993 }
994 }
995
996 /**
997 * Implementation of eap_method_t.initiate for the peer
998 */
999 static status_t peer_initiate(private_eap_sim_t *this, eap_payload_t **out)
1000 {
1001 /* peer never initiates */
1002 return FAILED;
1003 }
1004
1005 /**
1006 * Implementation of eap_method_t.initiate for the server
1007 */
1008 static status_t server_initiate(private_eap_sim_t *this, eap_payload_t **out)
1009 {
1010 /* version_list to derive MK, no padding */
1011 this->version_list = chunk_clone(this->version);
1012 /* build_payloads adds padding itself */
1013 *out = build_payload(this, this->identifier++, SIM_START,
1014 AT_VERSION_LIST, this->version, AT_END);
1015 return NEED_MORE;
1016 }
1017
1018 /**
1019 * Implementation of eap_method_t.get_type.
1020 */
1021 static eap_type_t get_type(private_eap_sim_t *this, u_int32_t *vendor)
1022 {
1023 *vendor = 0;
1024 return EAP_SIM;
1025 }
1026
1027 /**
1028 * Implementation of eap_method_t.get_msk.
1029 */
1030 static status_t get_msk(private_eap_sim_t *this, chunk_t *msk)
1031 {
1032 if (this->msk.ptr)
1033 {
1034 *msk = this->msk;
1035 return SUCCESS;
1036 }
1037 return FAILED;
1038 }
1039
1040 /**
1041 * Implementation of eap_method_t.is_mutual.
1042 */
1043 static bool is_mutual(private_eap_sim_t *this)
1044 {
1045 return TRUE;
1046 }
1047
1048 /**
1049 * Implementation of eap_method_t.destroy.
1050 */
1051 static void destroy(private_eap_sim_t *this)
1052 {
1053 this->peer->destroy(this->peer);
1054 this->peer->destroy(this->peer);
1055 DESTROY_IF(this->hasher);
1056 DESTROY_IF(this->prf);
1057 DESTROY_IF(this->signer);
1058 chunk_free(&this->nonce);
1059 chunk_free(&this->sreses);
1060 chunk_free(&this->version_list);
1061 chunk_free(&this->k_auth);
1062 chunk_free(&this->k_encr);
1063 chunk_free(&this->msk);
1064 chunk_free(&this->emsk);
1065 free(this);
1066 }
1067
1068 /**
1069 * Generic constructor for both roles
1070 */
1071 eap_sim_t *eap_sim_create_generic(eap_role_t role, identification_t *server,
1072 identification_t *peer)
1073 {
1074 private_eap_sim_t *this = malloc_thing(private_eap_sim_t);
1075 rng_t *rng;
1076
1077 this->nonce = chunk_empty;
1078 this->sreses = chunk_empty;
1079 this->peer = peer->clone(peer);
1080 this->tries = MAX_TRIES;
1081 this->version.ptr = version;
1082 this->version.len = sizeof(version);
1083 this->version_list = chunk_empty;
1084 this->k_auth = chunk_empty;
1085 this->k_encr = chunk_empty;
1086 this->msk = chunk_empty;
1087 this->emsk = chunk_empty;
1088 /* generate a non-zero identifier */
1089 do {
1090 this->identifier = random();
1091 } while (!this->identifier);
1092
1093 switch (role)
1094 {
1095 case EAP_SERVER:
1096 this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate;
1097 this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process;
1098 this->type = EAP_REQUEST;
1099 break;
1100 case EAP_PEER:
1101 this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate;
1102 this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process;
1103 this->type = EAP_RESPONSE;
1104 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
1105 if (!rng)
1106 {
1107 DBG1(DBG_IKE, "unable to generate NONCE for EAP_SIM");
1108 free(this);
1109 return NULL;
1110 }
1111 rng->allocate_bytes(rng, NONCE_LEN, &this->nonce);
1112 rng->destroy(rng);
1113 break;
1114 default:
1115 free(this);
1116 return NULL;
1117 }
1118 this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
1119 this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
1120 this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
1121 this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
1122
1123 this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
1124 this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160);
1125 this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128);
1126 if (!this->hasher || !this->prf || !this->signer)
1127 {
1128 DBG1(DBG_IKE, "initiating EAP-SIM failed, FIPS-PRF/SHA1 not supported");
1129 destroy(this);
1130 return NULL;
1131 }
1132 return &this->public;
1133 }
1134
1135 /*
1136 * Described in header.
1137 */
1138 eap_sim_t *eap_sim_create_server(identification_t *server,
1139 identification_t *peer)
1140 {
1141 return eap_sim_create_generic(EAP_SERVER, server, peer);
1142 }
1143
1144 /*
1145 * Described in header.
1146 */
1147 eap_sim_t *eap_sim_create_peer(identification_t *server,
1148 identification_t *peer)
1149 {
1150 return eap_sim_create_generic(EAP_PEER, server, peer);
1151 }
1152