2 * eap_md5.c EAP MD5 functionality.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2000,2001 The FreeRADIUS server project
21 * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
26 * MD5 Packet Format in EAP Type-Data
27 * --- ------ ------ -- --- ---------
29 * 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
30 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31 * | Value-Size | Value ...
32 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * Allocate a new MD5_PACKET
46 MD5_PACKET *eapmd5_alloc(void)
50 if ((rp = malloc(sizeof(MD5_PACKET))) == NULL) {
51 radlog(L_ERR, "rlm_eap_md5: out of memory");
54 memset(rp, 0, sizeof(MD5_PACKET));
61 void eapmd5_free(MD5_PACKET **md5_packet_ptr)
63 MD5_PACKET *md5_packet;
65 if (!md5_packet_ptr) return;
66 md5_packet = *md5_packet_ptr;
67 if (md5_packet == NULL) return;
69 if (md5_packet->value) free(md5_packet->value);
70 if (md5_packet->name) free(md5_packet->name);
74 *md5_packet_ptr = NULL;
78 * We expect only RESPONSE for which CHALLENGE, SUCCESS or FAILURE is sent back
80 MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds)
88 (eap_ds->response->code != PW_MD5_RESPONSE) ||
89 eap_ds->response->type.type != PW_EAP_MD5 ||
90 !eap_ds->response->type.data ||
91 (eap_ds->response->length < MD5_HEADER_LEN) ||
92 (eap_ds->response->type.data[0] <= 0) ) {
93 radlog(L_ERR, "rlm_eap_md5: corrupted data");
97 packet = eapmd5_alloc();
98 if (!packet) return NULL;
101 * Code, id & length for MD5 & EAP are same
102 * but md5_length = eap_length - 1(Type = 1 octet)
104 packet->code = eap_ds->response->code;
105 packet->id = eap_ds->response->id;
106 packet->length = eap_ds->response->length - 1;
107 packet->value_size = 0;
108 packet->value = NULL;
111 data = (md5_packet_t *)eap_ds->response->type.data;
113 packet->value_size = data->value_size;
115 packet->value = malloc(packet->value_size);
116 if (packet->value == NULL) {
117 radlog(L_ERR, "rlm_eap_md5: out of memory");
118 eapmd5_free(&packet);
121 memcpy(packet->value, data->value_name, packet->value_size);
124 * Name is optional and is present after Value, but we need to check for it
126 name_len = packet->length - (packet->value_size + 5);
128 packet->name = malloc(name_len+1);
130 radlog(L_ERR, "rlm_eap_md5: out of memory");
131 eapmd5_free(&packet);
134 memset(packet->name, 0, name_len+1);
135 memcpy(packet->name, data->value_name+packet->value_size, name_len);
142 * Identify whether the response that you got is either the
143 * response to the challenge that we sent or a new one.
144 * If it is a response to the request then issue success/failure
145 * else issue a challenge
147 MD5_PACKET *eapmd5_process(MD5_PACKET *packet, int id,
148 VALUE_PAIR *username, VALUE_PAIR* password, md5_packet_t *request)
150 unsigned char output[MAX_STRING_LEN];
153 if (!username || !password || !packet)
156 reply = eapmd5_alloc();
157 if (!reply) return NULL;
158 memset(output, 0, MAX_STRING_LEN);
162 /* verify and issue Success/failure */
163 eapmd5_challenge(packet->id, password->strvalue, password->length,
164 request->value_name, request->value_size, output);
166 if (memcmp(output, packet->value, packet->value_size) != 0) {
167 radlog(L_INFO, "rlm_eap_md5: Challenge failed");
168 reply->code = PW_MD5_FAILURE;
171 reply->code = PW_MD5_SUCCESS;
175 * Issue a challenge, value is a random number.
176 * If no value then generate some random number
178 eapmd5_challenge(id, password->strvalue, password->length,
179 packet->value, packet->value_size, output);
180 radlog(L_INFO, "rlm_eap_md5: Issuing Challenge to the user - %s",
181 (char *)username->strvalue);
182 reply->code = PW_MD5_CHALLENGE;
185 /* fill reply packet */
186 if (reply->code == PW_MD5_CHALLENGE) {
187 reply->value_size = packet->value_size;
188 reply->value = malloc(reply->value_size);
189 if (reply->value == NULL) {
190 radlog(L_ERR, "rlm_eap_md5: out of memory");
194 memcpy(reply->value, output, reply->value_size);
195 reply->length = packet->length;
197 reply->length = MD5_HEADER_LEN;
204 * If an EAP MD5 request needs to be initiated then
205 * create such a packet.
207 MD5_PACKET *eapmd5_initiate(EAP_DS *eap_ds)
211 reply = eapmd5_alloc();
213 radlog(L_ERR, "rlm_eap_md5: out of memory");
217 reply->code = PW_MD5_CHALLENGE;
218 reply->length = MD5_HEADER_LEN + 1 + MD5_LEN;
219 reply->value_size = MD5_LEN;
221 reply->value = malloc(reply->value_size);
222 if (reply->value == NULL) {
223 radlog(L_ERR, "rlm_eap_md5: out of memory");
229 * generate some random challenge value
231 * TODO: Make sure Challenge is always unique,
232 * no matter how many times it is called
234 librad_md5_calc((uint8_t *)reply->value, (uint8_t *)reply->value, MD5_LEN);
240 * challenge = MD5(id+password+MD5(random))
242 int eapmd5_challenge(int id,
243 unsigned char *password, int pass_len,
244 unsigned char *challenge, int challenge_len,
245 unsigned char *output)
249 char string[MAX_STRING_LEN];
251 if ((password == NULL) || (challenge == NULL)) {
260 memcpy(ptr, password, pass_len);
264 memcpy(ptr, challenge, challenge_len);
265 len += challenge_len;
267 librad_md5_calc((u_char *)output, (u_char *)string, len);
273 * compose the MD5 reply packet in the EAP reply typedata
275 int eapmd5_compose(EAP_DS *eap_ds, MD5_PACKET *reply)
280 if (reply->code < 3) {
282 eap_ds->request->type.type = PW_EAP_MD5;
284 eap_ds->request->type.data = malloc(reply->length - 4);
285 if (eap_ds->request->type.data == NULL) {
286 radlog(L_ERR, "rlm_eap_md5: out of memory");
289 ptr = eap_ds->request->type.data;
290 *ptr++ = (uint8_t)(reply->value_size & 0xFF);
291 memcpy(ptr, reply->value, reply->value_size);
293 eap_ds->request->type.length = reply->value_size + 1;
295 name_len = reply->length - (reply->value_size + 5);
296 if (reply->name && name_len) {
297 ptr += reply->value_size;
298 memcpy(ptr, reply->name, name_len);
299 eap_ds->request->type.length += name_len;
303 eap_ds->request->type.length = 0;
304 /* TODO: In future we might add message here wrt rfc1994 */
306 eap_ds->request->code = reply->code;