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