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