Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2010 Andreas Steffen
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #include "eap_ttls_peer.h"
! 17: #include "eap_ttls_avp.h"
! 18:
! 19: #include <utils/debug.h>
! 20: #include <daemon.h>
! 21: #include <radius_message.h>
! 22: #include <sa/eap/eap_method.h>
! 23:
! 24: typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t;
! 25:
! 26: /**
! 27: * Private data of an eap_ttls_peer_t object.
! 28: */
! 29: struct private_eap_ttls_peer_t {
! 30:
! 31: /**
! 32: * Public eap_ttls_peer_t interface.
! 33: */
! 34: eap_ttls_peer_t public;
! 35:
! 36: /**
! 37: * Server identity
! 38: */
! 39: identification_t *server;
! 40:
! 41: /**
! 42: * Peer identity
! 43: */
! 44: identification_t *peer;
! 45:
! 46: /**
! 47: * Current EAP-TTLS state
! 48: */
! 49: bool start_phase2;
! 50:
! 51: /**
! 52: * Current phase 2 EAP method
! 53: */
! 54: eap_method_t *method;
! 55:
! 56: /**
! 57: * Pending outbound EAP message
! 58: */
! 59: eap_payload_t *out;
! 60:
! 61: /**
! 62: * AVP handler
! 63: */
! 64: eap_ttls_avp_t *avp;
! 65: };
! 66:
! 67: METHOD(tls_application_t, process, status_t,
! 68: private_eap_ttls_peer_t *this, bio_reader_t *reader)
! 69: {
! 70: chunk_t avp_data = chunk_empty;
! 71: chunk_t eap_data = chunk_empty;
! 72: status_t status;
! 73: payload_t *payload;
! 74: eap_payload_t *in;
! 75: eap_packet_t *pkt;
! 76: eap_code_t code;
! 77: eap_type_t type, received_type;
! 78: uint32_t vendor, received_vendor;
! 79: uint16_t eap_len;
! 80: size_t eap_pos = 0;
! 81: bool concatenated = FALSE;
! 82:
! 83: do
! 84: {
! 85: status = this->avp->process(this->avp, reader, &avp_data);
! 86: switch (status)
! 87: {
! 88: case SUCCESS:
! 89: break;
! 90: case NEED_MORE:
! 91: DBG1(DBG_IKE, "need more AVP data");
! 92: return NEED_MORE;
! 93: case FAILED:
! 94: default:
! 95: return FAILED;
! 96: }
! 97:
! 98: if (eap_data.len == 0)
! 99: {
! 100: if (avp_data.len < 4)
! 101: {
! 102: DBG1(DBG_IKE, "AVP size to small to contain EAP header");
! 103: chunk_free(&avp_data);
! 104: return FAILED;
! 105: }
! 106: pkt = (eap_packet_t*)avp_data.ptr;
! 107: eap_len = untoh16(&pkt->length);
! 108:
! 109: if (eap_len <= avp_data.len)
! 110: {
! 111: /* standard: EAP packet contained in a single AVP */
! 112: eap_data = avp_data;
! 113: break;
! 114: }
! 115: else if (eap_len > reader->remaining(reader) + avp_data.len)
! 116: {
! 117: /* rough size check, ignoring AVP headers in remaining data */
! 118: DBG1(DBG_IKE, "EAP packet too large for EAP-TTLS AVP(s)");
! 119: chunk_free(&avp_data);
! 120: return FAILED;
! 121: }
! 122: else if (avp_data.len == MAX_RADIUS_ATTRIBUTE_SIZE)
! 123: {
! 124: /* non-standard: EAP packet segmented into multiple AVPs */
! 125: eap_data = chunk_alloc(eap_len);
! 126: concatenated = TRUE;
! 127: }
! 128: else
! 129: {
! 130: DBG1(DBG_IKE, "non-radius segmentation of EAP packet into AVPs");
! 131: chunk_free(&avp_data);
! 132: return FAILED;
! 133: }
! 134: }
! 135:
! 136: if (avp_data.len > eap_data.len - eap_pos)
! 137: {
! 138: DBG1(DBG_IKE, "AVP size too large to fit into EAP packet");
! 139: chunk_free(&avp_data);
! 140: chunk_free(&eap_data);
! 141: return FAILED;
! 142: }
! 143: memcpy(eap_data.ptr + eap_pos, avp_data.ptr, avp_data.len);
! 144: eap_pos += avp_data.len;
! 145: chunk_free(&avp_data);
! 146: }
! 147: while (eap_pos < eap_data.len);
! 148:
! 149: in = eap_payload_create_data(eap_data);
! 150: chunk_free(&eap_data);
! 151: payload = (payload_t*)in;
! 152:
! 153: if (payload->verify(payload) != SUCCESS)
! 154: {
! 155: in->destroy(in);
! 156: return FAILED;
! 157: }
! 158: code = in->get_code(in);
! 159: received_type = in->get_type(in, &received_vendor);
! 160: DBG1(DBG_IKE, "received tunneled EAP-TTLS AVP%s [EAP/%N/%N]",
! 161: concatenated ? "s" : "",
! 162: eap_code_short_names, code,
! 163: eap_type_short_names, received_type);
! 164: if (code != EAP_REQUEST)
! 165: {
! 166: DBG1(DBG_IKE, "%N expected", eap_code_names, EAP_REQUEST);
! 167: in->destroy(in);
! 168: return FAILED;
! 169: }
! 170:
! 171: /* yet another phase2 authentication? */
! 172: if (this->method)
! 173: {
! 174: type = this->method->get_type(this->method, &vendor);
! 175:
! 176: if (type != received_type || vendor != received_vendor)
! 177: {
! 178: this->method->destroy(this->method);
! 179: this->method = NULL;
! 180: }
! 181: }
! 182:
! 183: if (this->method == NULL)
! 184: {
! 185: if (received_vendor)
! 186: {
! 187: DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d "
! 188: "(id 0x%02X)", received_type, received_vendor,
! 189: in->get_identifier(in));
! 190: }
! 191: else
! 192: {
! 193: DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)",
! 194: eap_type_names, received_type, in->get_identifier(in));
! 195: }
! 196: this->method = charon->eap->create_instance(charon->eap,
! 197: received_type, received_vendor,
! 198: EAP_PEER, this->server, this->peer);
! 199: if (!this->method)
! 200: {
! 201: DBG1(DBG_IKE, "EAP method not supported");
! 202: this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0,
! 203: in->is_expanded(in));
! 204: in->destroy(in);
! 205: return NEED_MORE;
! 206: }
! 207: type = this->method->get_type(this->method, &vendor);
! 208: this->start_phase2 = FALSE;
! 209: }
! 210:
! 211: status = this->method->process(this->method, in, &this->out);
! 212: in->destroy(in);
! 213:
! 214: switch (status)
! 215: {
! 216: case SUCCESS:
! 217: this->method->destroy(this->method);
! 218: this->method = NULL;
! 219: /* fall through to NEED_MORE */
! 220: case NEED_MORE:
! 221: return NEED_MORE;
! 222: case FAILED:
! 223: default:
! 224: if (vendor)
! 225: {
! 226: DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed",
! 227: type, vendor);
! 228: }
! 229: else
! 230: {
! 231: DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
! 232: }
! 233: return FAILED;
! 234: }
! 235: }
! 236:
! 237: METHOD(tls_application_t, build, status_t,
! 238: private_eap_ttls_peer_t *this, bio_writer_t *writer)
! 239: {
! 240: chunk_t data;
! 241: eap_code_t code;
! 242: eap_type_t type;
! 243: uint32_t vendor;
! 244:
! 245: if (this->method == NULL && this->start_phase2)
! 246: {
! 247: /* generate an EAP Identity response */
! 248: this->method = charon->eap->create_instance(charon->eap, EAP_IDENTITY,
! 249: 0, EAP_PEER, this->server, this->peer);
! 250: if (this->method == NULL)
! 251: {
! 252: DBG1(DBG_IKE, "EAP_IDENTITY method not available");
! 253: return FAILED;
! 254: }
! 255: this->method->process(this->method, NULL, &this->out);
! 256: this->method->destroy(this->method);
! 257: this->method = NULL;
! 258: this->start_phase2 = FALSE;
! 259: }
! 260:
! 261: if (this->out)
! 262: {
! 263: code = this->out->get_code(this->out);
! 264: type = this->out->get_type(this->out, &vendor);
! 265: DBG1(DBG_IKE, "sending tunneled EAP-TTLS AVP [EAP/%N/%N]",
! 266: eap_code_short_names, code, eap_type_short_names, type);
! 267:
! 268: /* get the raw EAP message data */
! 269: data = this->out->get_data(this->out);
! 270: this->avp->build(this->avp, writer, data);
! 271:
! 272: this->out->destroy(this->out);
! 273: this->out = NULL;
! 274: }
! 275: return INVALID_STATE;
! 276: }
! 277:
! 278: METHOD(tls_application_t, destroy, void,
! 279: private_eap_ttls_peer_t *this)
! 280: {
! 281: this->server->destroy(this->server);
! 282: this->peer->destroy(this->peer);
! 283: DESTROY_IF(this->method);
! 284: DESTROY_IF(this->out);
! 285: this->avp->destroy(this->avp);
! 286: free(this);
! 287: }
! 288:
! 289: /**
! 290: * See header
! 291: */
! 292: eap_ttls_peer_t *eap_ttls_peer_create(identification_t *server,
! 293: identification_t *peer)
! 294: {
! 295: private_eap_ttls_peer_t *this;
! 296:
! 297: INIT(this,
! 298: .public = {
! 299: .application = {
! 300: .process = _process,
! 301: .build = _build,
! 302: .destroy = _destroy,
! 303: },
! 304: },
! 305: .server = server->clone(server),
! 306: .peer = peer->clone(peer),
! 307: .start_phase2 = TRUE,
! 308: .avp = eap_ttls_avp_create(),
! 309: );
! 310:
! 311: return &this->public;
! 312: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>