xref: /freebsd/contrib/wpa/src/eap_server/eap_server_md5.c (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * hostapd / EAP-MD5 server
3f05cddf9SRui Paulo  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "common.h"
12f05cddf9SRui Paulo #include "crypto/random.h"
13e28a4053SRui Paulo #include "eap_i.h"
14e28a4053SRui Paulo #include "eap_common/chap.h"
15e28a4053SRui Paulo 
16e28a4053SRui Paulo 
17e28a4053SRui Paulo #define CHALLENGE_LEN 16
18e28a4053SRui Paulo 
19e28a4053SRui Paulo struct eap_md5_data {
20e28a4053SRui Paulo 	u8 challenge[CHALLENGE_LEN];
21e28a4053SRui Paulo 	enum { CONTINUE, SUCCESS, FAILURE } state;
22e28a4053SRui Paulo };
23e28a4053SRui Paulo 
24e28a4053SRui Paulo 
eap_md5_init(struct eap_sm * sm)25e28a4053SRui Paulo static void * eap_md5_init(struct eap_sm *sm)
26e28a4053SRui Paulo {
27e28a4053SRui Paulo 	struct eap_md5_data *data;
28e28a4053SRui Paulo 
29e28a4053SRui Paulo 	data = os_zalloc(sizeof(*data));
30e28a4053SRui Paulo 	if (data == NULL)
31e28a4053SRui Paulo 		return NULL;
32e28a4053SRui Paulo 	data->state = CONTINUE;
33e28a4053SRui Paulo 
34e28a4053SRui Paulo 	return data;
35e28a4053SRui Paulo }
36e28a4053SRui Paulo 
37e28a4053SRui Paulo 
eap_md5_reset(struct eap_sm * sm,void * priv)38e28a4053SRui Paulo static void eap_md5_reset(struct eap_sm *sm, void *priv)
39e28a4053SRui Paulo {
40e28a4053SRui Paulo 	struct eap_md5_data *data = priv;
41e28a4053SRui Paulo 	os_free(data);
42e28a4053SRui Paulo }
43e28a4053SRui Paulo 
44e28a4053SRui Paulo 
eap_md5_buildReq(struct eap_sm * sm,void * priv,u8 id)45e28a4053SRui Paulo static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id)
46e28a4053SRui Paulo {
47e28a4053SRui Paulo 	struct eap_md5_data *data = priv;
48e28a4053SRui Paulo 	struct wpabuf *req;
49e28a4053SRui Paulo 
50f05cddf9SRui Paulo 	if (random_get_bytes(data->challenge, CHALLENGE_LEN)) {
51e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data");
52e28a4053SRui Paulo 		data->state = FAILURE;
53e28a4053SRui Paulo 		return NULL;
54e28a4053SRui Paulo 	}
55e28a4053SRui Paulo 
56e28a4053SRui Paulo 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHALLENGE_LEN,
57e28a4053SRui Paulo 			    EAP_CODE_REQUEST, id);
58e28a4053SRui Paulo 	if (req == NULL) {
59e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for "
60e28a4053SRui Paulo 			   "request");
61e28a4053SRui Paulo 		data->state = FAILURE;
62e28a4053SRui Paulo 		return NULL;
63e28a4053SRui Paulo 	}
64e28a4053SRui Paulo 
65e28a4053SRui Paulo 	wpabuf_put_u8(req, CHALLENGE_LEN);
66e28a4053SRui Paulo 	wpabuf_put_data(req, data->challenge, CHALLENGE_LEN);
67e28a4053SRui Paulo 	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", data->challenge,
68e28a4053SRui Paulo 		    CHALLENGE_LEN);
69e28a4053SRui Paulo 
70e28a4053SRui Paulo 	data->state = CONTINUE;
71e28a4053SRui Paulo 
72e28a4053SRui Paulo 	return req;
73e28a4053SRui Paulo }
74e28a4053SRui Paulo 
75e28a4053SRui Paulo 
eap_md5_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)76*c1d255d3SCy Schubert static bool eap_md5_check(struct eap_sm *sm, void *priv,
77e28a4053SRui Paulo 			  struct wpabuf *respData)
78e28a4053SRui Paulo {
79e28a4053SRui Paulo 	const u8 *pos;
80e28a4053SRui Paulo 	size_t len;
81e28a4053SRui Paulo 
82e28a4053SRui Paulo 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len);
83e28a4053SRui Paulo 	if (pos == NULL || len < 1) {
84e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
85*c1d255d3SCy Schubert 		return true;
86e28a4053SRui Paulo 	}
87e28a4053SRui Paulo 	if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) {
88e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "EAP-MD5: Invalid response "
89e28a4053SRui Paulo 			   "(response_len=%d payload_len=%lu",
90e28a4053SRui Paulo 			   *pos, (unsigned long) len);
91*c1d255d3SCy Schubert 		return true;
92e28a4053SRui Paulo 	}
93e28a4053SRui Paulo 
94*c1d255d3SCy Schubert 	return false;
95e28a4053SRui Paulo }
96e28a4053SRui Paulo 
97e28a4053SRui Paulo 
eap_md5_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)98e28a4053SRui Paulo static void eap_md5_process(struct eap_sm *sm, void *priv,
99e28a4053SRui Paulo 			    struct wpabuf *respData)
100e28a4053SRui Paulo {
101e28a4053SRui Paulo 	struct eap_md5_data *data = priv;
102e28a4053SRui Paulo 	const u8 *pos;
103e28a4053SRui Paulo 	size_t plen;
104e28a4053SRui Paulo 	u8 hash[CHAP_MD5_LEN], id;
105e28a4053SRui Paulo 
106e28a4053SRui Paulo 	if (sm->user == NULL || sm->user->password == NULL ||
107e28a4053SRui Paulo 	    sm->user->password_hash) {
108e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not "
109e28a4053SRui Paulo 			   "configured");
110e28a4053SRui Paulo 		data->state = FAILURE;
111e28a4053SRui Paulo 		return;
112e28a4053SRui Paulo 	}
113e28a4053SRui Paulo 
114e28a4053SRui Paulo 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen);
115e28a4053SRui Paulo 	if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN)
116e28a4053SRui Paulo 		return; /* Should not happen - frame already validated */
117e28a4053SRui Paulo 
118e28a4053SRui Paulo 	pos++; /* Skip response len */
119e28a4053SRui Paulo 	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN);
120e28a4053SRui Paulo 
121e28a4053SRui Paulo 	id = eap_get_id(respData);
122f05cddf9SRui Paulo 	if (chap_md5(id, sm->user->password, sm->user->password_len,
123f05cddf9SRui Paulo 		     data->challenge, CHALLENGE_LEN, hash)) {
124f05cddf9SRui Paulo 		wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
125f05cddf9SRui Paulo 		data->state = FAILURE;
126f05cddf9SRui Paulo 		return;
127f05cddf9SRui Paulo 	}
128e28a4053SRui Paulo 
1295b9c547cSRui Paulo 	if (os_memcmp_const(hash, pos, CHAP_MD5_LEN) == 0) {
130e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
131e28a4053SRui Paulo 		data->state = SUCCESS;
132e28a4053SRui Paulo 	} else {
133e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure");
134e28a4053SRui Paulo 		data->state = FAILURE;
135e28a4053SRui Paulo 	}
136e28a4053SRui Paulo }
137e28a4053SRui Paulo 
138e28a4053SRui Paulo 
eap_md5_isDone(struct eap_sm * sm,void * priv)139*c1d255d3SCy Schubert static bool eap_md5_isDone(struct eap_sm *sm, void *priv)
140e28a4053SRui Paulo {
141e28a4053SRui Paulo 	struct eap_md5_data *data = priv;
142e28a4053SRui Paulo 	return data->state != CONTINUE;
143e28a4053SRui Paulo }
144e28a4053SRui Paulo 
145e28a4053SRui Paulo 
eap_md5_isSuccess(struct eap_sm * sm,void * priv)146*c1d255d3SCy Schubert static bool eap_md5_isSuccess(struct eap_sm *sm, void *priv)
147e28a4053SRui Paulo {
148e28a4053SRui Paulo 	struct eap_md5_data *data = priv;
149e28a4053SRui Paulo 	return data->state == SUCCESS;
150e28a4053SRui Paulo }
151e28a4053SRui Paulo 
152e28a4053SRui Paulo 
eap_server_md5_register(void)153e28a4053SRui Paulo int eap_server_md5_register(void)
154e28a4053SRui Paulo {
155e28a4053SRui Paulo 	struct eap_method *eap;
156e28a4053SRui Paulo 
157e28a4053SRui Paulo 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
158e28a4053SRui Paulo 				      EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
159e28a4053SRui Paulo 	if (eap == NULL)
160e28a4053SRui Paulo 		return -1;
161e28a4053SRui Paulo 
162e28a4053SRui Paulo 	eap->init = eap_md5_init;
163e28a4053SRui Paulo 	eap->reset = eap_md5_reset;
164e28a4053SRui Paulo 	eap->buildReq = eap_md5_buildReq;
165e28a4053SRui Paulo 	eap->check = eap_md5_check;
166e28a4053SRui Paulo 	eap->process = eap_md5_process;
167e28a4053SRui Paulo 	eap->isDone = eap_md5_isDone;
168e28a4053SRui Paulo 	eap->isSuccess = eap_md5_isSuccess;
169e28a4053SRui Paulo 
170780fb4a2SCy Schubert 	return eap_server_method_register(eap);
171e28a4053SRui Paulo }
172