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 * SIM cardreader function loaded from library
158 * libraries get_triplet() function returning a triplet
160 sim_get_triplet_t get_triplet
;
163 * handle of the loaded library
168 * how many times we try to authenticate
173 * unique EAP identifier
178 * EAP message type this role sends
183 * version this implementation uses
188 * version list received from server
190 chunk_t version_list
;
193 * Nonce value used in AT_NONCE_MT
198 * concatenated SRES values
203 * k_encr key derived from MK
208 * k_auth key derived from MK, used for AT_MAC verification
213 * MSK, used for EAP-SIM based IKEv2 authentication
218 * EMSK, extendes MSK for further uses
223 /** length of the AT_NONCE_MT nonce value */
225 /** length of the AT_MAC value */
227 /** length of the AT_RAND value */
231 /** length of SRES */
233 /** length of the k_encr key */
235 /** length of the k_auth key */
237 /** length of the MSK */
239 /** length of the EMSK */
242 static char version
[] = {0x00,0x01};
243 /* client error codes used in AT_CLIENT_ERROR_CODE */
244 char client_error_general_buf
[] = {0x00, 0x01};
245 char client_error_unsupported_buf
[] = {0x00, 0x02};
246 char client_error_insufficient_buf
[] = {0x00, 0x03};
247 char client_error_notfresh_buf
[] = {0x00, 0x04};
248 chunk_t client_error_general
= chunk_from_buf(client_error_general_buf
);
249 chunk_t client_error_unsupported
= chunk_from_buf(client_error_unsupported_buf
);
250 chunk_t client_error_insufficient
= chunk_from_buf(client_error_insufficient_buf
);
251 chunk_t client_error_notfresh
= chunk_from_buf(client_error_notfresh_buf
);
254 * Read EAP and EAP-SIM header, return SIM type
256 static sim_subtype_t
read_header(chunk_t
*message
)
260 if (message
->len
< 8)
262 *message
= chunk_empty
;
265 type
= *(message
->ptr
+ 5);
266 *message
= chunk_skip(*message
, 8);
271 * read the next attribute from the chunk data
273 static sim_attribute_t
read_attribute(chunk_t
*message
, chunk_t
*data
)
275 sim_attribute_t attribute
;
278 DBG3(DBG_IKE
, "reading attribute from %B", message
);
280 if (message
->len
< 2)
284 attribute
= *message
->ptr
++;
285 length
= *message
->ptr
++ * 4 - 2;
287 DBG3(DBG_IKE
, "found attribute %N with length %d",
288 sim_attribute_names
, attribute
, length
);
290 if (length
> message
->len
)
295 data
->ptr
= message
->ptr
;
296 *message
= chunk_skip(*message
, length
);
301 * Build an EAP-SIM payload using a variable length attribute list.
302 * The variable argument takes a sim_attribute_t followed by its data in a chunk.
304 static eap_payload_t
*build_payload(private_eap_sim_t
*this, u_int8_t identifier
,
305 sim_subtype_t type
, ...)
307 chunk_t message
= chunk_alloca(512);
308 chunk_t pos
= message
;
309 eap_payload_t
*payload
;
311 sim_attribute_t attr
;
312 u_int8_t
*mac_pos
= NULL
;
313 chunk_t mac_data
= chunk_empty
;
315 /* write EAP header, skip length bytes */
316 *pos
.ptr
++ = this->type
;
317 *pos
.ptr
++ = identifier
;
320 /* write SIM header with type and subtype, zero reserved bytes */
321 *pos
.ptr
++ = EAP_SIM
;
327 va_start(args
, type
);
328 while ((attr
= va_arg(args
, sim_attribute_t
)) != AT_END
)
330 chunk_t data
= va_arg(args
, chunk_t
);
332 DBG3(DBG_IKE
, "building %N %B", sim_attribute_names
, attr
, &data
);
334 /* write attribute header */
340 case AT_CLIENT_ERROR_CODE
:
341 case AT_SELECTED_VERSION
:
343 *pos
.ptr
= data
.len
/4 + 1;
344 pos
= chunk_skip(pos
, 1);
345 memcpy(pos
.ptr
, data
.ptr
, data
.len
);
346 pos
= chunk_skip(pos
, data
.len
);
350 case AT_VERSION_LIST
:
352 u_int16_t act_len
= data
.len
;
353 /* align up to four byte */
356 chunk_t tmp
= chunk_alloca((data
.len
/4)*4 + 4);
357 memset(tmp
.ptr
, 0, tmp
.len
);
358 memcpy(tmp
.ptr
, data
.ptr
, data
.len
);
361 *pos
.ptr
= data
.len
/4 + 1;
362 pos
= chunk_skip(pos
, 1);
363 /* actual length in bytes */
364 *(u_int16_t
*)pos
.ptr
= htons(act_len
);
365 pos
= chunk_skip(pos
, sizeof(u_int16_t
));
366 memcpy(pos
.ptr
, data
.ptr
, data
.len
);
367 pos
= chunk_skip(pos
, data
.len
);
372 *pos
.ptr
= data
.len
/4 + 1;
373 pos
= chunk_skip(pos
, 1);
374 memset(pos
.ptr
, 0, 2);
375 pos
= chunk_skip(pos
, 2);
376 memcpy(pos
.ptr
, data
.ptr
, data
.len
);
377 pos
= chunk_skip(pos
, data
.len
);
382 *pos
.ptr
++ = 5; pos
.len
--;
383 *pos
.ptr
++ = 0; pos
.len
--;
384 *pos
.ptr
++ = 0; pos
.len
--;
386 memset(mac_pos
, 0, MAC_LEN
);
387 pos
= chunk_skip(pos
, MAC_LEN
);
393 *pos
.ptr
++ = data
.len
/4 + 1; pos
.len
--;
394 *pos
.ptr
++ = 0; pos
.len
--;
395 *pos
.ptr
++ = 0; pos
.len
--;
396 memcpy(pos
.ptr
, data
.ptr
, data
.len
);
397 pos
= chunk_skip(pos
, data
.len
);
401 DBG1(DBG_IKE
, "no rule to build EAP_SIM attribute %N, skipped",
402 sim_attribute_names
, attr
);
408 /* calculate message length, write into header */
409 message
.len
= pos
.ptr
- message
.ptr
;
410 *(u_int16_t
*)(message
.ptr
+ 2) = htons(message
.len
);
412 /* create MAC if AT_MAC attribte was included. Append supplied va_arg
413 * chunk mac_data to "to-sign" chunk */
416 this->signer
->set_key(this->signer
, this->k_auth
);
417 mac_data
= chunk_cata("cc", message
, mac_data
);
418 this->signer
->get_signature(this->signer
, mac_data
, mac_pos
);
419 DBG3(DBG_IKE
, "AT_MAC signature of %B\n is %b",
420 &mac_data
, mac_pos
, MAC_LEN
);
423 payload
= eap_payload_create_data(message
);
425 DBG3(DBG_IKE
, "created EAP message %B", &message
);
430 * process an EAP-SIM/Request/Start message
432 static status_t
peer_process_start(private_eap_sim_t
*this, eap_payload_t
*in
,
435 chunk_t message
, data
;
436 sim_attribute_t attribute
, include_id
= AT_END
;
439 identifier
= in
->get_identifier(in
);
440 message
= in
->get_data(in
);
441 read_header(&message
);
443 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
447 case AT_VERSION_LIST
:
449 /* check if server supports our implementation */
453 /* read actual length first */
454 data
.len
= min(data
.len
, ntohs(*(u_int16_t
*)data
.ptr
) + 2);
455 data
= chunk_skip(data
, 2);
456 chunk_free(&this->version_list
);
457 this->version_list
= chunk_clone(data
);
458 while (data
.len
>= this->version
.len
)
460 if (memeq(data
.ptr
, this->version
.ptr
, this->version
.len
))
465 data
= chunk_skip(data
, this->version
.len
);
470 DBG1(DBG_IKE
, "server does not support EAP_SIM "
471 "version number %#B", &this->version
);
472 *out
= build_payload(this, identifier
, SIM_CLIENT_ERROR
,
473 AT_CLIENT_ERROR_CODE
, client_error_unsupported
,
479 case AT_PERMANENT_ID_REQ
:
480 case AT_FULLAUTH_ID_REQ
:
482 /* only include AT_IDENTITY if requested */
483 include_id
= AT_IDENTITY
;
485 case AT_NOTIFICATION
:
490 code
= ntohs(*(u_int16_t
*)data
.ptr
);
492 if (code
<= 32767) /* no success bit */
494 DBG1(DBG_IKE
, "received %N error %d",
495 sim_attribute_names
, attribute
, code
);
496 *out
= build_payload(this,
497 in
->get_identifier(in
), SIM_CLIENT_ERROR
,
498 AT_CLIENT_ERROR_CODE
, client_error_general
,
504 DBG1(DBG_IKE
, "received %N code %d",
505 sim_attribute_names
, attribute
, code
);
510 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
511 sim_attribute_names
, attribute
);
516 /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */
517 *out
= build_payload(this, identifier
, SIM_START
,
518 AT_SELECTED_VERSION
, this->version
,
519 AT_NONCE_MT
, this->nonce
,
520 include_id
, this->peer
->get_encoding(this->peer
),
526 * derive EAP keys from kc
528 static void derive_keys(private_eap_sim_t
*this, chunk_t kcs
)
533 /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
534 tmp
= chunk_cata("ccccc", this->peer
->get_encoding(this->peer
), kcs
,
535 this->nonce
, this->version_list
, this->version
);
536 mk
= chunk_alloca(this->hasher
->get_hash_size(this->hasher
));
537 this->hasher
->get_hash(this->hasher
, tmp
, mk
.ptr
);
538 DBG3(DBG_IKE
, "MK = SHA1(%B\n) = %B", &tmp
, &mk
);
540 /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf()
541 * FIPS PRF has 320 bit block size, we need 160 byte for keys
542 * => run prf four times */
543 this->prf
->set_key(this->prf
, mk
);
544 tmp
= chunk_alloca(this->prf
->get_block_size(this->prf
) * 4);
545 for (i
= 0; i
< 4; i
++)
547 this->prf
->get_bytes(this->prf
, chunk_empty
, tmp
.ptr
+ tmp
.len
/ 4 * i
);
549 chunk_free(&this->k_encr
);
550 chunk_free(&this->k_auth
);
551 chunk_free(&this->msk
);
552 chunk_free(&this->emsk
);
553 chunk_split(tmp
, "aaaa", KENCR_LEN
, &this->k_encr
, KAUTH_LEN
, &this->k_auth
,
554 MSK_LEN
, &this->msk
, EMSK_LEN
, &this->emsk
);
555 DBG3(DBG_IKE
, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B",
556 &this->k_encr
, &this->k_auth
, &this->msk
, &this->emsk
);
560 * process an EAP-SIM/Request/Challenge message
562 static status_t
peer_process_challenge(private_eap_sim_t
*this,
563 eap_payload_t
*in
, eap_payload_t
**out
)
565 chunk_t message
, data
, tmp
, kcs
, kc
, sreses
, sres
;
566 sim_attribute_t attribute
;
568 chunk_t mac
= chunk_empty
, rands
= chunk_empty
;
570 if (this->tries
-- <= 0)
572 /* give up without notification. This hack is required as some buggy
573 * server implementations won't respect our client-error. */
577 identifier
= in
->get_identifier(in
);
578 message
= in
->get_data(in
);
579 read_header(&message
);
581 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
587 rands
= chunk_skip(data
, 2);
592 /* backup MAC, zero it inline for later verification */
593 data
= chunk_skip(data
, 2);
594 mac
= chunk_clonea(data
);
595 memset(data
.ptr
, 0, data
.len
);
598 case AT_NOTIFICATION
:
603 code
= ntohs(*(u_int16_t
*)data
.ptr
);
605 if (code
<= 32767) /* no success bit */
607 DBG1(DBG_IKE
, "received %N error %d",
608 sim_attribute_names
, attribute
, code
);
609 *out
= build_payload(this,
610 in
->get_identifier(in
), SIM_CLIENT_ERROR
,
611 AT_CLIENT_ERROR_CODE
, client_error_general
,
617 DBG1(DBG_IKE
, "received %N code %d",
618 sim_attribute_names
, attribute
, code
);
623 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
624 sim_attribute_names
, attribute
);
629 /* excepting two or three RAND, each 16 bytes. We require two valid
630 * and different RANDs */
631 if ((rands
.len
!= 2 * RAND_LEN
&& rands
.len
!= 3 * RAND_LEN
) ||
632 memeq(rands
.ptr
, rands
.ptr
+ RAND_LEN
, RAND_LEN
))
634 DBG1(DBG_IKE
, "no valid AT_RAND received");
635 *out
= build_payload(this, identifier
, SIM_CLIENT_ERROR
,
636 AT_CLIENT_ERROR_CODE
, client_error_insufficient
,
640 if (mac
.len
!= MAC_LEN
)
642 DBG1(DBG_IKE
, "no valid AT_MAC received");
643 *out
= build_payload(this, identifier
, SIM_CLIENT_ERROR
,
644 AT_CLIENT_ERROR_CODE
, client_error_general
,
649 /* get two or three KCs/SRESes from SIM using RANDs */
650 kcs
= kc
= chunk_alloca(rands
.len
/ 2);
651 sreses
= sres
= chunk_alloca(rands
.len
/ 4);
652 while (rands
.len
> 0)
654 int kc_len
= kc
.len
, sres_len
= sres
.len
;
656 if (this->alg(rands
.ptr
, RAND_LEN
, sres
.ptr
, &sres_len
, kc
.ptr
, &kc_len
))
658 DBG1(DBG_IKE
, "unable to get EAP-SIM triplet");
659 *out
= build_payload(this, identifier
, SIM_CLIENT_ERROR
,
660 AT_CLIENT_ERROR_CODE
, client_error_general
,
664 DBG3(DBG_IKE
, "got triplet for RAND %b\n Kc %b\n SRES %b",
665 rands
.ptr
, RAND_LEN
, sres
.ptr
, sres_len
, kc
.ptr
, kc_len
);
666 kc
= chunk_skip(kc
, kc_len
);
667 sres
= chunk_skip(sres
, sres_len
);
668 rands
= chunk_skip(rands
, RAND_LEN
);
671 derive_keys(this, kcs
);
673 /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */
674 this->signer
->set_key(this->signer
, this->k_auth
);
675 tmp
= chunk_cata("cc", in
->get_data(in
), this->nonce
);
676 if (!this->signer
->verify_signature(this->signer
, tmp
, mac
))
678 DBG1(DBG_IKE
, "AT_MAC verification failed");
679 *out
= build_payload(this, identifier
, SIM_CLIENT_ERROR
,
680 AT_CLIENT_ERROR_CODE
, client_error_general
,
685 /* build response, AT_MAC is built over "EAP packet | n*SRES" */
686 *out
= build_payload(this, identifier
, SIM_CHALLENGE
,
693 * process an EAP-SIM/Response/Challenge message
695 static status_t
server_process_challenge(private_eap_sim_t
*this,
696 eap_payload_t
*in
, eap_payload_t
**out
)
698 chunk_t message
, data
;
699 sim_attribute_t attribute
;
700 chunk_t mac
= chunk_empty
, tmp
;
702 message
= in
->get_data(in
);
703 read_header(&message
);
705 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
710 /* MAC has two reserved bytes */
711 if (data
.len
== MAC_LEN
+ 2)
712 { /* clone and zero MAC for verification */
713 mac
= chunk_clonea(chunk_skip(data
, 2));
714 memset(data
.ptr
, 0, data
.len
);
718 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
719 sim_attribute_names
, attribute
);
725 DBG1(DBG_IKE
, "no valid AT_MAC attribute received");
728 /* verify AT_MAC attribute, signature is over "EAP packet | n*SRES" */
729 this->signer
->set_key(this->signer
, this->k_auth
);
730 tmp
= chunk_cata("cc", in
->get_data(in
), this->sreses
);
731 if (!this->signer
->verify_signature(this->signer
, tmp
, mac
))
733 DBG1(DBG_IKE
, "AT_MAC verification failed");
740 * process an EAP-SIM/Response/Start message
742 static status_t
server_process_start(private_eap_sim_t
*this,
743 eap_payload_t
*in
, eap_payload_t
**out
)
745 chunk_t message
, data
;
746 sim_attribute_t attribute
;
747 bool supported
= FALSE
;
748 chunk_t rands
, rand
, kcs
, kc
, sreses
, sres
;
750 int len
, i
, rand_len
, kc_len
, sres_len
;
752 message
= in
->get_data(in
);
753 read_header(&message
);
755 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
760 if (data
.len
== NONCE_LEN
+ 2)
762 this->nonce
= chunk_clone(chunk_skip(data
, 2));
765 case AT_SELECTED_VERSION
:
766 if (chunk_equals(data
, this->version
))
772 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
773 sim_attribute_names
, attribute
);
777 if (!supported
|| !this->nonce
.ptr
)
779 DBG1(DBG_IKE
, "received incomplete EAP-SIM/Response/Start");
782 len
= snprintf(id
, sizeof(id
), "%D", this->peer
);
783 if (len
> sizeof(id
) || len
< 0)
788 /* read triplets from provider */
789 rand
= rands
= chunk_alloca(RAND_LEN
* TRIPLET_COUNT
);
790 kc
= kcs
= chunk_alloca(KC_LEN
* TRIPLET_COUNT
);
791 sres
= sreses
= chunk_alloca(SRES_LEN
* TRIPLET_COUNT
);
795 for (i
= 0; i
< TRIPLET_COUNT
; i
++)
800 if (this->get_triplet(id
, rand
.ptr
, &rand_len
, sres
.ptr
, &sres_len
,
803 DBG1(DBG_IKE
, "getting EAP-SIM triplet %d failed", i
);
806 rands
.len
+= rand_len
;
808 sreses
.len
+= sres_len
;
809 rand
= chunk_skip(rand
, rand_len
);
810 kc
= chunk_skip(kc
, kc_len
);
811 sres
= chunk_skip(sres
, sres_len
);
813 derive_keys(this, kcs
);
815 /* build MAC over "EAP packet | NONCE_MT" */
816 *out
= build_payload(this, this->identifier
++, SIM_CHALLENGE
, AT_RAND
,
817 rands
, AT_MAC
, this->nonce
, AT_END
);
818 this->sreses
= chunk_clone(sreses
);
823 * process an EAP-SIM/Request/Notification message
825 static status_t
peer_process_notification(private_eap_sim_t
*this,
826 eap_payload_t
*in
, eap_payload_t
**out
)
828 chunk_t message
, data
;
829 sim_attribute_t attribute
;
831 message
= in
->get_data(in
);
832 read_header(&message
);
834 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
838 case AT_NOTIFICATION
:
843 code
= ntohs(*(u_int16_t
*)data
.ptr
);
845 if (code
<= 32767) /* no success bit */
847 DBG1(DBG_IKE
, "received %N error %d",
848 sim_attribute_names
, attribute
, code
);
849 *out
= build_payload(this,
850 in
->get_identifier(in
), SIM_CLIENT_ERROR
,
851 AT_CLIENT_ERROR_CODE
, client_error_general
,
857 DBG1(DBG_IKE
, "received %N code %d",
858 sim_attribute_names
, attribute
, code
);
863 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
864 sim_attribute_names
, attribute
);
868 /* reply with empty notification */
869 *out
= build_payload(this, in
->get_identifier(in
), SIM_NOTIFICATION
, AT_END
);
874 * Process a client error
876 static status_t
server_process_client_error(private_eap_sim_t
*this,
877 eap_payload_t
*in
, eap_payload_t
**out
)
879 chunk_t message
, data
;
880 sim_attribute_t attribute
;
882 message
= in
->get_data(in
);
883 read_header(&message
);
885 while ((attribute
= read_attribute(&message
, &data
)) != AT_END
)
887 if (attribute
== AT_CLIENT_ERROR_CODE
)
892 code
= ntohs(*(u_int16_t
*)data
.ptr
);
894 DBG1(DBG_IKE
, "received %N error %d",
895 sim_attribute_names
, attribute
, code
);
899 DBG1(DBG_IKE
, "ignoring EAP_SIM attribute %N",
900 sim_attribute_names
, attribute
);
907 * Implementation of eap_method_t.process for the peer
909 static status_t
peer_process(private_eap_sim_t
*this,
910 eap_payload_t
*in
, eap_payload_t
**out
)
915 message
= in
->get_data(in
);
916 type
= read_header(&message
);
921 return peer_process_start(this, in
, out
);
923 return peer_process_challenge(this, in
, out
);
924 case SIM_NOTIFICATION
:
925 return peer_process_notification(this, in
, out
);
927 DBG1(DBG_IKE
, "unable to process EAP_SIM subtype %N",
928 sim_subtype_names
, type
);
929 *out
= build_payload(this, in
->get_identifier(in
), SIM_CLIENT_ERROR
,
930 AT_CLIENT_ERROR_CODE
, client_error_general
, AT_END
);
936 * Implementation of eap_method_t.process for the server
938 static status_t
server_process(private_eap_sim_t
*this,
939 eap_payload_t
*in
, eap_payload_t
**out
)
944 message
= in
->get_data(in
);
945 type
= read_header(&message
);
950 return server_process_start(this, in
, out
);
952 return server_process_challenge(this, in
, out
);
953 case SIM_CLIENT_ERROR
:
954 return server_process_client_error(this, in
, out
);
956 DBG1(DBG_IKE
, "unable to process EAP_SIM subtype %N",
957 sim_subtype_names
, type
);
963 * Implementation of eap_method_t.initiate for the peer
965 static status_t
peer_initiate(private_eap_sim_t
*this, eap_payload_t
**out
)
967 /* peer never initiates */
972 * Implementation of eap_method_t.initiate for the server
974 static status_t
server_initiate(private_eap_sim_t
*this, eap_payload_t
**out
)
976 /* version_list to derive MK, no padding */
977 this->version_list
= chunk_clone(this->version
);
978 /* build_payloads adds padding itself */
979 *out
= build_payload(this, this->identifier
++, SIM_START
,
980 AT_VERSION_LIST
, this->version
, AT_END
);
985 * Implementation of eap_method_t.get_type.
987 static eap_type_t
get_type(private_eap_sim_t
*this, u_int32_t
*vendor
)
994 * Implementation of eap_method_t.get_msk.
996 static status_t
get_msk(private_eap_sim_t
*this, chunk_t
*msk
)
1007 * Implementation of eap_method_t.is_mutual.
1009 static bool is_mutual(private_eap_sim_t
*this)
1015 * Implementation of eap_method_t.destroy.
1017 static void destroy(private_eap_sim_t
*this)
1019 dlclose(this->handle
);
1020 DESTROY_IF(this->hasher
);
1021 DESTROY_IF(this->prf
);
1022 DESTROY_IF(this->signer
);
1023 chunk_free(&this->nonce
);
1024 chunk_free(&this->sreses
);
1025 chunk_free(&this->version_list
);
1026 chunk_free(&this->k_auth
);
1027 chunk_free(&this->k_encr
);
1028 chunk_free(&this->msk
);
1029 chunk_free(&this->emsk
);
1034 * Generic constructor for both roles
1036 eap_sim_t
*eap_sim_create_generic(eap_role_t role
, identification_t
*server
,
1037 identification_t
*peer
)
1039 private_eap_sim_t
*this;
1044 this = malloc_thing(private_eap_sim_t
);
1046 this->get_triplet
= NULL
;
1047 this->nonce
= chunk_empty
;
1048 this->sreses
= chunk_empty
;
1050 this->tries
= MAX_TRIES
;
1051 this->version
.ptr
= version
;
1052 this->version
.len
= sizeof(version
);
1053 this->version_list
= chunk_empty
;
1054 this->k_auth
= chunk_empty
;
1055 this->k_encr
= chunk_empty
;
1056 this->msk
= chunk_empty
;
1057 this->emsk
= chunk_empty
;
1058 this->identifier
= random();
1060 this->handle
= dlopen(SIM_READER_LIB
, RTLD_LAZY
);
1061 if (this->handle
== NULL
)
1063 DBG1(DBG_IKE
, "unable to open SIM reader '%s'", SIM_READER_LIB
);
1070 name
= SIM_READER_ALG
;
1073 name
= SIM_READER_GET_TRIPLET
;
1079 symbol
= dlsym(this->handle
, name
);
1082 DBG1(DBG_IKE
, "unable to open SIM function '%s' in '%s'",
1083 name
, SIM_READER_LIB
);
1084 dlclose(this->handle
);
1091 this->public.eap_method_interface
.initiate
= (status_t(*)(eap_method_t
*,eap_payload_t
**))server_initiate
;
1092 this->public.eap_method_interface
.process
= (status_t(*)(eap_method_t
*,eap_payload_t
*,eap_payload_t
**))server_process
;
1093 this->get_triplet
= symbol
;
1094 this->type
= EAP_REQUEST
;
1097 this->public.eap_method_interface
.initiate
= (status_t(*)(eap_method_t
*,eap_payload_t
**))peer_initiate
;
1098 this->public.eap_method_interface
.process
= (status_t(*)(eap_method_t
*,eap_payload_t
*,eap_payload_t
**))peer_process
;
1100 this->type
= EAP_RESPONSE
;
1101 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
1104 DBG1(DBG_IKE
, "unable to generate NONCE for EAP_SIM");
1108 rng
->allocate_bytes(rng
, NONCE_LEN
, &this->nonce
);
1115 this->public.eap_method_interface
.get_type
= (eap_type_t(*)(eap_method_t
*,u_int32_t
*))get_type
;
1116 this->public.eap_method_interface
.is_mutual
= (bool(*)(eap_method_t
*))is_mutual
;
1117 this->public.eap_method_interface
.get_msk
= (status_t(*)(eap_method_t
*,chunk_t
*))get_msk
;
1118 this->public.eap_method_interface
.destroy
= (void(*)(eap_method_t
*))destroy
;
1120 this->hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
1121 this->prf
= lib
->crypto
->create_prf(lib
->crypto
, PRF_FIPS_SHA1_160
);
1122 this->signer
= lib
->crypto
->create_signer(lib
->crypto
, AUTH_HMAC_SHA1_128
);
1123 if (!this->hasher
|| !this->prf
|| !this->signer
)
1125 DBG1(DBG_IKE
, "initiating EAP-SIM failed, FIPS-PRF/SHA1 not supported");
1129 return &this->public;
1133 * Described in header.
1135 eap_sim_t
*eap_sim_create_server(identification_t
*server
,
1136 identification_t
*peer
)
1138 return eap_sim_create_generic(EAP_SERVER
, server
, peer
);
1142 * Described in header.
1144 eap_sim_t
*eap_sim_create_peer(identification_t
*server
,
1145 identification_t
*peer
)
1147 return eap_sim_create_generic(EAP_PEER
, server
, peer
);