Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2008-2009 Martin Willi
3: * HSR 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_aka_3gpp2_provider.h"
17:
18: #include <daemon.h>
19: #include <credentials/keys/shared_key.h>
20:
21: typedef struct private_eap_aka_3gpp2_provider_t private_eap_aka_3gpp2_provider_t;
22:
23: /**
24: * Private data of an eap_aka_3gpp2_provider_t object.
25: */
26: struct private_eap_aka_3gpp2_provider_t {
27:
28: /**
29: * Public eap_aka_3gpp2_provider_t interface.
30: */
31: eap_aka_3gpp2_provider_t public;
32:
33: /**
34: * AKA functions
35: */
36: eap_aka_3gpp2_functions_t *f;
37:
38: /**
39: * time based SQN, we use the same for all peers
40: */
41: char sqn[AKA_SQN_LEN];
42: };
43:
44: /** Authentication management field */
45: static char amf_def[AKA_AMF_LEN] = {0x00, 0x01};
46:
47: /**
48: * Get a shared key K from the credential database
49: */
50: bool eap_aka_3gpp2_get_k(identification_t *id, char k[AKA_K_LEN])
51: {
52: shared_key_t *shared;
53: chunk_t key;
54:
55: shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, id, NULL);
56: if (shared == NULL)
57: {
58: return FALSE;
59: }
60: key = shared->get_key(shared);
61: memset(k, '\0', AKA_K_LEN);
62: memcpy(k, key.ptr, min(key.len, AKA_K_LEN));
63: shared->destroy(shared);
64: return TRUE;
65: }
66:
67: /**
68: * get SQN using current time
69: */
70: void eap_aka_3gpp2_get_sqn(char sqn[AKA_SQN_LEN], int offset)
71: {
72: timeval_t time;
73:
74: gettimeofday(&time, NULL);
75: /* set sqn to an integer containing 4 bytes seconds + 2 bytes usecs */
76: time.tv_sec = htonl(time.tv_sec + offset);
77: /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */
78: time.tv_usec = htonl(time.tv_usec << 12);
79: memcpy(sqn, (char*)&time.tv_sec + sizeof(time_t) - 4, 4);
80: memcpy(sqn + 4, &time.tv_usec, 2);
81: }
82:
83: METHOD(simaka_provider_t, get_quintuplet, bool,
84: private_eap_aka_3gpp2_provider_t *this, identification_t *id,
85: char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len,
86: char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN])
87: {
88: rng_t *rng;
89: char mac[AKA_MAC_LEN], ak[AKA_AK_LEN], k[AKA_K_LEN];
90:
91: /* generate RAND: we use a registered RNG, not f0() proposed in S.S0055 */
92: rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
93: if (!rng || !rng->get_bytes(rng, AKA_RAND_LEN, rand))
94: {
95: DBG1(DBG_IKE, "generating RAND for AKA failed");
96: DESTROY_IF(rng);
97: return FALSE;
98: }
99: rng->destroy(rng);
100:
101: if (!eap_aka_3gpp2_get_k(id, k))
102: {
103: DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", id);
104: return FALSE;
105: }
106:
107: DBG3(DBG_IKE, "generated rand %b", rand, AKA_RAND_LEN);
108: DBG3(DBG_IKE, "using K %b", k, AKA_K_LEN);
109:
110: /* MAC, AK, XRES as expected from client */
111: if (!this->f->f1(this->f, k, rand, this->sqn, amf_def, mac) ||
112: !this->f->f5(this->f, k, rand, ak) ||
113: !this->f->f2(this->f, k, rand, xres))
114: {
115: return FALSE;
116: }
117: *xres_len = AKA_RES_MAX;
118: /* AUTN = (SQN xor AK) || AMF || MAC */
119: memcpy(autn, this->sqn, AKA_SQN_LEN);
120: memxor(autn, ak, AKA_AK_LEN);
121: memcpy(autn + AKA_SQN_LEN, amf_def, AKA_AMF_LEN);
122: memcpy(autn + AKA_SQN_LEN + AKA_AMF_LEN, mac, AKA_MAC_LEN);
123: DBG3(DBG_IKE, "AUTN %b", autn, AKA_AUTN_LEN);
124: /* CK/IK */
125: if (!this->f->f3(this->f, k, rand, ck) ||
126: !this->f->f4(this->f, k, rand, ik))
127: {
128: return FALSE;
129: }
130: chunk_increment(chunk_create(this->sqn, AKA_SQN_LEN));
131: return TRUE;
132: }
133:
134: METHOD(simaka_provider_t, resync, bool,
135: private_eap_aka_3gpp2_provider_t *this, identification_t *id,
136: char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
137: {
138: char *sqn, *macs;
139: char aks[AKA_AK_LEN], k[AKA_K_LEN], amf[AKA_AMF_LEN], xmacs[AKA_MAC_LEN];
140:
141: if (!eap_aka_3gpp2_get_k(id, k))
142: {
143: DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", id);
144: return FALSE;
145: }
146:
147: /* AUTHS = (AK xor SQN) | MAC */
148: sqn = auts;
149: macs = auts + AKA_SQN_LEN;
150: if (!this->f->f5star(this->f, k, rand, aks))
151: {
152: return FALSE;
153: }
154: memxor(sqn, aks, AKA_AK_LEN);
155:
156: /* verify XMACS, AMF of zero is used in resynchronization */
157: memset(amf, 0, AKA_AMF_LEN);
158: if (!this->f->f1star(this->f, k, rand, sqn, amf, xmacs))
159: {
160: return FALSE;
161: }
162: if (!memeq_const(macs, xmacs, AKA_MAC_LEN))
163: {
164: DBG1(DBG_IKE, "received MACS does not match XMACS");
165: DBG3(DBG_IKE, "MACS %b XMACS %b",
166: macs, AKA_MAC_LEN, xmacs, AKA_MAC_LEN);
167: return FALSE;
168: }
169: /* update stored SQN to received SQN + 1 */
170: memcpy(this->sqn, sqn, AKA_SQN_LEN);
171: chunk_increment(chunk_create(this->sqn, AKA_SQN_LEN));
172: return TRUE;
173: }
174:
175: METHOD(eap_aka_3gpp2_provider_t, destroy, void,
176: private_eap_aka_3gpp2_provider_t *this)
177: {
178: free(this);
179: }
180:
181: /**
182: * See header
183: */
184: eap_aka_3gpp2_provider_t *eap_aka_3gpp2_provider_create(
185: eap_aka_3gpp2_functions_t *f)
186: {
187: private_eap_aka_3gpp2_provider_t *this;
188:
189: INIT(this,
190: .public = {
191: .provider = {
192: .get_triplet = (void*)return_false,
193: .get_quintuplet = _get_quintuplet,
194: .resync = _resync,
195: .is_pseudonym = (void*)return_null,
196: .gen_pseudonym = (void*)return_null,
197: .is_reauth = (void*)return_null,
198: .gen_reauth = (void*)return_null,
199: },
200: .destroy = _destroy,
201: },
202: .f = f,
203: );
204: /* use an offset to accept clock skew between client/server without resync */
205: eap_aka_3gpp2_get_sqn(this->sqn, 180);
206:
207: return &this->public;
208: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>