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