LCOV - code coverage report
Current view: top level - src/eap_server - eap_server_tls_common.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 154 216 71.3 %
Date: 2014-05-28 Functions: 13 13 100.0 %

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

Generated by: LCOV version 1.10