xref: /dragonfly/contrib/wpa_supplicant/src/eap_server/eap_server_tls_common.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
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 
eap_tls_msg_alloc(EapType type,size_t payload_len,u8 code,u8 identifier)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           else if (type == EAP_WFA_UNAUTH_TLS_TYPE)
29                     return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
30                                              EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
31                                              code, identifier);
32           return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
33                                    identifier);
34 }
35 
36 
37 #ifdef CONFIG_TLS_INTERNAL
eap_server_tls_log_cb(void * ctx,const char * msg)38 static void eap_server_tls_log_cb(void *ctx, const char *msg)
39 {
40           struct eap_sm *sm = ctx;
41           eap_log_msg(sm, "TLS: %s", msg);
42 }
43 #endif /* CONFIG_TLS_INTERNAL */
44 
45 
eap_server_tls_ssl_init(struct eap_sm * sm,struct eap_ssl_data * data,int verify_peer,int eap_type)46 int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
47                                   int verify_peer, int eap_type)
48 {
49           u8 session_ctx[8];
50           unsigned int flags = sm->tls_flags;
51 
52           if (sm->ssl_ctx == NULL) {
53                     wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
54                     return -1;
55           }
56 
57           data->eap = sm;
58           data->phase2 = sm->init_phase2;
59 
60           data->conn = tls_connection_init(sm->ssl_ctx);
61           if (data->conn == NULL) {
62                     wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
63                                  "connection");
64                     return -1;
65           }
66 
67 #ifdef CONFIG_TLS_INTERNAL
68           tls_connection_set_log_cb(data->conn, eap_server_tls_log_cb, sm);
69 #ifdef CONFIG_TESTING_OPTIONS
70           tls_connection_set_test_flags(data->conn, sm->tls_test_flags);
71 #endif /* CONFIG_TESTING_OPTIONS */
72 #endif /* CONFIG_TLS_INTERNAL */
73 
74           if (eap_type != EAP_TYPE_FAST)
75                     flags |= TLS_CONN_DISABLE_SESSION_TICKET;
76           os_memcpy(session_ctx, "hostapd", 7);
77           session_ctx[7] = (u8) eap_type;
78           if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
79                                               flags, session_ctx,
80                                               sizeof(session_ctx))) {
81                     wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
82                                  "of TLS peer certificate");
83                     tls_connection_deinit(sm->ssl_ctx, data->conn);
84                     data->conn = NULL;
85                     return -1;
86           }
87 
88           data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
89           if (data->phase2) {
90                     /* Limit the fragment size in the inner TLS authentication
91                      * since the outer authentication with EAP-PEAP does not yet
92                      * support fragmentation */
93                     if (data->tls_out_limit > 100)
94                               data->tls_out_limit -= 100;
95           }
96           return 0;
97 }
98 
99 
eap_server_tls_ssl_deinit(struct eap_sm * sm,struct eap_ssl_data * data)100 void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
101 {
102           tls_connection_deinit(sm->ssl_ctx, data->conn);
103           eap_server_tls_free_in_buf(data);
104           wpabuf_free(data->tls_out);
105           data->tls_out = NULL;
106 }
107 
108 
eap_server_tls_derive_key(struct eap_sm * sm,struct eap_ssl_data * data,const char * label,const u8 * context,size_t context_len,size_t len)109 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
110                                      const char *label, const u8 *context,
111                                      size_t context_len, size_t len)
112 {
113           u8 *out;
114 
115           out = os_malloc(len);
116           if (out == NULL)
117                     return NULL;
118 
119           if (tls_connection_export_key(sm->ssl_ctx, data->conn, label,
120                                               context, context_len, out, len)) {
121                     os_free(out);
122                     return NULL;
123           }
124 
125           return out;
126 }
127 
128 
129 /**
130  * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data
131  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
132  * @data: Data for TLS processing
133  * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
134  * @len: Pointer to length of the session ID generated
135  * Returns: Pointer to allocated Session-Id on success or %NULL on failure
136  *
137  * This function derive the Session-Id based on the TLS session data
138  * (client/server random and method type).
139  *
140  * The caller is responsible for freeing the returned buffer.
141  */
eap_server_tls_derive_session_id(struct eap_sm * sm,struct eap_ssl_data * data,u8 eap_type,size_t * len)142 u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
143                                               struct eap_ssl_data *data, u8 eap_type,
144                                               size_t *len)
145 {
146           struct tls_random keys;
147           u8 *out;
148           const u8 context[] = { EAP_TYPE_TLS };
149 
150           if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
151                     u8 *id, *method_id;
152 
153                     /* Session-Id = <EAP-Type> || Method-Id
154                      * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
155                      *                          Type-Code, 64)
156                      */
157                     *len = 1 + 64;
158                     id = os_malloc(*len);
159                     if (!id)
160                               return NULL;
161                     method_id = eap_server_tls_derive_key(
162                               sm, data, "EXPORTER_EAP_TLS_Method-Id", context, 1, 64);
163                     if (!method_id) {
164                               os_free(id);
165                               return NULL;
166                     }
167                     id[0] = eap_type;
168                     os_memcpy(id + 1, method_id, 64);
169                     os_free(method_id);
170                     return id;
171           }
172 
173           if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
174                     return NULL;
175 
176           if (keys.client_random == NULL || keys.server_random == NULL)
177                     return NULL;
178 
179           *len = 1 + keys.client_random_len + keys.server_random_len;
180           out = os_malloc(*len);
181           if (out == NULL)
182                     return NULL;
183 
184           /* Session-Id = EAP type || client.random || server.random */
185           out[0] = eap_type;
186           os_memcpy(out + 1, keys.client_random, keys.client_random_len);
187           os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
188                       keys.server_random_len);
189 
190           return out;
191 }
192 
193 
eap_server_tls_build_msg(struct eap_ssl_data * data,int eap_type,int version,u8 id)194 struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
195                                                    int eap_type, int version, u8 id)
196 {
197           struct wpabuf *req;
198           u8 flags;
199           size_t send_len, plen;
200 
201           wpa_printf(MSG_DEBUG, "SSL: Generating Request");
202           if (data->tls_out == NULL) {
203                     wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__);
204                     return NULL;
205           }
206 
207           flags = version;
208           send_len = wpabuf_len(data->tls_out) - data->tls_out_pos;
209           if (1 + send_len > data->tls_out_limit) {
210                     send_len = data->tls_out_limit - 1;
211                     flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
212                     if (data->tls_out_pos == 0) {
213                               flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
214                               send_len -= 4;
215                     }
216           }
217 
218           plen = 1 + send_len;
219           if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
220                     plen += 4;
221 
222           req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id);
223           if (req == NULL)
224                     return NULL;
225 
226           wpabuf_put_u8(req, flags); /* Flags */
227           if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
228                     wpabuf_put_be32(req, wpabuf_len(data->tls_out));
229 
230           wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
231                               send_len);
232           data->tls_out_pos += send_len;
233 
234           if (data->tls_out_pos == wpabuf_len(data->tls_out)) {
235                     wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
236                                  "(message sent completely)",
237                                  (unsigned long) send_len);
238                     wpabuf_free(data->tls_out);
239                     data->tls_out = NULL;
240                     data->tls_out_pos = 0;
241                     data->state = MSG;
242           } else {
243                     wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
244                                  "(%lu more to send)", (unsigned long) send_len,
245                                  (unsigned long) wpabuf_len(data->tls_out) -
246                                  data->tls_out_pos);
247                     data->state = WAIT_FRAG_ACK;
248           }
249 
250           return req;
251 }
252 
253 
eap_server_tls_build_ack(u8 id,int eap_type,int version)254 struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
255 {
256           struct wpabuf *req;
257 
258           req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id);
259           if (req == NULL)
260                     return NULL;
261           wpa_printf(MSG_DEBUG, "SSL: Building ACK");
262           wpabuf_put_u8(req, version); /* Flags */
263           return req;
264 }
265 
266 
eap_server_tls_process_cont(struct eap_ssl_data * data,const u8 * buf,size_t len)267 static int eap_server_tls_process_cont(struct eap_ssl_data *data,
268                                                const u8 *buf, size_t len)
269 {
270           /* Process continuation of a pending message */
271           if (len > wpabuf_tailroom(data->tls_in)) {
272                     wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
273                     return -1;
274           }
275 
276           wpabuf_put_data(data->tls_in, buf, len);
277           wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
278                        "bytes more", (unsigned long) len,
279                        (unsigned long) wpabuf_tailroom(data->tls_in));
280 
281           return 0;
282 }
283 
284 
eap_server_tls_process_fragment(struct eap_ssl_data * data,u8 flags,u32 message_length,const u8 * buf,size_t len)285 static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
286                                                      u8 flags, u32 message_length,
287                                                      const u8 *buf, size_t len)
288 {
289           /* Process a fragment that is not the last one of the message */
290           if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
291                     wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
292                                  "fragmented packet");
293                     return -1;
294           }
295 
296           if (data->tls_in == NULL) {
297                     /* First fragment of the message */
298 
299                     /* Limit length to avoid rogue peers from causing large
300                      * memory allocations. */
301                     if (message_length > 65536) {
302                               wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
303                                            " over 64 kB)");
304                               return -1;
305                     }
306 
307                     if (len > message_length) {
308                               wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in "
309                                            "first fragment of frame (TLS Message "
310                                            "Length %d bytes)",
311                                            (int) len, (int) message_length);
312                               return -1;
313                     }
314 
315                     data->tls_in = wpabuf_alloc(message_length);
316                     if (data->tls_in == NULL) {
317                               wpa_printf(MSG_DEBUG, "SSL: No memory for message");
318                               return -1;
319                     }
320                     wpabuf_put_data(data->tls_in, buf, len);
321                     wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
322                                  "fragment, waiting for %lu bytes more",
323                                  (unsigned long) len,
324                                  (unsigned long) wpabuf_tailroom(data->tls_in));
325           }
326 
327           return 0;
328 }
329 
330 
eap_server_tls_phase1(struct eap_sm * sm,struct eap_ssl_data * data)331 int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
332 {
333           char buf[20];
334 
335           if (data->tls_out) {
336                     /* This should not happen.. */
337                     wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
338                                  "processing new message");
339                     wpabuf_free(data->tls_out);
340                     WPA_ASSERT(data->tls_out == NULL);
341           }
342 
343           data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
344                                                                       data->conn,
345                                                                       data->tls_in, NULL);
346           if (data->tls_out == NULL) {
347                     wpa_printf(MSG_INFO, "SSL: TLS processing failed");
348                     return -1;
349           }
350           if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
351                     /* TLS processing has failed - return error */
352                     wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
353                                  "report error");
354                     return -1;
355           }
356 
357           if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
358                     wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
359                     data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
360           }
361 
362           if (!sm->serial_num &&
363               tls_connection_established(sm->ssl_ctx, data->conn))
364                     sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx,
365                                                                                 data->conn);
366 
367           return 0;
368 }
369 
370 
eap_server_tls_reassemble(struct eap_ssl_data * data,u8 flags,const u8 ** pos,size_t * left)371 static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
372                                              const u8 **pos, size_t *left)
373 {
374           unsigned int tls_msg_len = 0;
375           const u8 *end = *pos + *left;
376 
377           wpa_hexdump(MSG_MSGDUMP, "SSL: Received data", *pos, *left);
378 
379           if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
380                     if (*left < 4) {
381                               wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
382                                            "length");
383                               return -1;
384                     }
385                     tls_msg_len = WPA_GET_BE32(*pos);
386                     wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
387                                  tls_msg_len);
388                     *pos += 4;
389                     *left -= 4;
390 
391                     if (*left > tls_msg_len) {
392                               wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
393                                            "bytes) smaller than this fragment (%d "
394                                            "bytes)", (int) tls_msg_len, (int) *left);
395                               return -1;
396                     }
397           }
398 
399           wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
400                        "Message Length %u", flags, tls_msg_len);
401 
402           if (data->state == WAIT_FRAG_ACK) {
403                     if (*left != 0) {
404                               wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
405                                            "WAIT_FRAG_ACK state");
406                               return -1;
407                     }
408                     wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
409                     return 1;
410           }
411 
412           if (data->tls_in &&
413               eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
414                     return -1;
415 
416           if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
417                     if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
418                                                                 *pos, end - *pos) < 0)
419                               return -1;
420 
421                     data->state = FRAG_ACK;
422                     return 1;
423           }
424 
425           if (data->state == FRAG_ACK) {
426                     wpa_printf(MSG_DEBUG, "SSL: All fragments received");
427                     data->state = MSG;
428           }
429 
430           if (data->tls_in == NULL) {
431                     /* Wrap unfragmented messages as wpabuf without extra copy */
432                     wpabuf_set(&data->tmpbuf, *pos, end - *pos);
433                     data->tls_in = &data->tmpbuf;
434           }
435 
436           return 0;
437 }
438 
439 
eap_server_tls_free_in_buf(struct eap_ssl_data * data)440 static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
441 {
442           if (data->tls_in != &data->tmpbuf)
443                     wpabuf_free(data->tls_in);
444           data->tls_in = NULL;
445 }
446 
447 
eap_server_tls_encrypt(struct eap_sm * sm,struct eap_ssl_data * data,const struct wpabuf * plain)448 struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
449                                                struct eap_ssl_data *data,
450                                                const struct wpabuf *plain)
451 {
452           struct wpabuf *buf;
453 
454           buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
455                                              plain);
456           if (buf == NULL) {
457                     wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
458                     return NULL;
459           }
460 
461           return buf;
462 }
463 
464 
eap_server_tls_process(struct eap_sm * sm,struct eap_ssl_data * data,struct wpabuf * respData,void * priv,int eap_type,int (* proc_version)(struct eap_sm * sm,void * priv,int peer_version),void (* proc_msg)(struct eap_sm * sm,void * priv,const struct wpabuf * respData))465 int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
466                                  struct wpabuf *respData, void *priv, int eap_type,
467                                  int (*proc_version)(struct eap_sm *sm, void *priv,
468                                                          int peer_version),
469                                  void (*proc_msg)(struct eap_sm *sm, void *priv,
470                                                       const struct wpabuf *respData))
471 {
472           const u8 *pos;
473           u8 flags;
474           size_t left;
475           int ret, res = 0;
476 
477           if (eap_type == EAP_UNAUTH_TLS_TYPE)
478                     pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
479                                                EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
480                                                &left);
481           else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
482                     pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
483                                                EAP_VENDOR_WFA_UNAUTH_TLS, respData,
484                                                &left);
485           else
486                     pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
487                                                &left);
488           if (pos == NULL || left < 1)
489                     return 0; /* Should not happen - frame already validated */
490           flags = *pos++;
491           left--;
492           wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
493                        (unsigned long) wpabuf_len(respData), flags);
494 
495           if (proc_version &&
496               proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
497                     return -1;
498 
499           ret = eap_server_tls_reassemble(data, flags, &pos, &left);
500           if (ret < 0) {
501                     res = -1;
502                     goto done;
503           } else if (ret == 1)
504                     return 0;
505 
506           if (proc_msg)
507                     proc_msg(sm, priv, respData);
508 
509           if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
510                     wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
511                                  "TLS processing");
512                     res = -1;
513           }
514 
515 done:
516           eap_server_tls_free_in_buf(data);
517 
518           return res;
519 }
520