removed some raw EAP debug output
[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
463 charon->sim->message_hook(charon->sim, &this->public, TRUE, this->encrypted);
464
465 return TRUE;
466 }
467
468 /**
469 * Decrypt a message and parse the decrypted attributes
470 */
471 static bool decrypt(private_simaka_message_t *this)
472 {
473 bool success;
474 crypter_t *crypter;
475 chunk_t plain;
476
477 crypter = this->crypto->get_crypter(this->crypto);
478 if (!crypter || !this->iv.len || !this->encr.len || this->encrypted)
479 {
480 return TRUE;
481 }
482 if (this->encr.len % crypter->get_block_size(crypter))
483 {
484 DBG1(DBG_IKE, "%N ENCR_DATA not a multiple of block size",
485 eap_type_names, this->hdr->type);
486 return FALSE;
487 }
488
489 crypter->decrypt(crypter, this->encr, this->iv, &plain);
490
491 this->encrypted = TRUE;
492 success = parse_attributes(this, plain);
493 this->encrypted = FALSE;
494 free(plain.ptr);
495 return success;
496 }
497
498 /**
499 * Implementation of simaka_message_t.parse
500 */
501 static bool parse(private_simaka_message_t *this)
502 {
503 chunk_t in;
504
505 if (this->attributes->get_count(this->attributes))
506 { /* Already parsed. Try to decrypt and parse AT_ENCR_DATA. */
507 return decrypt(this);
508 }
509
510 in = chunk_create((char*)this->hdr, ntohs(this->hdr->length));
511 if (!parse_attributes(this, chunk_skip(in, sizeof(hdr_t))))
512 {
513 return FALSE;
514 }
515 /* try to decrypt if we already have keys */
516 return decrypt(this);
517 }
518
519 /**
520 * Implementation of simaka_message_t.verify
521 */
522 static bool verify(private_simaka_message_t *this, chunk_t sigdata)
523 {
524 chunk_t data, backup;
525 signer_t *signer;
526
527 signer = this->crypto->get_signer(this->crypto);
528
529 switch (this->hdr->subtype)
530 {
531 case SIM_START:
532 case SIM_CLIENT_ERROR:
533 /* AKA_CLIENT_ERROR: */
534 case AKA_AUTHENTICATION_REJECT:
535 case AKA_SYNCHRONIZATION_FAILURE:
536 case AKA_IDENTITY:
537 /* skip MAC if available */
538 return TRUE;
539 case SIM_CHALLENGE:
540 case AKA_CHALLENGE:
541 case SIM_REAUTHENTICATION:
542 /* AKA_REAUTHENTICATION: */
543 {
544 if (!this->mac.ptr || !signer)
545 { /* require MAC, but not found */
546 DBG1(DBG_IKE, "%N message requires a MAC, but none found",
547 simaka_subtype_names, this->hdr->subtype);
548 return FALSE;
549 }
550 break;
551 }
552 case SIM_NOTIFICATION:
553 /* AKA_NOTIFICATION: */
554 {
555 if (this->p_bit)
556 { /* MAC not verified if in Phase 1 */
557 return TRUE;
558 }
559 if (!this->mac.ptr || !signer)
560 {
561 DBG1(DBG_IKE, "%N message has a phase 0 notify, but "
562 "no MAC found", simaka_subtype_names, this->hdr->subtype);
563 return FALSE;
564 }
565 break;
566 }
567 default:
568 /* unknown message? */
569 DBG1(DBG_IKE, "signature rule for %N messages missing",
570 simaka_subtype_names, this->hdr->subtype);
571 return FALSE;
572 }
573
574 /* zero MAC for verification */
575 backup = chunk_clonea(this->mac);
576 memset(this->mac.ptr, 0, this->mac.len);
577
578 data = chunk_create((char*)this->hdr, ntohs(this->hdr->length));
579 if (sigdata.len)
580 {
581 data = chunk_cata("cc", data, sigdata);
582 }
583 if (!signer->verify_signature(signer, data, backup))
584 {
585 DBG1(DBG_IKE, "%N MAC verification failed",
586 eap_type_names, this->hdr->type);
587 return FALSE;
588 }
589 return TRUE;
590 }
591
592 /**
593 * Implementation of simaka_message_t.generate
594 */
595 static eap_payload_t* generate(private_simaka_message_t *this, chunk_t sigdata)
596 {
597 /* buffers large enough for messages we generate */
598 char out_buf[1024], encr_buf[512];
599 enumerator_t *enumerator;
600 chunk_t out, encr, data, *target, mac = chunk_empty;
601 simaka_attribute_t type;
602 attr_hdr_t *hdr;
603 u_int16_t len;
604 signer_t *signer;
605
606 charon->sim->message_hook(charon->sim, &this->public, FALSE, TRUE);
607
608 out = chunk_create(out_buf, sizeof(out_buf));
609 encr = chunk_create(encr_buf, sizeof(encr_buf));
610
611 /* copy header */
612 memcpy(out.ptr, this->hdr, sizeof(hdr_t));
613 out = chunk_skip(out, sizeof(hdr_t));
614
615 /* encode attributes */
616 enumerator = create_attribute_enumerator(this);
617 while (enumerator->enumerate(enumerator, &type, &data))
618 {
619 /* encrypt this attribute? */
620 switch (type)
621 {
622 case AT_NONCE_S:
623 case AT_NEXT_PSEUDONYM:
624 case AT_NEXT_REAUTH_ID:
625 case AT_COUNTER:
626 case AT_COUNTER_TOO_SMALL:
627 target = &encr;
628 break;
629 case AT_NOTIFICATION:
630 /* P bit not set, encrypt */
631 if (!(data.ptr[0] & 0x40))
632 {
633 target = &encr;
634 break;
635 }
636 /* FALL */
637 default:
638 target = &out;
639 break;
640 }
641
642 hdr = (attr_hdr_t*)target->ptr;
643 hdr->type = type;
644
645 /* encode type specific */
646 switch (type)
647 {
648 /* attributes without data */
649 case AT_COUNTER_TOO_SMALL:
650 case AT_ANY_ID_REQ:
651 case AT_PERMANENT_ID_REQ:
652 case AT_FULLAUTH_ID_REQ:
653 {
654 hdr->length = 1;
655 memset(target->ptr + 2, 0, 2);
656 *target = chunk_skip(*target, 4);
657 break;
658 }
659 /* attributes with two bytes data */
660 case AT_COUNTER:
661 case AT_CLIENT_ERROR_CODE:
662 case AT_SELECTED_VERSION:
663 case AT_NOTIFICATION:
664 {
665 hdr->length = 1;
666 memcpy(target->ptr + 2, data.ptr, 2);
667 *target = chunk_skip(*target, 4);
668 break;
669 }
670 /* attributes with an additional actual-length in bits or bytes */
671 case AT_NEXT_PSEUDONYM:
672 case AT_NEXT_REAUTH_ID:
673 case AT_IDENTITY:
674 case AT_VERSION_LIST:
675 case AT_RES:
676 {
677 u_int16_t len, padding;
678
679 len = htons(data.len);
680 if (type == AT_RES)
681 { /* AT_RES uses length encoding in bits */
682 len *= 8;
683 }
684 memcpy(target->ptr + 2, &len, sizeof(len));
685 memcpy(target->ptr + 4, data.ptr, data.len);
686 hdr->length = data.len / 4 + 1;
687 padding = (4 - (data.len % 4)) % 4;
688 if (padding)
689 {
690 hdr->length++;
691 memset(target->ptr + 4 + data.len, 0, padding);
692 }
693 *target = chunk_skip(*target, hdr->length * 4);
694 break;
695 }
696 /* attributes with two reserved bytes, 16 bytes length */
697 case AT_NONCE_S:
698 case AT_NONCE_MT:
699 case AT_AUTN:
700 {
701 hdr->length = 5;
702 memset(target->ptr + 2, 0, 2);
703 memcpy(target->ptr + 4, data.ptr, data.len);
704 *target = chunk_skip(*target, 20);
705 break;
706 }
707 /* attributes with two reserved bytes, variable length */
708 case AT_RAND:
709 {
710 hdr->length = 1 + data.len / 4;
711 memset(target->ptr + 2, 0, 2);
712 memcpy(target->ptr + 4, data.ptr, data.len);
713 *target = chunk_skip(*target, data.len + 4);
714 break;
715 }
716 /* attributes with no reserved bytes, 14 bytes length */
717 case AT_AUTS:
718 {
719 hdr->length = 4;
720 memcpy(target->ptr + 2, data.ptr, data.len);
721 *target = chunk_skip(*target, 16);
722 break;
723 }
724 default:
725 {
726 DBG1(DBG_IKE, "no rule to encode %N, skipped",
727 simaka_attribute_names, type);
728 break;
729 }
730 }
731 }
732 enumerator->destroy(enumerator);
733
734 /* encrypt attributes, if any */
735 if (encr.len < sizeof(encr_buf))
736 {
737 chunk_t iv;
738 size_t bs, padding;
739 crypter_t *crypter;
740 rng_t *rng;
741
742 crypter = this->crypto->get_crypter(this->crypto);
743 bs = crypter->get_block_size(crypter);
744 iv.len = crypter->get_iv_size(crypter);
745
746 /* add AT_PADDING attribute */
747 padding = bs - ((sizeof(encr_buf) - encr.len) % bs);
748 if (padding)
749 {
750 hdr = (attr_hdr_t*)encr.ptr;
751 hdr->type = AT_PADDING;
752 hdr->length = padding / 4;
753 memset(encr.ptr + 2, 0, padding - 2);
754 encr = chunk_skip(encr, padding);
755 }
756 encr = chunk_create(encr_buf, sizeof(encr_buf) - encr.len);
757
758 /* add IV attribute */
759 hdr = (attr_hdr_t*)out.ptr;
760 hdr->type = AT_IV;
761 hdr->length = iv.len / 4 + 1;
762 memset(out.ptr + 2, 0, 2);
763 out = chunk_skip(out, 4);
764
765 rng = this->crypto->get_rng(this->crypto);
766 rng->get_bytes(rng, iv.len, out.ptr);
767
768 iv = chunk_clonea(chunk_create(out.ptr, iv.len));
769 out = chunk_skip(out, iv.len);
770
771 /* inline encryption */
772 crypter->encrypt(crypter, encr, iv, NULL);
773
774 /* add ENCR_DATA attribute */
775 hdr = (attr_hdr_t*)out.ptr;
776 hdr->type = AT_ENCR_DATA;
777 hdr->length = encr.len / 4 + 1;
778 memset(out.ptr + 2, 0, 2);
779 memcpy(out.ptr + 4, encr.ptr, encr.len);
780 out = chunk_skip(out, encr.len + 4);
781 }
782
783 /* include MAC ? */
784 signer = this->crypto->get_signer(this->crypto);
785 switch (this->hdr->subtype)
786 {
787 case SIM_CHALLENGE:
788 case AKA_CHALLENGE:
789 case SIM_REAUTHENTICATION:
790 /* AKA_REAUTHENTICATION: */
791 /* TODO: Notifications without P bit */
792 {
793 size_t bs;
794
795 bs = signer->get_block_size(signer);
796 hdr = (attr_hdr_t*)out.ptr;
797 hdr->type = AT_MAC;
798 hdr->length = bs / 4 + 1;
799 memset(out.ptr + 2, 0, 2 + bs);
800 mac = chunk_create(out.ptr + 4, bs);
801 out = chunk_skip(out, bs + 4);
802 break;
803 }
804 default:
805 break;
806 }
807
808 /* calculate message length */
809 out = chunk_create(out_buf, sizeof(out_buf) - out.len);
810 len = htons(out.len);
811 memcpy(out.ptr + 2, &len, sizeof(len));
812
813 /* generate MAC */
814 if (mac.len)
815 {
816 data = chunk_cata("cc", out, sigdata);
817 signer->get_signature(signer, data, mac.ptr);
818 }
819
820 charon->sim->message_hook(charon->sim, &this->public, FALSE, FALSE);
821
822 return eap_payload_create_data(out);
823 }
824
825 /**
826 * Implementation of simaka_message_t.destroy.
827 */
828 static void destroy(private_simaka_message_t *this)
829 {
830 this->attributes->destroy_function(this->attributes, free);
831 free(this->hdr);
832 free(this);
833 }
834
835 /**
836 * Generic constructor.
837 */
838 static simaka_message_t *simaka_message_create_data(chunk_t data,
839 simaka_crypto_t *crypto)
840 {
841 private_simaka_message_t *this;
842 hdr_t *hdr = (hdr_t*)data.ptr;
843
844 if (data.len < sizeof(hdr_t) || hdr->length != htons(data.len))
845 {
846 DBG1(DBG_IKE, "EAP-SIM/AKA header has invalid length");
847 return NULL;
848 }
849 if (hdr->code != EAP_REQUEST && hdr->code != EAP_RESPONSE)
850 {
851 DBG1(DBG_IKE, "invalid EAP code in EAP-SIM/AKA message",
852 eap_type_names, hdr->type);
853 return NULL;
854 }
855 if (hdr->type != EAP_SIM && hdr->type != EAP_AKA)
856 {
857 DBG1(DBG_IKE, "invalid EAP type in EAP-SIM/AKA message",
858 eap_type_names, hdr->type);
859 return NULL;
860 }
861
862 this = malloc_thing(private_simaka_message_t);
863
864 this->public.is_request = (bool(*)(simaka_message_t*))is_request;
865 this->public.get_identifier = (u_int8_t(*)(simaka_message_t*))get_identifier;
866 this->public.get_type = (eap_type_t(*)(simaka_message_t*))get_type;
867 this->public.get_subtype = (simaka_subtype_t(*)(simaka_message_t*))get_subtype;
868 this->public.create_attribute_enumerator = (enumerator_t*(*)(simaka_message_t*))create_attribute_enumerator;
869 this->public.add_attribute = (void(*)(simaka_message_t*, simaka_attribute_t type, chunk_t data))add_attribute;
870 this->public.parse = (bool(*)(simaka_message_t*))parse;
871 this->public.verify = (bool(*)(simaka_message_t*, chunk_t sigdata))verify;
872 this->public.generate = (eap_payload_t*(*)(simaka_message_t*, chunk_t sigdata))generate;
873 this->public.destroy = (void(*)(simaka_message_t*))destroy;
874
875 this->attributes = linked_list_create();
876 this->encrypted = FALSE;
877 this->crypto = crypto;
878 this->p_bit = TRUE;
879 this->mac = chunk_empty;
880 this->encr = chunk_empty;
881 this->iv = chunk_empty;
882 this->hdr = malloc(data.len);
883 memcpy(this->hdr, hdr, data.len);
884
885 return &this->public;
886 }
887
888 /**
889 * See header.
890 */
891 simaka_message_t *simaka_message_create_from_payload(eap_payload_t *payload,
892 simaka_crypto_t *crypto)
893 {
894 return simaka_message_create_data(payload->get_data(payload), crypto);
895 }
896
897 /**
898 * See header.
899 */
900 simaka_message_t *simaka_message_create(bool request, u_int8_t identifier,
901 eap_type_t type, simaka_subtype_t subtype,
902 simaka_crypto_t *crypto)
903 {
904 hdr_t hdr = {
905 .code = request ? EAP_REQUEST : EAP_RESPONSE,
906 .identifier = identifier,
907 .length = htons(sizeof(hdr_t)),
908 .type = type,
909 .subtype = subtype,
910 };
911 return simaka_message_create_data(chunk_create((char*)&hdr, sizeof(hdr)),
912 crypto);
913 }
914