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