1: /*
2: * Copyright (C) 2009 Martin Willi
3: * HSR 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: /** attribute 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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>