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