eap_tls_common.c

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

Generated on Sat Nov 21 23:16:52 2009 for hostapd by  doxygen 1.6.1