4 * @brief Implementation of eap_md5_t.
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28 typedef struct private_eap_md5_t private_eap_md5_t
;
31 * Private data of an eap_md5_t object.
33 struct private_eap_md5_t
{
36 * Public authenticator_t interface.
43 identification_t
*server
;
48 identification_t
*peer
;
51 * challenge sent by the server
56 * EAP message identififier
61 typedef struct eap_md5_header_t eap_md5_header_t
;
64 * packed eap MD5 header struct
66 struct eap_md5_header_t
{
67 /** EAP code (REQUEST/RESPONSE) */
69 /** unique message identifier */
71 /** length of whole message */
75 /** length of value (challenge) */
79 } __attribute__((__packed__
));
81 #define CHALLENGE_LEN 16
82 #define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t))
85 * Hash the challenge string, create response
87 static status_t
hash_challenge(private_eap_md5_t
*this, chunk_t
*response
)
89 chunk_t concat
, secret
;
92 if (charon
->credentials
->get_eap_key(charon
->credentials
, this->server
,
93 this->peer
, &secret
) != SUCCESS
)
95 DBG1(DBG_IKE
, "no EAP key found for hosts '%D' - '%D'",
96 this->server
, this->peer
);
99 concat
= chunk_cata("cmc", chunk_from_thing(this->identifier
),
100 secret
, this->challenge
);
101 hasher
= hasher_create(HASH_MD5
);
102 hasher
->allocate_hash(hasher
, concat
, response
);
103 hasher
->destroy(hasher
);
108 * Implementation of eap_method_t.initiate for the peer
110 static status_t
initiate_peer(private_eap_md5_t
*this, eap_payload_t
**out
)
112 /* peer never initiates */
117 * Implementation of eap_method_t.initiate for the server
119 static status_t
initiate_server(private_eap_md5_t
*this, eap_payload_t
**out
)
121 randomizer_t
*randomizer
;
123 eap_md5_header_t
*req
;
125 randomizer
= randomizer_create();
126 status
= randomizer
->allocate_pseudo_random_bytes(randomizer
, CHALLENGE_LEN
,
128 randomizer
->destroy(randomizer
);
129 if (status
!= SUCCESS
)
134 req
= alloca(PAYLOAD_LEN
);
135 req
->length
= htons(PAYLOAD_LEN
);
136 req
->code
= EAP_REQUEST
;
137 req
->identifier
= this->identifier
;
139 req
->value_size
= this->challenge
.len
;
140 memcpy(req
->value
, this->challenge
.ptr
, this->challenge
.len
);
142 *out
= eap_payload_create_data(chunk_create((void*)req
, PAYLOAD_LEN
));
147 * Implementation of eap_method_t.process for the peer
149 static status_t
process_peer(private_eap_md5_t
*this,
150 eap_payload_t
*in
, eap_payload_t
**out
)
154 eap_md5_header_t
*req
;
156 this->identifier
= in
->get_identifier(in
);
157 data
= in
->get_data(in
);
158 this->challenge
= chunk_clone(chunk_skip(data
, 6));
159 if (data
.len
< 6 || this->challenge
.len
< *(data
.ptr
+ 5))
161 DBG1(DBG_IKE
, "received invalid EAP-MD5 message");
164 if (hash_challenge(this, &response
) != SUCCESS
)
168 req
= alloca(PAYLOAD_LEN
);
169 req
->length
= htons(PAYLOAD_LEN
);
170 req
->code
= EAP_RESPONSE
;
171 req
->identifier
= this->identifier
;
173 req
->value_size
= response
.len
;
174 memcpy(req
->value
, response
.ptr
, response
.len
);
175 chunk_free(&response
);
177 *out
= eap_payload_create_data(chunk_create((void*)req
, PAYLOAD_LEN
));
182 * Implementation of eap_method_t.process for the server
184 static status_t
process_server(private_eap_md5_t
*this,
185 eap_payload_t
*in
, eap_payload_t
**out
)
187 chunk_t response
, expected
;
190 if (this->identifier
!= in
->get_identifier(in
))
192 DBG1(DBG_IKE
, "received invalid EAP-MD5 message");
195 if (hash_challenge(this, &expected
) != SUCCESS
)
199 data
= in
->get_data(in
);
200 response
= chunk_skip(data
, 6);
202 if (!chunk_equals(response
, expected
))
204 chunk_free(&expected
);
205 DBG1(DBG_IKE
, "EAP-MD5 verification failed");
208 chunk_free(&expected
);
213 * Implementation of eap_method_t.get_type.
215 static eap_type_t
get_type(private_eap_md5_t
*this)
221 * Implementation of eap_method_t.get_msk.
223 static status_t
get_msk(private_eap_md5_t
*this, chunk_t
*msk
)
229 * Implementation of eap_method_t.is_mutual.
231 static bool is_mutual(private_eap_md5_t
*this)
237 * Implementation of eap_method_t.destroy.
239 static void destroy(private_eap_md5_t
*this)
241 chunk_free(&this->challenge
);
246 * Described in header.
248 eap_md5_t
*eap_create(eap_role_t role
,
249 identification_t
*server
, identification_t
*peer
)
251 private_eap_md5_t
*this = malloc_thing(private_eap_md5_t
);
253 /* public functions */
257 this->public.eap_method_interface
.initiate
= (status_t(*)(eap_method_t
*,eap_payload_t
**))initiate_server
;
258 this->public.eap_method_interface
.process
= (status_t(*)(eap_method_t
*,eap_payload_t
*,eap_payload_t
**))process_server
;
261 this->public.eap_method_interface
.initiate
= (status_t(*)(eap_method_t
*,eap_payload_t
**))initiate_peer
;
262 this->public.eap_method_interface
.process
= (status_t(*)(eap_method_t
*,eap_payload_t
*,eap_payload_t
**))process_peer
;
268 this->public.eap_method_interface
.get_type
= (eap_type_t(*)(eap_method_t
*))get_type
;
269 this->public.eap_method_interface
.is_mutual
= (bool(*)(eap_method_t
*))is_mutual
;
270 this->public.eap_method_interface
.get_msk
= (status_t(*)(eap_method_t
*,chunk_t
*))get_msk
;
271 this->public.eap_method_interface
.destroy
= (void(*)(eap_method_t
*))destroy
;
275 this->server
= server
;
276 this->challenge
= chunk_empty
;
277 this->identifier
= random();
279 return &this->public;