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