remove @EAP_LDFLAGS@, no longer exists
[mech_eap.orig] / libeap / 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 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_tls_common.h"
20 #include "crypto/tls.h"
21
22
23 static void eap_tls_reset(struct eap_sm *sm, void *priv);
24
25
26 struct eap_tls_data {
27         struct eap_ssl_data ssl;
28         enum { START, CONTINUE, SUCCESS, FAILURE } state;
29         int established;
30 };
31
32
33 static const char * eap_tls_state_txt(int state)
34 {
35         switch (state) {
36         case START:
37                 return "START";
38         case CONTINUE:
39                 return "CONTINUE";
40         case SUCCESS:
41                 return "SUCCESS";
42         case FAILURE:
43                 return "FAILURE";
44         default:
45                 return "Unknown?!";
46         }
47 }
48
49
50 static void eap_tls_state(struct eap_tls_data *data, int state)
51 {
52         wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
53                    eap_tls_state_txt(data->state),
54                    eap_tls_state_txt(state));
55         data->state = state;
56 }
57
58
59 static void * eap_tls_init(struct eap_sm *sm)
60 {
61         struct eap_tls_data *data;
62
63         data = os_zalloc(sizeof(*data));
64         if (data == NULL)
65                 return NULL;
66         data->state = START;
67
68         if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
69                 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
70                 eap_tls_reset(sm, data);
71                 return NULL;
72         }
73
74         return data;
75 }
76
77
78 static void eap_tls_reset(struct eap_sm *sm, void *priv)
79 {
80         struct eap_tls_data *data = priv;
81         if (data == NULL)
82                 return;
83         eap_server_tls_ssl_deinit(sm, &data->ssl);
84         os_free(data);
85 }
86
87
88 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
89                                            struct eap_tls_data *data, u8 id)
90 {
91         struct wpabuf *req;
92
93         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
94                             id);
95         if (req == NULL) {
96                 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
97                            "request");
98                 eap_tls_state(data, FAILURE);
99                 return NULL;
100         }
101
102         wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
103
104         eap_tls_state(data, CONTINUE);
105
106         return req;
107 }
108
109
110 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
111 {
112         struct eap_tls_data *data = priv;
113         struct wpabuf *res;
114
115         if (data->ssl.state == FRAG_ACK) {
116                 return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
117         }
118
119         if (data->ssl.state == WAIT_FRAG_ACK) {
120                 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
121                                                id);
122                 goto check_established;
123         }
124
125         switch (data->state) {
126         case START:
127                 return eap_tls_build_start(sm, data, id);
128         case CONTINUE:
129                 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
130                         data->established = 1;
131                 break;
132         default:
133                 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
134                            __func__, data->state);
135                 return NULL;
136         }
137
138         res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
139
140 check_established:
141         if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
142                 /* TLS handshake has been completed and there are no more
143                  * fragments waiting to be sent out. */
144                 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
145                 eap_tls_state(data, SUCCESS);
146         }
147
148         return res;
149 }
150
151
152 static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
153                              struct wpabuf *respData)
154 {
155         const u8 *pos;
156         size_t len;
157
158         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
159         if (pos == NULL || len < 1) {
160                 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
161                 return TRUE;
162         }
163
164         return FALSE;
165 }
166
167
168 static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
169                                 const struct wpabuf *respData)
170 {
171         struct eap_tls_data *data = priv;
172         if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
173                 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
174                            "handshake message");
175                 return;
176         }
177         if (eap_server_tls_phase1(sm, &data->ssl) < 0)
178                 eap_tls_state(data, FAILURE);
179 }
180
181
182 static void eap_tls_process(struct eap_sm *sm, void *priv,
183                             struct wpabuf *respData)
184 {
185         struct eap_tls_data *data = priv;
186         if (eap_server_tls_process(sm, &data->ssl, respData, data,
187                                    EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
188             0)
189                 eap_tls_state(data, FAILURE);
190 }
191
192
193 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
194 {
195         struct eap_tls_data *data = priv;
196         return data->state == SUCCESS || data->state == FAILURE;
197 }
198
199
200 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
201 {
202         struct eap_tls_data *data = priv;
203         u8 *eapKeyData;
204
205         if (data->state != SUCCESS)
206                 return NULL;
207
208         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
209                                                "client EAP encryption",
210                                                EAP_TLS_KEY_LEN);
211         if (eapKeyData) {
212                 *len = EAP_TLS_KEY_LEN;
213                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
214                             eapKeyData, EAP_TLS_KEY_LEN);
215         } else {
216                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
217         }
218
219         return eapKeyData;
220 }
221
222
223 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
224 {
225         struct eap_tls_data *data = priv;
226         u8 *eapKeyData, *emsk;
227
228         if (data->state != SUCCESS)
229                 return NULL;
230
231         eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
232                                                "client EAP encryption",
233                                                EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
234         if (eapKeyData) {
235                 emsk = os_malloc(EAP_EMSK_LEN);
236                 if (emsk)
237                         os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
238                                   EAP_EMSK_LEN);
239                 os_free(eapKeyData);
240         } else
241                 emsk = NULL;
242
243         if (emsk) {
244                 *len = EAP_EMSK_LEN;
245                 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
246                             emsk, EAP_EMSK_LEN);
247         } else {
248                 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
249         }
250
251         return emsk;
252 }
253
254
255 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
256 {
257         struct eap_tls_data *data = priv;
258         return data->state == SUCCESS;
259 }
260
261
262 int eap_server_tls_register(void)
263 {
264         struct eap_method *eap;
265         int ret;
266
267         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
268                                       EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
269         if (eap == NULL)
270                 return -1;
271
272         eap->init = eap_tls_init;
273         eap->reset = eap_tls_reset;
274         eap->buildReq = eap_tls_buildReq;
275         eap->check = eap_tls_check;
276         eap->process = eap_tls_process;
277         eap->isDone = eap_tls_isDone;
278         eap->getKey = eap_tls_getKey;
279         eap->isSuccess = eap_tls_isSuccess;
280         eap->get_emsk = eap_tls_get_emsk;
281
282         ret = eap_server_method_register(eap);
283         if (ret)
284                 eap_server_method_free(eap);
285         return ret;
286 }