EAP-SIM/AKA crypto helper supports key derivation for fast reauthentication
[strongswan.git] / src / libsimaka / simaka_message.c
1 /*
2 * Copyright (C) 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 "simaka_message.h"
17
18 typedef struct private_simaka_message_t private_simaka_message_t;
19 typedef struct hdr_t hdr_t;
20 typedef struct attr_hdr_t attr_hdr_t;
21 typedef struct attr_t attr_t;
22
23 /**
24 * packed EAP-SIM/AKA header struct
25 */
26 struct hdr_t {
27 /** EAP code (REQUEST/RESPONSE) */
28 u_int8_t code;
29 /** unique message identifier */
30 u_int8_t identifier;
31 /** length of whole message */
32 u_int16_t length;
33 /** EAP type => EAP_SIM/EAP_AKA */
34 u_int8_t type;
35 /** SIM subtype */
36 u_int8_t subtype;
37 /** reserved bytes */
38 u_int16_t reserved;
39 } __attribute__((__packed__));
40
41 /**
42 * packed EAP-SIM/AKA attribute header struct
43 */
44 struct attr_hdr_t {
45 /** attribute type */
46 u_int8_t type;
47 /** attibute length */
48 u_int8_t length;
49 } __attribute__((__packed__));
50
51 /**
52 * SIM/AKA attribute, parsed
53 */
54 struct attr_t {
55 /** type of attribute */
56 simaka_attribute_t type;
57 /** length of data */
58 size_t len;
59 /** start of data, variable length */
60 char data[];
61 };
62
63 ENUM_BEGIN(simaka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY,
64 "AKA_CHALLENGE",
65 "AKA_AUTHENTICATION_REJECT",
66 "AKA_3",
67 "AKA_SYNCHRONIZATION_FAILURE",
68 "AKA_IDENTITY");
69 ENUM_NEXT(simaka_subtype_names, SIM_START, AKA_CLIENT_ERROR, AKA_IDENTITY,
70 "SIM_START",
71 "SIM_CHALLENGE",
72 "SIM/AKA_NOTIFICATION",
73 "SIM/AKA_REAUTHENTICATION",
74 "SIM/AKA_CLIENT_ERROR");
75 ENUM_END(simaka_subtype_names, AKA_CLIENT_ERROR);
76
77
78 ENUM_BEGIN(simaka_attribute_names, AT_RAND, AT_CLIENT_ERROR_CODE,
79 "AT_RAND",
80 "AT_AUTN",
81 "AT_RES",
82 "AT_AUTS",
83 "AT_5",
84 "AT_PADDING",
85 "AT_NONCE_MT",
86 "AT_8",
87 "AT_9",
88 "AT_PERMANENT_ID_REQ",
89 "AT_MAC",
90 "AT_NOTIFICATION",
91 "AT_ANY_ID_REQ",
92 "AT_IDENTITY",
93 "AT_VERSION_LIST",
94 "AT_SELECTED_VERSION",
95 "AT_FULLAUTH_ID_REQ",
96 "AT_18",
97 "AT_COUNTER",
98 "AT_COUNTER_TOO_SMALL",
99 "AT_NONCE_S",
100 "AT_CLIENT_ERROR_CODE");
101 ENUM_NEXT(simaka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
102 "AT_IV",
103 "AT_ENCR_DATA",
104 "AT_131",
105 "AT_NEXT_PSEUDONYM",
106 "AT_NEXT_REAUTH_ID",
107 "AT_CHECKCODE",
108 "AT_RESULT_IND");
109 ENUM_END(simaka_attribute_names, AT_RESULT_IND);
110
111
112 ENUM_BEGIN(simaka_notification_names, SIM_GENERAL_FAILURE_AA, SIM_GENERAL_FAILURE_AA,
113 "General failure after authentication");
114 ENUM_NEXT(simaka_notification_names, SIM_TEMP_DENIED, SIM_TEMP_DENIED, SIM_GENERAL_FAILURE_AA,
115 "User has been temporarily denied access");
116 ENUM_NEXT(simaka_notification_names, SIM_NOT_SUBSCRIBED, SIM_NOT_SUBSCRIBED, SIM_TEMP_DENIED,
117 "User has not subscribed to the requested service");
118 ENUM_NEXT(simaka_notification_names, SIM_GENERAL_FAILURE, SIM_GENERAL_FAILURE, SIM_NOT_SUBSCRIBED,
119 "General failure");
120 ENUM_NEXT(simaka_notification_names, SIM_SUCCESS, SIM_SUCCESS, SIM_GENERAL_FAILURE,
121 "User has been successfully authenticated");
122 ENUM_END(simaka_notification_names, SIM_SUCCESS);
123
124
125 ENUM(simaka_client_error_names, SIM_UNABLE_TO_PROCESS, SIM_RANDS_NOT_FRESH,
126 "unable to process packet",
127 "unsupported version",
128 "insufficient number of challenges",
129 "RANDs are not fresh",
130 );
131
132 /**
133 * Check if an EAP-SIM/AKA attribute is skippable
134 */
135 bool simaka_attribute_skippable(simaka_attribute_t attribute)
136 {
137 bool skippable = !(attribute >= 0 && attribute <= 127);
138
139 DBG1(DBG_IKE, "%sskippable EAP-SIM/AKA attribute %N",
140 skippable ? "ignoring " : "found non-",
141 simaka_attribute_names, attribute);
142 return skippable;
143 }
144
145 /**
146 * Private data of an simaka_message_t object.
147 */
148 struct private_simaka_message_t {
149
150 /**
151 * Public simaka_message_t interface.
152 */
153 simaka_message_t public;
154
155 /**
156 * EAP message, starting with EAP header
157 */
158 hdr_t *hdr;
159
160 /**
161 * List of parsed attributes, attr_t
162 */
163 linked_list_t *attributes;
164
165 /**
166 * Currently parsing AT_ENCR_DATA wrapped attributes?
167 */
168 bool encrypted;
169
170 /**
171 * crypto helper
172 */
173 simaka_crypto_t *crypto;
174
175 /**
176 * Phase a NOTIFICATION is sent within
177 */
178 bool p_bit;
179
180 /**
181 * MAC value, pointing into message
182 */
183 chunk_t mac;
184
185 /**
186 * ENCR_DATA value, pointing into message
187 */
188 chunk_t encr;
189
190 /**
191 * IV value, pointing into message
192 */
193 chunk_t iv;
194 };
195
196 /**
197 * Implementation of simaka_message_t.is_request
198 */
199 static bool is_request(private_simaka_message_t *this)
200 {
201 return this->hdr->code == EAP_REQUEST;
202 }
203
204 /**
205 * Implementation of simaka_message_t.get_identifier
206 */
207 static u_int8_t get_identifier(private_simaka_message_t *this)
208 {
209 return this->hdr->identifier;
210 }
211
212 /**
213 * Implementation of simaka_message_t.get_subtype
214 */
215 static simaka_subtype_t get_subtype(private_simaka_message_t *this)
216 {
217 return this->hdr->subtype;
218 }
219
220 /**
221 * Implementation of simaka_message_t.get_type
222 */
223 static eap_type_t get_type(private_simaka_message_t *this)
224 {
225 return this->hdr->type;
226 }
227
228 /**
229 * convert attr_t to type and data enumeration
230 */
231 static bool attr_enum_filter(void *null, attr_t **in, simaka_attribute_t *type,
232 void *dummy, chunk_t *data)
233 {
234 attr_t *attr = *in;
235
236 *type = attr->type;
237 *data = chunk_create(attr->data, attr->len);
238 return TRUE;
239 }
240
241 /**
242 * Implementation of simaka_message_t.create_attribute_enumerator
243 */
244 static enumerator_t* create_attribute_enumerator(private_simaka_message_t *this)
245 {
246 return enumerator_create_filter(
247 this->attributes->create_enumerator(this->attributes),
248 (void*)attr_enum_filter, NULL, NULL);
249 }
250
251 /**
252 * Implementation of simaka_message_t.add_attribute
253 */
254 static void add_attribute(private_simaka_message_t *this,
255 simaka_attribute_t type, chunk_t data)
256 {
257 attr_t *attr;
258
259 attr = malloc(sizeof(attr_t) + data.len);
260 attr->len = data.len;
261 attr->type = type;
262 memcpy(attr->data, data.ptr, data.len);
263
264 this->attributes->insert_last(this->attributes, attr);
265 }
266
267 /**
268 * Error handling for unencrypted attributes
269 */
270 static bool not_encrypted(simaka_attribute_t type)
271 {
272 DBG1(DBG_IKE, "received unencrypted %N", simaka_attribute_names, type);
273 return FALSE;
274 }
275
276 /**
277 * Error handling for invalid length
278 */
279 static bool invalid_length(simaka_attribute_t type)
280 {
281 DBG1(DBG_IKE, "invalid length of %N", simaka_attribute_names, type);
282 return FALSE;
283 }
284
285 /**
286 * Parse attributes from a chunk of data
287 */
288 static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
289 {
290 while (in.len)
291 {
292 attr_hdr_t *hdr;
293 chunk_t data;
294
295 if (in.len < sizeof(attr_hdr_t))
296 {
297 DBG1(DBG_IKE, "found short %N attribute header",
298 eap_type_names, this->hdr->type);
299 return FALSE;
300 }
301 hdr = (attr_hdr_t*)in.ptr;
302
303 switch (hdr->type)
304 {
305 /* attributes without data */
306 case AT_COUNTER_TOO_SMALL:
307 if (!this->encrypted)
308 {
309 return not_encrypted(hdr->type);
310 }
311 /* FALL */
312 case AT_ANY_ID_REQ:
313 case AT_PERMANENT_ID_REQ:
314 case AT_FULLAUTH_ID_REQ:
315 {
316 if (hdr->length != 1 || in.len < 4)
317 {
318 return invalid_length(hdr->type);
319 }
320 data = chunk_empty;
321 in = chunk_skip(in, 4);
322 break;
323 }
324 /* attributes with two bytes data */
325 case AT_COUNTER:
326 if (!this->encrypted)
327 {
328 return not_encrypted(hdr->type);
329 }
330 /* FALL */
331 case AT_CLIENT_ERROR_CODE:
332 case AT_SELECTED_VERSION:
333 case AT_NOTIFICATION:
334 {
335 if (hdr->length != 1 || in.len < 4)
336 {
337 return invalid_length(hdr->type);
338 }
339 data = chunk_create(in.ptr + 2, 2);
340 in = chunk_skip(in, 4);
341 break;
342 }
343 /* attributes with an additional actual-length in bits or bytes */
344 case AT_NEXT_PSEUDONYM:
345 case AT_NEXT_REAUTH_ID:
346 if (!this->encrypted)
347 {
348 return not_encrypted(hdr->type);
349 }
350 /* FALL */
351 case AT_RES:
352 case AT_IDENTITY:
353 case AT_VERSION_LIST:
354 {
355 u_int16_t len;
356
357 if (hdr->length < 1 || in.len < 4)
358 {
359 return invalid_length(hdr->type);
360 }
361 memcpy(&len, in.ptr + 2, 2);
362 len = ntohs(len);
363 if (hdr->type == AT_RES)
364 { /* AT_RES uses length encoding in bits */
365 len /= 8;
366 }
367 if (len > hdr->length * 4 || len > in.len)
368 {
369 return invalid_length(hdr->type);
370 }
371 data = chunk_create(in.ptr + 4, len);
372 in = chunk_skip(in, hdr->length * 4);
373 break;
374 }
375 /* attributes with two reserved bytes, 16 bytes length */
376 case AT_NONCE_S:
377 if (!this->encrypted)
378 {
379 return not_encrypted(hdr->type);
380 }
381 /* FALL */
382 case AT_AUTN:
383 case AT_NONCE_MT:
384 case AT_IV:
385 case AT_MAC:
386 {
387 if (hdr->length != 5 || in.len < 20)
388 {
389 return invalid_length(hdr->type);
390 }
391 data = chunk_create(in.ptr + 4, 16);
392 in = chunk_skip(in, 20);
393 break;
394 }
395 /* attributes with two reserved bytes, variable length */
396 case AT_ENCR_DATA:
397 case AT_RAND:
398 {
399 if (hdr->length * 4 > in.len || in.len < 4)
400 {
401 return invalid_length(hdr->type);
402 }
403 data = chunk_create(in.ptr + 4, hdr->length * 4 - 4);
404 in = chunk_skip(in, hdr->length * 4);
405 break;
406 }
407 /* attributes with no reserved bytes, 14 bytes length */
408 case AT_AUTS:
409 {
410 if (hdr->length != 4 || in.len < 16)
411 {
412 return invalid_length(hdr->type);
413 }
414 data = chunk_create(in.ptr + 2, 14);
415 in = chunk_skip(in, 16);
416 break;
417 }
418 /* other attributes (with 4n + 2 length) */
419 case AT_PADDING:
420 default:
421 {
422 if (hdr->length * 4 > in.len || in.len < 4)
423 {
424 return invalid_length(hdr->type);
425 }
426 data = chunk_create(in.ptr + 2, hdr->length * 4 - 2);
427 in = chunk_skip(in, hdr->length * 4);
428 break;
429 }
430 }
431
432 /* handle special attributes */
433 switch (hdr->type)
434 {
435 case AT_MAC:
436 this->mac = data;
437 break;
438 case AT_IV:
439 this->iv = data;
440 break;
441 case AT_ENCR_DATA:
442 this->encr = data;
443 break;
444 case AT_PADDING:
445 break;
446 case AT_NOTIFICATION:
447 if (this->p_bit)
448 { /* remember P bit for MAC verification */
449 this->p_bit = !!(data.ptr[0] & 0x40);
450 }
451 else if (!this->encrypted)
452 {
453 DBG1(DBG_IKE, "found P-bit 0 notify in unencrypted message");
454 return FALSE;
455 }
456 /* FALL */
457 default:
458 add_attribute(this, hdr->type, data);
459 break;
460 }
461 }
462 return TRUE;
463 }
464
465 /**
466 * Decrypt a message and parse the decrypted attributes
467 */
468 static bool decrypt(private_simaka_message_t *this)
469 {
470 bool success;
471 crypter_t *crypter;
472 chunk_t plain;
473
474 crypter = this->crypto->get_crypter(this->crypto);
475 if (!crypter || !this->iv.len || !this->encr.len || this->encrypted)
476 {
477 return TRUE;
478 }
479 if (this->encr.len % crypter->get_block_size(crypter))
480 {
481 DBG1(DBG_IKE, "%N ENCR_DATA not a multiple of block size",
482 eap_type_names, this->hdr->type);
483 return FALSE;
484 }
485
486 crypter->decrypt(crypter, this->encr, this->iv, &plain);
487
488 this->encrypted = TRUE;
489 success = parse_attributes(this, plain);
490 this->encrypted = FALSE;
491 free(plain.ptr);
492 return success;
493 }
494
495 /**
496 * Implementation of simaka_message_t.parse
497 */
498 static bool parse(private_simaka_message_t *this)
499 {
500 chunk_t in;
501
502 if (this->attributes->get_count(this->attributes))
503 { /* Already parsed. Try to decrypt and parse AT_ENCR_DATA. */
504 return decrypt(this);
505 }
506
507 in = chunk_create((char*)this->hdr, ntohs(this->hdr->length));
508 if (!parse_attributes(this, chunk_skip(in, sizeof(hdr_t))))
509 {
510 return FALSE;
511 }
512 /* try to decrypt if we already have keys */
513 return decrypt(this);
514 }
515
516 /**
517 * Implementation of simaka_message_t.verify
518 */
519 static bool verify(private_simaka_message_t *this, chunk_t sigdata)
520 {
521 chunk_t data, backup;
522 signer_t *signer;
523
524 signer = this->crypto->get_signer(this->crypto);
525
526 switch (this->hdr->subtype)
527 {
528 case SIM_START:
529 case SIM_CLIENT_ERROR:
530 /* AKA_CLIENT_ERROR: */
531 case AKA_AUTHENTICATION_REJECT:
532 case AKA_SYNCHRONIZATION_FAILURE:
533 case AKA_IDENTITY:
534 /* skip MAC if available */
535 return TRUE;
536 case SIM_CHALLENGE:
537 case AKA_CHALLENGE:
538 case SIM_REAUTHENTICATION:
539 /* AKA_REAUTHENTICATION: */
540 {
541 if (!this->mac.ptr || !signer)
542 { /* require MAC, but not found */
543 DBG1(DBG_IKE, "%N message requires a MAC, but none found",
544 simaka_subtype_names, this->hdr->subtype);
545 return FALSE;
546 }
547 break;
548 }
549 case SIM_NOTIFICATION:
550 /* AKA_NOTIFICATION: */
551 {
552 if (this->p_bit)
553 { /* MAC not verified if in Phase 1 */
554 return TRUE;
555 }
556 if (!this->mac.ptr || !signer)
557 {
558 DBG1(DBG_IKE, "%N message has a phase 0 notify, but "
559 "no MAC found", simaka_subtype_names, this->hdr->subtype);
560 return FALSE;
561 }
562 break;
563 }
564 default:
565 /* unknown message? */
566 DBG1(DBG_IKE, "signature rule for %N messages missing",
567 simaka_subtype_names, this->hdr->subtype);
568 return FALSE;
569 }
570
571 /* zero MAC for verification */
572 backup = chunk_clonea(this->mac);
573 memset(this->mac.ptr, 0, this->mac.len);
574
575 data = chunk_create((char*)this->hdr, ntohs(this->hdr->length));
576 if (sigdata.len)
577 {
578 data = chunk_cata("cc", data, sigdata);
579 }
580 if (!signer->verify_signature(signer, data, backup))
581 {
582 DBG1(DBG_IKE, "%N MAC verification failed",
583 eap_type_names, this->hdr->type);
584 return FALSE;
585 }
586 return TRUE;
587 }
588
589 /**
590 * Implementation of simaka_message_t.generate
591 */
592 static eap_payload_t* generate(private_simaka_message_t *this, chunk_t sigdata)
593 {
594 /* buffers large enough for messages we generate */
595 char out_buf[1024], encr_buf[512];
596 enumerator_t *enumerator;
597 chunk_t out, encr, data, *target, mac = chunk_empty;
598 simaka_attribute_t type;
599 attr_hdr_t *hdr;
600 u_int16_t len;
601 signer_t *signer;
602
603 out = chunk_create(out_buf, sizeof(out_buf));
604 encr = chunk_create(encr_buf, sizeof(encr_buf));
605
606 /* copy header */
607 memcpy(out.ptr, this->hdr, sizeof(hdr_t));
608 out = chunk_skip(out, sizeof(hdr_t));
609
610 /* encode attributes */
611 enumerator = create_attribute_enumerator(this);
612 while (enumerator->enumerate(enumerator, &type, &data))
613 {
614 /* encrypt this attribute? */
615 switch (type)
616 {
617 case AT_NONCE_S:
618 case AT_NEXT_PSEUDONYM:
619 case AT_NEXT_REAUTH_ID:
620 case AT_COUNTER:
621 case AT_COUNTER_TOO_SMALL:
622 target = &encr;
623 break;
624 case AT_NOTIFICATION:
625 /* P bit not set, encrypt */
626 if (!(data.ptr[0] & 0x40))
627 {
628 target = &encr;
629 break;
630 }
631 /* FALL */
632 default:
633 target = &out;
634 break;
635 }
636
637 hdr = (attr_hdr_t*)target->ptr;
638 hdr->type = type;
639
640 /* encode type specific */
641 switch (type)
642 {
643 /* attributes without data */
644 case AT_COUNTER_TOO_SMALL:
645 case AT_ANY_ID_REQ:
646 case AT_PERMANENT_ID_REQ:
647 case AT_FULLAUTH_ID_REQ:
648 {
649 hdr->length = 1;
650 memset(target->ptr + 2, 0, 2);
651 *target = chunk_skip(*target, 4);
652 break;
653 }
654 /* attributes with two bytes data */
655 case AT_COUNTER:
656 case AT_CLIENT_ERROR_CODE:
657 case AT_SELECTED_VERSION:
658 case AT_NOTIFICATION:
659 {
660 hdr->length = 1;
661 memcpy(target->ptr + 2, data.ptr, 2);
662 *target = chunk_skip(*target, 4);
663 break;
664 }
665 /* attributes with an additional actual-length in bits or bytes */
666 case AT_NEXT_PSEUDONYM:
667 case AT_NEXT_REAUTH_ID:
668 case AT_IDENTITY:
669 case AT_VERSION_LIST:
670 case AT_RES:
671 {
672 u_int16_t len, padding;
673
674 len = htons(data.len);
675 if (type == AT_RES)
676 { /* AT_RES uses length encoding in bits */
677 len *= 8;
678 }
679 memcpy(target->ptr + 2, &len, sizeof(len));
680 memcpy(target->ptr + 4, data.ptr, data.len);
681 hdr->length = data.len / 4 + 1;
682 padding = (4 - (data.len % 4)) % 4;
683 if (padding)
684 {
685 hdr->length++;
686 memset(target->ptr + 4 + data.len, 0, padding);
687 }
688 *target = chunk_skip(*target, hdr->length * 4);
689 break;
690 }
691 /* attributes with two reserved bytes, 16 bytes length */
692 case AT_NONCE_S:
693 case AT_NONCE_MT:
694 case AT_AUTN:
695 {
696 hdr->length = 5;
697 memset(target->ptr + 2, 0, 2);
698 memcpy(target->ptr + 4, data.ptr, data.len);
699 *target = chunk_skip(*target, 20);
700 break;
701 }
702 /* attributes with two reserved bytes, variable length */
703 case AT_RAND:
704 {
705 hdr->length = 1 + data.len / 4;
706 memset(target->ptr + 2, 0, 2);
707 memcpy(target->ptr + 4, data.ptr, data.len);
708 *target = chunk_skip(*target, data.len + 4);
709 break;
710 }
711 /* attributes with no reserved bytes, 14 bytes length */
712 case AT_AUTS:
713 {
714 hdr->length = 4;
715 memcpy(target->ptr + 2, data.ptr, data.len);
716 *target = chunk_skip(*target, 16);
717 break;
718 }
719 default:
720 {
721 DBG1(DBG_IKE, "no rule to encode %N, skipped",
722 simaka_attribute_names, type);
723 break;
724 }
725 }
726 }
727 enumerator->destroy(enumerator);
728
729 /* encrypt attributes, if any */
730 if (encr.len < sizeof(encr_buf))
731 {
732 chunk_t iv;
733 size_t bs, padding;
734 crypter_t *crypter;
735 rng_t *rng;
736
737 crypter = this->crypto->get_crypter(this->crypto);
738 bs = crypter->get_block_size(crypter);
739
740 /* add AT_PADDING attribute */
741 padding = bs - ((sizeof(encr_buf) - encr.len) % bs);
742 if (padding)
743 {
744 hdr = (attr_hdr_t*)encr.ptr;
745 hdr->type = AT_PADDING;
746 hdr->length = padding / 4;
747 memset(encr.ptr + 2, 0, padding - 2);
748 encr = chunk_skip(encr, padding);
749 }
750 encr = chunk_create(encr_buf, sizeof(encr_buf) - encr.len);
751
752 /* add IV attribute */
753 hdr = (attr_hdr_t*)out.ptr;
754 hdr->type = AT_IV;
755 hdr->length = bs / 4 + 1;
756 memset(out.ptr + 2, 0, 2);
757 out = chunk_skip(out, 4);
758
759 rng = this->crypto->get_rng(this->crypto);
760 rng->get_bytes(rng, bs, out.ptr);
761
762 iv = chunk_clonea(chunk_create(out.ptr, bs));
763 out = chunk_skip(out, bs);
764
765 /* inline encryption */
766 crypter->encrypt(crypter, encr, iv, NULL);
767
768 /* add ENCR_DATA attribute */
769 hdr = (attr_hdr_t*)out.ptr;
770 hdr->type = AT_ENCR_DATA;
771 hdr->length = encr.len / 4 + 1;
772 memset(out.ptr + 2, 0, 2);
773 memcpy(out.ptr + 4, encr.ptr, encr.len);
774 out = chunk_skip(out, encr.len + 4);
775 }
776
777 /* include MAC ? */
778 signer = this->crypto->get_signer(this->crypto);
779 switch (this->hdr->subtype)
780 {
781 case SIM_CHALLENGE:
782 case AKA_CHALLENGE:
783 case SIM_REAUTHENTICATION:
784 /* AKA_REAUTHENTICATION: */
785 /* TODO: Notifications without P bit */
786 {
787 size_t bs;
788
789 bs = signer->get_block_size(signer);
790 hdr = (attr_hdr_t*)out.ptr;
791 hdr->type = AT_MAC;
792 hdr->length = bs / 4 + 1;
793 memset(out.ptr + 2, 0, 2 + bs);
794 mac = chunk_create(out.ptr + 4, bs);
795 out = chunk_skip(out, bs + 4);
796 break;
797 }
798 default:
799 break;
800 }
801
802 /* calculate message length */
803 out = chunk_create(out_buf, sizeof(out_buf) - out.len);
804 len = htons(out.len);
805 memcpy(out.ptr + 2, &len, sizeof(len));
806
807 /* generate MAC */
808 if (mac.len)
809 {
810 data = chunk_cata("cc", out, sigdata);
811 signer->get_signature(signer, data, mac.ptr);
812 }
813 return eap_payload_create_data(out);
814 }
815
816 /**
817 * Implementation of simaka_message_t.destroy.
818 */
819 static void destroy(private_simaka_message_t *this)
820 {
821 this->attributes->destroy_function(this->attributes, free);
822 free(this->hdr);
823 free(this);
824 }
825
826 /**
827 * Generic constructor.
828 */
829 static simaka_message_t *simaka_message_create_data(chunk_t data,
830 simaka_crypto_t *crypto)
831 {
832 private_simaka_message_t *this;
833 hdr_t *hdr = (hdr_t*)data.ptr;
834
835 if (data.len < sizeof(hdr_t) || hdr->length != htons(data.len))
836 {
837 DBG1(DBG_IKE, "EAP-SIM/AKA header has invalid length");
838 return NULL;
839 }
840 if (hdr->code != EAP_REQUEST && hdr->code != EAP_RESPONSE)
841 {
842 DBG1(DBG_IKE, "invalid EAP code in EAP-SIM/AKA message",
843 eap_type_names, hdr->type);
844 return NULL;
845 }
846 if (hdr->type != EAP_SIM && hdr->type != EAP_AKA)
847 {
848 DBG1(DBG_IKE, "invalid EAP type in EAP-SIM/AKA message",
849 eap_type_names, hdr->type);
850 return NULL;
851 }
852
853 this = malloc_thing(private_simaka_message_t);
854
855 this->public.is_request = (bool(*)(simaka_message_t*))is_request;
856 this->public.get_identifier = (u_int8_t(*)(simaka_message_t*))get_identifier;
857 this->public.get_type = (eap_type_t(*)(simaka_message_t*))get_type;
858 this->public.get_subtype = (simaka_subtype_t(*)(simaka_message_t*))get_subtype;
859 this->public.create_attribute_enumerator = (enumerator_t*(*)(simaka_message_t*))create_attribute_enumerator;
860 this->public.add_attribute = (void(*)(simaka_message_t*, simaka_attribute_t type, chunk_t data))add_attribute;
861 this->public.parse = (bool(*)(simaka_message_t*))parse;
862 this->public.verify = (bool(*)(simaka_message_t*, chunk_t sigdata))verify;
863 this->public.generate = (eap_payload_t*(*)(simaka_message_t*, chunk_t sigdata))generate;
864 this->public.destroy = (void(*)(simaka_message_t*))destroy;
865
866 this->attributes = linked_list_create();
867 this->encrypted = FALSE;
868 this->crypto = crypto;
869 this->p_bit = TRUE;
870 this->mac = chunk_empty;
871 this->encr = chunk_empty;
872 this->iv = chunk_empty;
873 this->hdr = malloc(data.len);
874 memcpy(this->hdr, hdr, data.len);
875
876 return &this->public;
877 }
878
879 /**
880 * See header.
881 */
882 simaka_message_t *simaka_message_create_from_payload(eap_payload_t *payload,
883 simaka_crypto_t *crypto)
884 {
885 return simaka_message_create_data(payload->get_data(payload), crypto);
886 }
887
888 /**
889 * See header.
890 */
891 simaka_message_t *simaka_message_create(bool request, u_int8_t identifier,
892 eap_type_t type, simaka_subtype_t subtype,
893 simaka_crypto_t *crypto)
894 {
895 hdr_t hdr = {
896 .code = request ? EAP_REQUEST : EAP_RESPONSE,
897 .identifier = identifier,
898 .length = htons(sizeof(hdr_t)),
899 .type = type,
900 .subtype = subtype,
901 };
902 return simaka_message_create_data(chunk_create((char*)&hdr, sizeof(hdr)),
903 crypto);
904 }
905