2 * Copyright (C) 2007-2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #define GTC_REQUEST_MSG "password"
24 typedef struct private_eap_gtc_t private_eap_gtc_t
;
27 * Private data of an eap_gtc_t object.
29 struct private_eap_gtc_t
{
32 * Public authenticator_t interface.
39 identification_t
*server
;
44 identification_t
*peer
;
47 * EAP message identififier
52 typedef struct eap_gtc_header_t eap_gtc_header_t
;
55 * packed eap GTC header struct
57 struct eap_gtc_header_t
{
58 /** EAP code (REQUEST/RESPONSE) */
60 /** unique message identifier */
62 /** length of whole message */
68 } __attribute__((__packed__
));
70 METHOD(eap_method_t
, initiate_peer
, status_t
,
71 private_eap_gtc_t
*this, eap_payload_t
**out
)
73 /* peer never initiates */
77 METHOD(eap_method_t
, initiate_server
, status_t
,
78 private_eap_gtc_t
*this, eap_payload_t
**out
)
80 eap_gtc_header_t
*req
;
83 len
= strlen(GTC_REQUEST_MSG
);
84 req
= alloca(sizeof(eap_gtc_header_t
) + len
);
85 req
->length
= htons(sizeof(eap_gtc_header_t
) + len
);
86 req
->code
= EAP_REQUEST
;
87 req
->identifier
= this->identifier
;
89 memcpy(req
->data
, GTC_REQUEST_MSG
, len
);
91 *out
= eap_payload_create_data(chunk_create((void*)req
,
92 sizeof(eap_gtc_header_t
) + len
));
96 METHOD(eap_method_t
, process_peer
, status_t
,
97 private_eap_gtc_t
*this, eap_payload_t
*in
, eap_payload_t
**out
)
99 eap_gtc_header_t
*res
;
100 shared_key_t
*shared
;
104 shared
= lib
->credmgr
->get_shared(lib
->credmgr
, SHARED_EAP
,
105 this->peer
, this->server
);
108 DBG1(DBG_IKE
, "no EAP key found for '%Y' - '%Y'",
109 this->peer
, this->server
);
112 key
= shared
->get_key(shared
);
115 /* TODO: According to the draft we should "SASLprep" password, RFC4013. */
117 this->identifier
= in
->get_identifier(in
);
118 res
= alloca(sizeof(eap_gtc_header_t
) + len
);
119 res
->length
= htons(sizeof(eap_gtc_header_t
) + len
);
120 res
->code
= EAP_RESPONSE
;
121 res
->identifier
= this->identifier
;
123 memcpy(res
->data
, key
.ptr
, len
);
125 shared
->destroy(shared
);
127 *out
= eap_payload_create_data(chunk_create((void*)res
,
128 sizeof(eap_gtc_header_t
) + len
));
132 METHOD(eap_method_t
, process_server
, status_t
,
133 private_eap_gtc_t
*this, eap_payload_t
*in
, eap_payload_t
**out
)
135 status_t status
= FAILED
;
137 xauth_method_t
*xauth
;
138 cp_payload_t
*ci
, *co
;
141 user
= this->peer
->get_encoding(this->peer
);
142 pass
= chunk_skip(in
->get_data(in
), 5);
143 if (this->identifier
!= in
->get_identifier(in
) || !pass
.len
)
145 DBG1(DBG_IKE
, "received invalid EAP-GTC message");
149 /* get XAuth backend to use for credential verification. Default to PAM
150 * to support legacy EAP-GTC configurations */
151 backend
= lib
->settings
->get_str(lib
->settings
,
152 "%s.plugins.eap-gtc.backend", "pam", charon
->name
);
153 xauth
= charon
->xauth
->create_instance(charon
->xauth
, backend
, XAUTH_SERVER
,
154 this->server
, this->peer
);
157 DBG1(DBG_IKE
, "creating EAP-GTC XAuth backend '%s' failed", backend
);
160 if (xauth
->initiate(xauth
, &co
) == NEED_MORE
)
162 /* assume that "out" contains username/password attributes */
164 ci
= cp_payload_create_type(CONFIGURATION_V1
, CFG_REPLY
);
165 ci
->add_attribute(ci
, configuration_attribute_create_chunk(
166 CONFIGURATION_ATTRIBUTE_V1
, XAUTH_USER_NAME
, user
));
167 ci
->add_attribute(ci
, configuration_attribute_create_chunk(
168 CONFIGURATION_ATTRIBUTE_V1
, XAUTH_USER_PASSWORD
, pass
));
169 switch (xauth
->process(xauth
, ci
, &co
))
175 /* TODO: multiple exchanges currently not supported */
184 xauth
->destroy(xauth
);
188 METHOD(eap_method_t
, get_type
, eap_type_t
,
189 private_eap_gtc_t
*this, u_int32_t
*vendor
)
195 METHOD(eap_method_t
, get_msk
, status_t
,
196 private_eap_gtc_t
*this, chunk_t
*msk
)
201 METHOD(eap_method_t
, get_identifier
, u_int8_t
,
202 private_eap_gtc_t
*this)
204 return this->identifier
;
207 METHOD(eap_method_t
, set_identifier
, void,
208 private_eap_gtc_t
*this, u_int8_t identifier
)
210 this->identifier
= identifier
;
213 METHOD(eap_method_t
, is_mutual
, bool,
214 private_eap_gtc_t
*this)
219 METHOD(eap_method_t
, destroy
, void,
220 private_eap_gtc_t
*this)
222 this->peer
->destroy(this->peer
);
223 this->server
->destroy(this->server
);
228 * Generic constructor
230 static private_eap_gtc_t
*eap_gtc_create_generic(identification_t
*server
,
231 identification_t
*peer
)
233 private_eap_gtc_t
*this;
237 .eap_method_interface
= {
238 .get_type
= _get_type
,
239 .is_mutual
= _is_mutual
,
241 .get_identifier
= _get_identifier
,
242 .set_identifier
= _set_identifier
,
246 .peer
= peer
->clone(peer
),
247 .server
= server
->clone(server
),
256 eap_gtc_t
*eap_gtc_create_server(identification_t
*server
, identification_t
*peer
)
258 private_eap_gtc_t
*this = eap_gtc_create_generic(server
, peer
);
260 this->public.eap_method_interface
.initiate
= _initiate_server
;
261 this->public.eap_method_interface
.process
= _process_server
;
263 /* generate a non-zero identifier */
265 this->identifier
= random();
266 } while (!this->identifier
);
268 return &this->public;
274 eap_gtc_t
*eap_gtc_create_peer(identification_t
*server
, identification_t
*peer
)
276 private_eap_gtc_t
*this = eap_gtc_create_generic(server
, peer
);
278 this->public.eap_method_interface
.initiate
= _initiate_peer
;
279 this->public.eap_method_interface
.process
= _process_peer
;
281 return &this->public;