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