Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / wpa / src / eap_server / eap_tls.c
blob1b168c582b3af1e57f1c7d9908e9748c10095f1e
1 /*
2 * hostapd / EAP-TLS (RFC 2716)
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "eap_i.h"
19 #include "eap_tls_common.h"
20 #include "tls.h"
23 static void eap_tls_reset(struct eap_sm *sm, void *priv);
26 struct eap_tls_data {
27 struct eap_ssl_data ssl;
28 enum { START, CONTINUE, SUCCESS, FAILURE } state;
32 static const char * eap_tls_state_txt(int state)
34 switch (state) {
35 case START:
36 return "START";
37 case CONTINUE:
38 return "CONTINUE";
39 case SUCCESS:
40 return "SUCCESS";
41 case FAILURE:
42 return "FAILURE";
43 default:
44 return "Unknown?!";
49 static void eap_tls_state(struct eap_tls_data *data, int state)
51 wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
52 eap_tls_state_txt(data->state),
53 eap_tls_state_txt(state));
54 data->state = state;
58 static void * eap_tls_init(struct eap_sm *sm)
60 struct eap_tls_data *data;
62 data = os_zalloc(sizeof(*data));
63 if (data == NULL)
64 return NULL;
65 data->state = START;
67 if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
68 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
69 eap_tls_reset(sm, data);
70 return NULL;
73 return data;
77 static void eap_tls_reset(struct eap_sm *sm, void *priv)
79 struct eap_tls_data *data = priv;
80 if (data == NULL)
81 return;
82 eap_server_tls_ssl_deinit(sm, &data->ssl);
83 os_free(data);
87 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
88 struct eap_tls_data *data, u8 id)
90 struct wpabuf *req;
92 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
93 id);
94 if (req == NULL) {
95 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
96 "request");
97 eap_tls_state(data, FAILURE);
98 return NULL;
101 wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
103 eap_tls_state(data, CONTINUE);
105 return req;
109 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
111 struct eap_tls_data *data = priv;
114 if (data->ssl.state == FRAG_ACK) {
115 return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
118 if (data->ssl.state == WAIT_FRAG_ACK) {
119 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
120 id);
123 switch (data->state) {
124 case START:
125 return eap_tls_build_start(sm, data, id);
126 case CONTINUE:
127 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
128 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
129 eap_tls_state(data, SUCCESS);
131 break;
132 default:
133 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
134 __func__, data->state);
135 return NULL;
138 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
142 static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
143 struct wpabuf *respData)
145 const u8 *pos;
146 size_t len;
148 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
149 if (pos == NULL || len < 1) {
150 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
151 return TRUE;
154 return FALSE;
158 static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
159 const struct wpabuf *respData)
161 struct eap_tls_data *data = priv;
162 if (data->state == SUCCESS && wpabuf_len(data->ssl.in_buf) == 0) {
163 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
164 "handshake message");
165 return;
167 if (eap_server_tls_phase1(sm, &data->ssl) < 0)
168 eap_tls_state(data, FAILURE);
172 static void eap_tls_process(struct eap_sm *sm, void *priv,
173 struct wpabuf *respData)
175 struct eap_tls_data *data = priv;
176 if (eap_server_tls_process(sm, &data->ssl, respData, data,
177 EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
179 eap_tls_state(data, FAILURE);
183 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
185 struct eap_tls_data *data = priv;
186 return data->state == SUCCESS || data->state == FAILURE;
190 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
192 struct eap_tls_data *data = priv;
193 u8 *eapKeyData;
195 if (data->state != SUCCESS)
196 return NULL;
198 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
199 "client EAP encryption",
200 EAP_TLS_KEY_LEN);
201 if (eapKeyData) {
202 *len = EAP_TLS_KEY_LEN;
203 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
204 eapKeyData, EAP_TLS_KEY_LEN);
205 } else {
206 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
209 return eapKeyData;
213 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
215 struct eap_tls_data *data = priv;
216 u8 *eapKeyData, *emsk;
218 if (data->state != SUCCESS)
219 return NULL;
221 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
222 "client EAP encryption",
223 EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
224 if (eapKeyData) {
225 emsk = os_malloc(EAP_EMSK_LEN);
226 if (emsk)
227 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
228 EAP_EMSK_LEN);
229 os_free(eapKeyData);
230 } else
231 emsk = NULL;
233 if (emsk) {
234 *len = EAP_EMSK_LEN;
235 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
236 emsk, EAP_EMSK_LEN);
237 } else {
238 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
241 return emsk;
245 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
247 struct eap_tls_data *data = priv;
248 return data->state == SUCCESS;
252 int eap_server_tls_register(void)
254 struct eap_method *eap;
255 int ret;
257 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
258 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
259 if (eap == NULL)
260 return -1;
262 eap->init = eap_tls_init;
263 eap->reset = eap_tls_reset;
264 eap->buildReq = eap_tls_buildReq;
265 eap->check = eap_tls_check;
266 eap->process = eap_tls_process;
267 eap->isDone = eap_tls_isDone;
268 eap->getKey = eap_tls_getKey;
269 eap->isSuccess = eap_tls_isSuccess;
270 eap->get_emsk = eap_tls_get_emsk;
272 ret = eap_server_method_register(eap);
273 if (ret)
274 eap_server_method_free(eap);
275 return ret;