⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eapsimlib.c

📁 RADIUS认证协议
💻 C
字号:
/* * eapsimlib.c    based upon draft-haverinen-pppext-eap-sim-11.txt. * * The development of the EAP/SIM support was funded by Internet Foundation * Austria (http://www.nic.at/ipa). * * code common to EAP-SIM clients and to servers. * * Version:     $Id: eapsimlib.c,v 1.7.2.2 2005/01/26 20:31:31 aland Exp $ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * Copyright 2000-2003  The FreeRADIUS server project * Copyright 2003  Michael Richardson <mcr@sandelman.ottawa.on.ca> *//* *  EAP-SIM PACKET FORMAT *  ------- ------ ------ * * EAP Request and Response Packet Format * --- ------- --- -------- ------ ------ *  0                   1                   2                   3 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |     Code      |  Identifier   |            Length             | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |     Type      |  SIM-Type     |   SIM-Length  |     value ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * with SIM-Type/SIM-Length/Value... repeating. SIM-Length is in units * of 32 bits, and includes the Sim-Type/Sim-Length fields. * * The SIM-Type's are mapped to ATTRIBUTE_EAP_SIM_BASE+Sim-type and * unmapped by these functions. * */#include "libradius.h"#include "eap_types.h"#include "eap_sim.h"#include "sha1.h"static const char rcsid[] = "$Id: eapsimlib.c,v 1.7.2.2 2005/01/26 20:31:31 aland Exp $";/* * given a radius request with many attribues in the EAP-SIM range, build * them all into a single EAP-SIM body. * */int map_eapsim_basictypes(RADIUS_PACKET *r, EAP_PACKET *ep){	VALUE_PAIR       *vp;	int               encoded_size;	uint8_t          *encodedmsg, *attr;	unsigned int      id, eapcode;	unsigned char    *macspace, *append;	int               appendlen;	unsigned char     subtype;	macspace = NULL;	append = NULL;	appendlen = 0;	/*	 * encodedmsg is now an EAP-SIM message.	 * it might be too big for putting into an EAP-Type-SIM	 *	 */	vp = pairfind(r->vps, ATTRIBUTE_EAP_SIM_SUBTYPE);	if(vp == NULL)	{		subtype = eapsim_start;	}	else	{		subtype = vp->lvalue;	}	vp = pairfind(r->vps, ATTRIBUTE_EAP_ID);	if(vp == NULL)	{		id = ((int)getpid() & 0xff);	}	else	{		id = vp->lvalue;	}	vp = pairfind(r->vps, ATTRIBUTE_EAP_CODE);	if(vp == NULL)	{		eapcode = PW_EAP_REQUEST;	}	else	{		eapcode = vp->lvalue;	}	/*	 * take a walk through the attribute list to see how much space	 * that we need to encode all of this.	 */	encoded_size = 0;	for(vp = r->vps; vp != NULL; vp = vp->next)	{		int roundedlen;		int vplen;		if(vp->attribute < ATTRIBUTE_EAP_SIM_BASE ||		   vp->attribute >= ATTRIBUTE_EAP_SIM_BASE+256)		{			continue;		}		vplen = vp->length;		/*		 * the AT_MAC attribute is a bit different, when we get to this		 * attribute, we pull the contents out, save it for later		 * processing, set the size to 16 bytes (plus 2 bytes padding).		 * 		 * At this point, we only care about the size.		 */		if(vp->attribute == ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC) {			vplen = 18;		}		/* round up to next multiple of 4, after taking in		 * account the type and length bytes		 */		roundedlen = (vplen + 2 + 3) & ~3;		encoded_size += roundedlen;	}	if (ep->code != PW_EAP_SUCCESS)		ep->code = eapcode;	ep->id = (id & 0xff);	ep->type.type = PW_EAP_SIM;	/*	 * if no attributes were found, do very little.	 *	 */	if(encoded_size == 0)	{	        encodedmsg = malloc(3);		/* FIX: could be NULL */		encodedmsg[0]=subtype;		encodedmsg[1]=0;		encodedmsg[2]=0;		ep->type.length = 3;		ep->type.data = encodedmsg;		return 0;	}	/*	 * figured out the length, so malloc some space for the results.	 *	 * Note that we do not bother going through an "EAP" stage, which	 * is a bit strange compared to the unmap, which expects to see	 * an EAP-SIM virtual attributes.	 *	 * EAP is 1-code, 1-identifier, 2-length, 1-type = 5 overhead.	 *	 * SIM code adds a subtype, and 2 bytes of reserved = 3.	 *	 */	/* malloc space for it */	encoded_size += 3;	encodedmsg = malloc(encoded_size);	if (encodedmsg == NULL) {		radlog(L_ERR, "eapsim: out of memory allocating %d bytes", encoded_size+5);		return 0;	}	memset(encodedmsg, 0, encoded_size);	/*	 * now walk the attributes again, sticking them in.	 *	 * we go three bytes into the encoded message, because there are two	 * bytes of reserved, and we will fill the "subtype" in later.	 *	 */	attr = encodedmsg+3;	for(vp = r->vps; vp != NULL; vp = vp->next)	{		int roundedlen;		if(vp->attribute < ATTRIBUTE_EAP_SIM_BASE ||		   vp->attribute >= ATTRIBUTE_EAP_SIM_BASE+256)		{			continue;		}		/*		 * the AT_MAC attribute is a bit different, when we get to this		 * attribute, we pull the contents out, save it for later		 * processing, set the size to 16 bytes (plus 2 bytes padding).		 * 		 * At this point, we put in zeros, and remember where the		 * sixteen bytes go.		 */		if(vp->attribute == ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC) {			roundedlen = 20;			memset(&attr[2], 0, 18);			macspace = &attr[4];			append = vp->strvalue;			appendlen = vp->length;		}		else {			roundedlen = (vp->length + 2 + 3) & ~3;			memset(attr, 0, roundedlen);			memcpy(&attr[2], vp->strvalue, vp->length);		}		attr[0] = vp->attribute - ATTRIBUTE_EAP_SIM_BASE;		attr[1] = roundedlen >> 2;		attr += roundedlen;	}	encodedmsg[0] = subtype;	ep->type.length = encoded_size;	ep->type.data = encodedmsg;	/*	 * if macspace was set and we have a key,	 * then we should calculate the HMAC-SHA1 of the resulting EAP-SIM	 * packet, appended with the value of append.	 */	vp = pairfind(r->vps, ATTRIBUTE_EAP_SIM_KEY);	if(macspace != NULL && vp != NULL)	{		unsigned char   *buffer;		eap_packet_t	*hdr;		uint16_t         hmaclen, total_length = 0;		unsigned char    sha1digest[20];		total_length = EAP_HEADER_LEN + 1 + encoded_size;		hmaclen = total_length + appendlen;		buffer = (unsigned char *)malloc(hmaclen);		hdr = (eap_packet_t *)buffer;		if (!hdr) {			radlog(L_ERR, "rlm_eap: out of memory");			free(encodedmsg);			return 0;		}		hdr->code = eapcode & 0xFF;		hdr->id = (id & 0xFF);		total_length = htons(total_length);		memcpy(hdr->length, &total_length, sizeof(uint16_t));		hdr->data[0] = PW_EAP_SIM;		/* copy the data */		memcpy(&hdr->data[1], encodedmsg, encoded_size);		/* copy the nonce */		memcpy(&hdr->data[encoded_size+1], append, appendlen);		/* HMAC it! */		lrad_hmac_sha1(buffer, hmaclen,			       vp->strvalue, vp->length,			       sha1digest);		/* done with the buffer, free it */		free(buffer);		/* now copy the digest to where it belongs in the AT_MAC */                /* note that it is truncated to 128-bits */		memcpy(macspace, sha1digest, 16);	}	/* if we had an AT_MAC and no key, then fail */	if(macspace != NULL && vp == NULL)	{		if(encodedmsg != NULL)			free(encodedmsg);		return 0;	}	return 1;}int map_eapsim_types(RADIUS_PACKET *r){	EAP_PACKET ep;	int ret;	memset(&ep, 0, sizeof(ep));	ret = map_eapsim_basictypes(r, &ep);	if(ret != 1) {		return ret;	}	eap_basic_compose(r, &ep);	return 1;}/* * given a radius request with an EAP-SIM body, decode it into TLV pairs * * return value is TRUE if it succeeded, false if there was something * wrong and the packet should be discarded. * */int unmap_eapsim_basictypes(RADIUS_PACKET *r,			    uint8_t *attr, unsigned int attrlen){	VALUE_PAIR              *newvp;	int                     eapsim_attribute;	unsigned int            eapsim_len;	int                     es_attribute_count;	es_attribute_count=0;	/* big enough to have even a single attribute */	if(attrlen < 5) {		radlog(L_ERR, "eap: EAP-Sim attribute too short: %d < 2", attrlen);		return 0;	}	newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, PW_TYPE_INTEGER);	newvp->lvalue = attr[0];	newvp->length = 1;	pairadd(&(r->vps), newvp);	attr     += 3;	attrlen  -= 3;	/* now, loop processing each attribute that we find */	while(attrlen > 0)	{		if(attrlen < 2) {			radlog(L_ERR, "eap: EAP-Sim attribute %d too short: %d < 2", es_attribute_count, attrlen);			return 0;		}		eapsim_attribute = attr[0];		eapsim_len = attr[1] * 4;		if(eapsim_len > attrlen) {			radlog(L_ERR, "eap: EAP-Sim attribute %d (no.%d) has length longer than data (%d > %d)"			       , eapsim_attribute			       , es_attribute_count, eapsim_len, attrlen);			return 0;		}		if(eapsim_len > MAX_STRING_LEN) {			eapsim_len = MAX_STRING_LEN;		}		if (eapsim_len < 2) {			radlog(L_ERR, "eap: EAP-Sim attribute %d (no.%d) has length too small",			       eapsim_attribute, es_attribute_count);			       return 0;		}		newvp = paircreate(eapsim_attribute+ATTRIBUTE_EAP_SIM_BASE, PW_TYPE_OCTETS);		memcpy(newvp->strvalue, &attr[2], eapsim_len-2);		newvp->length = eapsim_len-2;		pairadd(&(r->vps), newvp);		newvp = NULL;		/* advance pointers, decrement length */		attr += eapsim_len;		attrlen  -= eapsim_len;		es_attribute_count++;	}	return 1;}int unmap_eapsim_types(RADIUS_PACKET *r){	VALUE_PAIR             *esvp;	esvp = pairfind(r->vps, ATTRIBUTE_EAP_BASE+PW_EAP_SIM);	if (esvp == NULL) {		radlog(L_ERR, "eap: EAP-Sim attribute not found");		return 0;	}	return unmap_eapsim_basictypes(r, esvp->strvalue, esvp->length);}/* * calculate the MAC for the EAP message, given the key. * The "extra" will be appended to the EAP message and included in the * HMAC. * */inteapsim_checkmac(VALUE_PAIR *rvps,		uint8_t key[EAPSIM_AUTH_SIZE],		uint8_t *extra, int extralen,		uint8_t calcmac[20]){	int ret;	eap_packet_t *e;	uint8_t *buffer;	int elen,len;	VALUE_PAIR *mac;	mac = pairfind(rvps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC);	if(mac == NULL	   || mac->length != 18) {		/* can't check a packet with no AT_MAC attribute */		return 0;	}	/* get original copy of EAP message, note that it was sanitized	 * to have a valid length, which we depend upon.	 */	e = eap_attribute(rvps);	if(e == NULL)	{		return 0;	}	/* make copy big enough for everything */	elen = e->length[0]*256 + e->length[1];	len = elen + extralen;	buffer = malloc(len);	if(buffer == NULL)	{		free(e);		return 0;	}	memcpy(buffer, e, elen);	memcpy(buffer+elen, extra, extralen);	/*	 * now look for the AT_MAC attribute in the copy of the buffer	 * and make sure that the checksum is zero.	 *	 */	{		uint8_t *attr;		/* first attribute is 8 bytes into the EAP packet.		 * 4 bytes for EAP, 1 for type, 1 for subtype, 2 reserved.		 */		attr = buffer+8;		while(attr < (buffer+elen)) {			if(attr[0] == PW_EAP_SIM_MAC) {				/* zero the data portion, after making sure				 * the size is >=5. Maybe future versions.				 * will use more bytes, so be liberal.				 */				if(attr[1] < 5) {					ret = 0;					goto done;				}				memset(&attr[4], 0, (attr[1]-1)*4);			}			/* advance the pointer */			attr += attr[1]*4;		}	}	/* now, HMAC-SHA1 it with the key. */	lrad_hmac_sha1(buffer, len,		       key, 16,		       calcmac);	if(memcmp(&mac->strvalue[2], calcmac, 16) == 0)	{		ret = 1;	} else {		ret = 0;	} done:	free(e);	free(buffer);	return(ret);}/* * definitions changed to take a buffer for unknowns * as this is more thread safe. */const char *simstates[]={ "init", "start", NULL };const char *sim_state2name(enum eapsim_clientstates state,			   char *statenamebuf,			   int   statenamebuflen){	if(state >= eapsim_client_maxstates)	{		snprintf(statenamebuf, statenamebuflen,			 "eapstate:%d", state);		return statenamebuf;	}	else	{		return simstates[state];	}}const char *subtypes[]={ "subtype0", "subtype1", "subtype2", "subtype3",			 "subtype4", "subtype5", "subtype6", "subtype7",			 "subtype8", "subtype9",			 "start",			 "challenge",			 "notification",			 "reauth",			 NULL };const char *sim_subtype2name(enum eapsim_subtype subtype,			     char *subtypenamebuf,			     int   subtypenamebuflen){	if(subtype >= eapsim_max_subtype)	{		snprintf(subtypenamebuf, subtypenamebuflen,			 "illegal-subtype:%d", subtype);		return subtypenamebuf;	}	else	{		return subtypes[subtype];	}}#ifdef TEST_CASE#include <assert.h>const char *radius_dir = RADDBDIR;int radlog(int lvl, const char *msg, ...){	va_list ap;	int r;	va_start(ap, msg);	r = vfprintf(stderr, msg, ap);	va_end(ap);	fputc('\n', stderr);	return r;}main(int argc, char *argv[]){	int filedone;	RADIUS_PACKET *req,*req2;	VALUE_PAIR *vp, *vpkey, *vpextra;	extern unsigned int sha1_data_problems;	req = NULL;	req2 = NULL;	filedone = 0;	if(argc>1) {	  sha1_data_problems = 1;	}	if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {		librad_perror("radclient");		return 1;	}	if ((req = rad_alloc(1)) == NULL) {		librad_perror("radclient");		exit(1);	}	if ((req2 = rad_alloc(1)) == NULL) {		librad_perror("radclient");		exit(1);	}	while(!filedone) {		if(req->vps) pairfree(&req->vps);		if(req2->vps) pairfree(&req2->vps);		if ((req->vps = readvp2(stdin, &filedone, "eapsimlib:")) == NULL) {			break;		}		printf("\nRead:\n");		vp_printlist(stdout, req->vps);		map_eapsim_types(req);		map_eap_types(req);		printf("Mapped to:\n");		vp_printlist(stdout, req->vps);		/* find the EAP-Message, copy it to req2 */		vp = paircopy2(req->vps, PW_EAP_MESSAGE);		if(vp == NULL) continue;		pairadd(&req2->vps, vp);		/* only call unmap for sim types here */		unmap_eap_types(req2);		unmap_eapsim_types(req2);		printf("Unmapped to:\n");		vp_printlist(stdout, req2->vps);		vp = pairfind(req2->vps,			      ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC);		vpkey   = pairfind(req->vps, ATTRIBUTE_EAP_SIM_KEY);		vpextra = pairfind(req->vps, ATTRIBUTE_EAP_SIM_EXTRA);		if(vp != NULL && vpkey != NULL && vpextra!=NULL) {			uint8_t calcmac[16];			/* find the EAP-Message, copy it to req2 */			memset(calcmac, 0, sizeof(calcmac));			printf("Confirming MAC...");			if(eapsim_checkmac(req2->vps, vpkey->strvalue,					   vpextra->strvalue, vpextra->length,					   calcmac)) {				printf("succeed\n");			} else {				int i, j;				printf("calculated MAC (");				for (i = 0; i < 20; i++) {					if(j==4) {						printf("_");						j=0;					}					j++;					printf("%02x", calcmac[i]);				}				printf(" did not match\n");			}		}		fflush(stdout);	}}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -