2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
20 #include <crypto/hashers/hasher.h>
22 typedef struct private_eap_md5_t private_eap_md5_t
;
25 * Private data of an eap_md5_t object.
27 struct private_eap_md5_t
{
30 * Public authenticator_t interface.
37 identification_t
*server
;
42 identification_t
*peer
;
45 * challenge sent by the server
50 * EAP message identifier
55 typedef struct eap_md5_header_t eap_md5_header_t
;
58 * packed eap MD5 header struct
60 struct eap_md5_header_t
{
61 /** EAP code (REQUEST/RESPONSE) */
63 /** unique message identifier */
65 /** length of whole message */
69 /** length of value (challenge) */
73 } __attribute__((__packed__
));
75 #define CHALLENGE_LEN 16
76 #define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t))
79 * Hash the challenge string, create response
81 static status_t
hash_challenge(private_eap_md5_t
*this, chunk_t
*response
,
82 identification_t
*me
, identification_t
*other
)
88 shared
= lib
->credmgr
->get_shared(lib
->credmgr
, SHARED_EAP
, me
, other
);
91 DBG1(DBG_IKE
, "no EAP key found for hosts '%Y' - '%Y'", me
, other
);
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
);
100 DBG1(DBG_IKE
, "EAP-MD5 failed, MD5 not supported");
103 hasher
->allocate_hash(hasher
, concat
, response
);
104 hasher
->destroy(hasher
);
108 METHOD(eap_method_t
, initiate_peer
, status_t
,
109 private_eap_md5_t
*this, eap_payload_t
**out
)
111 /* peer never initiates */
115 METHOD(eap_method_t
, initiate_server
, status_t
,
116 private_eap_md5_t
*this, eap_payload_t
**out
)
119 eap_md5_header_t
*req
;
121 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
126 rng
->allocate_bytes(rng
, CHALLENGE_LEN
, &this->challenge
);
129 req
= alloca(PAYLOAD_LEN
);
130 req
->length
= htons(PAYLOAD_LEN
);
131 req
->code
= EAP_REQUEST
;
132 req
->identifier
= this->identifier
;
134 req
->value_size
= this->challenge
.len
;
135 memcpy(req
->value
, this->challenge
.ptr
, this->challenge
.len
);
137 *out
= eap_payload_create_data(chunk_create((void*)req
, PAYLOAD_LEN
));
141 METHOD(eap_method_t
, process_peer
, status_t
,
142 private_eap_md5_t
*this, eap_payload_t
*in
, eap_payload_t
**out
)
146 eap_md5_header_t
*req
;
148 this->identifier
= in
->get_identifier(in
);
149 data
= in
->get_data(in
);
150 if (data
.len
< 6 || data
.ptr
[5] + 6 > data
.len
)
152 DBG1(DBG_IKE
, "received invalid EAP-MD5 message");
155 this->challenge
= chunk_clone(chunk_create(data
.ptr
+ 6, data
.ptr
[5]));
156 if (hash_challenge(this, &response
, this->peer
, this->server
) != SUCCESS
)
160 req
= alloca(PAYLOAD_LEN
);
161 req
->length
= htons(PAYLOAD_LEN
);
162 req
->code
= EAP_RESPONSE
;
163 req
->identifier
= this->identifier
;
165 req
->value_size
= response
.len
;
166 memcpy(req
->value
, response
.ptr
, response
.len
);
167 chunk_free(&response
);
169 *out
= eap_payload_create_data(chunk_create((void*)req
, PAYLOAD_LEN
));
173 METHOD(eap_method_t
, process_server
, status_t
,
174 private_eap_md5_t
*this, eap_payload_t
*in
, eap_payload_t
**out
)
176 chunk_t response
, expected
;
179 data
= in
->get_data(in
);
180 if (this->identifier
!= in
->get_identifier(in
) ||
181 data
.len
< 6 || data
.ptr
[5] + 6 > data
.len
)
183 DBG1(DBG_IKE
, "received invalid EAP-MD5 message");
186 if (hash_challenge(this, &expected
, this->server
, this->peer
) != SUCCESS
)
190 response
= chunk_create(data
.ptr
+ 6, data
.ptr
[5]);
191 if (response
.len
< expected
.len
||
192 !memeq(response
.ptr
, expected
.ptr
, expected
.len
))
194 chunk_free(&expected
);
195 DBG1(DBG_IKE
, "EAP-MD5 verification failed");
198 chunk_free(&expected
);
202 METHOD(eap_method_t
, get_type
, eap_type_t
,
203 private_eap_md5_t
*this, u_int32_t
*vendor
)
209 METHOD(eap_method_t
, get_msk
, status_t
,
210 private_eap_md5_t
*this, chunk_t
*msk
)
215 METHOD(eap_method_t
, is_mutual
, bool,
216 private_eap_md5_t
*this)
221 METHOD(eap_method_t
, get_identifier
, u_int8_t
,
222 private_eap_md5_t
*this)
224 return this->identifier
;
227 METHOD(eap_method_t
, set_identifier
, void,
228 private_eap_md5_t
*this, u_int8_t identifier
)
230 this->identifier
= identifier
;
233 METHOD(eap_method_t
, destroy
, void,
234 private_eap_md5_t
*this)
236 this->peer
->destroy(this->peer
);
237 this->server
->destroy(this->server
);
238 chunk_free(&this->challenge
);
245 eap_md5_t
*eap_md5_create_server(identification_t
*server
, identification_t
*peer
)
247 private_eap_md5_t
*this;
252 .initiate
= _initiate_server
,
253 .process
= _process_server
,
254 .get_type
= _get_type
,
255 .is_mutual
= _is_mutual
,
257 .get_identifier
= _get_identifier
,
258 .set_identifier
= _set_identifier
,
262 .peer
= peer
->clone(peer
),
263 .server
= server
->clone(server
),
266 /* generate a non-zero identifier */
268 this->identifier
= random();
269 } while (!this->identifier
);
271 return &this->public;
277 eap_md5_t
*eap_md5_create_peer(identification_t
*server
, identification_t
*peer
)
279 private_eap_md5_t
*this;
284 .initiate
= _initiate_peer
,
285 .process
= _process_peer
,
286 .get_type
= _get_type
,
287 .is_mutual
= _is_mutual
,
292 .peer
= peer
->clone(peer
),
293 .server
= server
->clone(server
),
296 return &this->public;