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