File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libsimaka / simaka_message.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:43 2020 UTC (4 years, 3 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    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>