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
);
54 METHOD(simaka_card_t
, get_quintuplet
, status_t
,
55 private_eap_aka_3gpp2_card_t
*this, identification_t
*id
,
56 char rand
[AKA_RAND_LEN
], char autn
[AKA_AUTN_LEN
], char ck
[AKA_CK_LEN
],
57 char ik
[AKA_IK_LEN
], char res
[AKA_RES_MAX
], int *res_len
)
60 char k
[AKA_K_LEN
], ak
[AKA_AK_LEN
], sqn
[AKA_SQN_LEN
], xmac
[AKA_MAC_LEN
];
62 if (!eap_aka_3gpp2_get_k(id
, k
))
64 DBG1(DBG_IKE
, "no EAP key found for %Y to authenticate with AKA", id
);
68 /* AUTN = SQN xor AK | AMF | MAC */
69 DBG3(DBG_IKE
, "received autn %b", autn
, AKA_AUTN_LEN
);
70 DBG3(DBG_IKE
, "using K %b", k
, AKA_K_LEN
);
71 DBG3(DBG_IKE
, "using rand %b", rand
, AKA_RAND_LEN
);
72 memcpy(sqn
, autn
, AKA_SQN_LEN
);
73 amf
= autn
+ AKA_SQN_LEN
;
74 mac
= autn
+ AKA_SQN_LEN
+ AKA_AMF_LEN
;
76 /* XOR anonymity key AK into SQN to decrypt it */
77 this->f
->f5(this->f
, k
, rand
, ak
);
78 DBG3(DBG_IKE
, "using ak %b", ak
, AKA_AK_LEN
);
79 memxor(sqn
, ak
, AKA_SQN_LEN
);
80 DBG3(DBG_IKE
, "using sqn %b", sqn
, AKA_SQN_LEN
);
82 /* calculate expected MAC and compare against received one */
83 this->f
->f1(this->f
, k
, rand
, sqn
, amf
, xmac
);
84 if (!memeq(mac
, xmac
, AKA_MAC_LEN
))
86 DBG1(DBG_IKE
, "received MAC does not match XMAC");
87 DBG3(DBG_IKE
, "MAC %b\nXMAC %b", mac
, AKA_MAC_LEN
, xmac
, AKA_MAC_LEN
);
91 if (this->seq_check
&& memcmp(this->sqn
, sqn
, AKA_SQN_LEN
) >= 0)
93 DBG3(DBG_IKE
, "received SQN %b\ncurrent SQN %b",
94 sqn
, AKA_SQN_LEN
, this->sqn
, AKA_SQN_LEN
);
98 /* update stored SQN to the received one */
99 memcpy(this->sqn
, sqn
, AKA_SQN_LEN
);
102 this->f
->f3(this->f
, k
, rand
, ck
);
103 this->f
->f4(this->f
, k
, rand
, ik
);
105 this->f
->f2(this->f
, k
, rand
, res
);
106 *res_len
= AKA_RES_MAX
;
111 METHOD(simaka_card_t
, resync
, bool,
112 private_eap_aka_3gpp2_card_t
*this, identification_t
*id
,
113 char rand
[AKA_RAND_LEN
], char auts
[AKA_AUTS_LEN
])
115 char amf
[AKA_AMF_LEN
], k
[AKA_K_LEN
], aks
[AKA_AK_LEN
], macs
[AKA_MAC_LEN
];
117 if (!eap_aka_3gpp2_get_k(id
, k
))
119 DBG1(DBG_IKE
, "no EAP key found for %Y to resync AKA", id
);
123 /* AMF is set to zero in resync */
124 memset(amf
, 0, AKA_AMF_LEN
);
125 this->f
->f5star(this->f
, k
, rand
, aks
);
126 this->f
->f1star(this->f
, k
, rand
, this->sqn
, amf
, macs
);
127 /* AUTS = SQN xor AKS | MACS */
128 memcpy(auts
, this->sqn
, AKA_SQN_LEN
);
129 memxor(auts
, aks
, AKA_AK_LEN
);
130 memcpy(auts
+ AKA_AK_LEN
, macs
, AKA_MAC_LEN
);
135 METHOD(eap_aka_3gpp2_card_t
, destroy
, void,
136 private_eap_aka_3gpp2_card_t
*this)
144 eap_aka_3gpp2_card_t
*eap_aka_3gpp2_card_create(eap_aka_3gpp2_functions_t
*f
)
146 private_eap_aka_3gpp2_card_t
*this;
151 .get_triplet
= (void*)return_false
,
152 .get_quintuplet
= _get_quintuplet
,
154 .get_pseudonym
= (void*)return_null
,
155 .set_pseudonym
= (void*)nop
,
156 .get_reauth
= (void*)return_null
,
157 .set_reauth
= (void*)nop
,
162 .seq_check
= lib
->settings
->get_bool(lib
->settings
,
163 "charon.plugins.eap-aka-3gpp2.seq_check",
164 #ifdef SEQ_CHECK /* handle legacy compile time configuration as default */
166 #else /* !SEQ_CHECK */
168 #endif /* SEQ_CHECK */
171 eap_aka_3gpp2_get_sqn(this->sqn
, 0);
173 return &this->public;