Migratd simaka_crypto to INIT/METHOD macros
[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 <utils/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 = !(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 /**
202 * Implementation of simaka_message_t.is_request
203 */
204 static bool is_request(private_simaka_message_t *this)
205 {
206 return this->hdr->code == EAP_REQUEST;
207 }
208
209 /**
210 * Implementation of simaka_message_t.get_identifier
211 */
212 static u_int8_t get_identifier(private_simaka_message_t *this)
213 {
214 return this->hdr->identifier;
215 }
216
217 /**
218 * Implementation of simaka_message_t.get_subtype
219 */
220 static simaka_subtype_t get_subtype(private_simaka_message_t *this)
221 {
222 return this->hdr->subtype;
223 }
224
225 /**
226 * Implementation of simaka_message_t.get_type
227 */
228 static eap_type_t get_type(private_simaka_message_t *this)
229 {
230 return this->hdr->type;
231 }
232
233 /**
234 * convert attr_t to type and data enumeration
235 */
236 static bool attr_enum_filter(void *null, attr_t **in, simaka_attribute_t *type,
237 void *dummy, chunk_t *data)
238 {
239 attr_t *attr = *in;
240
241 *type = attr->type;
242 *data = chunk_create(attr->data, attr->len);
243 return TRUE;
244 }
245
246 /**
247 * Implementation of simaka_message_t.create_attribute_enumerator
248 */
249 static enumerator_t* create_attribute_enumerator(private_simaka_message_t *this)
250 {
251 return enumerator_create_filter(
252 this->attributes->create_enumerator(this->attributes),
253 (void*)attr_enum_filter, NULL, NULL);
254 }
255
256 /**
257 * Implementation of simaka_message_t.add_attribute
258 */
259 static void add_attribute(private_simaka_message_t *this,
260 simaka_attribute_t type, chunk_t data)
261 {
262 attr_t *attr;
263
264 attr = malloc(sizeof(attr_t) + data.len);
265 attr->len = data.len;
266 attr->type = type;
267 memcpy(attr->data, data.ptr, data.len);
268
269 this->attributes->insert_last(this->attributes, attr);
270 }
271
272 /**
273 * Error handling for unencrypted attributes
274 */
275 static bool not_encrypted(simaka_attribute_t type)
276 {
277 DBG1(DBG_LIB, "received unencrypted %N", simaka_attribute_names, type);
278 return FALSE;
279 }
280
281 /**
282 * Error handling for invalid length
283 */
284 static bool invalid_length(simaka_attribute_t type)
285 {
286 DBG1(DBG_LIB, "invalid length of %N", simaka_attribute_names, type);
287 return FALSE;
288 }
289
290 /**
291 * Call SIM/AKA message hooks
292 */
293 static void call_hook(private_simaka_message_t *this,
294 bool inbound, bool decrypted)
295 {
296 simaka_manager_t *mgr;
297
298 switch (this->hdr->type)
299 {
300 case EAP_SIM:
301 mgr = lib->get(lib, "sim-manager");
302 break;
303 case EAP_AKA:
304 mgr = lib->get(lib, "aka-manager");
305 break;
306 default:
307 return;
308 }
309 mgr->message_hook(mgr, &this->public, inbound, decrypted);
310 }
311
312 /**
313 * Parse attributes from a chunk of data
314 */
315 static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
316 {
317 while (in.len)
318 {
319 attr_hdr_t *hdr;
320 chunk_t data;
321
322 if (in.len < sizeof(attr_hdr_t))
323 {
324 DBG1(DBG_LIB, "found short %N attribute header",
325 eap_type_names, this->hdr->type);
326 return FALSE;
327 }
328 hdr = (attr_hdr_t*)in.ptr;
329
330 switch (hdr->type)
331 {
332 /* attributes without data */
333 case AT_COUNTER_TOO_SMALL:
334 if (!this->encrypted)
335 {
336 return not_encrypted(hdr->type);
337 }
338 /* FALL */
339 case AT_ANY_ID_REQ:
340 case AT_PERMANENT_ID_REQ:
341 case AT_FULLAUTH_ID_REQ:
342 {
343 if (hdr->length != 1 || in.len < 4)
344 {
345 return invalid_length(hdr->type);
346 }
347 data = chunk_empty;
348 in = chunk_skip(in, 4);
349 break;
350 }
351 /* attributes with two bytes data */
352 case AT_COUNTER:
353 if (!this->encrypted)
354 {
355 return not_encrypted(hdr->type);
356 }
357 /* FALL */
358 case AT_CLIENT_ERROR_CODE:
359 case AT_SELECTED_VERSION:
360 case AT_NOTIFICATION:
361 {
362 if (hdr->length != 1 || in.len < 4)
363 {
364 return invalid_length(hdr->type);
365 }
366 data = chunk_create(in.ptr + 2, 2);
367 in = chunk_skip(in, 4);
368 break;
369 }
370 /* attributes with an additional actual-length in bits or bytes */
371 case AT_NEXT_PSEUDONYM:
372 case AT_NEXT_REAUTH_ID:
373 if (!this->encrypted)
374 {
375 return not_encrypted(hdr->type);
376 }
377 /* FALL */
378 case AT_RES:
379 case AT_IDENTITY:
380 case AT_VERSION_LIST:
381 {
382 u_int16_t len;
383
384 if (hdr->length < 1 || in.len < 4)
385 {
386 return invalid_length(hdr->type);
387 }
388 memcpy(&len, in.ptr + 2, 2);
389 len = ntohs(len);
390 if (hdr->type == AT_RES)
391 { /* AT_RES uses length encoding in bits */
392 len /= 8;
393 }
394 if (len > hdr->length * 4 || len > in.len)
395 {
396 return invalid_length(hdr->type);
397 }
398 data = chunk_create(in.ptr + 4, len);
399 in = chunk_skip(in, hdr->length * 4);
400 break;
401 }
402 /* attributes with two reserved bytes, 16 bytes length */
403 case AT_NONCE_S:
404 if (!this->encrypted)
405 {
406 return not_encrypted(hdr->type);
407 }
408 /* FALL */
409 case AT_AUTN:
410 case AT_NONCE_MT:
411 case AT_IV:
412 case AT_MAC:
413 {
414 if (hdr->length != 5 || in.len < 20)
415 {
416 return invalid_length(hdr->type);
417 }
418 data = chunk_create(in.ptr + 4, 16);
419 in = chunk_skip(in, 20);
420 break;
421 }
422 /* attributes with two reserved bytes, variable length */
423 case AT_ENCR_DATA:
424 case AT_RAND:
425 {
426 if (hdr->length * 4 > in.len || in.len < 4)
427 {
428 return invalid_length(hdr->type);
429 }
430 data = chunk_create(in.ptr + 4, hdr->length * 4 - 4);
431 in = chunk_skip(in, hdr->length * 4);
432 break;
433 }
434 /* attributes with no reserved bytes, 14 bytes length */
435 case AT_AUTS:
436 {
437 if (hdr->length != 4 || in.len < 16)
438 {
439 return invalid_length(hdr->type);
440 }
441 data = chunk_create(in.ptr + 2, 14);
442 in = chunk_skip(in, 16);
443 break;
444 }
445 /* other attributes (with 4n + 2 length) */
446 case AT_PADDING:
447 default:
448 {
449 if (hdr->length * 4 > in.len || in.len < 4)
450 {
451 return invalid_length(hdr->type);
452 }
453 data = chunk_create(in.ptr + 2, hdr->length * 4 - 2);
454 in = chunk_skip(in, hdr->length * 4);
455 break;
456 }
457 }
458
459 /* handle special attributes */
460 switch (hdr->type)
461 {
462 case AT_MAC:
463 this->mac = data;
464 break;
465 case AT_IV:
466 this->iv = data;
467 break;
468 case AT_ENCR_DATA:
469 this->encr = data;
470 break;
471 case AT_PADDING:
472 break;
473 case AT_NOTIFICATION:
474 if (this->p_bit)
475 { /* remember P bit for MAC verification */
476 this->p_bit = !!(data.ptr[0] & 0x40);
477 }
478 else if (!this->encrypted)
479 {
480 DBG1(DBG_LIB, "found P-bit 0 notify in unencrypted message");
481 return FALSE;
482 }
483 /* FALL */
484 default:
485 add_attribute(this, hdr->type, data);
486 break;
487 }
488 }
489
490 call_hook(this, TRUE, this->encrypted);
491
492 return TRUE;
493 }
494
495 /**
496 * Decrypt a message and parse the decrypted attributes
497 */
498 static bool decrypt(private_simaka_message_t *this)
499 {
500 bool success;
501 crypter_t *crypter;
502 chunk_t plain;
503
504 crypter = this->crypto->get_crypter(this->crypto);
505 if (!crypter || !this->iv.len || !this->encr.len || this->encrypted)
506 {
507 return TRUE;
508 }
509 if (this->encr.len % crypter->get_block_size(crypter))
510 {
511 DBG1(DBG_LIB, "%N ENCR_DATA not a multiple of block size",
512 eap_type_names, this->hdr->type);
513 return FALSE;
514 }
515
516 crypter->decrypt(crypter, this->encr, this->iv, &plain);
517
518 this->encrypted = TRUE;
519 success = parse_attributes(this, plain);
520 this->encrypted = FALSE;
521 free(plain.ptr);
522 return success;
523 }
524
525 /**
526 * Implementation of simaka_message_t.parse
527 */
528 static bool parse(private_simaka_message_t *this)
529 {
530 chunk_t in;
531
532 if (this->attributes->get_count(this->attributes))
533 { /* Already parsed. Try to decrypt and parse AT_ENCR_DATA. */
534 return decrypt(this);
535 }
536
537 in = chunk_create((char*)this->hdr, ntohs(this->hdr->length));
538 if (!parse_attributes(this, chunk_skip(in, sizeof(hdr_t))))
539 {
540 return FALSE;
541 }
542 /* try to decrypt if we already have keys */
543 return decrypt(this);
544 }
545
546 /**
547 * Implementation of simaka_message_t.verify
548 */
549 static bool verify(private_simaka_message_t *this, chunk_t sigdata)
550 {
551 chunk_t data, backup;
552 signer_t *signer;
553
554 signer = this->crypto->get_signer(this->crypto);
555
556 switch (this->hdr->subtype)
557 {
558 case SIM_START:
559 case SIM_CLIENT_ERROR:
560 /* AKA_CLIENT_ERROR: */
561 case AKA_AUTHENTICATION_REJECT:
562 case AKA_SYNCHRONIZATION_FAILURE:
563 case AKA_IDENTITY:
564 /* skip MAC if available */
565 return TRUE;
566 case SIM_CHALLENGE:
567 case AKA_CHALLENGE:
568 case SIM_REAUTHENTICATION:
569 /* AKA_REAUTHENTICATION: */
570 {
571 if (!this->mac.ptr || !signer)
572 { /* require MAC, but not found */
573 DBG1(DBG_LIB, "%N message requires a MAC, but none found",
574 simaka_subtype_names, this->hdr->subtype);
575 return FALSE;
576 }
577 break;
578 }
579 case SIM_NOTIFICATION:
580 /* AKA_NOTIFICATION: */
581 {
582 if (this->p_bit)
583 { /* MAC not verified if in Phase 1 */
584 return TRUE;
585 }
586 if (!this->mac.ptr || !signer)
587 {
588 DBG1(DBG_LIB, "%N message has a phase 0 notify, but "
589 "no MAC found", simaka_subtype_names, this->hdr->subtype);
590 return FALSE;
591 }
592 break;
593 }
594 default:
595 /* unknown message? */
596 DBG1(DBG_LIB, "signature rule for %N messages missing",
597 simaka_subtype_names, this->hdr->subtype);
598 return FALSE;
599 }
600
601 /* zero MAC for verification */
602 backup = chunk_clonea(this->mac);
603 memset(this->mac.ptr, 0, this->mac.len);
604
605 data = chunk_create((char*)this->hdr, ntohs(this->hdr->length));
606 if (sigdata.len)
607 {
608 data = chunk_cata("cc", data, sigdata);
609 }
610 if (!signer->verify_signature(signer, data, backup))
611 {
612 DBG1(DBG_LIB, "%N MAC verification failed",
613 eap_type_names, this->hdr->type);
614 return FALSE;
615 }
616 return TRUE;
617 }
618
619 /**
620 * Implementation of simaka_message_t.generate
621 */
622 static chunk_t generate(private_simaka_message_t *this, chunk_t sigdata)
623 {
624 /* buffers large enough for messages we generate */
625 char out_buf[1024], encr_buf[512];
626 enumerator_t *enumerator;
627 chunk_t out, encr, data, *target, mac = chunk_empty;
628 simaka_attribute_t type;
629 attr_hdr_t *hdr;
630 u_int16_t len;
631 signer_t *signer;
632
633 call_hook(this, FALSE, TRUE);
634
635 out = chunk_create(out_buf, sizeof(out_buf));
636 encr = chunk_create(encr_buf, sizeof(encr_buf));
637
638 /* copy header */
639 memcpy(out.ptr, this->hdr, sizeof(hdr_t));
640 out = chunk_skip(out, sizeof(hdr_t));
641
642 /* encode attributes */
643 enumerator = create_attribute_enumerator(this);
644 while (enumerator->enumerate(enumerator, &type, &data))
645 {
646 /* encrypt this attribute? */
647 switch (type)
648 {
649 case AT_NONCE_S:
650 case AT_NEXT_PSEUDONYM:
651 case AT_NEXT_REAUTH_ID:
652 case AT_COUNTER:
653 case AT_COUNTER_TOO_SMALL:
654 target = &encr;
655 break;
656 case AT_NOTIFICATION:
657 /* P bit not set, encrypt */
658 if (!(data.ptr[0] & 0x40))
659 {
660 target = &encr;
661 break;
662 }
663 /* FALL */
664 default:
665 target = &out;
666 break;
667 }
668
669 hdr = (attr_hdr_t*)target->ptr;
670 hdr->type = type;
671
672 /* encode type specific */
673 switch (type)
674 {
675 /* attributes without data */
676 case AT_COUNTER_TOO_SMALL:
677 case AT_ANY_ID_REQ:
678 case AT_PERMANENT_ID_REQ:
679 case AT_FULLAUTH_ID_REQ:
680 {
681 hdr->length = 1;
682 memset(target->ptr + 2, 0, 2);
683 *target = chunk_skip(*target, 4);
684 break;
685 }
686 /* attributes with two bytes data */
687 case AT_COUNTER:
688 case AT_CLIENT_ERROR_CODE:
689 case AT_SELECTED_VERSION:
690 case AT_NOTIFICATION:
691 {
692 hdr->length = 1;
693 memcpy(target->ptr + 2, data.ptr, 2);
694 *target = chunk_skip(*target, 4);
695 break;
696 }
697 /* attributes with an additional actual-length in bits or bytes */
698 case AT_NEXT_PSEUDONYM:
699 case AT_NEXT_REAUTH_ID:
700 case AT_IDENTITY:
701 case AT_VERSION_LIST:
702 case AT_RES:
703 {
704 u_int16_t len, padding;
705
706 len = htons(data.len);
707 if (type == AT_RES)
708 { /* AT_RES uses length encoding in bits */
709 len *= 8;
710 }
711 memcpy(target->ptr + 2, &len, sizeof(len));
712 memcpy(target->ptr + 4, data.ptr, data.len);
713 hdr->length = data.len / 4 + 1;
714 padding = (4 - (data.len % 4)) % 4;
715 if (padding)
716 {
717 hdr->length++;
718 memset(target->ptr + 4 + data.len, 0, padding);
719 }
720 *target = chunk_skip(*target, hdr->length * 4);
721 break;
722 }
723 /* attributes with two reserved bytes, 16 bytes length */
724 case AT_NONCE_S:
725 case AT_NONCE_MT:
726 case AT_AUTN:
727 {
728 hdr->length = 5;
729 memset(target->ptr + 2, 0, 2);
730 memcpy(target->ptr + 4, data.ptr, data.len);
731 *target = chunk_skip(*target, 20);
732 break;
733 }
734 /* attributes with two reserved bytes, variable length */
735 case AT_RAND:
736 {
737 hdr->length = 1 + data.len / 4;
738 memset(target->ptr + 2, 0, 2);
739 memcpy(target->ptr + 4, data.ptr, data.len);
740 *target = chunk_skip(*target, data.len + 4);
741 break;
742 }
743 /* attributes with no reserved bytes, 14 bytes length */
744 case AT_AUTS:
745 {
746 hdr->length = 4;
747 memcpy(target->ptr + 2, data.ptr, data.len);
748 *target = chunk_skip(*target, 16);
749 break;
750 }
751 default:
752 {
753 DBG1(DBG_LIB, "no rule to encode %N, skipped",
754 simaka_attribute_names, type);
755 break;
756 }
757 }
758 }
759 enumerator->destroy(enumerator);
760
761 /* encrypt attributes, if any */
762 if (encr.len < sizeof(encr_buf))
763 {
764 chunk_t iv;
765 size_t bs, padding;
766 crypter_t *crypter;
767 rng_t *rng;
768
769 crypter = this->crypto->get_crypter(this->crypto);
770 bs = crypter->get_block_size(crypter);
771 iv.len = crypter->get_iv_size(crypter);
772
773 /* add AT_PADDING attribute */
774 padding = bs - ((sizeof(encr_buf) - encr.len) % bs);
775 if (padding)
776 {
777 hdr = (attr_hdr_t*)encr.ptr;
778 hdr->type = AT_PADDING;
779 hdr->length = padding / 4;
780 memset(encr.ptr + 2, 0, padding - 2);
781 encr = chunk_skip(encr, padding);
782 }
783 encr = chunk_create(encr_buf, sizeof(encr_buf) - encr.len);
784
785 /* add IV attribute */
786 hdr = (attr_hdr_t*)out.ptr;
787 hdr->type = AT_IV;
788 hdr->length = iv.len / 4 + 1;
789 memset(out.ptr + 2, 0, 2);
790 out = chunk_skip(out, 4);
791
792 rng = this->crypto->get_rng(this->crypto);
793 rng->get_bytes(rng, iv.len, out.ptr);
794
795 iv = chunk_clonea(chunk_create(out.ptr, iv.len));
796 out = chunk_skip(out, iv.len);
797
798 /* inline encryption */
799 crypter->encrypt(crypter, encr, iv, NULL);
800
801 /* add ENCR_DATA attribute */
802 hdr = (attr_hdr_t*)out.ptr;
803 hdr->type = AT_ENCR_DATA;
804 hdr->length = encr.len / 4 + 1;
805 memset(out.ptr + 2, 0, 2);
806 memcpy(out.ptr + 4, encr.ptr, encr.len);
807 out = chunk_skip(out, encr.len + 4);
808 }
809
810 /* include MAC ? */
811 signer = this->crypto->get_signer(this->crypto);
812 switch (this->hdr->subtype)
813 {
814 case SIM_CHALLENGE:
815 case AKA_CHALLENGE:
816 case SIM_REAUTHENTICATION:
817 /* AKA_REAUTHENTICATION: */
818 /* TODO: Notifications without P bit */
819 {
820 size_t bs;
821
822 bs = signer->get_block_size(signer);
823 hdr = (attr_hdr_t*)out.ptr;
824 hdr->type = AT_MAC;
825 hdr->length = bs / 4 + 1;
826 memset(out.ptr + 2, 0, 2 + bs);
827 mac = chunk_create(out.ptr + 4, bs);
828 out = chunk_skip(out, bs + 4);
829 break;
830 }
831 default:
832 break;
833 }
834
835 /* calculate message length */
836 out = chunk_create(out_buf, sizeof(out_buf) - out.len);
837 len = htons(out.len);
838 memcpy(out.ptr + 2, &len, sizeof(len));
839
840 /* generate MAC */
841 if (mac.len)
842 {
843 data = chunk_cata("cc", out, sigdata);
844 signer->get_signature(signer, data, mac.ptr);
845 }
846
847 call_hook(this, FALSE, FALSE);
848
849 return chunk_clone(out);
850 }
851
852 /**
853 * Implementation of simaka_message_t.destroy.
854 */
855 static void destroy(private_simaka_message_t *this)
856 {
857 this->attributes->destroy_function(this->attributes, free);
858 free(this->hdr);
859 free(this);
860 }
861
862 /**
863 * Generic constructor.
864 */
865 static simaka_message_t *simaka_message_create_data(chunk_t data,
866 simaka_crypto_t *crypto)
867 {
868 private_simaka_message_t *this;
869 hdr_t *hdr = (hdr_t*)data.ptr;
870
871 if (data.len < sizeof(hdr_t) || hdr->length != htons(data.len))
872 {
873 DBG1(DBG_LIB, "EAP-SIM/AKA header has invalid length");
874 return NULL;
875 }
876 if (hdr->code != EAP_REQUEST && hdr->code != EAP_RESPONSE)
877 {
878 DBG1(DBG_LIB, "invalid EAP code in EAP-SIM/AKA message",
879 eap_type_names, hdr->type);
880 return NULL;
881 }
882 if (hdr->type != EAP_SIM && hdr->type != EAP_AKA)
883 {
884 DBG1(DBG_LIB, "invalid EAP type in EAP-SIM/AKA message",
885 eap_type_names, hdr->type);
886 return NULL;
887 }
888
889 this = malloc_thing(private_simaka_message_t);
890
891 this->public.is_request = (bool(*)(simaka_message_t*))is_request;
892 this->public.get_identifier = (u_int8_t(*)(simaka_message_t*))get_identifier;
893 this->public.get_type = (eap_type_t(*)(simaka_message_t*))get_type;
894 this->public.get_subtype = (simaka_subtype_t(*)(simaka_message_t*))get_subtype;
895 this->public.create_attribute_enumerator = (enumerator_t*(*)(simaka_message_t*))create_attribute_enumerator;
896 this->public.add_attribute = (void(*)(simaka_message_t*, simaka_attribute_t type, chunk_t data))add_attribute;
897 this->public.parse = (bool(*)(simaka_message_t*))parse;
898 this->public.verify = (bool(*)(simaka_message_t*, chunk_t sigdata))verify;
899 this->public.generate = (chunk_t(*)(simaka_message_t*, chunk_t sigdata))generate;
900 this->public.destroy = (void(*)(simaka_message_t*))destroy;
901
902 this->attributes = linked_list_create();
903 this->encrypted = FALSE;
904 this->crypto = crypto;
905 this->p_bit = TRUE;
906 this->mac = chunk_empty;
907 this->encr = chunk_empty;
908 this->iv = chunk_empty;
909 this->hdr = malloc(data.len);
910 memcpy(this->hdr, hdr, data.len);
911
912 return &this->public;
913 }
914
915 /**
916 * See header.
917 */
918 simaka_message_t *simaka_message_create_from_payload(chunk_t data,
919 simaka_crypto_t *crypto)
920 {
921 return simaka_message_create_data(data, crypto);
922 }
923
924 /**
925 * See header.
926 */
927 simaka_message_t *simaka_message_create(bool request, u_int8_t identifier,
928 eap_type_t type, simaka_subtype_t subtype,
929 simaka_crypto_t *crypto)
930 {
931 hdr_t hdr = {
932 .code = request ? EAP_REQUEST : EAP_RESPONSE,
933 .identifier = identifier,
934 .length = htons(sizeof(hdr_t)),
935 .type = type,
936 .subtype = subtype,
937 };
938 return simaka_message_create_data(chunk_create((char*)&hdr, sizeof(hdr)),
939 crypto);
940 }
941