Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_md5/eap_md5.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2007 Martin Willi
! 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_md5.h"
! 17:
! 18: #include <daemon.h>
! 19: #include <library.h>
! 20: #include <crypto/hashers/hasher.h>
! 21:
! 22: typedef struct private_eap_md5_t private_eap_md5_t;
! 23:
! 24: /**
! 25: * Private data of an eap_md5_t object.
! 26: */
! 27: struct private_eap_md5_t {
! 28:
! 29: /**
! 30: * Public authenticator_t interface.
! 31: */
! 32: eap_md5_t public;
! 33:
! 34: /**
! 35: * ID of the server
! 36: */
! 37: identification_t *server;
! 38:
! 39: /**
! 40: * ID of the peer
! 41: */
! 42: identification_t *peer;
! 43:
! 44: /**
! 45: * challenge sent by the server
! 46: */
! 47: chunk_t challenge;
! 48:
! 49: /**
! 50: * EAP message identifier
! 51: */
! 52: uint8_t identifier;
! 53: };
! 54:
! 55: typedef struct eap_md5_header_t eap_md5_header_t;
! 56:
! 57: /**
! 58: * packed eap MD5 header struct
! 59: */
! 60: struct eap_md5_header_t {
! 61: /** EAP code (REQUEST/RESPONSE) */
! 62: uint8_t code;
! 63: /** unique message identifier */
! 64: uint8_t identifier;
! 65: /** length of whole message */
! 66: uint16_t length;
! 67: /** EAP type */
! 68: uint8_t type;
! 69: /** length of value (challenge) */
! 70: uint8_t value_size;
! 71: /** actual value */
! 72: uint8_t value[];
! 73: } __attribute__((__packed__));
! 74:
! 75: #define CHALLENGE_LEN 16
! 76: #define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t))
! 77:
! 78: /**
! 79: * Hash the challenge string, create response
! 80: */
! 81: static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response,
! 82: identification_t *me, identification_t *other)
! 83: {
! 84: shared_key_t *shared;
! 85: chunk_t concat;
! 86: hasher_t *hasher;
! 87:
! 88: shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, me, other);
! 89: if (shared == NULL)
! 90: {
! 91: DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'", me, other);
! 92: return NOT_FOUND;
! 93: }
! 94: concat = chunk_cata("ccc", chunk_from_thing(this->identifier),
! 95: shared->get_key(shared), this->challenge);
! 96: shared->destroy(shared);
! 97: hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
! 98: if (hasher == NULL)
! 99: {
! 100: DBG1(DBG_IKE, "EAP-MD5 failed, MD5 not supported");
! 101: return FAILED;
! 102: }
! 103: if (!hasher->allocate_hash(hasher, concat, response))
! 104: {
! 105: hasher->destroy(hasher);
! 106: return FAILED;
! 107: }
! 108: hasher->destroy(hasher);
! 109: return SUCCESS;
! 110: }
! 111:
! 112: METHOD(eap_method_t, initiate_peer, status_t,
! 113: private_eap_md5_t *this, eap_payload_t **out)
! 114: {
! 115: /* peer never initiates */
! 116: return FAILED;
! 117: }
! 118:
! 119: METHOD(eap_method_t, initiate_server, status_t,
! 120: private_eap_md5_t *this, eap_payload_t **out)
! 121: {
! 122: rng_t *rng;
! 123: eap_md5_header_t *req;
! 124:
! 125: rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
! 126: if (!rng || !rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge))
! 127: {
! 128: DESTROY_IF(rng);
! 129: return FAILED;
! 130: }
! 131: rng->destroy(rng);
! 132:
! 133: req = alloca(PAYLOAD_LEN);
! 134: req->length = htons(PAYLOAD_LEN);
! 135: req->code = EAP_REQUEST;
! 136: req->identifier = this->identifier;
! 137: req->type = EAP_MD5;
! 138: req->value_size = this->challenge.len;
! 139: memcpy(req->value, this->challenge.ptr, this->challenge.len);
! 140:
! 141: *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN));
! 142: return NEED_MORE;
! 143: }
! 144:
! 145: METHOD(eap_method_t, process_peer, status_t,
! 146: private_eap_md5_t *this, eap_payload_t *in, eap_payload_t **out)
! 147: {
! 148: chunk_t response;
! 149: chunk_t data;
! 150: eap_md5_header_t *req;
! 151:
! 152: this->identifier = in->get_identifier(in);
! 153: data = in->get_data(in);
! 154: if (data.len < 6 || data.ptr[5] + 6 > data.len)
! 155: {
! 156: DBG1(DBG_IKE, "received invalid EAP-MD5 message");
! 157: return FAILED;
! 158: }
! 159: this->challenge = chunk_clone(chunk_create(data.ptr + 6, data.ptr[5]));
! 160: if (hash_challenge(this, &response, this->peer, this->server) != SUCCESS)
! 161: {
! 162: return FAILED;
! 163: }
! 164: req = alloca(PAYLOAD_LEN);
! 165: req->length = htons(PAYLOAD_LEN);
! 166: req->code = EAP_RESPONSE;
! 167: req->identifier = this->identifier;
! 168: req->type = EAP_MD5;
! 169: req->value_size = response.len;
! 170: memcpy(req->value, response.ptr, response.len);
! 171: chunk_free(&response);
! 172:
! 173: *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN));
! 174: return NEED_MORE;
! 175: }
! 176:
! 177: METHOD(eap_method_t, process_server, status_t,
! 178: private_eap_md5_t *this, eap_payload_t *in, eap_payload_t **out)
! 179: {
! 180: chunk_t response, expected;
! 181: chunk_t data;
! 182:
! 183: data = in->get_data(in);
! 184: if (this->identifier != in->get_identifier(in) ||
! 185: data.len < 6 || data.ptr[5] + 6 > data.len)
! 186: {
! 187: DBG1(DBG_IKE, "received invalid EAP-MD5 message");
! 188: return FAILED;
! 189: }
! 190: if (hash_challenge(this, &expected, this->server, this->peer) != SUCCESS)
! 191: {
! 192: return FAILED;
! 193: }
! 194: response = chunk_create(data.ptr + 6, data.ptr[5]);
! 195: if (response.len < expected.len ||
! 196: !memeq_const(response.ptr, expected.ptr, expected.len))
! 197: {
! 198: chunk_free(&expected);
! 199: DBG1(DBG_IKE, "EAP-MD5 verification failed");
! 200: return FAILED;
! 201: }
! 202: chunk_free(&expected);
! 203: return SUCCESS;
! 204: }
! 205:
! 206: METHOD(eap_method_t, get_type, eap_type_t,
! 207: private_eap_md5_t *this, uint32_t *vendor)
! 208: {
! 209: *vendor = 0;
! 210: return EAP_MD5;
! 211: }
! 212:
! 213: METHOD(eap_method_t, get_msk, status_t,
! 214: private_eap_md5_t *this, chunk_t *msk)
! 215: {
! 216: return FAILED;
! 217: }
! 218:
! 219: METHOD(eap_method_t, is_mutual, bool,
! 220: private_eap_md5_t *this)
! 221: {
! 222: return FALSE;
! 223: }
! 224:
! 225: METHOD(eap_method_t, get_identifier, uint8_t,
! 226: private_eap_md5_t *this)
! 227: {
! 228: return this->identifier;
! 229: }
! 230:
! 231: METHOD(eap_method_t, set_identifier, void,
! 232: private_eap_md5_t *this, uint8_t identifier)
! 233: {
! 234: this->identifier = identifier;
! 235: }
! 236:
! 237: METHOD(eap_method_t, destroy, void,
! 238: private_eap_md5_t *this)
! 239: {
! 240: this->peer->destroy(this->peer);
! 241: this->server->destroy(this->server);
! 242: chunk_free(&this->challenge);
! 243: free(this);
! 244: }
! 245:
! 246: /*
! 247: * See header
! 248: */
! 249: eap_md5_t *eap_md5_create_server(identification_t *server, identification_t *peer)
! 250: {
! 251: private_eap_md5_t *this;
! 252:
! 253: INIT(this,
! 254: .public = {
! 255: .eap_method = {
! 256: .initiate = _initiate_server,
! 257: .process = _process_server,
! 258: .get_type = _get_type,
! 259: .is_mutual = _is_mutual,
! 260: .get_msk = _get_msk,
! 261: .get_identifier = _get_identifier,
! 262: .set_identifier = _set_identifier,
! 263: .destroy = _destroy,
! 264: },
! 265: },
! 266: .peer = peer->clone(peer),
! 267: .server = server->clone(server),
! 268: );
! 269:
! 270: /* generate a non-zero identifier */
! 271: do {
! 272: this->identifier = random();
! 273: } while (!this->identifier);
! 274:
! 275: return &this->public;
! 276: }
! 277:
! 278: /*
! 279: * See header
! 280: */
! 281: eap_md5_t *eap_md5_create_peer(identification_t *server, identification_t *peer)
! 282: {
! 283: private_eap_md5_t *this;
! 284:
! 285: INIT(this,
! 286: .public = {
! 287: .eap_method = {
! 288: .initiate = _initiate_peer,
! 289: .process = _process_peer,
! 290: .get_type = _get_type,
! 291: .is_mutual = _is_mutual,
! 292: .get_msk = _get_msk,
! 293: .destroy = _destroy,
! 294: },
! 295: },
! 296: .peer = peer->clone(peer),
! 297: .server = server->clone(server),
! 298: );
! 299:
! 300: return &this->public;
! 301: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>