Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_peap/eap_peap_server.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2011 Andreas Steffen
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_peap_server.h"
17: #include "eap_peap_avp.h"
18:
19: #include <utils/debug.h>
20: #include <daemon.h>
21:
22: typedef struct private_eap_peap_server_t private_eap_peap_server_t;
23:
24: /**
25: * Private data of an eap_peap_server_t object.
26: */
27: struct private_eap_peap_server_t {
28:
29: /**
30: * Public eap_peap_server_t interface.
31: */
32: eap_peap_server_t public;
33:
34: /**
35: * Server identity
36: */
37: identification_t *server;
38:
39: /**
40: * Peer identity
41: */
42: identification_t *peer;
43:
44: /**
45: * Current EAP-PEAP phase2 state
46: */
47: bool start_phase2;
48:
49: /**
50: * Current EAP-PEAP phase2 TNC state
51: */
52: bool start_phase2_tnc;
53:
54: /**
55: * Starts phase 2 with EAP Identity request
56: */
57: bool start_phase2_id;
58:
59: /**
60: * Final EAP-PEAP phase2 result
61: */
62: eap_code_t phase2_result;
63:
64: /**
65: * Outer phase 1 EAP method
66: */
67: eap_method_t *ph1_method;
68:
69: /**
70: * Current phase 2 EAP method
71: */
72: eap_method_t *ph2_method;
73:
74: /**
75: * Pending outbound EAP message
76: */
77: eap_payload_t *out;
78:
79: /**
80: * AVP handler
81: */
82: eap_peap_avp_t *avp;
83: };
84:
85: /**
86: * Start EAP client authentication protocol
87: */
88: static status_t start_phase2_auth(private_eap_peap_server_t *this)
89: {
90: char *eap_type_str;
91: eap_type_t type;
92:
93: eap_type_str = lib->settings->get_str(lib->settings,
94: "%s.plugins.eap-peap.phase2_method", "mschapv2",
95: lib->ns);
96: type = eap_type_from_string(eap_type_str);
97: if (type == 0)
98: {
99: DBG1(DBG_IKE, "unrecognized phase2 method \"%s\"", eap_type_str);
100: return FAILED;
101: }
102: DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, type);
103: this->ph2_method = charon->eap->create_instance(charon->eap, type, 0,
104: EAP_SERVER, this->server, this->peer);
105: if (this->ph2_method == NULL)
106: {
107: DBG1(DBG_IKE, "%N method not available", eap_type_names, type);
108: return FAILED;
109: }
110:
111: /* synchronize EAP message identifiers of inner protocol with outer */
112: this->ph2_method->set_identifier(this->ph2_method,
113: this->ph1_method->get_identifier(this->ph1_method) + 1);
114:
115: if (this->ph2_method->initiate(this->ph2_method, &this->out) == NEED_MORE)
116: {
117: return NEED_MORE;
118: }
119: else
120: {
121: DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
122: return FAILED;
123: }
124: }
125:
126: /**
127: * If configured, start EAP-TNC protocol
128: */
129: static status_t start_phase2_tnc(private_eap_peap_server_t *this)
130: {
131: if (this->start_phase2_tnc && lib->settings->get_bool(lib->settings,
132: "%s.plugins.eap-peap.phase2_tnc", FALSE, lib->ns))
133: {
134: DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, EAP_TNC);
135: this->ph2_method = charon->eap->create_instance(charon->eap, EAP_TNC,
136: 0, EAP_SERVER, this->server, this->peer);
137: if (this->ph2_method == NULL)
138: {
139: DBG1(DBG_IKE, "%N method not available", eap_type_names, EAP_TNC);
140: return FAILED;
141: }
142: this->start_phase2_tnc = FALSE;
143:
144: /* synchronize EAP message identifiers of inner protocol with outer */
145: this->ph2_method->set_identifier(this->ph2_method,
146: this->ph1_method->get_identifier(this->ph1_method) + 1);
147:
148: if (this->ph2_method->initiate(this->ph2_method, &this->out) == NEED_MORE)
149: {
150: return NEED_MORE;
151: }
152: else
153: {
154: DBG1(DBG_IKE, "%N method failed", eap_type_names, EAP_TNC);
155: return FAILED;
156: }
157: }
158: return SUCCESS;
159: }
160:
161: METHOD(tls_application_t, process, status_t,
162: private_eap_peap_server_t *this, bio_reader_t *reader)
163: {
164: chunk_t data = chunk_empty;
165: status_t status;
166: payload_t *payload;
167: eap_payload_t *in;
168: eap_code_t code;
169: eap_type_t type = EAP_NAK, received_type;
170: uint32_t vendor, received_vendor;
171:
172: status = this->avp->process(this->avp, reader, &data,
173: this->ph1_method->get_identifier(this->ph1_method));
174: switch (status)
175: {
176: case SUCCESS:
177: break;
178: case NEED_MORE:
179: return NEED_MORE;
180: case FAILED:
181: default:
182: return FAILED;
183: }
184:
185: in = eap_payload_create_data(data);
186: DBG3(DBG_IKE, "%B", &data);
187: chunk_free(&data);
188: payload = (payload_t*)in;
189:
190: if (payload->verify(payload) != SUCCESS)
191: {
192: in->destroy(in);
193: return FAILED;
194: }
195:
196: code = in->get_code(in);
197: if (code == EAP_REQUEST || code == EAP_RESPONSE)
198: {
199: received_type = in->get_type(in, &received_vendor);
200: DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [EAP/%N/%N]",
201: eap_code_short_names, code,
202: eap_type_short_names, received_type);
203: if (code != EAP_RESPONSE)
204: {
205: DBG1(DBG_IKE, "%N expected", eap_code_names, EAP_RESPONSE);
206: in->destroy(in);
207: return FAILED;
208: }
209: }
210: else
211: {
212: DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [EAP/%N]",
213: eap_code_short_names, code);
214: in->destroy(in);
215: /* if EAP_SUCCESS check if to continue phase2 with EAP-TNC */
216: return (this->phase2_result == EAP_SUCCESS && code == EAP_SUCCESS) ?
217: start_phase2_tnc(this) : FAILED;
218: }
219:
220: if (this->ph2_method)
221: {
222: type = this->ph2_method->get_type(this->ph2_method, &vendor);
223:
224: if (type != received_type || vendor != received_vendor)
225: {
226: if (received_vendor == 0 && received_type == EAP_NAK)
227: {
228: DBG1(DBG_IKE, "peer does not support %N", eap_type_names, type);
229: }
230: else
231: {
232: DBG1(DBG_IKE, "received invalid EAP response");
233: }
234: in->destroy(in);
235: return FAILED;
236: }
237: }
238:
239: if (!received_vendor && received_type == EAP_IDENTITY)
240: {
241: chunk_t eap_id;
242:
243: if (this->ph2_method == NULL)
244: {
245: /* Received an EAP Identity response without a matching request */
246: this->ph2_method = charon->eap->create_instance(charon->eap,
247: EAP_IDENTITY, 0, EAP_SERVER,
248: this->server, this->peer);
249: if (this->ph2_method == NULL)
250: {
251: DBG1(DBG_IKE, "%N method not available",
252: eap_type_names, EAP_IDENTITY);
253: in->destroy(in);
254: return FAILED;
255: }
256: }
257:
258: if (this->ph2_method->process(this->ph2_method, in, &this->out) != SUCCESS)
259: {
260:
261: DBG1(DBG_IKE, "%N method failed", eap_type_names, EAP_IDENTITY);
262: in->destroy(in);
263: return FAILED;
264: }
265:
266: if (this->ph2_method->get_msk(this->ph2_method, &eap_id) == SUCCESS)
267: {
268: this->peer->destroy(this->peer);
269: this->peer = identification_create_from_data(eap_id);
270: DBG1(DBG_IKE, "received EAP identity '%Y'", this->peer);
271: }
272:
273: in->destroy(in);
274: this->ph2_method->destroy(this->ph2_method);
275: this->ph2_method = NULL;
276:
277: /* Start Phase 2 of EAP-PEAP authentication */
278: if (lib->settings->get_bool(lib->settings,
279: "%s.plugins.eap-peap.request_peer_auth", FALSE, lib->ns))
280: {
281: return start_phase2_tnc(this);
282: }
283: else
284: {
285: return start_phase2_auth(this);
286: }
287: }
288:
289: if (this->ph2_method == 0)
290: {
291: DBG1(DBG_IKE, "no %N phase2 method installed", eap_type_names, EAP_PEAP);
292: in->destroy(in);
293: return FAILED;
294: }
295:
296: status = this->ph2_method->process(this->ph2_method, in, &this->out);
297: in->destroy(in);
298:
299: switch (status)
300: {
301: case SUCCESS:
302: DBG1(DBG_IKE, "%N phase2 authentication of '%Y' with %N successful",
303: eap_type_names, EAP_PEAP, this->peer,
304: eap_type_names, type);
305: this->ph2_method->destroy(this->ph2_method);
306: this->ph2_method = NULL;
307:
308: /* EAP-PEAP requires the sending of an inner EAP_SUCCESS message */
309: this->phase2_result = EAP_SUCCESS;
310: this->out = eap_payload_create_code(this->phase2_result, 1 +
311: this->ph1_method->get_identifier(this->ph1_method));
312: return NEED_MORE;
313: case NEED_MORE:
314: break;
315: case FAILED:
316: default:
317: if (vendor)
318: {
319: DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed",
320: type, vendor);
321: }
322: else
323: {
324: DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
325: }
326: /* EAP-PEAP requires the sending of an inner EAP_FAILURE message */
327: this->phase2_result = EAP_FAILURE;
328: this->out = eap_payload_create_code(this->phase2_result, 1 +
329: this->ph1_method->get_identifier(this->ph1_method));
330: return NEED_MORE;
331: }
332: return status;
333: }
334:
335: METHOD(tls_application_t, build, status_t,
336: private_eap_peap_server_t *this, bio_writer_t *writer)
337: {
338: chunk_t data;
339: eap_code_t code;
340: eap_type_t type;
341: uint32_t vendor;
342:
343: if (this->ph2_method == NULL && this->start_phase2 && this->start_phase2_id)
344: {
345: /*
346: * Start Phase 2 with an EAP Identity request either piggybacked right
347: * onto the TLS Finished payload or delayed after the reception of an
348: * empty EAP Acknowledge message.
349: */
350: this->ph2_method = charon->eap->create_instance(charon->eap, EAP_IDENTITY,
351: 0, EAP_SERVER, this->server, this->peer);
352: if (this->ph2_method == NULL)
353: {
354: DBG1(DBG_IKE, "%N method not available",
355: eap_type_names, EAP_IDENTITY);
356: return FAILED;
357: }
358:
359: /* synchronize EAP message identifiers of inner protocol with outer */
360: this->ph2_method->set_identifier(this->ph2_method,
361: this->ph1_method->get_identifier(this->ph1_method));
362:
363: this->ph2_method->initiate(this->ph2_method, &this->out);
364: this->start_phase2 = FALSE;
365: }
366:
367: this->start_phase2_id = TRUE;
368:
369: if (this->out)
370: {
371: code = this->out->get_code(this->out);
372: type = this->out->get_type(this->out, &vendor);
373: if (code == EAP_REQUEST || code == EAP_RESPONSE)
374: {
375: DBG1(DBG_IKE, "sending tunneled EAP-PEAP AVP [EAP/%N/%N]",
376: eap_code_short_names, code, eap_type_short_names, type);
377: }
378: else
379: {
380: DBG1(DBG_IKE, "sending tunneled EAP-PEAP AVP [EAP/%N]",
381: eap_code_short_names, code);
382: }
383:
384: /* get the raw EAP message data */
385: data = this->out->get_data(this->out);
386: DBG3(DBG_IKE, "%B", &data);
387: this->avp->build(this->avp, writer, data);
388:
389: this->out->destroy(this->out);
390: this->out = NULL;
391: }
392: return INVALID_STATE;
393: }
394:
395: METHOD(tls_application_t, destroy, void,
396: private_eap_peap_server_t *this)
397: {
398: this->server->destroy(this->server);
399: this->peer->destroy(this->peer);
400: DESTROY_IF(this->ph2_method);
401: DESTROY_IF(this->out);
402: this->avp->destroy(this->avp);
403: free(this);
404: }
405:
406: /**
407: * See header
408: */
409: eap_peap_server_t *eap_peap_server_create(identification_t *server,
410: identification_t *peer,
411: eap_method_t *eap_method)
412: {
413: private_eap_peap_server_t *this;
414:
415: INIT(this,
416: .public = {
417: .application = {
418: .process = _process,
419: .build = _build,
420: .destroy = _destroy,
421: },
422: },
423: .server = server->clone(server),
424: .peer = peer->clone(peer),
425: .ph1_method = eap_method,
426: .start_phase2 = TRUE,
427: .start_phase2_tnc = TRUE,
428: .start_phase2_id = lib->settings->get_bool(lib->settings,
429: "%s.plugins.eap-peap.phase2_piggyback",
430: FALSE, lib->ns),
431: .phase2_result = EAP_FAILURE,
432: .avp = eap_peap_avp_create(TRUE),
433: );
434:
435: return &this->public;
436: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>