]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/wpa/src/eap_server/eap_server_tls_common.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / wpa / src / eap_server / eap_server_tls_common.c
1 /*
2  * EAP-TLS/PEAP/TTLS/FAST server common functions
3  * Copyright (c) 2004-2009, 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 "crypto/sha1.h"
13 #include "crypto/tls.h"
14 #include "eap_i.h"
15 #include "eap_tls_common.h"
16
17
18 static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
19
20
21 struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
22                                   u8 code, u8 identifier)
23 {
24         if (type == EAP_UNAUTH_TLS_TYPE)
25                 return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
26                                      EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
27                                      code, identifier);
28         return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
29                              identifier);
30 }
31
32
33 int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
34                             int verify_peer)
35 {
36         data->eap = sm;
37         data->phase2 = sm->init_phase2;
38
39         data->conn = tls_connection_init(sm->ssl_ctx);
40         if (data->conn == NULL) {
41                 wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
42                            "connection");
43                 return -1;
44         }
45
46         if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
47                 wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
48                            "of TLS peer certificate");
49                 tls_connection_deinit(sm->ssl_ctx, data->conn);
50                 data->conn = NULL;
51                 return -1;
52         }
53
54         data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
55         if (data->phase2) {
56                 /* Limit the fragment size in the inner TLS authentication
57                  * since the outer authentication with EAP-PEAP does not yet
58                  * support fragmentation */
59                 if (data->tls_out_limit > 100)
60                         data->tls_out_limit -= 100;
61         }
62         return 0;
63 }
64
65
66 void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
67 {
68         tls_connection_deinit(sm->ssl_ctx, data->conn);
69         eap_server_tls_free_in_buf(data);
70         wpabuf_free(data->tls_out);
71         data->tls_out = NULL;
72 }
73
74
75 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
76                                char *label, size_t len)
77 {
78         struct tls_keys keys;
79         u8 *rnd = NULL, *out;
80
81         out = os_malloc(len);
82         if (out == NULL)
83                 return NULL;
84
85         if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
86             0)
87                 return out;
88
89         if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
90                 goto fail;
91
92         if (keys.client_random == NULL || keys.server_random == NULL ||
93             keys.master_key == NULL)
94                 goto fail;
95
96         rnd = os_malloc(keys.client_random_len + keys.server_random_len);
97         if (rnd == NULL)
98                 goto fail;
99         os_memcpy(rnd, keys.client_random, keys.client_random_len);
100         os_memcpy(rnd + keys.client_random_len, keys.server_random,
101                   keys.server_random_len);
102
103         if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
104                              label, rnd, keys.client_random_len +
105                              keys.server_random_len, out, len))
106                 goto fail;
107
108         os_free(rnd);
109         return out;
110
111 fail:
112         os_free(out);
113         os_free(rnd);
114         return NULL;
115 }
116
117
118 struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
119                                          int eap_type, int version, u8 id)
120 {
121         struct wpabuf *req;
122         u8 flags;
123         size_t send_len, plen;
124
125         wpa_printf(MSG_DEBUG, "SSL: Generating Request");
126         if (data->tls_out == NULL) {
127                 wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__);
128                 return NULL;
129         }
130
131         flags = version;
132         send_len = wpabuf_len(data->tls_out) - data->tls_out_pos;
133         if (1 + send_len > data->tls_out_limit) {
134                 send_len = data->tls_out_limit - 1;
135                 flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
136                 if (data->tls_out_pos == 0) {
137                         flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
138                         send_len -= 4;
139                 }
140         }
141
142         plen = 1 + send_len;
143         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
144                 plen += 4;
145
146         req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id);
147         if (req == NULL)
148                 return NULL;
149
150         wpabuf_put_u8(req, flags); /* Flags */
151         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
152                 wpabuf_put_be32(req, wpabuf_len(data->tls_out));
153
154         wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
155                         send_len);
156         data->tls_out_pos += send_len;
157
158         if (data->tls_out_pos == wpabuf_len(data->tls_out)) {
159                 wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
160                            "(message sent completely)",
161                            (unsigned long) send_len);
162                 wpabuf_free(data->tls_out);
163                 data->tls_out = NULL;
164                 data->tls_out_pos = 0;
165                 data->state = MSG;
166         } else {
167                 wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
168                            "(%lu more to send)", (unsigned long) send_len,
169                            (unsigned long) wpabuf_len(data->tls_out) -
170                            data->tls_out_pos);
171                 data->state = WAIT_FRAG_ACK;
172         }
173
174         return req;
175 }
176
177
178 struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
179 {
180         struct wpabuf *req;
181
182         req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id);
183         if (req == NULL)
184                 return NULL;
185         wpa_printf(MSG_DEBUG, "SSL: Building ACK");
186         wpabuf_put_u8(req, version); /* Flags */
187         return req;
188 }
189
190
191 static int eap_server_tls_process_cont(struct eap_ssl_data *data,
192                                        const u8 *buf, size_t len)
193 {
194         /* Process continuation of a pending message */
195         if (len > wpabuf_tailroom(data->tls_in)) {
196                 wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
197                 return -1;
198         }
199
200         wpabuf_put_data(data->tls_in, buf, len);
201         wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
202                    "bytes more", (unsigned long) len,
203                    (unsigned long) wpabuf_tailroom(data->tls_in));
204
205         return 0;
206 }
207
208
209 static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
210                                            u8 flags, u32 message_length,
211                                            const u8 *buf, size_t len)
212 {
213         /* Process a fragment that is not the last one of the message */
214         if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
215                 wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
216                            "fragmented packet");
217                 return -1;
218         }
219
220         if (data->tls_in == NULL) {
221                 /* First fragment of the message */
222
223                 /* Limit length to avoid rogue peers from causing large
224                  * memory allocations. */
225                 if (message_length > 65536) {
226                         wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
227                                    " over 64 kB)");
228                         return -1;
229                 }
230
231                 if (len > message_length) {
232                         wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in "
233                                    "first fragment of frame (TLS Message "
234                                    "Length %d bytes)",
235                                    (int) len, (int) message_length);
236                         return -1;
237                 }
238
239                 data->tls_in = wpabuf_alloc(message_length);
240                 if (data->tls_in == NULL) {
241                         wpa_printf(MSG_DEBUG, "SSL: No memory for message");
242                         return -1;
243                 }
244                 wpabuf_put_data(data->tls_in, buf, len);
245                 wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
246                            "fragment, waiting for %lu bytes more",
247                            (unsigned long) len,
248                            (unsigned long) wpabuf_tailroom(data->tls_in));
249         }
250
251         return 0;
252 }
253
254
255 int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
256 {
257         if (data->tls_out) {
258                 /* This should not happen.. */
259                 wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
260                            "processing new message");
261                 wpabuf_free(data->tls_out);
262                 WPA_ASSERT(data->tls_out == NULL);
263         }
264
265         data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
266                                                         data->conn,
267                                                         data->tls_in, NULL);
268         if (data->tls_out == NULL) {
269                 wpa_printf(MSG_INFO, "SSL: TLS processing failed");
270                 return -1;
271         }
272         if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
273                 /* TLS processing has failed - return error */
274                 wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
275                            "report error");
276                 return -1;
277         }
278
279         return 0;
280 }
281
282
283 static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
284                                      const u8 **pos, size_t *left)
285 {
286         unsigned int tls_msg_len = 0;
287         const u8 *end = *pos + *left;
288
289         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
290                 if (*left < 4) {
291                         wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
292                                    "length");
293                         return -1;
294                 }
295                 tls_msg_len = WPA_GET_BE32(*pos);
296                 wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
297                            tls_msg_len);
298                 *pos += 4;
299                 *left -= 4;
300
301                 if (*left > tls_msg_len) {
302                         wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
303                                    "bytes) smaller than this fragment (%d "
304                                    "bytes)", (int) tls_msg_len, (int) *left);
305                         return -1;
306                 }
307         }
308
309         wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
310                    "Message Length %u", flags, tls_msg_len);
311
312         if (data->state == WAIT_FRAG_ACK) {
313                 if (*left != 0) {
314                         wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
315                                    "WAIT_FRAG_ACK state");
316                         return -1;
317                 }
318                 wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
319                 return 1;
320         }
321
322         if (data->tls_in &&
323             eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
324                 return -1;
325                 
326         if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
327                 if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
328                                                     *pos, end - *pos) < 0)
329                         return -1;
330
331                 data->state = FRAG_ACK;
332                 return 1;
333         }
334
335         if (data->state == FRAG_ACK) {
336                 wpa_printf(MSG_DEBUG, "SSL: All fragments received");
337                 data->state = MSG;
338         }
339
340         if (data->tls_in == NULL) {
341                 /* Wrap unfragmented messages as wpabuf without extra copy */
342                 wpabuf_set(&data->tmpbuf, *pos, end - *pos);
343                 data->tls_in = &data->tmpbuf;
344         }
345
346         return 0;
347 }
348
349
350 static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
351 {
352         if (data->tls_in != &data->tmpbuf)
353                 wpabuf_free(data->tls_in);
354         data->tls_in = NULL;
355 }
356
357
358 struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
359                                        struct eap_ssl_data *data,
360                                        const struct wpabuf *plain)
361 {
362         struct wpabuf *buf;
363
364         buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
365                                      plain);
366         if (buf == NULL) {
367                 wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
368                 return NULL;
369         }
370
371         return buf;
372 }
373
374
375 int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
376                            struct wpabuf *respData, void *priv, int eap_type,
377                            int (*proc_version)(struct eap_sm *sm, void *priv,
378                                                int peer_version),
379                            void (*proc_msg)(struct eap_sm *sm, void *priv,
380                                             const struct wpabuf *respData))
381 {
382         const u8 *pos;
383         u8 flags;
384         size_t left;
385         int ret, res = 0;
386
387         if (eap_type == EAP_UNAUTH_TLS_TYPE)
388                 pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
389                                        EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
390                                        &left);
391         else
392                 pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
393                                        &left);
394         if (pos == NULL || left < 1)
395                 return 0; /* Should not happen - frame already validated */
396         flags = *pos++;
397         left--;
398         wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
399                    (unsigned long) wpabuf_len(respData), flags);
400
401         if (proc_version &&
402             proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
403                 return -1;
404
405         ret = eap_server_tls_reassemble(data, flags, &pos, &left);
406         if (ret < 0) {
407                 res = -1;
408                 goto done;
409         } else if (ret == 1)
410                 return 0;
411
412         if (proc_msg)
413                 proc_msg(sm, priv, respData);
414
415         if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
416                 wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
417                            "TLS processing");
418                 res = -1;
419         }
420
421 done:
422         eap_server_tls_free_in_buf(data);
423
424         return res;
425 }