📄 state.c
字号:
/* * state.c To generate and verify State attribute * * $Id: state.c,v 1.10 2004/03/19 02:22:16 mcr 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 2001 hereUare Communications, Inc. <raghud@hereuare.com> */#include <fcntl.h>#include <stdlib.h>#include <string.h>#include "rlm_eap.h"static const char rcsid[] = "$Id: state.c,v 1.10 2004/03/19 02:22:16 mcr Exp $";/* * Global key to generate & verify State * * This is needed only once per instance of the server, * and putting it in the rlm_eap_t is just too much effort. * * Putting it here is ugly, but it works. */static int key_initialized = 0;static unsigned char state_key[AUTH_VECTOR_LEN];/* * Generate & Verify the State attribute * * In the simplest implementation, we would just use the * challenge as state. Unfortunately, the RADIUS secret protects * only the User-Password attribute; an attacker that can remove * packets from the wire and insert new ones can simply insert a * replayed state without having to know the secret. * * However, RADIUS packets containing EAP conversations MUST be * signed with Message-Authenticator, at which point, they MUST * know the secret, in order to get to the EAP module. And if * they know the secret, they can do many worse things than * re-playing a State attribute. Their only alternative is to * re-play entire packets, which is caught by the server core. * * In any case, we sign our state with data unique to this * specific request. A NAS would use the Request Authenticator, * we don't know what that will be when the State is returned to * us, so we'll use a time stamp. * * Our replay prevention is limited to a time interval * (inst->maxdelay). We could keep track of all challenges * issued over that time interval, to ensure that the challenges * were unique. However, they're 8-bytes of data from a good * PRNG, which means that it's pretty damn unlikely that they'll * be re-used. * * Our state, then, is (challenge + hmac(challenge + time, key)), * where '+' denotes concatentation, 'challenge' is the octets * of the challenge, 'time' is the 'time_t' in host byte order, * and 'key' is a random key, generated once in eap_init(). * * This means that only the server which generates a challenge * can verify it; this should be OK if your NAS's load balance * across RADIUS servers by a "first available" algorithm. If * your NAS's round-robin (ugh), you could use the RADIUS * secret instead, but read RFC 2104 first, and make very sure * you really want to do this. */void generate_key(void){ unsigned int i; if (key_initialized) return; /* * Use a cryptographically strong method to generate * pseudo-random numbers. */ for (i = 0; i < sizeof(state_key); i++) { state_key[i] = lrad_rand(); } key_initialized = 1;}/* * For clarity. Also, to avoid giving away * too much information, we only put 8 octets of the HMAC * into the State attribute, instead of all 16. * * As a security feature, it's a little hokey, but WTF. * * Also, ensure that EAP_CHALLENGE_LEN + EAP_USE_OF_HMAC = EAP_STATE_LEN */#define EAP_CHALLENGE_LEN (8)#define EAP_HMAC_SIZE (16)#define EAP_USE_OF_HMAC (8)/* * Our state, is (challenge + time + hmac(challenge + time, key)) * * If it's too long, then some clients chop it (sigh) */VALUE_PAIR *generate_state(time_t timestamp){ unsigned int i; unsigned char challenge[EAP_CHALLENGE_LEN]; unsigned char hmac[EAP_HMAC_SIZE]; unsigned char value[EAP_CHALLENGE_LEN + sizeof(timestamp)]; VALUE_PAIR *state; /* Generate challenge (a random value). */ for (i = 0; i < sizeof(challenge); i++) { challenge[i] = lrad_rand(); } memcpy(value, challenge, sizeof(challenge)); memcpy(value + sizeof(challenge), ×tamp, sizeof(timestamp)); /* * hmac(challenge + timestamp) */ lrad_hmac_md5(value, sizeof(value), state_key, sizeof(state_key), hmac); /* * Create the state attribute. * * Note that the timestamp is used internally, but is NOT * sent to the client! */ state = paircreate(PW_STATE, PW_TYPE_OCTETS); if (state == NULL) { radlog(L_ERR, "rlm_eap: out of memory"); return NULL; } memcpy(state->strvalue, challenge, sizeof(challenge)); memcpy(state->strvalue + sizeof(challenge), hmac, EAP_USE_OF_HMAC); state->length = sizeof(challenge) + EAP_USE_OF_HMAC; return state;}/* * Returns 0 on success, non-zero otherwise. */int verify_state(VALUE_PAIR *state, time_t timestamp){ unsigned char hmac[EAP_HMAC_SIZE]; unsigned char value[EAP_CHALLENGE_LEN + sizeof(timestamp)]; /* * The length is wrong. Don't do anything. */ if (state->length != EAP_STATE_LEN) { return -1; } /* * The first 16 octets of the State attribute constains * the random challenge. */ memcpy(value, state->strvalue, EAP_CHALLENGE_LEN); memcpy(value + EAP_CHALLENGE_LEN, ×tamp, sizeof(timestamp)); /* Generate hmac. */ lrad_hmac_md5(value, sizeof(value), state_key, sizeof(state_key), hmac); /* * Compare the hmac we calculated to the one in the * packet. */ return memcmp(hmac, state->strvalue + EAP_CHALLENGE_LEN, EAP_USE_OF_HMAC);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -