eap_server_tls_common.c
Go to the documentation of this file.
00001 /*
00002  * EAP-TLS/PEAP/TTLS/FAST server common functions
00003  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "crypto/sha1.h"
00019 #include "crypto/tls.h"
00020 #include "eap_i.h"
00021 #include "eap_tls_common.h"
00022 
00023 
00024 static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
00025 
00026 
00027 int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
00028                             int verify_peer)
00029 {
00030         data->eap = sm;
00031         data->phase2 = sm->init_phase2;
00032 
00033         data->conn = tls_connection_init(sm->ssl_ctx);
00034         if (data->conn == NULL) {
00035                 wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
00036                            "connection");
00037                 return -1;
00038         }
00039 
00040         if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
00041                 wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
00042                            "of TLS peer certificate");
00043                 tls_connection_deinit(sm->ssl_ctx, data->conn);
00044                 data->conn = NULL;
00045                 return -1;
00046         }
00047 
00048         /* TODO: make this configurable */
00049         data->tls_out_limit = 1398;
00050         if (data->phase2) {
00051                 /* Limit the fragment size in the inner TLS authentication
00052                  * since the outer authentication with EAP-PEAP does not yet
00053                  * support fragmentation */
00054                 if (data->tls_out_limit > 100)
00055                         data->tls_out_limit -= 100;
00056         }
00057         return 0;
00058 }
00059 
00060 
00061 void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
00062 {
00063         tls_connection_deinit(sm->ssl_ctx, data->conn);
00064         eap_server_tls_free_in_buf(data);
00065         wpabuf_free(data->tls_out);
00066         data->tls_out = NULL;
00067 }
00068 
00069 
00070 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
00071                                char *label, size_t len)
00072 {
00073         struct tls_keys keys;
00074         u8 *rnd = NULL, *out;
00075 
00076         out = os_malloc(len);
00077         if (out == NULL)
00078                 return NULL;
00079 
00080         if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
00081             0)
00082                 return out;
00083 
00084         if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
00085                 goto fail;
00086 
00087         if (keys.client_random == NULL || keys.server_random == NULL ||
00088             keys.master_key == NULL)
00089                 goto fail;
00090 
00091         rnd = os_malloc(keys.client_random_len + keys.server_random_len);
00092         if (rnd == NULL)
00093                 goto fail;
00094         os_memcpy(rnd, keys.client_random, keys.client_random_len);
00095         os_memcpy(rnd + keys.client_random_len, keys.server_random,
00096                   keys.server_random_len);
00097 
00098         if (tls_prf(keys.master_key, keys.master_key_len,
00099                     label, rnd, keys.client_random_len +
00100                     keys.server_random_len, out, len))
00101                 goto fail;
00102 
00103         os_free(rnd);
00104         return out;
00105 
00106 fail:
00107         os_free(out);
00108         os_free(rnd);
00109         return NULL;
00110 }
00111 
00112 
00113 struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
00114                                          int eap_type, int version, u8 id)
00115 {
00116         struct wpabuf *req;
00117         u8 flags;
00118         size_t send_len, plen;
00119 
00120         wpa_printf(MSG_DEBUG, "SSL: Generating Request");
00121         if (data->tls_out == NULL) {
00122                 wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__);
00123                 return NULL;
00124         }
00125 
00126         flags = version;
00127         send_len = wpabuf_len(data->tls_out) - data->tls_out_pos;
00128         if (1 + send_len > data->tls_out_limit) {
00129                 send_len = data->tls_out_limit - 1;
00130                 flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
00131                 if (data->tls_out_pos == 0) {
00132                         flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
00133                         send_len -= 4;
00134                 }
00135         }
00136 
00137         plen = 1 + send_len;
00138         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
00139                 plen += 4;
00140 
00141         req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
00142                             EAP_CODE_REQUEST, id);
00143         if (req == NULL)
00144                 return NULL;
00145 
00146         wpabuf_put_u8(req, flags); /* Flags */
00147         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
00148                 wpabuf_put_be32(req, wpabuf_len(data->tls_out));
00149 
00150         wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
00151                         send_len);
00152         data->tls_out_pos += send_len;
00153 
00154         if (data->tls_out_pos == wpabuf_len(data->tls_out)) {
00155                 wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
00156                            "(message sent completely)",
00157                            (unsigned long) send_len);
00158                 wpabuf_free(data->tls_out);
00159                 data->tls_out = NULL;
00160                 data->tls_out_pos = 0;
00161                 data->state = MSG;
00162         } else {
00163                 wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
00164                            "(%lu more to send)", (unsigned long) send_len,
00165                            (unsigned long) wpabuf_len(data->tls_out) -
00166                            data->tls_out_pos);
00167                 data->state = WAIT_FRAG_ACK;
00168         }
00169 
00170         return req;
00171 }
00172 
00173 
00174 struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
00175 {
00176         struct wpabuf *req;
00177 
00178         req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
00179                             id);
00180         if (req == NULL)
00181                 return NULL;
00182         wpa_printf(MSG_DEBUG, "SSL: Building ACK");
00183         wpabuf_put_u8(req, version); /* Flags */
00184         return req;
00185 }
00186 
00187 
00188 static int eap_server_tls_process_cont(struct eap_ssl_data *data,
00189                                        const u8 *buf, size_t len)
00190 {
00191         /* Process continuation of a pending message */
00192         if (len > wpabuf_tailroom(data->tls_in)) {
00193                 wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
00194                 return -1;
00195         }
00196 
00197         wpabuf_put_data(data->tls_in, buf, len);
00198         wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
00199                    "bytes more", (unsigned long) len,
00200                    (unsigned long) wpabuf_tailroom(data->tls_in));
00201 
00202         return 0;
00203 }
00204 
00205 
00206 static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
00207                                            u8 flags, u32 message_length,
00208                                            const u8 *buf, size_t len)
00209 {
00210         /* Process a fragment that is not the last one of the message */
00211         if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
00212                 wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
00213                            "fragmented packet");
00214                 return -1;
00215         }
00216 
00217         if (data->tls_in == NULL) {
00218                 /* First fragment of the message */
00219 
00220                 /* Limit length to avoid rogue peers from causing large
00221                  * memory allocations. */
00222                 if (message_length > 65536) {
00223                         wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
00224                                    " over 64 kB)");
00225                         return -1;
00226                 }
00227 
00228                 data->tls_in = wpabuf_alloc(message_length);
00229                 if (data->tls_in == NULL) {
00230                         wpa_printf(MSG_DEBUG, "SSL: No memory for message");
00231                         return -1;
00232                 }
00233                 wpabuf_put_data(data->tls_in, buf, len);
00234                 wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
00235                            "fragment, waiting for %lu bytes more",
00236                            (unsigned long) len,
00237                            (unsigned long) wpabuf_tailroom(data->tls_in));
00238         }
00239 
00240         return 0;
00241 }
00242 
00243 
00244 int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
00245 {
00246         if (data->tls_out) {
00247                 /* This should not happen.. */
00248                 wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
00249                            "processing new message");
00250                 wpabuf_free(data->tls_out);
00251                 WPA_ASSERT(data->tls_out == NULL);
00252         }
00253 
00254         data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
00255                                                         data->conn,
00256                                                         data->tls_in, NULL);
00257         if (data->tls_out == NULL) {
00258                 wpa_printf(MSG_INFO, "SSL: TLS processing failed");
00259                 return -1;
00260         }
00261         if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
00262                 /* TLS processing has failed - return error */
00263                 wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
00264                            "report error");
00265                 return -1;
00266         }
00267 
00268         return 0;
00269 }
00270 
00271 
00272 static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
00273                                      const u8 **pos, size_t *left)
00274 {
00275         unsigned int tls_msg_len = 0;
00276         const u8 *end = *pos + *left;
00277 
00278         if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
00279                 if (*left < 4) {
00280                         wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
00281                                    "length");
00282                         return -1;
00283                 }
00284                 tls_msg_len = WPA_GET_BE32(*pos);
00285                 wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
00286                            tls_msg_len);
00287                 *pos += 4;
00288                 *left -= 4;
00289         }
00290 
00291         wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
00292                    "Message Length %u", flags, tls_msg_len);
00293 
00294         if (data->state == WAIT_FRAG_ACK) {
00295                 if (*left != 0) {
00296                         wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
00297                                    "WAIT_FRAG_ACK state");
00298                         return -1;
00299                 }
00300                 wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
00301                 return 1;
00302         }
00303 
00304         if (data->tls_in &&
00305             eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
00306                 return -1;
00307                 
00308         if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
00309                 if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
00310                                                     *pos, end - *pos) < 0)
00311                         return -1;
00312 
00313                 data->state = FRAG_ACK;
00314                 return 1;
00315         }
00316 
00317         if (data->state == FRAG_ACK) {
00318                 wpa_printf(MSG_DEBUG, "SSL: All fragments received");
00319                 data->state = MSG;
00320         }
00321 
00322         if (data->tls_in == NULL) {
00323                 /* Wrap unfragmented messages as wpabuf without extra copy */
00324                 wpabuf_set(&data->tmpbuf, *pos, end - *pos);
00325                 data->tls_in = &data->tmpbuf;
00326         }
00327 
00328         return 0;
00329 }
00330 
00331 
00332 static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
00333 {
00334         if (data->tls_in != &data->tmpbuf)
00335                 wpabuf_free(data->tls_in);
00336         data->tls_in = NULL;
00337 }
00338 
00339 
00340 struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
00341                                        struct eap_ssl_data *data,
00342                                        const struct wpabuf *plain)
00343 {
00344         struct wpabuf *buf;
00345 
00346         buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
00347                                      plain);
00348         if (buf == NULL) {
00349                 wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
00350                 return NULL;
00351         }
00352 
00353         return buf;
00354 }
00355 
00356 
00357 int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
00358                            struct wpabuf *respData, void *priv, int eap_type,
00359                            int (*proc_version)(struct eap_sm *sm, void *priv,
00360                                                int peer_version),
00361                            void (*proc_msg)(struct eap_sm *sm, void *priv,
00362                                             const struct wpabuf *respData))
00363 {
00364         const u8 *pos;
00365         u8 flags;
00366         size_t left;
00367         int ret, res = 0;
00368 
00369         pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
00370         if (pos == NULL || left < 1)
00371                 return 0; /* Should not happen - frame already validated */
00372         flags = *pos++;
00373         left--;
00374         wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
00375                    (unsigned long) wpabuf_len(respData), flags);
00376 
00377         if (proc_version &&
00378             proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
00379                 return -1;
00380 
00381         ret = eap_server_tls_reassemble(data, flags, &pos, &left);
00382         if (ret < 0) {
00383                 res = -1;
00384                 goto done;
00385         } else if (ret == 1)
00386                 return 0;
00387 
00388         if (proc_msg)
00389                 proc_msg(sm, priv, respData);
00390 
00391         if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
00392                 wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
00393                            "TLS processing");
00394                 res = -1;
00395         }
00396 
00397 done:
00398         eap_server_tls_free_in_buf(data);
00399 
00400         return res;
00401 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:37