2 * Copyright (C) 2008-2009 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
16 #include "eap_aka_3gpp2_card.h"
20 typedef struct private_eap_aka_3gpp2_card_t private_eap_aka_3gpp2_card_t
;
23 * Private data of an eap_aka_3gpp2_card_t object.
25 struct private_eap_aka_3gpp2_card_t
{
28 * Public eap_aka_3gpp2_card_t interface.
30 eap_aka_3gpp2_card_t
public;
35 eap_aka_3gpp2_functions_t
*f
;
38 * do sequence number checking?
43 * SQN stored in this pseudo-USIM
45 char sqn
[AKA_SQN_LEN
];
49 * Functions from eap_aka_3gpp2_provider.c
51 bool eap_aka_3gpp2_get_k(identification_t
*id
, char k
[AKA_K_LEN
]);
52 void eap_aka_3gpp2_get_sqn(char sqn
[AKA_SQN_LEN
], int offset
);
55 * Implementation of simaka_card_t.get_quintuplet
57 static status_t
get_quintuplet(private_eap_aka_3gpp2_card_t
*this,
58 identification_t
*id
, char rand
[AKA_RAND_LEN
],
59 char autn
[AKA_AUTN_LEN
], char ck
[AKA_CK_LEN
],
60 char ik
[AKA_IK_LEN
], char res
[AKA_RES_MAX
],
64 char k
[AKA_K_LEN
], ak
[AKA_AK_LEN
], sqn
[AKA_SQN_LEN
], xmac
[AKA_MAC_LEN
];
66 if (!eap_aka_3gpp2_get_k(id
, k
))
68 DBG1(DBG_IKE
, "no EAP key found for %Y to authenticate with AKA", id
);
72 /* AUTN = SQN xor AK | AMF | MAC */
73 DBG3(DBG_IKE
, "received autn %b", autn
, AKA_AUTN_LEN
);
74 DBG3(DBG_IKE
, "using K %b", k
, AKA_K_LEN
);
75 DBG3(DBG_IKE
, "using rand %b", rand
, AKA_RAND_LEN
);
76 memcpy(sqn
, autn
, AKA_SQN_LEN
);
77 amf
= autn
+ AKA_SQN_LEN
;
78 mac
= autn
+ AKA_SQN_LEN
+ AKA_AMF_LEN
;
80 /* XOR anonymity key AK into SQN to decrypt it */
81 this->f
->f5(this->f
, k
, rand
, ak
);
82 DBG3(DBG_IKE
, "using ak %b", ak
, AKA_AK_LEN
);
83 memxor(sqn
, ak
, AKA_SQN_LEN
);
84 DBG3(DBG_IKE
, "using sqn %b", sqn
, AKA_SQN_LEN
);
86 /* calculate expected MAC and compare against received one */
87 this->f
->f1(this->f
, k
, rand
, sqn
, amf
, xmac
);
88 if (!memeq(mac
, xmac
, AKA_MAC_LEN
))
90 DBG1(DBG_IKE
, "received MAC does not match XMAC");
91 DBG3(DBG_IKE
, "MAC %b\nXMAC %b", mac
, AKA_MAC_LEN
, xmac
, AKA_MAC_LEN
);
95 if (this->seq_check
&& memcmp(this->sqn
, sqn
, AKA_SQN_LEN
) >= 0)
97 DBG3(DBG_IKE
, "received SQN %b\ncurrent SQN %b",
98 sqn
, AKA_SQN_LEN
, this->sqn
, AKA_SQN_LEN
);
102 /* update stored SQN to the received one */
103 memcpy(this->sqn
, sqn
, AKA_SQN_LEN
);
106 this->f
->f3(this->f
, k
, rand
, ck
);
107 this->f
->f4(this->f
, k
, rand
, ik
);
109 this->f
->f2(this->f
, k
, rand
, res
);
110 *res_len
= AKA_RES_MAX
;
116 * Implementation of simaka_card_t.resync
118 static bool resync(private_eap_aka_3gpp2_card_t
*this, identification_t
*id
,
119 char rand
[AKA_RAND_LEN
], char auts
[AKA_AUTS_LEN
])
121 char amf
[AKA_AMF_LEN
], k
[AKA_K_LEN
], aks
[AKA_AK_LEN
], macs
[AKA_MAC_LEN
];
123 if (!eap_aka_3gpp2_get_k(id
, k
))
125 DBG1(DBG_IKE
, "no EAP key found for %Y to resync AKA", id
);
129 /* AMF is set to zero in resync */
130 memset(amf
, 0, AKA_AMF_LEN
);
131 this->f
->f5star(this->f
, k
, rand
, aks
);
132 this->f
->f1star(this->f
, k
, rand
, this->sqn
, amf
, macs
);
133 /* AUTS = SQN xor AKS | MACS */
134 memcpy(auts
, this->sqn
, AKA_SQN_LEN
);
135 memxor(auts
, aks
, AKA_AK_LEN
);
136 memcpy(auts
+ AKA_AK_LEN
, macs
, AKA_MAC_LEN
);
142 * Implementation of eap_aka_3gpp2_card_t.destroy.
144 static void destroy(private_eap_aka_3gpp2_card_t
*this)
152 eap_aka_3gpp2_card_t
*eap_aka_3gpp2_card_create(eap_aka_3gpp2_functions_t
*f
)
154 private_eap_aka_3gpp2_card_t
*this = malloc_thing(private_eap_aka_3gpp2_card_t
);
156 this->public.card
.get_triplet
= (bool(*)(simaka_card_t
*, identification_t
*id
, char rand
[SIM_RAND_LEN
], char sres
[SIM_SRES_LEN
], char kc
[SIM_KC_LEN
]))return_false
;
157 this->public.card
.get_quintuplet
= (status_t(*)(simaka_card_t
*, identification_t
*id
, char rand
[AKA_RAND_LEN
], char autn
[AKA_AUTN_LEN
], char ck
[AKA_CK_LEN
], char ik
[AKA_IK_LEN
], char res
[AKA_RES_MAX
], int *res_len
))get_quintuplet
;
158 this->public.card
.resync
= (bool(*)(simaka_card_t
*, identification_t
*id
, char rand
[AKA_RAND_LEN
], char auts
[AKA_AUTS_LEN
]))resync
;
159 this->public.card
.get_pseudonym
= (identification_t
*(*)(simaka_card_t
*, identification_t
*id
))return_null
;
160 this->public.card
.set_pseudonym
= (void(*)(simaka_card_t
*, identification_t
*id
, identification_t
*pseudonym
))nop
;
161 this->public.card
.get_reauth
= (identification_t
*(*)(simaka_card_t
*, identification_t
*id
, char mk
[HASH_SIZE_SHA1
], u_int16_t
*counter
))return_null
;
162 this->public.card
.set_reauth
= (void(*)(simaka_card_t
*, identification_t
*id
, identification_t
* next
, char mk
[HASH_SIZE_SHA1
], u_int16_t counter
))nop
;
163 this->public.destroy
= (void(*)(eap_aka_3gpp2_card_t
*))destroy
;
166 this->seq_check
= lib
->settings
->get_bool(lib
->settings
,
167 "charon.plugins.eap-aka-3gpp2.seq_check",
168 #ifdef SEQ_CHECK /* handle legacy compile time configuration as default */
170 #else /* !SEQ_CHECK */
172 #endif /* SEQ_CHECK */
174 eap_aka_3gpp2_get_sqn(this->sqn
, 0);
176 return &this->public;