2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
27 /* number of triplets for one authentication */
28 #define TRIPLET_COUNT 3
30 typedef enum sim_subtype_t sim_subtype_t
;
33 * Subtypes of SIM messages
38 SIM_NOTIFICATION
= 12,
39 SIM_CLIENT_ERROR
= 14,
42 ENUM(sim_subtype_names
, SIM_START
, SIM_CLIENT_ERROR
,
50 typedef enum sim_attribute_t sim_attribute_t
;
53 * Attributes in SIM messages
55 enum sim_attribute_t
{
56 /** defines the end of attribute list */
64 AT_PERMANENT_ID_REQ
= 10,
70 AT_SELECTED_VERSION
= 16,
71 AT_FULLAUTH_ID_REQ
= 17,
73 AT_COUNTER_TOO_SMALL
= 20,
75 AT_CLIENT_ERROR_CODE
= 22,
78 AT_NEXT_PSEUDONYM
= 132,
79 AT_NEXT_REAUTH_ID
= 133,
84 ENUM_BEGIN(sim_attribute_names
, AT_END
, AT_CLIENT_ERROR_CODE
,
96 "AT_PERMANENT_ID_REQ",
102 "AT_SELECTED_VERSION",
103 "AT_FULLAUTH_ID_REQ",
106 "AT_COUNTER_TOO_SMALL",
108 "AT_CLIENT_ERROR_CODE");
109 ENUM_NEXT(sim_attribute_names
, AT_IV
, AT_RESULT_IND
, AT_CLIENT_ERROR_CODE
,
117 ENUM_END(sim_attribute_names
, AT_RESULT_IND
);
120 typedef struct private_eap_sim_t private_eap_sim_t
;
123 * Private data of an eap_sim_t object.
125 struct private_eap_sim_t
{
128 * Public authenticator_t interface.
135 identification_t
*peer
;
153 * how many times we try to authenticate
158 * unique EAP identifier
163 * EAP message type this role sends
168 * version this implementation uses
173 * version list received from server
175 chunk_t version_list
;
178 * Nonce value used in AT_NONCE_MT
183 * concatenated SRES values
188 * k_encr key derived from MK
193 * k_auth key derived from MK, used for AT_MAC verification
198 * MSK, used for EAP-SIM based IKEv2 authentication
203 * EMSK, extended MSK for further uses
208 /** length of the AT_NONCE_MT nonce value */
210 /** length of the AT_MAC value */
212 /** length of the AT_RAND value */
216 /** length of SRES */
218 /** length of the k_encr key */
220 /** length of the k_auth key */
222 /** length of the MSK */
224 /** length of the EMSK */
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
);
239 * Read EAP and EAP-SIM header, return SIM type
241 static sim_subtype_t
read_header(chunk_t
*message
)
245 if (message
->len
< 8)
247 *message
= chunk_empty
;
250 type
= *(message
->ptr
+ 5);
251 *message
= chunk_skip(*message
, 8);
256 * read the next attribute from the chunk data
258 static sim_attribute_t
read_attribute(chunk_t
*message
, chunk_t
*data
)
260 sim_attribute_t attribute
;
263 DBG3(DBG_IKE
, "reading attribute from %B", message
);
265 if (message
->len
< 2)
269 attribute
= *message
->ptr
++;
270 length
= *message
->ptr
++ * 4 - 2;
272 DBG3(DBG_IKE
, "found attribute %N with length %d",
273 sim_attribute_names
, attribute
, length
);
275 if (length
> message
->len
)
280 data
->ptr
= message
->ptr
;
281 *message
= chunk_skip(*message
, length
);
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.
289 static eap_payload_t
*build_payload(private_eap_sim_t
*this, u_int8_t identifier
,
290 sim_subtype_t type
, ...)
292 chunk_t message
= chunk_alloca(512);
293 chunk_t pos
= message
;
294 eap_payload_t
*payload
;
296 sim_attribute_t attr
;
297 u_int8_t
*mac_pos
= NULL
;
298 chunk_t mac_data
= chunk_empty
;
300 /* write EAP header, skip length bytes */
301 *pos
.ptr
++ = this->type
;
302 *pos
.ptr
++ = identifier
;
305 /* write SIM header with type and subtype, zero reserved bytes */
306 *pos
.ptr
++ = EAP_SIM
;
312 va_start(args
, type
);
313 while ((attr
= va_arg(args
, sim_attribute_t
)) != AT_END
)
315 chunk_t data
= va_arg(args
, chunk_t
);
317 DBG3(DBG_IKE
, "building %N %B", sim_attribute_names
, attr
, &data
);
319 /* write attribute header */
325 case AT_CLIENT_ERROR_CODE
:
326 case AT_SELECTED_VERSION
:
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
);
335 case AT_VERSION_LIST
:
337 u_int16_t act_len
= data
.len
;
338 /* align up to four byte */
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
);
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
);
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
);
367 *pos
.ptr
++ = 5; pos
.len
--;
368 *pos
.ptr
++ = 0; pos
.len
--;
369 *pos
.ptr
++ = 0; pos
.len
--;
371 memset(mac_pos
, 0, MAC_LEN
);
372 pos
= chunk_skip(pos
, MAC_LEN
);
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
);
386 DBG1(DBG_IKE
, "no rule to build EAP_SIM attribute %N, skipped",
387 sim_attribute_names
, attr
);
393 /* calculate message length, write into header */
394 message
.len
= pos
.ptr
- message
.ptr
;
395 *(u_int16_t
*)(message
.ptr
+ 2) = htons(message
.len
);
397 /* create MAC if AT_MAC attribte was included. Append supplied va_arg
398 * chunk mac_data to "to-sign" chunk */
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
);
408 payload
= eap_payload_create_data(message
);
410 DBG3(DBG_IKE
, "created EAP message %B", &message
);
415 * process an EAP-SIM/Request/Start message
417 static status_t
peer_process_start(private_eap_sim_t
*this, eap_payload_t
*in
,
420 chunk_t message
, data
;
421 sim_attribute_t attribute
, include_id
= AT_END
;
424 identifier
= in
->get_identifier(in
);
425 message
= in
->get_data(in
);
426 read_header(&message
);
428 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
432 case AT_VERSION_LIST
:
434 /* check if server supports our implementation */
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
)
445 if (memeq(data
.ptr
, this->version
.ptr
, this->version
.len
))
450 data
= chunk_skip(data
, this->version
.len
);
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
,
464 case AT_PERMANENT_ID_REQ
:
465 case AT_FULLAUTH_ID_REQ
:
467 /* only include AT_IDENTITY if requested */
468 include_id
= AT_IDENTITY
;
470 case AT_NOTIFICATION
:
475 code
= ntohs(*(u_int16_t
*)data
.ptr
);
477 if (code
<= 32767) /* no success bit */
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
,
489 DBG1(DBG_IKE
, "received %N code %d",
490 sim_attribute_names
, attribute
, code
);
495 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
496 sim_attribute_names
, attribute
);
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
),
511 * derive EAP keys from kc
513 static void derive_keys(private_eap_sim_t
*this, chunk_t kcs
)
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
);
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
++)
532 this->prf
->get_bytes(this->prf
, chunk_empty
, tmp
.ptr
+ tmp
.len
/ 4 * i
);
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
);
545 * Read a triplet from the SIM card
547 static bool get_card_triplet(private_eap_sim_t
*this,
548 char *rand
, char *sres
, char *kc
)
550 enumerator_t
*enumerator
;
551 sim_card_t
*card
= NULL
, *current
;
552 id_match_t match
, best
= ID_MATCH_NONE
;
553 bool success
= FALSE
;
555 /* find the best matching SIM */
556 enumerator
= charon
->sim
->create_card_enumerator(charon
->sim
);
557 while (enumerator
->enumerate(enumerator
, ¤t
))
559 match
= this->peer
->matches(this->peer
, current
->get_imsi(current
));
569 success
= card
->get_triplet(card
, rand
, sres
, kc
);
571 enumerator
->destroy(enumerator
);
574 DBG1(DBG_IKE
, "no SIM card found matching '%D'", this->peer
);
580 * process an EAP-SIM/Request/Challenge message
582 static status_t
peer_process_challenge(private_eap_sim_t
*this,
583 eap_payload_t
*in
, eap_payload_t
**out
)
585 chunk_t message
, data
, tmp
, kcs
, kc
, sreses
, sres
;
586 sim_attribute_t attribute
;
588 chunk_t mac
= chunk_empty
, rands
= chunk_empty
;
590 if (this->tries
-- <= 0)
592 /* give up without notification. This hack is required as some buggy
593 * server implementations won't respect our client-error. */
597 identifier
= in
->get_identifier(in
);
598 message
= in
->get_data(in
);
599 read_header(&message
);
601 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
607 rands
= chunk_skip(data
, 2);
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
);
618 case AT_NOTIFICATION
:
623 code
= ntohs(*(u_int16_t
*)data
.ptr
);
625 if (code
<= 32767) /* no success bit */
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
,
637 DBG1(DBG_IKE
, "received %N code %d",
638 sim_attribute_names
, attribute
, code
);
643 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
644 sim_attribute_names
, attribute
);
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
))
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
,
660 if (mac
.len
!= MAC_LEN
)
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
,
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
)
674 if (!get_card_triplet(this, rands
.ptr
, sres
.ptr
, kc
.ptr
))
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
,
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
);
689 derive_keys(this, kcs
);
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
))
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
,
703 /* build response, AT_MAC is built over "EAP packet | n*SRES" */
704 *out
= build_payload(this, identifier
, SIM_CHALLENGE
,
711 * process an EAP-SIM/Response/Challenge message
713 static status_t
server_process_challenge(private_eap_sim_t
*this,
714 eap_payload_t
*in
, eap_payload_t
**out
)
716 chunk_t message
, data
;
717 sim_attribute_t attribute
;
718 chunk_t mac
= chunk_empty
, tmp
;
720 message
= in
->get_data(in
);
721 read_header(&message
);
723 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
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
);
736 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
737 sim_attribute_names
, attribute
);
743 DBG1(DBG_IKE
, "no valid AT_MAC attribute received");
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
))
751 DBG1(DBG_IKE
, "AT_MAC verification failed");
758 * Fetch a triplet from a provider
760 static bool get_provider_triplet(private_eap_sim_t
*this,
761 char *rand
, char *sres
, char *kc
)
763 enumerator_t
*enumerator
;
764 sim_provider_t
*provider
;
767 enumerator
= charon
->sim
->create_provider_enumerator(charon
->sim
);
768 while (enumerator
->enumerate(enumerator
, &provider
))
770 if (provider
->get_triplet(provider
, this->peer
, rand
, sres
, kc
))
772 enumerator
->destroy(enumerator
);
777 enumerator
->destroy(enumerator
);
778 DBG1(DBG_IKE
, "tried %d SIM providers, but none had a triplet for '%D'",
784 * process an EAP-SIM/Response/Start message
786 static status_t
server_process_start(private_eap_sim_t
*this,
787 eap_payload_t
*in
, eap_payload_t
**out
)
789 chunk_t message
, data
;
790 sim_attribute_t attribute
;
791 bool supported
= FALSE
;
792 chunk_t rands
, rand
, kcs
, kc
, sreses
, sres
;
795 message
= in
->get_data(in
);
796 read_header(&message
);
798 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
803 if (data
.len
== NONCE_LEN
+ 2)
805 this->nonce
= chunk_clone(chunk_skip(data
, 2));
808 case AT_SELECTED_VERSION
:
809 if (chunk_equals(data
, this->version
))
815 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
816 sim_attribute_names
, attribute
);
820 if (!supported
|| !this->nonce
.ptr
)
822 DBG1(DBG_IKE
, "received incomplete EAP-SIM/Response/Start");
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
);
833 for (i
= 0; i
< TRIPLET_COUNT
; i
++)
835 if (!get_provider_triplet(this, rand
.ptr
, sres
.ptr
, kc
.ptr
))
837 DBG1(DBG_IKE
, "getting EAP-SIM triplet %d failed", i
);
840 rands
.len
+= RAND_LEN
;
841 sreses
.len
+= SRES_LEN
;
843 rand
= chunk_skip(rand
, RAND_LEN
);
844 sres
= chunk_skip(sres
, SRES_LEN
);
845 kc
= chunk_skip(kc
, KC_LEN
);
847 derive_keys(this, kcs
);
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
);
857 * process an EAP-SIM/Request/Notification message
859 static status_t
peer_process_notification(private_eap_sim_t
*this,
860 eap_payload_t
*in
, eap_payload_t
**out
)
862 chunk_t message
, data
;
863 sim_attribute_t attribute
;
865 message
= in
->get_data(in
);
866 read_header(&message
);
868 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
872 case AT_NOTIFICATION
:
877 code
= ntohs(*(u_int16_t
*)data
.ptr
);
879 if (code
<= 32767) /* no success bit */
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
,
891 DBG1(DBG_IKE
, "received %N code %d",
892 sim_attribute_names
, attribute
, code
);
897 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
898 sim_attribute_names
, attribute
);
902 /* reply with empty notification */
903 *out
= build_payload(this, in
->get_identifier(in
), SIM_NOTIFICATION
, AT_END
);
908 * Process a client error
910 static status_t
server_process_client_error(private_eap_sim_t
*this,
911 eap_payload_t
*in
, eap_payload_t
**out
)
913 chunk_t message
, data
;
914 sim_attribute_t attribute
;
916 message
= in
->get_data(in
);
917 read_header(&message
);
919 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
921 if (attribute
== AT_CLIENT_ERROR_CODE
)
926 code
= ntohs(*(u_int16_t
*)data
.ptr
);
928 DBG1(DBG_IKE
, "received %N error %d",
929 sim_attribute_names
, attribute
, code
);
933 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
934 sim_attribute_names
, attribute
);
941 * Implementation of eap_method_t.process for the peer
943 static status_t
peer_process(private_eap_sim_t
*this,
944 eap_payload_t
*in
, eap_payload_t
**out
)
949 message
= in
->get_data(in
);
950 type
= read_header(&message
);
955 return peer_process_start(this, in
, out
);
957 return peer_process_challenge(this, in
, out
);
958 case SIM_NOTIFICATION
:
959 return peer_process_notification(this, in
, out
);
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
);
970 * Implementation of eap_method_t.process for the server
972 static status_t
server_process(private_eap_sim_t
*this,
973 eap_payload_t
*in
, eap_payload_t
**out
)
978 message
= in
->get_data(in
);
979 type
= read_header(&message
);
984 return server_process_start(this, in
, out
);
986 return server_process_challenge(this, in
, out
);
987 case SIM_CLIENT_ERROR
:
988 return server_process_client_error(this, in
, out
);
990 DBG1(DBG_IKE
, "unable to process EAP_SIM subtype %N",
991 sim_subtype_names
, type
);
997 * Implementation of eap_method_t.initiate for the peer
999 static status_t
peer_initiate(private_eap_sim_t
*this, eap_payload_t
**out
)
1001 /* peer never initiates */
1006 * Implementation of eap_method_t.initiate for the server
1008 static status_t
server_initiate(private_eap_sim_t
*this, eap_payload_t
**out
)
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
);
1019 * Implementation of eap_method_t.get_type.
1021 static eap_type_t
get_type(private_eap_sim_t
*this, u_int32_t
*vendor
)
1028 * Implementation of eap_method_t.get_msk.
1030 static status_t
get_msk(private_eap_sim_t
*this, chunk_t
*msk
)
1041 * Implementation of eap_method_t.is_mutual.
1043 static bool is_mutual(private_eap_sim_t
*this)
1049 * Implementation of eap_method_t.destroy.
1051 static void destroy(private_eap_sim_t
*this)
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
);
1069 * Generic constructor for both roles
1071 eap_sim_t
*eap_sim_create_generic(eap_role_t role
, identification_t
*server
,
1072 identification_t
*peer
)
1074 private_eap_sim_t
*this = malloc_thing(private_eap_sim_t
);
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 */
1090 this->identifier
= random();
1091 } while (!this->identifier
);
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
;
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
);
1107 DBG1(DBG_IKE
, "unable to generate NONCE for EAP_SIM");
1111 rng
->allocate_bytes(rng
, NONCE_LEN
, &this->nonce
);
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
;
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
)
1128 DBG1(DBG_IKE
, "initiating EAP-SIM failed, FIPS-PRF/SHA1 not supported");
1132 return &this->public;
1136 * Described in header.
1138 eap_sim_t
*eap_sim_create_server(identification_t
*server
,
1139 identification_t
*peer
)
1141 return eap_sim_create_generic(EAP_SERVER
, server
, peer
);
1145 * Described in header.
1147 eap_sim_t
*eap_sim_create_peer(identification_t
*server
,
1148 identification_t
*peer
)
1150 return eap_sim_create_generic(EAP_PEER
, server
, peer
);