eap_tnc.c
Go to the documentation of this file.
00001 /*
00002  * EAP peer method: EAP-TNC (Trusted Network Connect)
00003  * Copyright (c) 2007, 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 "base64.h"
00019 #include "eap_i.h"
00020 #include "tncc.h"
00021 
00022 
00023 struct eap_tnc_data {
00024         enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
00025         struct tncc_data *tncc;
00026         struct wpabuf *in_buf;
00027         struct wpabuf *out_buf;
00028         size_t out_used;
00029         size_t fragment_size;
00030 };
00031 
00032 
00033 /* EAP-TNC Flags */
00034 #define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
00035 #define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
00036 #define EAP_TNC_FLAGS_START 0x20
00037 #define EAP_TNC_VERSION_MASK 0x07
00038 
00039 #define EAP_TNC_VERSION 1
00040 
00041 
00042 static void * eap_tnc_init(struct eap_sm *sm)
00043 {
00044         struct eap_tnc_data *data;
00045 
00046         data = os_zalloc(sizeof(*data));
00047         if (data == NULL)
00048                 return NULL;
00049         data->state = WAIT_START;
00050         data->fragment_size = 1300;
00051         data->tncc = tncc_init();
00052         if (data->tncc == NULL) {
00053                 os_free(data);
00054                 return NULL;
00055         }
00056 
00057         return data;
00058 }
00059 
00060 
00061 static void eap_tnc_deinit(struct eap_sm *sm, void *priv)
00062 {
00063         struct eap_tnc_data *data = priv;
00064 
00065         wpabuf_free(data->in_buf);
00066         wpabuf_free(data->out_buf);
00067         tncc_deinit(data->tncc);
00068         os_free(data);
00069 }
00070 
00071 
00072 static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
00073 {
00074         struct wpabuf *msg;
00075 
00076         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
00077         if (msg == NULL) {
00078                 wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
00079                            "for fragment ack");
00080                 return NULL;
00081         }
00082         wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
00083 
00084         wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
00085 
00086         return msg;
00087 }
00088 
00089 
00090 static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
00091                                          struct eap_method_ret *ret, u8 id)
00092 {
00093         struct wpabuf *resp;
00094         u8 flags;
00095         size_t send_len, plen;
00096 
00097         ret->ignore = FALSE;
00098         wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
00099         ret->allowNotifications = TRUE;
00100 
00101         flags = EAP_TNC_VERSION;
00102         send_len = wpabuf_len(data->out_buf) - data->out_used;
00103         if (1 + send_len > data->fragment_size) {
00104                 send_len = data->fragment_size - 1;
00105                 flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
00106                 if (data->out_used == 0) {
00107                         flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
00108                         send_len -= 4;
00109                 }
00110         }
00111 
00112         plen = 1 + send_len;
00113         if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
00114                 plen += 4;
00115         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
00116                              EAP_CODE_RESPONSE, id);
00117         if (resp == NULL)
00118                 return NULL;
00119 
00120         wpabuf_put_u8(resp, flags); /* Flags */
00121         if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
00122                 wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
00123 
00124         wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
00125                         send_len);
00126         data->out_used += send_len;
00127 
00128         ret->methodState = METHOD_MAY_CONT;
00129         ret->decision = DECISION_FAIL;
00130 
00131         if (data->out_used == wpabuf_len(data->out_buf)) {
00132                 wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
00133                            "(message sent completely)",
00134                            (unsigned long) send_len);
00135                 wpabuf_free(data->out_buf);
00136                 data->out_buf = NULL;
00137                 data->out_used = 0;
00138         } else {
00139                 wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
00140                            "(%lu more to send)", (unsigned long) send_len,
00141                            (unsigned long) wpabuf_len(data->out_buf) -
00142                            data->out_used);
00143                 data->state = WAIT_FRAG_ACK;
00144         }
00145 
00146         return resp;
00147 }
00148 
00149 
00150 static int eap_tnc_process_cont(struct eap_tnc_data *data,
00151                                 const u8 *buf, size_t len)
00152 {
00153         /* Process continuation of a pending message */
00154         if (len > wpabuf_tailroom(data->in_buf)) {
00155                 wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
00156                 data->state = FAIL;
00157                 return -1;
00158         }
00159 
00160         wpabuf_put_data(data->in_buf, buf, len);
00161         wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
00162                    "%lu bytes more", (unsigned long) len,
00163                    (unsigned long) wpabuf_tailroom(data->in_buf));
00164 
00165         return 0;
00166 }
00167 
00168 
00169 static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
00170                                                 struct eap_method_ret *ret,
00171                                                 u8 id, u8 flags,
00172                                                 u32 message_length,
00173                                                 const u8 *buf, size_t len)
00174 {
00175         /* Process a fragment that is not the last one of the message */
00176         if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
00177                 wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
00178                            "fragmented packet");
00179                 ret->ignore = TRUE;
00180                 return NULL;
00181         }
00182 
00183         if (data->in_buf == NULL) {
00184                 /* First fragment of the message */
00185                 data->in_buf = wpabuf_alloc(message_length);
00186                 if (data->in_buf == NULL) {
00187                         wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
00188                                    "message");
00189                         ret->ignore = TRUE;
00190                         return NULL;
00191                 }
00192                 wpabuf_put_data(data->in_buf, buf, len);
00193                 wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
00194                            "fragment, waiting for %lu bytes more",
00195                            (unsigned long) len,
00196                            (unsigned long) wpabuf_tailroom(data->in_buf));
00197         }
00198 
00199         return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
00200 }
00201 
00202 
00203 static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
00204                                        struct eap_method_ret *ret,
00205                                        const struct wpabuf *reqData)
00206 {
00207         struct eap_tnc_data *data = priv;
00208         struct wpabuf *resp;
00209         const u8 *pos, *end;
00210         u8 *rpos, *rpos1;
00211         size_t len, rlen;
00212         size_t imc_len;
00213         char *start_buf, *end_buf;
00214         size_t start_len, end_len;
00215         int tncs_done = 0;
00216         u8 flags, id;
00217         u32 message_length = 0;
00218         struct wpabuf tmpbuf;
00219 
00220         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
00221         if (pos == NULL) {
00222                 wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
00223                            pos, (unsigned long) len);
00224                 ret->ignore = TRUE;
00225                 return NULL;
00226         }
00227 
00228         id = eap_get_id(reqData);
00229 
00230         end = pos + len;
00231 
00232         if (len == 0)
00233                 flags = 0; /* fragment ack */
00234         else
00235                 flags = *pos++;
00236 
00237         if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
00238                 wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
00239                            flags & EAP_TNC_VERSION_MASK);
00240                 ret->ignore = TRUE;
00241                 return NULL;
00242         }
00243 
00244         if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
00245                 if (end - pos < 4) {
00246                         wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
00247                         ret->ignore = TRUE;
00248                         return NULL;
00249                 }
00250                 message_length = WPA_GET_BE32(pos);
00251                 pos += 4;
00252 
00253                 if (message_length < (u32) (end - pos)) {
00254                         wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
00255                                    "Length (%d; %ld remaining in this msg)",
00256                                    message_length, (long) (end - pos));
00257                         ret->ignore = TRUE;
00258                         return NULL;
00259                 }
00260         }
00261 
00262         wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
00263                    "Message Length %u", flags, message_length);
00264 
00265         if (data->state == WAIT_FRAG_ACK) {
00266                 if (len > 1) {
00267                         wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
00268                                    "WAIT_FRAG_ACK state");
00269                         ret->ignore = TRUE;
00270                         return NULL;
00271                 }
00272                 wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
00273                 data->state = PROC_MSG;
00274                 return eap_tnc_build_msg(data, ret, id);
00275         }
00276 
00277         if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
00278                 ret->ignore = TRUE;
00279                 return NULL;
00280         }
00281                 
00282         if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
00283                 return eap_tnc_process_fragment(data, ret, id, flags,
00284                                                 message_length, pos,
00285                                                 end - pos);
00286         }
00287 
00288         if (data->in_buf == NULL) {
00289                 /* Wrap unfragmented messages as wpabuf without extra copy */
00290                 wpabuf_set(&tmpbuf, pos, end - pos);
00291                 data->in_buf = &tmpbuf;
00292         }
00293 
00294         if (data->state == WAIT_START) {
00295                 if (!(flags & EAP_TNC_FLAGS_START)) {
00296                         wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
00297                                    "start flag in the first message");
00298                         ret->ignore = TRUE;
00299                         goto fail;
00300                 }
00301 
00302                 tncc_init_connection(data->tncc);
00303 
00304                 data->state = PROC_MSG;
00305         } else {
00306                 enum tncc_process_res res;
00307 
00308                 if (flags & EAP_TNC_FLAGS_START) {
00309                         wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
00310                                    "flag again");
00311                         ret->ignore = TRUE;
00312                         goto fail;
00313                 }
00314 
00315                 res = tncc_process_if_tnccs(data->tncc,
00316                                             wpabuf_head(data->in_buf),
00317                                             wpabuf_len(data->in_buf));
00318                 switch (res) {
00319                 case TNCCS_PROCESS_ERROR:
00320                         ret->ignore = TRUE;
00321                         goto fail;
00322                 case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
00323                 case TNCCS_RECOMMENDATION_ERROR:
00324                         wpa_printf(MSG_DEBUG, "EAP-TNC: No "
00325                                    "TNCCS-Recommendation received");
00326                         break;
00327                 case TNCCS_RECOMMENDATION_ALLOW:
00328                         wpa_msg(sm->msg_ctx, MSG_INFO,
00329                                 "TNC: Recommendation = allow");
00330                         tncs_done = 1;
00331                         break;
00332                 case TNCCS_RECOMMENDATION_NONE:
00333                         wpa_msg(sm->msg_ctx, MSG_INFO,
00334                                 "TNC: Recommendation = none");
00335                         tncs_done = 1;
00336                         break;
00337                 case TNCCS_RECOMMENDATION_ISOLATE:
00338                         wpa_msg(sm->msg_ctx, MSG_INFO,
00339                                 "TNC: Recommendation = isolate");
00340                         tncs_done = 1;
00341                         break;
00342                 }
00343         }
00344 
00345         if (data->in_buf != &tmpbuf)
00346                 wpabuf_free(data->in_buf);
00347         data->in_buf = NULL;
00348 
00349         ret->ignore = FALSE;
00350         ret->methodState = METHOD_MAY_CONT;
00351         ret->decision = DECISION_UNCOND_SUCC;
00352         ret->allowNotifications = TRUE;
00353 
00354         if (data->out_buf) {
00355                 data->state = PROC_MSG;
00356                 return eap_tnc_build_msg(data, ret, id);
00357         }
00358 
00359         if (tncs_done) {
00360                 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
00361                                      EAP_CODE_RESPONSE, eap_get_id(reqData));
00362                 if (resp == NULL)
00363                         return NULL;
00364 
00365                 wpabuf_put_u8(resp, EAP_TNC_VERSION);
00366                 wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
00367                            "empty ACK message");
00368                 return resp;
00369         }
00370 
00371         imc_len = tncc_total_send_len(data->tncc);
00372 
00373         start_buf = tncc_if_tnccs_start(data->tncc);
00374         if (start_buf == NULL)
00375                 return NULL;
00376         start_len = os_strlen(start_buf);
00377         end_buf = tncc_if_tnccs_end();
00378         if (end_buf == NULL) {
00379                 os_free(start_buf);
00380                 return NULL;
00381         }
00382         end_len = os_strlen(end_buf);
00383 
00384         rlen = start_len + imc_len + end_len;
00385         resp = wpabuf_alloc(rlen);
00386         if (resp == NULL) {
00387                 os_free(start_buf);
00388                 os_free(end_buf);
00389                 return NULL;
00390         }
00391 
00392         wpabuf_put_data(resp, start_buf, start_len);
00393         os_free(start_buf);
00394 
00395         rpos1 = wpabuf_put(resp, 0);
00396         rpos = tncc_copy_send_buf(data->tncc, rpos1);
00397         wpabuf_put(resp, rpos - rpos1);
00398 
00399         wpabuf_put_data(resp, end_buf, end_len);
00400         os_free(end_buf);
00401 
00402         wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
00403                           wpabuf_head(resp), wpabuf_len(resp));
00404 
00405         data->out_buf = resp;
00406         data->state = PROC_MSG;
00407         return eap_tnc_build_msg(data, ret, id);
00408 
00409 fail:
00410         if (data->in_buf == &tmpbuf)
00411                 data->in_buf = NULL;
00412         return NULL;
00413 }
00414 
00415 
00416 int eap_peer_tnc_register(void)
00417 {
00418         struct eap_method *eap;
00419         int ret;
00420 
00421         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
00422                                     EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
00423         if (eap == NULL)
00424                 return -1;
00425 
00426         eap->init = eap_tnc_init;
00427         eap->deinit = eap_tnc_deinit;
00428         eap->process = eap_tnc_process;
00429 
00430         ret = eap_peer_method_register(eap);
00431         if (ret)
00432                 eap_peer_method_free(eap);
00433         return ret;
00434 }


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