Use (as client) and verify (as server) configured XAuth identities
[strongswan.git] / src / libcharon / sa / tasks / xauth.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
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 "xauth.h"
17
18 #include <daemon.h>
19 #include <hydra.h>
20 #include <encoding/payloads/cp_payload.h>
21
22 typedef struct private_xauth_t private_xauth_t;
23
24 /**
25 * Status types exchanged
26 */
27 typedef enum {
28 XAUTH_FAILED = 0,
29 XAUTH_OK = 1,
30 } xauth_status_t;
31
32 /**
33 * Private members of a xauth_t task.
34 */
35 struct private_xauth_t {
36
37 /**
38 * Public methods and task_t interface.
39 */
40 xauth_t public;
41
42 /**
43 * Assigned IKE_SA.
44 */
45 ike_sa_t *ike_sa;
46
47 /**
48 * Are we the XAUTH initiator?
49 */
50 bool initiator;
51
52 /**
53 * XAuth backend to use
54 */
55 xauth_method_t *xauth;
56
57 /**
58 * XAuth username
59 */
60 identification_t *user;
61
62 /**
63 * Generated configuration payload
64 */
65 cp_payload_t *cp;
66
67 /**
68 * status of Xauth exchange
69 */
70 xauth_status_t status;
71 };
72
73 /**
74 * Load XAuth backend
75 */
76 static xauth_method_t *load_method(private_xauth_t* this)
77 {
78 identification_t *server, *peer;
79 enumerator_t *enumerator;
80 xauth_method_t *xauth;
81 xauth_role_t role;
82 peer_cfg_t *peer_cfg;
83 auth_cfg_t *auth;
84 char *name;
85
86 if (this->initiator)
87 {
88 server = this->ike_sa->get_my_id(this->ike_sa);
89 peer = this->ike_sa->get_other_id(this->ike_sa);
90 role = XAUTH_SERVER;
91 }
92 else
93 {
94 peer = this->ike_sa->get_my_id(this->ike_sa);
95 server = this->ike_sa->get_other_id(this->ike_sa);
96 role = XAUTH_PEER;
97 }
98 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
99 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator);
100 if (!enumerator->enumerate(enumerator, &auth) ||
101 (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
102 {
103 if (!enumerator->enumerate(enumerator, &auth) ||
104 (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
105 {
106 DBG1(DBG_CFG, "no XAuth authentication round found");
107 enumerator->destroy(enumerator);
108 return NULL;
109 }
110 }
111 name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
112 this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
113 if (!this->initiator && this->user)
114 { /* use XAUTH username, if configured */
115 peer = this->user;
116 }
117 enumerator->destroy(enumerator);
118 xauth = charon->xauth->create_instance(charon->xauth, name, role,
119 server, peer);
120 if (!xauth)
121 {
122 if (name)
123 {
124 DBG1(DBG_CFG, "no XAuth method found named '%s'");
125 }
126 else
127 {
128 DBG1(DBG_CFG, "no XAuth method found");
129 }
130 }
131 return xauth;
132 }
133
134 /**
135 * Set IKE_SA to established state
136 */
137 static void establish(private_xauth_t *this)
138 {
139 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
140 this->ike_sa->get_name(this->ike_sa),
141 this->ike_sa->get_unique_id(this->ike_sa),
142 this->ike_sa->get_my_host(this->ike_sa),
143 this->ike_sa->get_my_id(this->ike_sa),
144 this->ike_sa->get_other_host(this->ike_sa),
145 this->ike_sa->get_other_id(this->ike_sa));
146
147 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
148 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
149 }
150
151 METHOD(task_t, build_i_status, status_t,
152 private_xauth_t *this, message_t *message)
153 {
154 cp_payload_t *cp;
155
156 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
157 cp->add_attribute(cp,
158 configuration_attribute_create_value(XAUTH_STATUS, this->status));
159
160 message->add_payload(message, (payload_t *)cp);
161
162 return NEED_MORE;
163 }
164
165 METHOD(task_t, build_i, status_t,
166 private_xauth_t *this, message_t *message)
167 {
168 if (!this->xauth)
169 {
170 cp_payload_t *cp;
171
172 this->xauth = load_method(this);
173 if (!this->xauth)
174 {
175 return FAILED;
176 }
177 if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE)
178 {
179 return FAILED;
180 }
181 message->add_payload(message, (payload_t *)cp);
182 return NEED_MORE;
183 }
184
185 if (this->cp)
186 { /* send previously generated payload */
187 message->add_payload(message, (payload_t *)this->cp);
188 this->cp = NULL;
189 return NEED_MORE;
190 }
191 return FAILED;
192 }
193
194 METHOD(task_t, build_r_ack, status_t,
195 private_xauth_t *this, message_t *message)
196 {
197 cp_payload_t *cp;
198
199 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK);
200 cp->add_attribute(cp,
201 configuration_attribute_create_chunk(
202 CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty));
203
204 message->add_payload(message, (payload_t *)cp);
205
206 if (this->status == XAUTH_OK)
207 {
208 establish(this);
209 return SUCCESS;
210 }
211 return FAILED;
212 }
213
214 METHOD(task_t, process_r, status_t,
215 private_xauth_t *this, message_t *message)
216 {
217 cp_payload_t *cp;
218
219 if (!this->xauth)
220 {
221 this->xauth = load_method(this);
222 if (!this->xauth)
223 { /* send empty reply */
224 return NEED_MORE;
225 }
226 }
227 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
228 if (!cp)
229 {
230 DBG1(DBG_IKE, "configuration payload missing in XAuth request");
231 return FAILED;
232 }
233 if (cp->get_type(cp) == CFG_REQUEST)
234 {
235 switch (this->xauth->process(this->xauth, cp, &this->cp))
236 {
237 case NEED_MORE:
238 return NEED_MORE;
239 case SUCCESS:
240 case FAILED:
241 default:
242 break;
243 }
244 this->cp = NULL;
245 return NEED_MORE;
246 }
247 if (cp->get_type(cp) == CFG_SET)
248 {
249 configuration_attribute_t *attribute;
250 enumerator_t *enumerator;
251
252 enumerator = cp->create_attribute_enumerator(cp);
253 while (enumerator->enumerate(enumerator, &attribute))
254 {
255 if (attribute->get_type(attribute) == XAUTH_STATUS)
256 {
257 this->status = attribute->get_value(attribute);
258 }
259 }
260 enumerator->destroy(enumerator);
261 if (this->status == XAUTH_OK)
262 {
263 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
264 this->xauth->get_identity(this->xauth));
265 establish(this);
266 }
267 else
268 {
269 DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
270 this->xauth->get_identity(this->xauth));
271 }
272 }
273 this->public.task.build = _build_r_ack;
274 return NEED_MORE;
275 }
276
277 METHOD(task_t, build_r, status_t,
278 private_xauth_t *this, message_t *message)
279 {
280 if (!this->cp)
281 { /* send empty reply if building data failed */
282 this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
283 }
284 message->add_payload(message, (payload_t *)this->cp);
285 this->cp = NULL;
286 return NEED_MORE;
287 }
288
289 METHOD(task_t, process_i_status, status_t,
290 private_xauth_t *this, message_t *message)
291 {
292 cp_payload_t *cp;
293
294 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
295 if (!cp || cp->get_type(cp) != CFG_ACK)
296 {
297 DBG1(DBG_IKE, "received invalid XAUTH status response");
298 return FAILED;
299 }
300 if (this->status != XAUTH_OK)
301 {
302 DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
303 return FAILED;
304 }
305 establish(this);
306 return SUCCESS;
307 }
308
309 METHOD(task_t, process_i, status_t,
310 private_xauth_t *this, message_t *message)
311 {
312 identification_t *id;
313 cp_payload_t *cp;
314
315 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
316 if (!cp)
317 {
318 DBG1(DBG_IKE, "configuration payload missing in XAuth response");
319 return FAILED;
320 }
321 switch (this->xauth->process(this->xauth, cp, &this->cp))
322 {
323 case NEED_MORE:
324 return NEED_MORE;
325 case SUCCESS:
326 id = this->xauth->get_identity(this->xauth);
327 if (this->user && !id->matches(id, this->user))
328 {
329 DBG1(DBG_IKE, "XAuth username '%Y' does not match to "
330 "configured username '%Y'", id, this->user);
331 break;
332 }
333 DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
334 this->status = XAUTH_OK;
335 break;
336 case FAILED:
337 DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
338 this->xauth->get_identity(this->xauth));
339 break;
340 default:
341 return FAILED;
342 }
343 this->public.task.build = _build_i_status;
344 this->public.task.process = _process_i_status;
345 return NEED_MORE;
346 }
347
348 METHOD(task_t, get_type, task_type_t,
349 private_xauth_t *this)
350 {
351 return TASK_XAUTH;
352 }
353
354 METHOD(task_t, migrate, void,
355 private_xauth_t *this, ike_sa_t *ike_sa)
356 {
357 this->ike_sa = ike_sa;
358 }
359
360 METHOD(task_t, destroy, void,
361 private_xauth_t *this)
362 {
363 DESTROY_IF(this->xauth);
364 DESTROY_IF(this->cp);
365 free(this);
366 }
367
368 /*
369 * Described in header.
370 */
371 xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
372 {
373 private_xauth_t *this;
374
375 INIT(this,
376 .public = {
377 .task = {
378 .get_type = _get_type,
379 .migrate = _migrate,
380 .destroy = _destroy,
381 },
382 },
383 .initiator = initiator,
384 .ike_sa = ike_sa,
385 .status = XAUTH_FAILED,
386 );
387
388 if (initiator)
389 {
390 this->public.task.build = _build_i;
391 this->public.task.process = _process_i;
392 }
393 else
394 {
395 this->public.task.build = _build_r;
396 this->public.task.process = _process_r;
397 }
398 return &this->public;
399 }