]>
Commit | Line | Data |
---|---|---|
f27f6296 | 1 | /* |
66277067 | 2 | * Copyright (C) 2012-2018 Tobias Brunner |
a44bb934 | 3 | * Copyright (C) 2006-2009 Martin Willi |
19ef2aec TB |
4 | * |
5 | * Copyright (C) secunet Security Networks AG | |
f27f6296 MW |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
16 | */ | |
17 | ||
f27f6296 MW |
18 | #include "eap_authenticator.h" |
19 | ||
20 | #include <daemon.h> | |
15a682f4 | 21 | #include <sa/ikev2/keymat_v2.h> |
326a9423 | 22 | #include <sa/eap/eap_method.h> |
a44bb934 MW |
23 | #include <encoding/payloads/auth_payload.h> |
24 | #include <encoding/payloads/eap_payload.h> | |
f27f6296 MW |
25 | |
26 | typedef struct private_eap_authenticator_t private_eap_authenticator_t; | |
27 | ||
28 | /** | |
29 | * Private data of an eap_authenticator_t object. | |
30 | */ | |
31 | struct private_eap_authenticator_t { | |
7daf5226 | 32 | |
f27f6296 MW |
33 | /** |
34 | * Public authenticator_t interface. | |
35 | */ | |
36 | eap_authenticator_t public; | |
7daf5226 | 37 | |
f27f6296 MW |
38 | /** |
39 | * Assigned IKE_SA | |
40 | */ | |
41 | ike_sa_t *ike_sa; | |
7daf5226 | 42 | |
f27f6296 | 43 | /** |
25f2d52f | 44 | * others nonce to include in AUTH calculation |
f27f6296 | 45 | */ |
25f2d52f | 46 | chunk_t received_nonce; |
7daf5226 | 47 | |
a44bb934 | 48 | /** |
25f2d52f | 49 | * our nonce to include in AUTH calculation |
a44bb934 | 50 | */ |
25f2d52f | 51 | chunk_t sent_nonce; |
7daf5226 | 52 | |
25f2d52f MW |
53 | /** |
54 | * others IKE_SA_INIT message data to include in AUTH calculation | |
55 | */ | |
56 | chunk_t received_init; | |
7daf5226 | 57 | |
25f2d52f MW |
58 | /** |
59 | * our IKE_SA_INIT message data to include in AUTH calculation | |
60 | */ | |
61 | chunk_t sent_init; | |
7daf5226 | 62 | |
f3b02d88 TB |
63 | /** |
64 | * IntAuth data to include in AUTH calculation | |
65 | */ | |
66 | chunk_t int_auth; | |
67 | ||
5f15faeb MW |
68 | /** |
69 | * Reserved bytes of ID payload | |
70 | */ | |
71 | char reserved[3]; | |
72 | ||
66277067 TB |
73 | /** |
74 | * PPK to use | |
75 | */ | |
76 | chunk_t ppk; | |
77 | ||
78 | /** | |
79 | * Add a NO_PPK_AUTH notify | |
80 | */ | |
81 | bool no_ppk_auth; | |
82 | ||
f27f6296 MW |
83 | /** |
84 | * Current EAP method processing | |
85 | */ | |
86 | eap_method_t *method; | |
7daf5226 | 87 | |
f27f6296 MW |
88 | /** |
89 | * MSK used to build and verify auth payload | |
90 | */ | |
91 | chunk_t msk; | |
7daf5226 | 92 | |
82290106 | 93 | /** |
a44bb934 | 94 | * EAP authentication method completed successfully |
82290106 | 95 | */ |
a44bb934 | 96 | bool eap_complete; |
7daf5226 | 97 | |
f34702ff MW |
98 | /** |
99 | * Set if we require mutual EAP due EAP-only authentication | |
100 | */ | |
101 | bool require_mutual; | |
102 | ||
82290106 | 103 | /** |
a44bb934 | 104 | * authentication payload verified successfully |
82290106 | 105 | */ |
a44bb934 | 106 | bool auth_complete; |
7daf5226 | 107 | |
82290106 | 108 | /** |
a44bb934 | 109 | * generated EAP payload |
82290106 | 110 | */ |
a44bb934 | 111 | eap_payload_t *eap_payload; |
7daf5226 | 112 | |
a44bb934 MW |
113 | /** |
114 | * EAP identity of peer | |
115 | */ | |
116 | identification_t *eap_identity; | |
f27f6296 | 117 | }; |
a44bb934 | 118 | |
f27f6296 | 119 | /** |
a44bb934 | 120 | * load an EAP method |
f27f6296 | 121 | */ |
a44bb934 | 122 | static eap_method_t *load_method(private_eap_authenticator_t *this, |
f6e6fcd2 | 123 | eap_type_t type, pen_t vendor, eap_role_t role) |
f27f6296 | 124 | { |
36eafea2 MW |
125 | identification_t *server, *peer, *aaa; |
126 | auth_cfg_t *auth; | |
7daf5226 | 127 | |
a44bb934 | 128 | if (role == EAP_SERVER) |
f27f6296 | 129 | { |
a44bb934 MW |
130 | server = this->ike_sa->get_my_id(this->ike_sa); |
131 | peer = this->ike_sa->get_other_id(this->ike_sa); | |
36eafea2 | 132 | auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); |
f27f6296 | 133 | } |
a44bb934 MW |
134 | else |
135 | { | |
136 | server = this->ike_sa->get_other_id(this->ike_sa); | |
137 | peer = this->ike_sa->get_my_id(this->ike_sa); | |
36eafea2 | 138 | auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); |
a44bb934 MW |
139 | } |
140 | if (this->eap_identity) | |
141 | { | |
142 | peer = this->eap_identity; | |
143 | } | |
36eafea2 MW |
144 | aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY); |
145 | if (aaa) | |
146 | { | |
147 | server = aaa; | |
148 | } | |
a44bb934 MW |
149 | return charon->eap->create_instance(charon->eap, type, vendor, |
150 | role, server, peer); | |
f27f6296 MW |
151 | } |
152 | ||
82290106 | 153 | /** |
a44bb934 | 154 | * Initiate EAP conversation as server |
82290106 | 155 | */ |
a44bb934 MW |
156 | static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, |
157 | bool do_identity) | |
82290106 | 158 | { |
a44bb934 MW |
159 | auth_cfg_t *auth; |
160 | eap_type_t type; | |
82290106 | 161 | identification_t *id; |
f6e6fcd2 | 162 | pen_t vendor; |
a44bb934 | 163 | eap_payload_t *out; |
83c282eb | 164 | char *action; |
7daf5226 | 165 | |
a44bb934 | 166 | auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); |
7daf5226 | 167 | |
a44bb934 MW |
168 | /* initiate EAP-Identity exchange if required */ |
169 | if (!this->eap_identity && do_identity) | |
82290106 | 170 | { |
a44bb934 MW |
171 | id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); |
172 | if (id) | |
82290106 | 173 | { |
53913d76 | 174 | if (id->get_type(id) == ID_ANY) |
82290106 | 175 | { |
53913d76 MW |
176 | this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER); |
177 | if (this->method) | |
a44bb934 | 178 | { |
53913d76 MW |
179 | if (this->method->initiate(this->method, &out) == NEED_MORE) |
180 | { | |
c76b8a21 AS |
181 | DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", |
182 | eap_type_names, EAP_IDENTITY, | |
183 | this->method->get_identifier(this->method)); | |
53913d76 MW |
184 | return out; |
185 | } | |
186 | this->method->destroy(this->method); | |
a44bb934 | 187 | } |
53913d76 MW |
188 | DBG1(DBG_IKE, "EAP-Identity request configured, " |
189 | "but not supported"); | |
190 | } | |
191 | else | |
192 | { | |
193 | DBG1(DBG_IKE, "using configured EAP-Identity %Y", id); | |
194 | this->eap_identity = id->clone(id); | |
82290106 MW |
195 | } |
196 | } | |
197 | } | |
a44bb934 MW |
198 | /* invoke real EAP method */ |
199 | type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); | |
200 | vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); | |
83c282eb | 201 | action = "loading"; |
a44bb934 | 202 | this->method = load_method(this, type, vendor, EAP_SERVER); |
83c282eb | 203 | if (this->method) |
82290106 | 204 | { |
83c282eb AS |
205 | action = "initiating"; |
206 | if (this->method->initiate(this->method, &out) == NEED_MORE) | |
a44bb934 | 207 | { |
7f2e3091 | 208 | type = this->method->get_type(this->method, &vendor); |
83c282eb AS |
209 | if (vendor) |
210 | { | |
9efd7d7e TB |
211 | DBG1(DBG_IKE, "initiating EAP vendor type %d-%N method (id 0x%02X)", |
212 | type, pen_names, vendor, out->get_identifier(out)); | |
83c282eb AS |
213 | } |
214 | else | |
215 | { | |
c98ed04d | 216 | DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", eap_type_names, |
de931542 | 217 | type, out->get_identifier(out)); |
83c282eb AS |
218 | } |
219 | return out; | |
a44bb934 | 220 | } |
7f2e3091 TB |
221 | /* type might have changed for virtual methods */ |
222 | type = this->method->get_type(this->method, &vendor); | |
82290106 | 223 | } |
a44bb934 | 224 | if (vendor) |
82290106 | 225 | { |
9efd7d7e TB |
226 | DBG1(DBG_IKE, "%s EAP vendor type %d-%N method failed", |
227 | action, type, pen_names, vendor); | |
82290106 MW |
228 | } |
229 | else | |
230 | { | |
83c282eb | 231 | DBG1(DBG_IKE, "%s %N method failed", action, eap_type_names, type); |
82290106 | 232 | } |
a44bb934 | 233 | return eap_payload_create_code(EAP_FAILURE, 0); |
82290106 MW |
234 | } |
235 | ||
f6116e61 MW |
236 | /** |
237 | * Replace the existing EAP-Identity in other auth config | |
238 | */ | |
239 | static void replace_eap_identity(private_eap_authenticator_t *this) | |
240 | { | |
b447af65 | 241 | identification_t *eap_identity; |
f6116e61 | 242 | auth_cfg_t *cfg; |
f6116e61 | 243 | |
b447af65 | 244 | eap_identity = this->eap_identity->clone(this->eap_identity); |
f6116e61 | 245 | cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); |
7e84c427 | 246 | cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, eap_identity); |
f6116e61 MW |
247 | } |
248 | ||
82290106 | 249 | /** |
a44bb934 | 250 | * Handle EAP exchange as server |
82290106 | 251 | */ |
a44bb934 MW |
252 | static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, |
253 | eap_payload_t *in) | |
82290106 | 254 | { |
34742f1b | 255 | eap_type_t type, received_type, conf_type; |
f6e6fcd2 | 256 | pen_t vendor, received_vendor, conf_vendor; |
a44bb934 | 257 | eap_payload_t *out; |
34742f1b | 258 | auth_cfg_t *auth; |
7daf5226 | 259 | |
a44bb934 | 260 | if (in->get_code(in) != EAP_RESPONSE) |
f27f6296 | 261 | { |
a44bb934 MW |
262 | DBG1(DBG_IKE, "received %N, sending %N", |
263 | eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE); | |
264 | return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); | |
f27f6296 | 265 | } |
7daf5226 | 266 | |
a44bb934 MW |
267 | type = this->method->get_type(this->method, &vendor); |
268 | received_type = in->get_type(in, &received_vendor); | |
269 | if (type != received_type || vendor != received_vendor) | |
f27f6296 | 270 | { |
a44bb934 | 271 | if (received_vendor == 0 && received_type == EAP_NAK) |
82290106 | 272 | { |
34742f1b TB |
273 | auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); |
274 | conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); | |
275 | conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); | |
276 | if ((type == EAP_IDENTITY && !vendor) || | |
277 | (type == conf_type && vendor == conf_vendor)) | |
278 | { | |
279 | DBG1(DBG_IKE, "received %N, sending %N", | |
280 | eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE); | |
281 | return eap_payload_create_code(EAP_FAILURE, | |
282 | in->get_identifier(in)); | |
283 | } | |
284 | /* virtual methods handle NAKs in process() */ | |
82290106 | 285 | } |
a44bb934 MW |
286 | else |
287 | { | |
288 | DBG1(DBG_IKE, "received invalid EAP response, sending %N", | |
289 | eap_code_names, EAP_FAILURE); | |
34742f1b | 290 | return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); |
a44bb934 | 291 | } |
f27f6296 | 292 | } |
7daf5226 | 293 | |
a44bb934 | 294 | switch (this->method->process(this->method, in, &out)) |
f27f6296 | 295 | { |
a44bb934 MW |
296 | case NEED_MORE: |
297 | return out; | |
298 | case SUCCESS: | |
aa59a7f2 | 299 | if (!vendor && type == EAP_IDENTITY) |
a44bb934 MW |
300 | { |
301 | chunk_t data; | |
7daf5226 | 302 | |
a44bb934 MW |
303 | if (this->method->get_msk(this->method, &data) == SUCCESS) |
304 | { | |
f6116e61 | 305 | this->eap_identity = identification_create_from_data(data); |
d24a74c5 | 306 | DBG1(DBG_IKE, "received EAP identity '%Y'", |
a44bb934 | 307 | this->eap_identity); |
f6116e61 | 308 | replace_eap_identity(this); |
a44bb934 MW |
309 | } |
310 | /* restart EAP exchange, but with real method */ | |
311 | this->method->destroy(this->method); | |
312 | return server_initiate_eap(this, FALSE); | |
313 | } | |
64cc9acb | 314 | switch (this->method->get_msk(this->method, &this->msk)) |
a44bb934 | 315 | { |
64cc9acb TB |
316 | case SUCCESS: |
317 | this->msk = chunk_clone(this->msk); | |
318 | break; | |
319 | case NOT_SUPPORTED: | |
320 | break; | |
321 | case FAILED: | |
322 | default: | |
323 | DBG1(DBG_IKE, "failed to establish MSK"); | |
324 | goto failure; | |
a44bb934 MW |
325 | } |
326 | if (vendor) | |
327 | { | |
9efd7d7e TB |
328 | DBG1(DBG_IKE, "EAP vendor specific method %d-%N succeeded, " |
329 | "%sMSK established", type, pen_names, vendor, | |
a44bb934 MW |
330 | this->msk.ptr ? "" : "no "); |
331 | } | |
332 | else | |
333 | { | |
334 | DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established", | |
335 | eap_type_names, type, this->msk.ptr ? "" : "no "); | |
336 | } | |
337 | this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, | |
338 | TRUE); | |
a44bb934 MW |
339 | this->eap_complete = TRUE; |
340 | return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in)); | |
341 | case FAILED: | |
342 | default: | |
64cc9acb | 343 | failure: |
7f2e3091 TB |
344 | /* type might have changed for virtual methods */ |
345 | type = this->method->get_type(this->method, &vendor); | |
a44bb934 MW |
346 | if (vendor) |
347 | { | |
9efd7d7e TB |
348 | DBG1(DBG_IKE, "EAP vendor specific method %d-%N failed for " |
349 | "peer %Y", type, pen_names, vendor, | |
a44bb934 MW |
350 | this->ike_sa->get_other_id(this->ike_sa)); |
351 | } | |
352 | else | |
353 | { | |
d24a74c5 | 354 | DBG1(DBG_IKE, "EAP method %N failed for peer %Y", |
a44bb934 MW |
355 | eap_type_names, type, |
356 | this->ike_sa->get_other_id(this->ike_sa)); | |
357 | } | |
358 | return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); | |
f27f6296 | 359 | } |
f27f6296 MW |
360 | } |
361 | ||
362 | /** | |
363 | * Processing method for a peer | |
364 | */ | |
a44bb934 MW |
365 | static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, |
366 | eap_payload_t *in) | |
f27f6296 | 367 | { |
78e8dca9 | 368 | eap_type_t type, conf_type; |
f6e6fcd2 | 369 | pen_t vendor, conf_vendor; |
a44bb934 MW |
370 | auth_cfg_t *auth; |
371 | eap_payload_t *out; | |
372 | identification_t *id; | |
7daf5226 | 373 | |
0f806802 | 374 | type = in->get_type(in, &vendor); |
7daf5226 | 375 | |
0f806802 | 376 | if (!vendor && type == EAP_IDENTITY) |
3bc0b1a8 | 377 | { |
a44bb934 MW |
378 | DESTROY_IF(this->eap_identity); |
379 | auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); | |
380 | id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); | |
381 | if (!id || id->get_type(id) == ID_ANY) | |
382 | { | |
383 | id = this->ike_sa->get_my_id(this->ike_sa); | |
384 | } | |
c76b8a21 AS |
385 | DBG1(DBG_IKE, "server requested %N (id 0x%02X), sending '%Y'", |
386 | eap_type_names, type, in->get_identifier(in), id); | |
a44bb934 | 387 | this->eap_identity = id->clone(id); |
7daf5226 | 388 | |
a44bb934 MW |
389 | this->method = load_method(this, type, vendor, EAP_PEER); |
390 | if (this->method) | |
3bc0b1a8 | 391 | { |
a44bb934 MW |
392 | if (this->method->process(this->method, in, &out) == SUCCESS) |
393 | { | |
394 | this->method->destroy(this->method); | |
395 | this->method = NULL; | |
396 | return out; | |
397 | } | |
398 | this->method->destroy(this->method); | |
399 | this->method = NULL; | |
3bc0b1a8 | 400 | } |
af04233e TB |
401 | /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no |
402 | * EAP method (types 3-253, 255) */ | |
a44bb934 MW |
403 | DBG1(DBG_IKE, "%N not supported, sending EAP_NAK", |
404 | eap_type_names, type); | |
78e8dca9 | 405 | return eap_payload_create_nak(in->get_identifier(in), 0, 0, FALSE); |
3bc0b1a8 | 406 | } |
f27f6296 MW |
407 | if (this->method == NULL) |
408 | { | |
0f806802 MW |
409 | if (vendor) |
410 | { | |
9efd7d7e TB |
411 | DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%N ", |
412 | "(id 0x%02X)", type, pen_names, vendor, in->get_identifier(in)); | |
0f806802 MW |
413 | } |
414 | else | |
415 | { | |
c98ed04d | 416 | DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)", |
de931542 | 417 | eap_type_names, type, in->get_identifier(in)); |
0f806802 | 418 | } |
78e8dca9 TB |
419 | auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); |
420 | conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); | |
421 | conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); | |
422 | if (conf_type != EAP_NAK && | |
423 | (conf_type != type || conf_vendor != vendor)) | |
424 | { | |
425 | if (conf_vendor) | |
426 | { | |
9efd7d7e TB |
427 | DBG1(DBG_IKE, "requesting EAP method %d-%N, sending EAP_NAK", |
428 | conf_type, pen_names, conf_vendor); | |
78e8dca9 TB |
429 | } |
430 | else | |
431 | { | |
432 | DBG1(DBG_IKE, "requesting %N authentication, sending EAP_NAK", | |
433 | eap_type_names, conf_type); | |
434 | } | |
435 | return eap_payload_create_nak(in->get_identifier(in), conf_type, | |
cc4eec56 | 436 | conf_vendor, in->is_expanded(in)); |
78e8dca9 | 437 | } |
82290106 | 438 | this->method = load_method(this, type, vendor, EAP_PEER); |
a44bb934 | 439 | if (!this->method) |
f27f6296 | 440 | { |
a44bb934 | 441 | DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK"); |
78e8dca9 | 442 | return eap_payload_create_nak(in->get_identifier(in), 0, 0, |
cc4eec56 | 443 | in->is_expanded(in)); |
f27f6296 MW |
444 | } |
445 | } | |
7daf5226 | 446 | |
0f806802 | 447 | type = this->method->get_type(this->method, &vendor); |
7daf5226 | 448 | |
a44bb934 MW |
449 | if (this->method->process(this->method, in, &out) == NEED_MORE) |
450 | { /* client methods should never return SUCCESS */ | |
451 | return out; | |
452 | } | |
7daf5226 | 453 | |
a44bb934 | 454 | if (vendor) |
f27f6296 | 455 | { |
9efd7d7e TB |
456 | DBG1(DBG_IKE, "vendor specific EAP method %d-%N failed", type, |
457 | pen_names, vendor); | |
a44bb934 MW |
458 | } |
459 | else | |
460 | { | |
461 | DBG1(DBG_IKE, "%N method failed", eap_type_names, type); | |
f27f6296 | 462 | } |
a44bb934 | 463 | return NULL; |
f27f6296 MW |
464 | } |
465 | ||
82290106 | 466 | /** |
a44bb934 | 467 | * Verify AUTH payload |
82290106 | 468 | */ |
25f2d52f MW |
469 | static bool verify_auth(private_eap_authenticator_t *this, message_t *message, |
470 | chunk_t nonce, chunk_t init) | |
82290106 | 471 | { |
a44bb934 | 472 | auth_payload_t *auth_payload; |
66277067 | 473 | notify_payload_t *notify; |
a44bb934 MW |
474 | chunk_t auth_data, recv_auth_data; |
475 | identification_t *other_id; | |
476 | auth_cfg_t *auth; | |
a0563846 | 477 | keymat_v2_t *keymat; |
49a20ef0 | 478 | eap_type_t type; |
f6e6fcd2 | 479 | pen_t vendor; |
7daf5226 | 480 | |
a44bb934 | 481 | auth_payload = (auth_payload_t*)message->get_payload(message, |
3ecfc83c | 482 | PLV2_AUTH); |
a44bb934 | 483 | if (!auth_payload) |
82290106 | 484 | { |
a44bb934 MW |
485 | DBG1(DBG_IKE, "AUTH payload missing"); |
486 | return FALSE; | |
82290106 | 487 | } |
66277067 TB |
488 | recv_auth_data = auth_payload->get_data(auth_payload); |
489 | ||
490 | if (this->ike_sa->supports_extension(this->ike_sa, EXT_PPK) && | |
491 | !this->ppk.ptr) | |
492 | { /* look for a NO_PPK_AUTH notify if we have no PPK */ | |
493 | notify = message->get_notify(message, NO_PPK_AUTH); | |
494 | if (notify) | |
495 | { | |
496 | DBG1(DBG_IKE, "no PPK available, using NO_PPK_AUTH notify"); | |
497 | recv_auth_data = notify->get_notification_data(notify); | |
498 | } | |
499 | } | |
500 | ||
a44bb934 | 501 | other_id = this->ike_sa->get_other_id(this->ike_sa); |
a0563846 | 502 | keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); |
f3b02d88 TB |
503 | if (!keymat->get_psk_sig(keymat, TRUE, init, nonce, this->int_auth, |
504 | this->msk, this->ppk, other_id, this->reserved, | |
505 | &auth_data)) | |
2baae8e3 MW |
506 | { |
507 | return FALSE; | |
508 | } | |
161a0157 | 509 | if (!auth_data.len || !chunk_equals_const(auth_data, recv_auth_data)) |
a44bb934 MW |
510 | { |
511 | DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed", | |
512 | this->msk.ptr ? "" : "out"); | |
513 | chunk_free(&auth_data); | |
514 | return FALSE; | |
515 | } | |
516 | chunk_free(&auth_data); | |
7daf5226 | 517 | |
d24a74c5 | 518 | DBG1(DBG_IKE, "authentication of '%Y' with %N successful", |
a44bb934 MW |
519 | other_id, auth_class_names, AUTH_CLASS_EAP); |
520 | this->auth_complete = TRUE; | |
521 | auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); | |
522 | auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); | |
49a20ef0 TB |
523 | |
524 | type = this->method->get_type(this->method, &vendor); | |
525 | auth->add(auth, AUTH_RULE_EAP_TYPE, type); | |
526 | if (vendor) | |
527 | { | |
528 | auth->add(auth, AUTH_RULE_EAP_VENDOR, vendor); | |
529 | } | |
a44bb934 MW |
530 | return TRUE; |
531 | } | |
532 | ||
533 | /** | |
534 | * Build AUTH payload | |
535 | */ | |
2baae8e3 | 536 | static bool build_auth(private_eap_authenticator_t *this, message_t *message, |
25f2d52f | 537 | chunk_t nonce, chunk_t init) |
a44bb934 MW |
538 | { |
539 | auth_payload_t *auth_payload; | |
540 | identification_t *my_id; | |
541 | chunk_t auth_data; | |
a0563846 | 542 | keymat_v2_t *keymat; |
7daf5226 | 543 | |
a44bb934 | 544 | my_id = this->ike_sa->get_my_id(this->ike_sa); |
a0563846 | 545 | keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); |
7daf5226 | 546 | |
d24a74c5 | 547 | DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N", |
a44bb934 | 548 | my_id, auth_class_names, AUTH_CLASS_EAP); |
7daf5226 | 549 | |
f3b02d88 TB |
550 | if (!keymat->get_psk_sig(keymat, FALSE, init, nonce, this->int_auth, |
551 | this->msk, this->ppk, my_id, this->reserved, | |
552 | &auth_data)) | |
2baae8e3 MW |
553 | { |
554 | return FALSE; | |
555 | } | |
a44bb934 MW |
556 | auth_payload = auth_payload_create(); |
557 | auth_payload->set_auth_method(auth_payload, AUTH_PSK); | |
558 | auth_payload->set_data(auth_payload, auth_data); | |
559 | message->add_payload(message, (payload_t*)auth_payload); | |
560 | chunk_free(&auth_data); | |
66277067 TB |
561 | |
562 | if (this->no_ppk_auth) | |
563 | { | |
f3b02d88 | 564 | if (!keymat->get_psk_sig(keymat, FALSE, init, nonce, this->int_auth, |
d0131f70 TB |
565 | this->msk, chunk_empty, my_id, this->reserved, |
566 | &auth_data)) | |
66277067 TB |
567 | { |
568 | DBG1(DBG_IKE, "failed adding NO_PPK_AUTH notify"); | |
569 | return FALSE; | |
570 | } | |
571 | message->add_notify(message, FALSE, NO_PPK_AUTH, auth_data); | |
572 | chunk_free(&auth_data); | |
573 | } | |
2baae8e3 | 574 | return TRUE; |
82290106 MW |
575 | } |
576 | ||
45c4021b AS |
577 | METHOD(authenticator_t, process_server, status_t, |
578 | private_eap_authenticator_t *this, message_t *message) | |
f27f6296 | 579 | { |
a44bb934 | 580 | eap_payload_t *eap_payload; |
7daf5226 | 581 | |
a44bb934 MW |
582 | if (this->eap_complete) |
583 | { | |
25f2d52f | 584 | if (!verify_auth(this, message, this->sent_nonce, this->received_init)) |
a44bb934 MW |
585 | { |
586 | return FAILED; | |
587 | } | |
0c608316 MW |
588 | if (this->method->get_auth) |
589 | { | |
590 | auth_cfg_t *auth; | |
591 | ||
592 | auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); | |
593 | auth->merge(auth, this->method->get_auth(this->method), FALSE); | |
594 | } | |
a44bb934 MW |
595 | return NEED_MORE; |
596 | } | |
7daf5226 | 597 | |
a44bb934 | 598 | if (!this->method) |
f27f6296 | 599 | { |
a44bb934 MW |
600 | this->eap_payload = server_initiate_eap(this, TRUE); |
601 | } | |
602 | else | |
603 | { | |
604 | eap_payload = (eap_payload_t*)message->get_payload(message, | |
3ecfc83c | 605 | PLV2_EAP); |
a44bb934 MW |
606 | if (!eap_payload) |
607 | { | |
f27f6296 | 608 | return FAILED; |
a44bb934 MW |
609 | } |
610 | this->eap_payload = server_process_eap(this, eap_payload); | |
f27f6296 | 611 | } |
a44bb934 | 612 | return NEED_MORE; |
f27f6296 MW |
613 | } |
614 | ||
45c4021b AS |
615 | METHOD(authenticator_t, build_server, status_t, |
616 | private_eap_authenticator_t *this, message_t *message) | |
f27f6296 | 617 | { |
a44bb934 MW |
618 | if (this->eap_payload) |
619 | { | |
620 | eap_code_t code; | |
7daf5226 | 621 | |
a44bb934 MW |
622 | code = this->eap_payload->get_code(this->eap_payload); |
623 | message->add_payload(message, (payload_t*)this->eap_payload); | |
624 | this->eap_payload = NULL; | |
625 | if (code == EAP_FAILURE) | |
626 | { | |
627 | return FAILED; | |
628 | } | |
629 | return NEED_MORE; | |
630 | } | |
2baae8e3 MW |
631 | if (this->eap_complete && this->auth_complete && |
632 | build_auth(this, message, this->received_nonce, this->sent_init)) | |
a44bb934 | 633 | { |
a44bb934 MW |
634 | return SUCCESS; |
635 | } | |
636 | return FAILED; | |
637 | } | |
638 | ||
45c4021b AS |
639 | METHOD(authenticator_t, process_client, status_t, |
640 | private_eap_authenticator_t *this, message_t *message) | |
a44bb934 MW |
641 | { |
642 | eap_payload_t *eap_payload; | |
7daf5226 | 643 | |
a44bb934 | 644 | if (this->eap_complete) |
f27f6296 | 645 | { |
25f2d52f | 646 | if (!verify_auth(this, message, this->sent_nonce, this->received_init)) |
f27f6296 | 647 | { |
a44bb934 | 648 | return FAILED; |
f27f6296 | 649 | } |
f34702ff MW |
650 | if (this->require_mutual && !this->method->is_mutual(this->method)) |
651 | { /* we require mutual authentication due to EAP-only */ | |
f6e6fcd2 | 652 | pen_t vendor; |
f34702ff MW |
653 | |
654 | DBG1(DBG_IKE, "EAP-only authentication requires a mutual and " | |
655 | "MSK deriving EAP method, but %N is not", | |
656 | eap_type_names, this->method->get_type(this->method, &vendor)); | |
657 | return FAILED; | |
658 | } | |
a44bb934 MW |
659 | return SUCCESS; |
660 | } | |
7daf5226 | 661 | |
a44bb934 | 662 | eap_payload = (eap_payload_t*)message->get_payload(message, |
3ecfc83c | 663 | PLV2_EAP); |
a44bb934 MW |
664 | if (eap_payload) |
665 | { | |
666 | switch (eap_payload->get_code(eap_payload)) | |
f27f6296 | 667 | { |
a44bb934 MW |
668 | case EAP_REQUEST: |
669 | { | |
670 | this->eap_payload = client_process_eap(this, eap_payload); | |
cd37e131 MW |
671 | if (this->eap_payload) |
672 | { | |
673 | return NEED_MORE; | |
674 | } | |
675 | return FAILED; | |
a44bb934 MW |
676 | } |
677 | case EAP_SUCCESS: | |
f27f6296 | 678 | { |
a44bb934 | 679 | eap_type_t type; |
f6e6fcd2 | 680 | pen_t vendor; |
a44bb934 | 681 | auth_cfg_t *cfg; |
7daf5226 | 682 | |
64cc9acb | 683 | if (!this->method) |
f27f6296 | 684 | { |
64cc9acb TB |
685 | DBG1(DBG_IKE, "received unexpected %N", |
686 | eap_code_names, eap_payload->get_code(eap_payload)); | |
687 | return FAILED; | |
688 | } | |
689 | switch (this->method->get_msk(this->method, &this->msk)) | |
690 | { | |
691 | case SUCCESS: | |
692 | this->msk = chunk_clone(this->msk); | |
693 | break; | |
694 | case NOT_SUPPORTED: | |
695 | break; | |
696 | case FAILED: | |
697 | default: | |
698 | DBG1(DBG_IKE, "received %N but failed to establish MSK", | |
699 | eap_code_names, eap_payload->get_code(eap_payload)); | |
700 | return FAILED; | |
f27f6296 | 701 | } |
a44bb934 MW |
702 | type = this->method->get_type(this->method, &vendor); |
703 | if (vendor) | |
f27f6296 | 704 | { |
9efd7d7e TB |
705 | DBG1(DBG_IKE, "EAP vendor specific method %d-%N succeeded, " |
706 | "%sMSK established", type, pen_names, vendor, | |
a44bb934 | 707 | this->msk.ptr ? "" : "no "); |
f27f6296 | 708 | } |
a44bb934 | 709 | else |
f27f6296 | 710 | { |
a44bb934 MW |
711 | DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established", |
712 | eap_type_names, type, this->msk.ptr ? "" : "no "); | |
f27f6296 | 713 | } |
a44bb934 MW |
714 | cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); |
715 | cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); | |
716 | if (vendor) | |
717 | { | |
718 | cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); | |
719 | } | |
720 | this->eap_complete = TRUE; | |
721 | return NEED_MORE; | |
722 | } | |
723 | case EAP_FAILURE: | |
724 | default: | |
725 | { | |
726 | DBG1(DBG_IKE, "received %N, EAP authentication failed", | |
727 | eap_code_names, eap_payload->get_code(eap_payload)); | |
728 | return FAILED; | |
f27f6296 | 729 | } |
f27f6296 MW |
730 | } |
731 | } | |
a44bb934 | 732 | return FAILED; |
f27f6296 MW |
733 | } |
734 | ||
45c4021b AS |
735 | METHOD(authenticator_t, build_client, status_t, |
736 | private_eap_authenticator_t *this, message_t *message) | |
f27f6296 | 737 | { |
a44bb934 | 738 | if (this->eap_payload) |
f27f6296 | 739 | { |
a44bb934 MW |
740 | message->add_payload(message, (payload_t*)this->eap_payload); |
741 | this->eap_payload = NULL; | |
742 | return NEED_MORE; | |
f27f6296 | 743 | } |
2baae8e3 MW |
744 | if (this->eap_complete && |
745 | build_auth(this, message, this->received_nonce, this->sent_init)) | |
a44bb934 | 746 | { |
a44bb934 MW |
747 | return NEED_MORE; |
748 | } | |
749 | return NEED_MORE; | |
f27f6296 MW |
750 | } |
751 | ||
45c4021b AS |
752 | METHOD(authenticator_t, is_mutual, bool, |
753 | private_eap_authenticator_t *this) | |
f34702ff | 754 | { |
d8a94c18 MW |
755 | if (this->method) |
756 | { | |
f6e6fcd2 | 757 | pen_t vendor; |
d8a94c18 MW |
758 | |
759 | if (this->method->get_type(this->method, &vendor) != EAP_IDENTITY || | |
760 | vendor != 0) | |
761 | { | |
762 | return this->method->is_mutual(this->method); | |
763 | } | |
764 | } | |
f34702ff MW |
765 | /* we don't know yet, but insist on it after EAP is complete */ |
766 | this->require_mutual = TRUE; | |
767 | return TRUE; | |
768 | } | |
769 | ||
66277067 TB |
770 | METHOD(authenticator_t, use_ppk, void, |
771 | private_eap_authenticator_t *this, chunk_t ppk, bool no_ppk_auth) | |
772 | { | |
773 | this->ppk = ppk; | |
774 | this->no_ppk_auth = no_ppk_auth; | |
775 | } | |
776 | ||
f3b02d88 TB |
777 | METHOD(authenticator_t, set_int_auth, void, |
778 | private_eap_authenticator_t *this, chunk_t int_auth) | |
779 | { | |
780 | this->int_auth = int_auth; | |
781 | } | |
782 | ||
45c4021b AS |
783 | METHOD(authenticator_t, destroy, void, |
784 | private_eap_authenticator_t *this) | |
f27f6296 MW |
785 | { |
786 | DESTROY_IF(this->method); | |
a44bb934 MW |
787 | DESTROY_IF(this->eap_payload); |
788 | DESTROY_IF(this->eap_identity); | |
f27f6296 MW |
789 | chunk_free(&this->msk); |
790 | free(this); | |
791 | } | |
792 | ||
793 | /* | |
794 | * Described in header. | |
795 | */ | |
a44bb934 | 796 | eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, |
25f2d52f | 797 | chunk_t received_nonce, chunk_t sent_nonce, |
5f15faeb MW |
798 | chunk_t received_init, chunk_t sent_init, |
799 | char reserved[3]) | |
f27f6296 | 800 | { |
45c4021b AS |
801 | private_eap_authenticator_t *this; |
802 | ||
803 | INIT(this, | |
804 | .public = { | |
805 | .authenticator = { | |
806 | .build = _build_client, | |
807 | .process = _process_client, | |
66277067 | 808 | .use_ppk = _use_ppk, |
f3b02d88 | 809 | .set_int_auth = _set_int_auth, |
45c4021b AS |
810 | .is_mutual = _is_mutual, |
811 | .destroy = _destroy, | |
812 | }, | |
813 | }, | |
814 | .ike_sa = ike_sa, | |
815 | .received_init = received_init, | |
816 | .received_nonce = received_nonce, | |
817 | .sent_init = sent_init, | |
818 | .sent_nonce = sent_nonce, | |
45c4021b | 819 | ); |
5f15faeb | 820 | memcpy(this->reserved, reserved, sizeof(this->reserved)); |
7daf5226 | 821 | |
a44bb934 MW |
822 | return &this->public; |
823 | } | |
824 | ||
825 | /* | |
826 | * Described in header. | |
827 | */ | |
828 | eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, | |
25f2d52f | 829 | chunk_t received_nonce, chunk_t sent_nonce, |
5f15faeb MW |
830 | chunk_t received_init, chunk_t sent_init, |
831 | char reserved[3]) | |
a44bb934 | 832 | { |
45c4021b AS |
833 | private_eap_authenticator_t *this; |
834 | ||
835 | INIT(this, | |
ba31fe1f MW |
836 | .public = { |
837 | .authenticator = { | |
838 | .build = _build_server, | |
839 | .process = _process_server, | |
66277067 | 840 | .use_ppk = _use_ppk, |
f3b02d88 | 841 | .set_int_auth = _set_int_auth, |
ba31fe1f MW |
842 | .is_mutual = _is_mutual, |
843 | .destroy = _destroy, | |
844 | }, | |
45c4021b AS |
845 | }, |
846 | .ike_sa = ike_sa, | |
847 | .received_init = received_init, | |
848 | .received_nonce = received_nonce, | |
849 | .sent_init = sent_init, | |
850 | .sent_nonce = sent_nonce, | |
45c4021b | 851 | ); |
5f15faeb | 852 | memcpy(this->reserved, reserved, sizeof(this->reserved)); |
7daf5226 | 853 | |
f27f6296 MW |
854 | return &this->public; |
855 | } |