WPS: Add explicit message length limit of 50000 bytes
[mech_eap.git] / src / eap_server / eap_server_tls.c
1 /*
2  * hostapd / EAP-TLS (RFC 2716)
3  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "eap_i.h"
13 #include "eap_tls_common.h"
14 #include "crypto/tls.h"
15
16
17 static void eap_tls_reset(struct eap_sm *sm, void *priv);
18
19
20 struct eap_tls_data {
21         struct eap_ssl_data ssl;
22         enum { START, CONTINUE, SUCCESS, FAILURE } state;
23         int established;
24         u8 eap_type;
25 };
26
27
28 static const char * eap_tls_state_txt(int state)
29 {
30         switch (state) {
31         case START:
32                 return "START";
33         case CONTINUE:
34                 return "CONTINUE";
35         case SUCCESS:
36                 return "SUCCESS";
37         case FAILURE:
38                 return "FAILURE";
39         default:
40                 return "Unknown?!";
41         }
42 }
43
44
45 static void eap_tls_state(struct eap_tls_data *data, int state)
46 {
47         wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
48                    eap_tls_state_txt(data->state),
49                    eap_tls_state_txt(state));
50         data->state = state;
51 }
52
53
54 static void * eap_tls_init(struct eap_sm *sm)
55 {
56         struct eap_tls_data *data;
57
58         data = os_zalloc(sizeof(*data));
59         if (data == NULL)
60                 return NULL;
61         data->state = START;
62
63         if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
64                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
65                 eap_tls_reset(sm, data);
66                 return NULL;
67         }
68
69         data->eap_type = EAP_TYPE_TLS;
70
71         return data;
72 }
73
74
75 #ifdef EAP_SERVER_UNAUTH_TLS
76 static void * eap_unauth_tls_init(struct eap_sm *sm)
77 {
78         struct eap_tls_data *data;
79
80         data = os_zalloc(sizeof(*data));
81         if (data == NULL)
82                 return NULL;
83         data->state = START;
84
85         if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
86                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
87                 eap_tls_reset(sm, data);
88                 return NULL;
89         }
90
91         data->eap_type = EAP_UNAUTH_TLS_TYPE;
92         return data;
93 }
94 #endif /* EAP_SERVER_UNAUTH_TLS */
95
96
97 #ifdef CONFIG_HS20
98 static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
99 {
100         struct eap_tls_data *data;
101
102         data = os_zalloc(sizeof(*data));
103         if (data == NULL)
104                 return NULL;
105         data->state = START;
106
107         if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
108                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
109                 eap_tls_reset(sm, data);
110                 return NULL;
111         }
112
113         data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
114         return data;
115 }
116 #endif /* CONFIG_HS20 */
117
118
119 static void eap_tls_reset(struct eap_sm *sm, void *priv)
120 {
121         struct eap_tls_data *data = priv;
122         if (data == NULL)
123                 return;
124         eap_server_tls_ssl_deinit(sm, &data->ssl);
125         os_free(data);
126 }
127
128
129 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
130                                            struct eap_tls_data *data, u8 id)
131 {
132         struct wpabuf *req;
133
134         req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
135         if (req == NULL) {
136                 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
137                            "request");
138                 eap_tls_state(data, FAILURE);
139                 return NULL;
140         }
141
142         wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
143
144         eap_tls_state(data, CONTINUE);
145
146         return req;
147 }
148
149
150 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
151 {
152         struct eap_tls_data *data = priv;
153         struct wpabuf *res;
154
155         if (data->ssl.state == FRAG_ACK) {
156                 return eap_server_tls_build_ack(id, data->eap_type, 0);
157         }
158
159         if (data->ssl.state == WAIT_FRAG_ACK) {
160                 res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
161                                                id);
162                 goto check_established;
163         }
164
165         switch (data->state) {
166         case START:
167                 return eap_tls_build_start(sm, data, id);
168         case CONTINUE:
169                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
170                         data->established = 1;
171                 break;
172         default:
173                 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
174                            __func__, data->state);
175                 return NULL;
176         }
177
178         res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
179
180 check_established:
181         if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
182                 /* TLS handshake has been completed and there are no more
183                  * fragments waiting to be sent out. */
184                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
185                 eap_tls_state(data, SUCCESS);
186         }
187
188         return res;
189 }
190
191
192 static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
193                              struct wpabuf *respData)
194 {
195         struct eap_tls_data *data = priv;
196         const u8 *pos;
197         size_t len;
198
199         if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
200                 pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
201                                        EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
202                                        &len);
203         else if (data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
204                 pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
205                                        EAP_VENDOR_WFA_UNAUTH_TLS, respData,
206                                        &len);
207         else
208                 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
209                                        respData, &len);
210         if (pos == NULL || len < 1) {
211                 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
212                 return TRUE;
213         }
214
215         return FALSE;
216 }
217
218
219 static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
220                                 const struct wpabuf *respData)
221 {
222         struct eap_tls_data *data = priv;
223         if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
224                 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
225                            "handshake message");
226                 return;
227         }
228         if (eap_server_tls_phase1(sm, &data->ssl) < 0)
229                 eap_tls_state(data, FAILURE);
230 }
231
232
233 static void eap_tls_process(struct eap_sm *sm, void *priv,
234                             struct wpabuf *respData)
235 {
236         struct eap_tls_data *data = priv;
237         if (eap_server_tls_process(sm, &data->ssl, respData, data,
238                                    data->eap_type, NULL, eap_tls_process_msg) <
239             0)
240                 eap_tls_state(data, FAILURE);
241 }
242
243
244 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
245 {
246         struct eap_tls_data *data = priv;
247         return data->state == SUCCESS || data->state == FAILURE;
248 }
249
250
251 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
252 {
253         struct eap_tls_data *data = priv;
254         u8 *eapKeyData;
255
256         if (data->state != SUCCESS)
257                 return NULL;
258
259         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
260                                                "client EAP encryption",
261                                                EAP_TLS_KEY_LEN);
262         if (eapKeyData) {
263                 *len = EAP_TLS_KEY_LEN;
264                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
265                             eapKeyData, EAP_TLS_KEY_LEN);
266         } else {
267                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
268         }
269
270         return eapKeyData;
271 }
272
273
274 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
275 {
276         struct eap_tls_data *data = priv;
277         u8 *eapKeyData, *emsk;
278
279         if (data->state != SUCCESS)
280                 return NULL;
281
282         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
283                                                "client EAP encryption",
284                                                EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
285         if (eapKeyData) {
286                 emsk = os_malloc(EAP_EMSK_LEN);
287                 if (emsk)
288                         os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
289                                   EAP_EMSK_LEN);
290                 os_free(eapKeyData);
291         } else
292                 emsk = NULL;
293
294         if (emsk) {
295                 *len = EAP_EMSK_LEN;
296                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
297                             emsk, EAP_EMSK_LEN);
298         } else {
299                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
300         }
301
302         return emsk;
303 }
304
305
306 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
307 {
308         struct eap_tls_data *data = priv;
309         return data->state == SUCCESS;
310 }
311
312
313 int eap_server_tls_register(void)
314 {
315         struct eap_method *eap;
316         int ret;
317
318         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
319                                       EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
320         if (eap == NULL)
321                 return -1;
322
323         eap->init = eap_tls_init;
324         eap->reset = eap_tls_reset;
325         eap->buildReq = eap_tls_buildReq;
326         eap->check = eap_tls_check;
327         eap->process = eap_tls_process;
328         eap->isDone = eap_tls_isDone;
329         eap->getKey = eap_tls_getKey;
330         eap->isSuccess = eap_tls_isSuccess;
331         eap->get_emsk = eap_tls_get_emsk;
332
333         ret = eap_server_method_register(eap);
334         if (ret)
335                 eap_server_method_free(eap);
336         return ret;
337 }
338
339
340 #ifdef EAP_SERVER_UNAUTH_TLS
341 int eap_server_unauth_tls_register(void)
342 {
343         struct eap_method *eap;
344         int ret;
345
346         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
347                                       EAP_VENDOR_UNAUTH_TLS,
348                                       EAP_VENDOR_TYPE_UNAUTH_TLS,
349                                       "UNAUTH-TLS");
350         if (eap == NULL)
351                 return -1;
352
353         eap->init = eap_unauth_tls_init;
354         eap->reset = eap_tls_reset;
355         eap->buildReq = eap_tls_buildReq;
356         eap->check = eap_tls_check;
357         eap->process = eap_tls_process;
358         eap->isDone = eap_tls_isDone;
359         eap->getKey = eap_tls_getKey;
360         eap->isSuccess = eap_tls_isSuccess;
361         eap->get_emsk = eap_tls_get_emsk;
362
363         ret = eap_server_method_register(eap);
364         if (ret)
365                 eap_server_method_free(eap);
366         return ret;
367 }
368 #endif /* EAP_SERVER_UNAUTH_TLS */
369
370
371 #ifdef CONFIG_HS20
372 int eap_server_wfa_unauth_tls_register(void)
373 {
374         struct eap_method *eap;
375         int ret;
376
377         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
378                                       EAP_VENDOR_WFA_NEW,
379                                       EAP_VENDOR_WFA_UNAUTH_TLS,
380                                       "WFA-UNAUTH-TLS");
381         if (eap == NULL)
382                 return -1;
383
384         eap->init = eap_wfa_unauth_tls_init;
385         eap->reset = eap_tls_reset;
386         eap->buildReq = eap_tls_buildReq;
387         eap->check = eap_tls_check;
388         eap->process = eap_tls_process;
389         eap->isDone = eap_tls_isDone;
390         eap->getKey = eap_tls_getKey;
391         eap->isSuccess = eap_tls_isSuccess;
392         eap->get_emsk = eap_tls_get_emsk;
393
394         ret = eap_server_method_register(eap);
395         if (ret)
396                 eap_server_method_free(eap);
397         return ret;
398 }
399 #endif /* CONFIG_HS20 */