Migrated EAP-SIM to libsimaka, separated server/peer implementations
[strongswan.git] / src / charon / plugins / eap_sim / eap_sim_peer.c
1 /*
2 * Copyright (C) 2007-2009 Martin Willi
3 * 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_sim_peer.h"
17
18 #include <daemon.h>
19
20 #include <simaka_message.h>
21
22 /* number of tries we do authenticate */
23 #define MAX_TRIES 3
24
25 /* number of triplets for one authentication */
26 #define TRIPLET_COUNT 3
27
28 /** length of the AT_NONCE_MT/AT_NONCE_S nonce value */
29 #define NONCE_LEN 16
30 /** length of the AT_MAC value */
31 #define MAC_LEN 16
32 /** length of the AT_RAND value */
33 #define RAND_LEN 16
34 /** length of Kc */
35 #define KC_LEN 8
36 /** length of SRES */
37 #define SRES_LEN 4
38 /** length of the k_encr key */
39 #define KENCR_LEN 16
40 /** length of the k_auth key */
41 #define KAUTH_LEN 16
42 /** length of the MSK */
43 #define MSK_LEN 64
44 /** length of the EMSK */
45 #define EMSK_LEN 64
46
47 typedef struct private_eap_sim_peer_t private_eap_sim_peer_t;
48
49 /**
50 * Private data of an eap_sim_peer_t object.
51 */
52 struct private_eap_sim_peer_t {
53
54 /**
55 * Public authenticator_t interface.
56 */
57 eap_sim_peer_t public;
58
59 /**
60 * permanent ID of peer
61 */
62 identification_t *peer;
63
64 /**
65 * RNG to create nonces, IVs
66 */
67 rng_t *rng;
68
69 /**
70 * hashing function
71 */
72 hasher_t *hasher;
73
74 /**
75 * prf
76 */
77 prf_t *prf;
78
79 /**
80 * MAC function
81 */
82 signer_t *signer;
83
84 /**
85 * encryption function
86 */
87 crypter_t *crypter;
88
89 /**
90 * how many times we try to authenticate
91 */
92 int tries;
93
94 /**
95 * version list received from server
96 */
97 chunk_t version_list;
98
99 /**
100 * Nonce value used in AT_NONCE_MT/AT_NONCE_S
101 */
102 chunk_t nonce;
103
104 /**
105 * MSK, used for EAP-SIM based IKEv2 authentication
106 */
107 chunk_t msk;
108 };
109
110 /* version of SIM protocol we speak */
111 static chunk_t version = chunk_from_chars(0x00,0x01);
112 /* client error codes used in AT_CLIENT_ERROR_CODE */
113 static chunk_t client_error_general = chunk_from_chars(0x00, 0x01);
114 static chunk_t client_error_unsupported = chunk_from_chars(0x00, 0x02);
115 static chunk_t client_error_insufficient = chunk_from_chars(0x00, 0x03);
116
117 /**
118 * Read a triplet from the SIM card
119 */
120 static bool get_card_triplet(private_eap_sim_peer_t *this,
121 char *rand, char *sres, char *kc)
122 {
123 enumerator_t *enumerator;
124 sim_card_t *card;
125 bool success = FALSE;
126
127 enumerator = charon->sim->create_card_enumerator(charon->sim);
128 while (enumerator->enumerate(enumerator, &card))
129 {
130 if (card->get_triplet(card, this->peer, rand, sres, kc))
131 {
132 success = TRUE;
133 break;
134 }
135 }
136 enumerator->destroy(enumerator);
137 if (!success)
138 {
139 DBG1(DBG_IKE, "no SIM card found with triplets for '%Y'", this->peer);
140 }
141 return success;
142 }
143
144 /**
145 * Derive EAP keys from kc when using full authentication
146 */
147 static void derive_keys_full(private_eap_sim_peer_t *this, chunk_t kcs)
148 {
149 char mk[HASH_SIZE_SHA1], k_encr[KENCR_LEN], k_auth[KAUTH_LEN];
150 chunk_t tmp;
151 int i;
152
153 /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
154 tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer),
155 kcs, this->nonce, this->version_list, version);
156 this->hasher->get_hash(this->hasher, tmp, mk);
157 DBG3(DBG_IKE, "MK = SHA1(%B\n) = %b", &tmp, mk, HASH_SIZE_SHA1);
158
159 /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf()
160 * We currently don't need EMSK, so three prf() are sufficient */
161 this->prf->set_key(this->prf, chunk_create(mk, HASH_SIZE_SHA1));
162 tmp = chunk_alloca(this->prf->get_block_size(this->prf) * 3);
163 for (i = 0; i < 3; i++)
164 {
165 this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 3 * i);
166 }
167 memcpy(k_encr, tmp.ptr, KENCR_LEN);
168 tmp = chunk_skip(tmp, KENCR_LEN);
169 memcpy(k_auth, tmp.ptr, KAUTH_LEN);
170 tmp = chunk_skip(tmp, KAUTH_LEN);
171 free(this->msk.ptr);
172 this->msk = chunk_alloc(MSK_LEN);
173 memcpy(this->msk.ptr, tmp.ptr, MSK_LEN);
174 DBG3(DBG_IKE, "K_encr %b\nK_auth %b\nMSK %B",
175 k_encr, KENCR_LEN, k_auth, KAUTH_LEN, &this->msk);
176
177 this->signer->set_key(this->signer, chunk_create(k_auth, KAUTH_LEN));
178 this->crypter->set_key(this->crypter, chunk_create(k_encr, KENCR_LEN));
179 }
180
181 /**
182 * Send a SIM_CLIENT_ERROR
183 */
184 static eap_payload_t* create_client_error(private_eap_sim_peer_t *this,
185 u_int8_t identifier, chunk_t code)
186 {
187 simaka_message_t *message;
188 eap_payload_t *out;
189
190 message = simaka_message_create(FALSE, identifier,
191 EAP_SIM, SIM_CLIENT_ERROR);
192 message->add_attribute(message, AT_CLIENT_ERROR_CODE, code);
193 out = message->generate(message, NULL, NULL, NULL, chunk_empty);
194 message->destroy(message);
195 return out;
196 }
197
198 /**
199 * process an EAP-SIM/Request/Start message
200 */
201 static status_t process_start(private_eap_sim_peer_t *this,
202 simaka_message_t *in, eap_payload_t **out)
203 {
204 simaka_message_t *message;
205 enumerator_t *enumerator;
206 simaka_attribute_t type;
207 chunk_t data;
208 bool supported = FALSE;
209
210 enumerator = in->create_attribute_enumerator(in);
211 while (enumerator->enumerate(enumerator, &type, &data))
212 {
213 switch (type)
214 {
215 case AT_VERSION_LIST:
216 {
217 free(this->version_list.ptr);
218 this->version_list = chunk_clone(data);
219 while (data.len >= version.len)
220 {
221 if (memeq(data.ptr, version.ptr, version.len))
222 {
223 supported = TRUE;
224 break;
225 }
226 }
227 break;
228 }
229 default:
230 DBG1(DBG_IKE, "ignoring EAP-SIM attribute %N",
231 simaka_attribute_names, type);
232 break;
233 }
234 }
235 enumerator->destroy(enumerator);
236
237 if (!supported)
238 {
239 DBG1(DBG_IKE, "server does not support EAP-SIM version number 1");
240 *out = create_client_error(this, in->get_identifier(in),
241 client_error_unsupported);
242 return NEED_MORE;
243 }
244
245 /* generate AT_NONCE_MT value */
246 free(this->nonce.ptr);
247 this->rng->allocate_bytes(this->rng, NONCE_LEN, &this->nonce);
248
249 message = simaka_message_create(FALSE, in->get_identifier(in),
250 EAP_SIM, SIM_START);
251 message->add_attribute(message, AT_SELECTED_VERSION, version);
252 message->add_attribute(message, AT_NONCE_MT, this->nonce);
253 *out = message->generate(message, NULL, NULL, NULL, chunk_empty);
254 message->destroy(message);
255
256 return NEED_MORE;
257 }
258
259 /**
260 * process an EAP-SIM/Request/Challenge message
261 */
262 static status_t process_challenge(private_eap_sim_peer_t *this,
263 simaka_message_t *in, eap_payload_t **out)
264 {
265 simaka_message_t *message;
266 enumerator_t *enumerator;
267 simaka_attribute_t type;
268 chunk_t data, rands = chunk_empty, kcs, kc, sreses, sres;
269
270 if (this->tries-- <= 0)
271 {
272 /* give up without notification. This hack is required as some buggy
273 * server implementations won't respect our client-error. */
274 return FAILED;
275 }
276
277 enumerator = in->create_attribute_enumerator(in);
278 while (enumerator->enumerate(enumerator, &type, &data))
279 {
280 switch (type)
281 {
282 case AT_RAND:
283 {
284 rands = data;
285 break;
286 }
287 default:
288 DBG1(DBG_IKE, "ignoring EAP-SIM attribute %N",
289 simaka_attribute_names, type);
290 break;
291 }
292 }
293 enumerator->destroy(enumerator);
294
295 /* excepting two or three RAND, each 16 bytes. We require two valid
296 * and different RANDs */
297 if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) ||
298 memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN))
299 {
300 DBG1(DBG_IKE, "no valid AT_RAND received");
301 *out = create_client_error(this, in->get_identifier(in),
302 client_error_insufficient);
303 return NEED_MORE;
304 }
305 /* get two or three KCs/SRESes from SIM using RANDs */
306 kcs = kc = chunk_alloca(rands.len / 2);
307 sreses = sres = chunk_alloca(rands.len / 4);
308 while (rands.len >= RAND_LEN)
309 {
310 if (!get_card_triplet(this, rands.ptr, sres.ptr, kc.ptr))
311 {
312 DBG1(DBG_IKE, "unable to get EAP-SIM triplet");
313 *out = create_client_error(this, in->get_identifier(in),
314 client_error_general);
315 return NEED_MORE;
316 }
317 DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b",
318 rands.ptr, RAND_LEN, sres.ptr, SRES_LEN, kc.ptr, KC_LEN);
319 kc = chunk_skip(kc, KC_LEN);
320 sres = chunk_skip(sres, SRES_LEN);
321 rands = chunk_skip(rands, RAND_LEN);
322 }
323
324 derive_keys_full(this, kcs);
325
326 /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */
327 if (!in->verify(in, this->signer, this->nonce))
328 {
329 DBG1(DBG_IKE, "AT_MAC verification failed");
330 *out = create_client_error(this, in->get_identifier(in),
331 client_error_general);
332 return NEED_MORE;
333 }
334
335 /* build response with AT_MAC, built over "EAP packet | n*SRES" */
336 message = simaka_message_create(FALSE, in->get_identifier(in),
337 EAP_SIM, SIM_CHALLENGE);
338 *out = message->generate(message, NULL, NULL, this->signer, sreses);
339 message->destroy(message);
340 return NEED_MORE;
341 }
342
343 /**
344 * process an EAP-SIM/Request/Notification message
345 */
346 static status_t process_notification(private_eap_sim_peer_t *this,
347 simaka_message_t *in, eap_payload_t **out)
348 {
349 simaka_message_t *message;
350 enumerator_t *enumerator;
351 simaka_attribute_t type;
352 chunk_t data;
353 bool success = TRUE;
354
355 enumerator = in->create_attribute_enumerator(in);
356 while (enumerator->enumerate(enumerator, &type, &data))
357 {
358 if (type == AT_NOTIFICATION)
359 {
360 /* test success bit */
361 if (!(data.ptr[0] & 0x80))
362 {
363 success = FALSE;
364 DBG1(DBG_IKE, "received EAP-SIM notification error %#B", &data);
365 }
366 else
367 {
368 DBG1(DBG_IKE, "received EAP-SIM notification code %#B", &data);
369 }
370 }
371 }
372 enumerator->destroy(enumerator);
373
374 if (success)
375 { /* empty notification reply */
376 message = simaka_message_create(FALSE, in->get_identifier(in),
377 EAP_SIM, SIM_NOTIFICATION);
378 *out = message->generate(message, NULL, NULL, NULL, chunk_empty);
379 message->destroy(message);
380 }
381 else
382 {
383 *out = create_client_error(this, in->get_identifier(in),
384 client_error_general);
385 }
386 return NEED_MORE;
387 }
388
389 /**
390 * Implementation of eap_method_t.process
391 */
392 static status_t process(private_eap_sim_peer_t *this,
393 eap_payload_t *in, eap_payload_t **out)
394 {
395 simaka_message_t *message;
396 status_t status;
397
398 message = simaka_message_create_from_payload(in);
399 if (!message)
400 {
401 *out = create_client_error(this, in->get_identifier(in),
402 client_error_general);
403 return NEED_MORE;
404 }
405 if (!message->parse(message, this->crypter))
406 {
407 message->destroy(message);
408 *out = create_client_error(this, in->get_identifier(in),
409 client_error_general);
410 return NEED_MORE;
411 }
412 switch (message->get_subtype(message))
413 {
414 case SIM_START:
415 status = process_start(this, message, out);
416 break;
417 case SIM_CHALLENGE:
418 status = process_challenge(this, message, out);
419 break;
420 case SIM_NOTIFICATION:
421 status = process_notification(this, message, out);
422 break;
423 default:
424 *out = create_client_error(this, in->get_identifier(in),
425 client_error_general);
426 status = NEED_MORE;
427 break;
428 }
429 message->destroy(message);
430 return status;
431 }
432
433 /**
434 * Implementation of eap_method_t.initiate
435 */
436 static status_t initiate(private_eap_sim_peer_t *this, eap_payload_t **out)
437 {
438 /* peer never initiates */
439 return FAILED;
440 }
441
442 /**
443 * Implementation of eap_method_t.get_type.
444 */
445 static eap_type_t get_type(private_eap_sim_peer_t *this, u_int32_t *vendor)
446 {
447 *vendor = 0;
448 return EAP_SIM;
449 }
450
451 /**
452 * Implementation of eap_method_t.get_msk.
453 */
454 static status_t get_msk(private_eap_sim_peer_t *this, chunk_t *msk)
455 {
456 if (this->msk.ptr)
457 {
458 *msk = this->msk;
459 return SUCCESS;
460 }
461 return FAILED;
462 }
463
464 /**
465 * Implementation of eap_method_t.is_mutual.
466 */
467 static bool is_mutual(private_eap_sim_peer_t *this)
468 {
469 return TRUE;
470 }
471
472 /**
473 * Implementation of eap_method_t.destroy.
474 */
475 static void destroy(private_eap_sim_peer_t *this)
476 {
477 this->peer->destroy(this->peer);
478 DESTROY_IF(this->rng);
479 DESTROY_IF(this->hasher);
480 DESTROY_IF(this->prf);
481 DESTROY_IF(this->signer);
482 DESTROY_IF(this->crypter);
483 free(this->version_list.ptr);
484 free(this->nonce.ptr);
485 free(this->msk.ptr);
486 free(this);
487 }
488
489 /*
490 * Described in header.
491 */
492 eap_sim_peer_t *eap_sim_peer_create(identification_t *server,
493 identification_t *peer)
494 {
495 private_eap_sim_peer_t *this = malloc_thing(private_eap_sim_peer_t);
496
497 this->peer = peer->clone(peer);
498 this->tries = MAX_TRIES;
499 this->version_list = chunk_empty;
500 this->nonce = chunk_empty;
501 this->msk = chunk_empty;
502
503 this->public.interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
504 this->public.interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
505 this->public.interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
506 this->public.interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
507 this->public.interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
508 this->public.interface.destroy = (void(*)(eap_method_t*))destroy;
509
510 this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
511 this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
512 this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160);
513 this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128);
514 this->crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, 16);
515 if (!this->rng || !this->hasher || !this->prf ||
516 !this->signer || !this->crypter)
517 {
518 DBG1(DBG_IKE, "unable to use EAP-SIM, missing algorithms");
519 destroy(this);
520 return NULL;
521 }
522 return &this->public;
523 }
524