]>
Commit | Line | Data |
---|---|---|
1be296df AS |
1 | /* |
2 | * Copyright (C) 2011 Andreas Steffen | |
3 | * Copyright (C) 2011 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_peer.h" | |
17 | #include "eap_peap_avp.h" | |
18 | ||
f05b4272 | 19 | #include <utils/debug.h> |
1be296df AS |
20 | #include <daemon.h> |
21 | ||
22 | typedef struct private_eap_peap_peer_t private_eap_peap_peer_t; | |
23 | ||
24 | /** | |
25 | * Private data of an eap_peap_peer_t object. | |
26 | */ | |
27 | struct private_eap_peap_peer_t { | |
28 | ||
29 | /** | |
30 | * Public eap_peap_peer_t interface. | |
31 | */ | |
32 | eap_peap_peer_t public; | |
33 | ||
34 | /** | |
35 | * Server identity | |
36 | */ | |
37 | identification_t *server; | |
38 | ||
39 | /** | |
40 | * Peer identity | |
41 | */ | |
42 | identification_t *peer; | |
43 | ||
1be296df AS |
44 | /** |
45 | * Outer phase 1 EAP method | |
46 | */ | |
47 | eap_method_t *ph1_method; | |
48 | ||
49 | /** | |
50 | * Current phase 2 EAP method | |
51 | */ | |
52 | eap_method_t *ph2_method; | |
53 | ||
54 | /** | |
55 | * Pending outbound EAP message | |
56 | */ | |
57 | eap_payload_t *out; | |
58 | ||
59 | /** | |
60 | * AVP handler | |
61 | */ | |
62 | eap_peap_avp_t *avp; | |
63 | }; | |
64 | ||
65 | METHOD(tls_application_t, process, status_t, | |
7e432eff | 66 | private_eap_peap_peer_t *this, bio_reader_t *reader) |
1be296df AS |
67 | { |
68 | chunk_t data = chunk_empty; | |
69 | status_t status; | |
70 | payload_t *payload; | |
71 | eap_payload_t *in; | |
72 | eap_code_t code; | |
73 | eap_type_t type, received_type; | |
74 | u_int32_t vendor, received_vendor; | |
75 | ||
76 | status = this->avp->process(this->avp, reader, &data, | |
77 | this->ph1_method->get_identifier(this->ph1_method)); | |
78 | switch (status) | |
79 | { | |
80 | case SUCCESS: | |
81 | break; | |
82 | case NEED_MORE: | |
83 | return NEED_MORE; | |
84 | case FAILED: | |
85 | default: | |
86 | return FAILED; | |
87 | } | |
af04233e | 88 | |
1be296df AS |
89 | in = eap_payload_create_data(data); |
90 | DBG3(DBG_IKE, "%B", &data); | |
91 | chunk_free(&data); | |
92 | payload = (payload_t*)in; | |
93 | ||
94 | if (payload->verify(payload) != SUCCESS) | |
95 | { | |
96 | in->destroy(in); | |
97 | return FAILED; | |
98 | } | |
99 | ||
100 | code = in->get_code(in); | |
101 | if (code == EAP_REQUEST || code == EAP_RESPONSE) | |
102 | { | |
103 | received_type = in->get_type(in, &received_vendor); | |
104 | DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [EAP/%N/%N]", | |
105 | eap_code_short_names, code, | |
106 | eap_type_short_names, received_type); | |
107 | if (code != EAP_REQUEST) | |
108 | { | |
109 | DBG1(DBG_IKE, "%N expected", eap_code_names, EAP_REQUEST); | |
110 | in->destroy(in); | |
111 | return FAILED; | |
112 | } | |
113 | } | |
114 | else | |
115 | { | |
116 | DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [EAP/%N]", | |
117 | eap_code_short_names, code); | |
118 | this->out = eap_payload_create_code(code, in->get_identifier(in)); | |
119 | in->destroy(in); | |
120 | return NEED_MORE; | |
121 | } | |
122 | ||
30c42831 AS |
123 | /* yet another phase2 authentication? */ |
124 | if (this->ph2_method) | |
125 | { | |
126 | type = this->ph2_method->get_type(this->ph2_method, &vendor); | |
127 | ||
128 | if (type != received_type || vendor != received_vendor) | |
129 | { | |
130 | this->ph2_method->destroy(this->ph2_method); | |
131 | this->ph2_method = NULL; | |
132 | } | |
133 | } | |
134 | ||
1be296df AS |
135 | if (this->ph2_method == NULL) |
136 | { | |
137 | if (received_vendor) | |
138 | { | |
139 | DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d " | |
c98ed04d | 140 | "(id 0x%02X", received_type, received_vendor, |
1be296df AS |
141 | in->get_identifier(in)); |
142 | } | |
143 | else | |
144 | { | |
c98ed04d | 145 | DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)", |
1be296df AS |
146 | eap_type_names, received_type, in->get_identifier(in)); |
147 | } | |
148 | this->ph2_method = charon->eap->create_instance(charon->eap, | |
149 | received_type, received_vendor, | |
150 | EAP_PEER, this->server, this->peer); | |
151 | if (!this->ph2_method) | |
152 | { | |
153 | DBG1(DBG_IKE, "EAP method not supported"); | |
78e8dca9 | 154 | this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0, |
cc4eec56 | 155 | in->is_expanded(in)); |
1be296df AS |
156 | in->destroy(in); |
157 | return NEED_MORE; | |
158 | } | |
30c42831 | 159 | type = this->ph2_method->get_type(this->ph2_method, &vendor); |
1be296df AS |
160 | } |
161 | ||
1be296df AS |
162 | status = this->ph2_method->process(this->ph2_method, in, &this->out); |
163 | in->destroy(in); | |
164 | ||
165 | switch (status) | |
166 | { | |
167 | case SUCCESS: | |
168 | this->ph2_method->destroy(this->ph2_method); | |
169 | this->ph2_method = NULL; | |
30c42831 | 170 | /* fall through to NEED_MORE */ |
1be296df | 171 | case NEED_MORE: |
1be296df AS |
172 | return NEED_MORE; |
173 | case FAILED: | |
174 | default: | |
175 | if (vendor) | |
176 | { | |
177 | DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", | |
178 | type, vendor); | |
179 | } | |
180 | else | |
181 | { | |
182 | DBG1(DBG_IKE, "%N method failed", eap_type_names, type); | |
183 | } | |
184 | return FAILED; | |
185 | } | |
186 | } | |
187 | ||
188 | METHOD(tls_application_t, build, status_t, | |
7e432eff | 189 | private_eap_peap_peer_t *this, bio_writer_t *writer) |
1be296df AS |
190 | { |
191 | chunk_t data; | |
192 | eap_code_t code; | |
193 | eap_type_t type; | |
194 | u_int32_t vendor; | |
195 | ||
1be296df AS |
196 | if (this->out) |
197 | { | |
198 | code = this->out->get_code(this->out); | |
199 | type = this->out->get_type(this->out, &vendor); | |
200 | if (code == EAP_REQUEST || code == EAP_RESPONSE) | |
201 | { | |
202 | DBG1(DBG_IKE, "sending tunneled EAP-PEAP AVP [EAP/%N/%N]", | |
203 | eap_code_short_names, code, eap_type_short_names, type); | |
204 | } | |
205 | else | |
206 | { | |
207 | DBG1(DBG_IKE, "sending tunneled EAP-PEAP AVP [EAP/%N]", | |
208 | eap_code_short_names, code); | |
209 | } | |
210 | ||
211 | /* get the raw EAP message data */ | |
212 | data = this->out->get_data(this->out); | |
213 | DBG3(DBG_IKE, "%B", &data); | |
214 | this->avp->build(this->avp, writer, data); | |
215 | ||
216 | this->out->destroy(this->out); | |
217 | this->out = NULL; | |
218 | } | |
219 | return INVALID_STATE; | |
220 | } | |
221 | ||
222 | METHOD(tls_application_t, destroy, void, | |
223 | private_eap_peap_peer_t *this) | |
224 | { | |
225 | this->server->destroy(this->server); | |
226 | this->peer->destroy(this->peer); | |
227 | DESTROY_IF(this->ph2_method); | |
228 | DESTROY_IF(this->out); | |
229 | this->avp->destroy(this->avp); | |
230 | free(this); | |
231 | } | |
232 | ||
233 | /** | |
234 | * See header | |
235 | */ | |
236 | eap_peap_peer_t *eap_peap_peer_create(identification_t *server, | |
237 | identification_t *peer, | |
238 | eap_method_t *eap_method) | |
239 | { | |
240 | private_eap_peap_peer_t *this; | |
241 | ||
242 | INIT(this, | |
243 | .public = { | |
244 | .application = { | |
245 | .process = _process, | |
246 | .build = _build, | |
247 | .destroy = _destroy, | |
248 | }, | |
249 | }, | |
250 | .server = server->clone(server), | |
251 | .peer = peer->clone(peer), | |
252 | .ph1_method = eap_method, | |
1be296df AS |
253 | .avp = eap_peap_avp_create(FALSE), |
254 | ); | |
255 | ||
256 | return &this->public; | |
257 | } |