Line data Source code
1 : /*
2 : * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3 : * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "includes.h"
10 :
11 : #include "common.h"
12 : #include "crypto/sha1.h"
13 : #include "crypto/tls.h"
14 : #include "eap_common/eap_tlv_common.h"
15 : #include "eap_common/eap_peap_common.h"
16 : #include "eap_i.h"
17 : #include "eap_tls_common.h"
18 : #include "eap_config.h"
19 : #include "tncc.h"
20 :
21 :
22 : /* Maximum supported PEAP version
23 : * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
24 : * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
25 : */
26 : #define EAP_PEAP_VERSION 1
27 :
28 :
29 : static void eap_peap_deinit(struct eap_sm *sm, void *priv);
30 :
31 :
32 : struct eap_peap_data {
33 : struct eap_ssl_data ssl;
34 :
35 : int peap_version, force_peap_version, force_new_label;
36 :
37 : const struct eap_method *phase2_method;
38 : void *phase2_priv;
39 : int phase2_success;
40 : int phase2_eap_success;
41 : int phase2_eap_started;
42 :
43 : struct eap_method_type phase2_type;
44 : struct eap_method_type *phase2_types;
45 : size_t num_phase2_types;
46 :
47 : int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
48 : * EAP-Success
49 : * 1 = reply with tunneled EAP-Success to inner
50 : * EAP-Success and expect AS to send outer
51 : * (unencrypted) EAP-Success after this
52 : * 2 = reply with PEAP/TLS ACK to inner
53 : * EAP-Success and expect AS to send outer
54 : * (unencrypted) EAP-Success after this */
55 : int resuming; /* starting a resumed session */
56 : int reauth; /* reauthentication */
57 : u8 *key_data;
58 : u8 *session_id;
59 : size_t id_len;
60 :
61 : struct wpabuf *pending_phase2_req;
62 : struct wpabuf *pending_resp;
63 : enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
64 : int crypto_binding_used;
65 : u8 binding_nonce[32];
66 : u8 ipmk[40];
67 : u8 cmk[20];
68 : int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
69 : * is enabled. */
70 : };
71 :
72 :
73 41 : static void eap_peap_parse_phase1(struct eap_peap_data *data,
74 : const char *phase1)
75 : {
76 : const char *pos;
77 :
78 41 : pos = os_strstr(phase1, "peapver=");
79 41 : if (pos) {
80 31 : data->force_peap_version = atoi(pos + 8);
81 31 : data->peap_version = data->force_peap_version;
82 31 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d",
83 : data->force_peap_version);
84 : }
85 :
86 41 : if (os_strstr(phase1, "peaplabel=1")) {
87 2 : data->force_new_label = 1;
88 2 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key "
89 : "derivation");
90 : }
91 :
92 41 : if (os_strstr(phase1, "peap_outer_success=0")) {
93 1 : data->peap_outer_success = 0;
94 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on "
95 : "tunneled EAP-Success");
96 40 : } else if (os_strstr(phase1, "peap_outer_success=1")) {
97 1 : data->peap_outer_success = 1;
98 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success "
99 : "after receiving tunneled EAP-Success");
100 39 : } else if (os_strstr(phase1, "peap_outer_success=2")) {
101 1 : data->peap_outer_success = 2;
102 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after "
103 : "receiving tunneled EAP-Success");
104 : }
105 :
106 41 : if (os_strstr(phase1, "crypto_binding=0")) {
107 1 : data->crypto_binding = NO_BINDING;
108 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
109 40 : } else if (os_strstr(phase1, "crypto_binding=1")) {
110 1 : data->crypto_binding = OPTIONAL_BINDING;
111 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
112 39 : } else if (os_strstr(phase1, "crypto_binding=2")) {
113 17 : data->crypto_binding = REQUIRE_BINDING;
114 17 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
115 : }
116 :
117 : #ifdef EAP_TNC
118 41 : if (os_strstr(phase1, "tnc=soh2")) {
119 1 : data->soh = 2;
120 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
121 40 : } else if (os_strstr(phase1, "tnc=soh1")) {
122 1 : data->soh = 1;
123 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled");
124 39 : } else if (os_strstr(phase1, "tnc=soh")) {
125 4 : data->soh = 2;
126 4 : wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
127 : }
128 : #endif /* EAP_TNC */
129 41 : }
130 :
131 :
132 68 : static void * eap_peap_init(struct eap_sm *sm)
133 : {
134 : struct eap_peap_data *data;
135 68 : struct eap_peer_config *config = eap_get_config(sm);
136 :
137 68 : data = os_zalloc(sizeof(*data));
138 68 : if (data == NULL)
139 1 : return NULL;
140 67 : sm->peap_done = FALSE;
141 67 : data->peap_version = EAP_PEAP_VERSION;
142 67 : data->force_peap_version = -1;
143 67 : data->peap_outer_success = 2;
144 67 : data->crypto_binding = OPTIONAL_BINDING;
145 :
146 67 : if (config && config->phase1)
147 41 : eap_peap_parse_phase1(data, config->phase1);
148 :
149 67 : if (eap_peer_select_phase2_methods(config, "auth=",
150 : &data->phase2_types,
151 : &data->num_phase2_types) < 0) {
152 2 : eap_peap_deinit(sm, data);
153 2 : return NULL;
154 : }
155 :
156 65 : data->phase2_type.vendor = EAP_VENDOR_IETF;
157 65 : data->phase2_type.method = EAP_TYPE_NONE;
158 :
159 65 : if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) {
160 1 : wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
161 1 : eap_peap_deinit(sm, data);
162 1 : return NULL;
163 : }
164 :
165 64 : return data;
166 : }
167 :
168 :
169 149 : static void eap_peap_free_key(struct eap_peap_data *data)
170 : {
171 149 : if (data->key_data) {
172 70 : bin_clear_free(data->key_data, EAP_TLS_KEY_LEN);
173 70 : data->key_data = NULL;
174 : }
175 149 : }
176 :
177 :
178 67 : static void eap_peap_deinit(struct eap_sm *sm, void *priv)
179 : {
180 67 : struct eap_peap_data *data = priv;
181 67 : if (data == NULL)
182 67 : return;
183 67 : if (data->phase2_priv && data->phase2_method)
184 53 : data->phase2_method->deinit(sm, data->phase2_priv);
185 67 : os_free(data->phase2_types);
186 67 : eap_peer_tls_ssl_deinit(sm, &data->ssl);
187 67 : eap_peap_free_key(data);
188 67 : os_free(data->session_id);
189 67 : wpabuf_free(data->pending_phase2_req);
190 67 : wpabuf_free(data->pending_resp);
191 67 : os_free(data);
192 : }
193 :
194 :
195 : /**
196 : * eap_tlv_build_nak - Build EAP-TLV NAK message
197 : * @id: EAP identifier for the header
198 : * @nak_type: TLV type (EAP_TLV_*)
199 : * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
200 : *
201 : * This function builds an EAP-TLV NAK message. The caller is responsible for
202 : * freeing the returned buffer.
203 : */
204 0 : static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
205 : {
206 : struct wpabuf *msg;
207 :
208 0 : msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
209 : EAP_CODE_RESPONSE, id);
210 0 : if (msg == NULL)
211 0 : return NULL;
212 :
213 0 : wpabuf_put_u8(msg, 0x80); /* Mandatory */
214 0 : wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
215 0 : wpabuf_put_be16(msg, 6); /* Length */
216 0 : wpabuf_put_be32(msg, 0); /* Vendor-Id */
217 0 : wpabuf_put_be16(msg, nak_type); /* NAK-Type */
218 :
219 0 : return msg;
220 : }
221 :
222 :
223 17 : static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
224 : u8 *isk, size_t isk_len)
225 : {
226 : u8 *key;
227 : size_t key_len;
228 :
229 17 : os_memset(isk, 0, isk_len);
230 34 : if (data->phase2_method == NULL || data->phase2_priv == NULL ||
231 34 : data->phase2_method->isKeyAvailable == NULL ||
232 17 : data->phase2_method->getKey == NULL)
233 0 : return 0;
234 :
235 34 : if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
236 17 : (key = data->phase2_method->getKey(sm, data->phase2_priv,
237 : &key_len)) == NULL) {
238 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
239 : "from Phase 2");
240 1 : return -1;
241 : }
242 :
243 16 : if (key_len > isk_len)
244 0 : key_len = isk_len;
245 16 : os_memcpy(isk, key, key_len);
246 16 : os_free(key);
247 :
248 16 : return 0;
249 : }
250 :
251 :
252 18 : static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
253 : {
254 : u8 *tk;
255 : u8 isk[32], imck[60];
256 : int resumed;
257 :
258 : /*
259 : * Tunnel key (TK) is the first 60 octets of the key generated by
260 : * phase 1 of PEAP (based on TLS).
261 : */
262 18 : tk = data->key_data;
263 18 : if (tk == NULL)
264 0 : return -1;
265 18 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
266 :
267 18 : resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn);
268 18 : wpa_printf(MSG_DEBUG,
269 : "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d",
270 : data->reauth, resumed, data->phase2_eap_started,
271 : data->phase2_success);
272 18 : if (data->reauth && !data->phase2_eap_started && resumed) {
273 : /* Fast-connect: IPMK|CMK = TK */
274 1 : os_memcpy(data->ipmk, tk, 40);
275 1 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
276 1 : data->ipmk, 40);
277 1 : os_memcpy(data->cmk, tk + 40, 20);
278 1 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
279 1 : data->cmk, 20);
280 1 : return 0;
281 : }
282 :
283 17 : if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
284 1 : return -1;
285 16 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
286 :
287 : /*
288 : * IPMK Seed = "Inner Methods Compound Keys" | ISK
289 : * TempKey = First 40 octets of TK
290 : * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
291 : * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
292 : * in the end of the label just before ISK; is that just a typo?)
293 : */
294 16 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
295 16 : if (peap_prfplus(data->peap_version, tk, 40,
296 : "Inner Methods Compound Keys",
297 : isk, sizeof(isk), imck, sizeof(imck)) < 0)
298 1 : return -1;
299 15 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
300 : imck, sizeof(imck));
301 :
302 15 : os_memcpy(data->ipmk, imck, 40);
303 15 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
304 15 : os_memcpy(data->cmk, imck + 40, 20);
305 15 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
306 :
307 15 : return 0;
308 : }
309 :
310 :
311 14 : static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
312 : struct eap_peap_data *data,
313 : struct wpabuf *buf)
314 : {
315 : u8 *mac;
316 14 : u8 eap_type = EAP_TYPE_PEAP;
317 : const u8 *addr[2];
318 : size_t len[2];
319 : u16 tlv_type;
320 :
321 : /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
322 14 : addr[0] = wpabuf_put(buf, 0);
323 14 : len[0] = 60;
324 14 : addr[1] = &eap_type;
325 14 : len[1] = 1;
326 :
327 14 : tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
328 14 : wpabuf_put_be16(buf, tlv_type);
329 14 : wpabuf_put_be16(buf, 56);
330 :
331 14 : wpabuf_put_u8(buf, 0); /* Reserved */
332 14 : wpabuf_put_u8(buf, data->peap_version); /* Version */
333 14 : wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
334 14 : wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
335 14 : wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
336 14 : mac = wpabuf_put(buf, 20); /* Compound_MAC */
337 14 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
338 28 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
339 14 : addr[0], len[0]);
340 28 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
341 14 : addr[1], len[1]);
342 14 : if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0)
343 1 : return -1;
344 13 : wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
345 13 : data->crypto_binding_used = 1;
346 :
347 13 : return 0;
348 : }
349 :
350 :
351 : /**
352 : * eap_tlv_build_result - Build EAP-TLV Result message
353 : * @id: EAP identifier for the header
354 : * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
355 : * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
356 : *
357 : * This function builds an EAP-TLV Result message. The caller is responsible
358 : * for freeing the returned buffer.
359 : */
360 19 : static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
361 : struct eap_peap_data *data,
362 : int crypto_tlv_used,
363 : int id, u16 status)
364 : {
365 : struct wpabuf *msg;
366 : size_t len;
367 :
368 19 : if (data->crypto_binding == NO_BINDING)
369 1 : crypto_tlv_used = 0;
370 :
371 19 : len = 6;
372 19 : if (crypto_tlv_used)
373 15 : len += 60; /* Cryptobinding TLV */
374 19 : msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
375 : EAP_CODE_RESPONSE, id);
376 19 : if (msg == NULL)
377 1 : return NULL;
378 :
379 18 : wpabuf_put_u8(msg, 0x80); /* Mandatory */
380 18 : wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
381 18 : wpabuf_put_be16(msg, 2); /* Length */
382 18 : wpabuf_put_be16(msg, status); /* Status */
383 :
384 18 : if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
385 1 : wpabuf_free(msg);
386 1 : return NULL;
387 : }
388 :
389 17 : return msg;
390 : }
391 :
392 :
393 18 : static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
394 : struct eap_peap_data *data,
395 : const u8 *crypto_tlv,
396 : size_t crypto_tlv_len)
397 : {
398 : u8 buf[61], mac[SHA1_MAC_LEN];
399 : const u8 *pos;
400 :
401 18 : if (eap_peap_derive_cmk(sm, data) < 0) {
402 2 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
403 2 : return -1;
404 : }
405 :
406 16 : if (crypto_tlv_len != 4 + 56) {
407 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
408 : "length %d", (int) crypto_tlv_len);
409 0 : return -1;
410 : }
411 :
412 16 : pos = crypto_tlv;
413 16 : pos += 4; /* TLV header */
414 16 : if (pos[1] != data->peap_version) {
415 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
416 : "mismatch (was %d; expected %d)",
417 0 : pos[1], data->peap_version);
418 0 : return -1;
419 : }
420 :
421 16 : if (pos[3] != 0) {
422 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
423 0 : "SubType %d", pos[3]);
424 0 : return -1;
425 : }
426 16 : pos += 4;
427 16 : os_memcpy(data->binding_nonce, pos, 32);
428 16 : pos += 32; /* Nonce */
429 :
430 : /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
431 16 : os_memcpy(buf, crypto_tlv, 60);
432 16 : os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
433 16 : buf[60] = EAP_TYPE_PEAP;
434 16 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
435 : buf, sizeof(buf));
436 16 : hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
437 :
438 16 : if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
439 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
440 : "cryptobinding TLV");
441 1 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
442 : pos, SHA1_MAC_LEN);
443 1 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
444 : mac, SHA1_MAC_LEN);
445 1 : return -1;
446 : }
447 :
448 15 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
449 :
450 15 : return 0;
451 : }
452 :
453 :
454 : /**
455 : * eap_tlv_process - Process a received EAP-TLV message and generate a response
456 : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
457 : * @ret: Return values from EAP request validation and processing
458 : * @req: EAP-TLV request to be processed. The caller must have validated that
459 : * the buffer is large enough to contain full request (hdr->length bytes) and
460 : * that the EAP type is EAP_TYPE_TLV.
461 : * @resp: Buffer to return a pointer to the allocated response message. This
462 : * field should be initialized to %NULL before the call. The value will be
463 : * updated if a response message is generated. The caller is responsible for
464 : * freeing the allocated message.
465 : * @force_failure: Force negotiation to fail
466 : * Returns: 0 on success, -1 on failure
467 : */
468 20 : static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
469 : struct eap_method_ret *ret,
470 : const struct wpabuf *req, struct wpabuf **resp,
471 : int force_failure)
472 : {
473 : size_t left, tlv_len;
474 : const u8 *pos;
475 20 : const u8 *result_tlv = NULL, *crypto_tlv = NULL;
476 20 : size_t result_tlv_len = 0, crypto_tlv_len = 0;
477 : int tlv_type, mandatory;
478 :
479 : /* Parse TLVs */
480 20 : pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
481 20 : if (pos == NULL)
482 0 : return -1;
483 20 : wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
484 79 : while (left >= 4) {
485 39 : mandatory = !!(pos[0] & 0x80);
486 39 : tlv_type = WPA_GET_BE16(pos) & 0x3fff;
487 39 : pos += 2;
488 39 : tlv_len = WPA_GET_BE16(pos);
489 39 : pos += 2;
490 39 : left -= 4;
491 39 : if (tlv_len > left) {
492 0 : wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
493 : "(tlv_len=%lu left=%lu)",
494 : (unsigned long) tlv_len,
495 : (unsigned long) left);
496 0 : return -1;
497 : }
498 39 : switch (tlv_type) {
499 : case EAP_TLV_RESULT_TLV:
500 20 : result_tlv = pos;
501 20 : result_tlv_len = tlv_len;
502 20 : break;
503 : case EAP_TLV_CRYPTO_BINDING_TLV:
504 19 : crypto_tlv = pos;
505 19 : crypto_tlv_len = tlv_len;
506 19 : break;
507 : default:
508 0 : wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
509 : "%d%s", tlv_type,
510 : mandatory ? " (mandatory)" : "");
511 0 : if (mandatory) {
512 : /* NAK TLV and ignore all TLVs in this packet.
513 : */
514 0 : *resp = eap_tlv_build_nak(eap_get_id(req),
515 : tlv_type);
516 0 : return *resp == NULL ? -1 : 0;
517 : }
518 : /* Ignore this TLV, but process other TLVs */
519 0 : break;
520 : }
521 :
522 39 : pos += tlv_len;
523 39 : left -= tlv_len;
524 : }
525 20 : if (left) {
526 0 : wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
527 : "Request (left=%lu)", (unsigned long) left);
528 0 : return -1;
529 : }
530 :
531 : /* Process supported TLVs */
532 20 : if (crypto_tlv && data->crypto_binding != NO_BINDING) {
533 18 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
534 : crypto_tlv, crypto_tlv_len);
535 36 : if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
536 : crypto_tlv_len + 4) < 0) {
537 3 : if (result_tlv == NULL)
538 0 : return -1;
539 3 : force_failure = 1;
540 3 : crypto_tlv = NULL; /* do not include Cryptobinding TLV
541 : * in response, if the received
542 : * cryptobinding was invalid. */
543 : }
544 2 : } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
545 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
546 1 : return -1;
547 : }
548 :
549 19 : if (result_tlv) {
550 : int status, resp_status;
551 19 : wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
552 : result_tlv, result_tlv_len);
553 19 : if (result_tlv_len < 2) {
554 0 : wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
555 : "(len=%lu)",
556 : (unsigned long) result_tlv_len);
557 0 : return -1;
558 : }
559 19 : status = WPA_GET_BE16(result_tlv);
560 19 : if (status == EAP_TLV_RESULT_SUCCESS) {
561 19 : wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
562 : "- EAP-TLV/Phase2 Completed");
563 19 : if (force_failure) {
564 3 : wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
565 : " - force failed Phase 2");
566 3 : resp_status = EAP_TLV_RESULT_FAILURE;
567 3 : ret->decision = DECISION_FAIL;
568 : } else {
569 16 : resp_status = EAP_TLV_RESULT_SUCCESS;
570 16 : ret->decision = DECISION_UNCOND_SUCC;
571 : }
572 0 : } else if (status == EAP_TLV_RESULT_FAILURE) {
573 0 : wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
574 0 : resp_status = EAP_TLV_RESULT_FAILURE;
575 0 : ret->decision = DECISION_FAIL;
576 : } else {
577 0 : wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
578 : "Status %d", status);
579 0 : resp_status = EAP_TLV_RESULT_FAILURE;
580 0 : ret->decision = DECISION_FAIL;
581 : }
582 19 : ret->methodState = METHOD_DONE;
583 :
584 38 : *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
585 19 : eap_get_id(req), resp_status);
586 : }
587 :
588 19 : return 0;
589 : }
590 :
591 :
592 226 : static int eap_peap_phase2_request(struct eap_sm *sm,
593 : struct eap_peap_data *data,
594 : struct eap_method_ret *ret,
595 : struct wpabuf *req,
596 : struct wpabuf **resp)
597 : {
598 226 : struct eap_hdr *hdr = wpabuf_mhead(req);
599 226 : size_t len = be_to_host16(hdr->length);
600 : u8 *pos;
601 : struct eap_method_ret iret;
602 226 : struct eap_peer_config *config = eap_get_config(sm);
603 :
604 226 : if (len <= sizeof(struct eap_hdr)) {
605 0 : wpa_printf(MSG_INFO, "EAP-PEAP: too short "
606 : "Phase 2 request (len=%lu)", (unsigned long) len);
607 0 : return -1;
608 : }
609 226 : pos = (u8 *) (hdr + 1);
610 226 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
611 226 : switch (*pos) {
612 : case EAP_TYPE_IDENTITY:
613 66 : *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
614 66 : break;
615 : case EAP_TYPE_TLV:
616 20 : os_memset(&iret, 0, sizeof(iret));
617 39 : if (eap_tlv_process(sm, data, &iret, req, resp,
618 20 : data->phase2_eap_started &&
619 19 : !data->phase2_eap_success)) {
620 1 : ret->methodState = METHOD_DONE;
621 1 : ret->decision = DECISION_FAIL;
622 1 : return -1;
623 : }
624 19 : if (iret.methodState == METHOD_DONE ||
625 0 : iret.methodState == METHOD_MAY_CONT) {
626 19 : ret->methodState = iret.methodState;
627 19 : ret->decision = iret.decision;
628 19 : data->phase2_success = 1;
629 : }
630 19 : break;
631 : case EAP_TYPE_EXPANDED:
632 : #ifdef EAP_TNC
633 6 : if (data->soh) {
634 : const u8 *epos;
635 : size_t eleft;
636 :
637 6 : epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
638 : req, &eleft);
639 6 : if (epos) {
640 : struct wpabuf *buf;
641 6 : wpa_printf(MSG_DEBUG,
642 : "EAP-PEAP: SoH EAP Extensions");
643 6 : buf = tncc_process_soh_request(data->soh,
644 : epos, eleft);
645 6 : if (buf) {
646 4 : *resp = eap_msg_alloc(
647 : EAP_VENDOR_MICROSOFT, 0x21,
648 : wpabuf_len(buf),
649 : EAP_CODE_RESPONSE,
650 4 : hdr->identifier);
651 4 : if (*resp == NULL) {
652 1 : ret->methodState = METHOD_DONE;
653 1 : ret->decision = DECISION_FAIL;
654 1 : wpabuf_free(buf);
655 1 : return -1;
656 : }
657 3 : wpabuf_put_buf(*resp, buf);
658 3 : wpabuf_free(buf);
659 3 : break;
660 : }
661 : }
662 : }
663 : #endif /* EAP_TNC */
664 : /* fall through */
665 : default:
666 272 : if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
667 136 : data->phase2_type.method == EAP_TYPE_NONE) {
668 : size_t i;
669 136 : for (i = 0; i < data->num_phase2_types; i++) {
670 63 : if (data->phase2_types[i].vendor !=
671 63 : EAP_VENDOR_IETF ||
672 63 : data->phase2_types[i].method != *pos)
673 9 : continue;
674 :
675 54 : data->phase2_type.vendor =
676 54 : data->phase2_types[i].vendor;
677 54 : data->phase2_type.method =
678 54 : data->phase2_types[i].method;
679 54 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
680 : "Phase 2 EAP vendor %d method %d",
681 : data->phase2_type.vendor,
682 : data->phase2_type.method);
683 54 : break;
684 : }
685 : }
686 267 : if (*pos != data->phase2_type.method ||
687 131 : *pos == EAP_TYPE_NONE) {
688 5 : if (eap_peer_tls_phase2_nak(data->phase2_types,
689 : data->num_phase2_types,
690 : hdr, resp))
691 1 : return -1;
692 4 : return 0;
693 : }
694 :
695 131 : if (data->phase2_priv == NULL) {
696 54 : data->phase2_method = eap_peer_get_eap_method(
697 : data->phase2_type.vendor,
698 54 : data->phase2_type.method);
699 54 : if (data->phase2_method) {
700 54 : sm->init_phase2 = 1;
701 54 : data->phase2_priv =
702 54 : data->phase2_method->init(sm);
703 54 : sm->init_phase2 = 0;
704 : }
705 : }
706 131 : if (data->phase2_priv == NULL || data->phase2_method == NULL) {
707 1 : wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
708 1 : "Phase 2 EAP method %d", *pos);
709 1 : ret->methodState = METHOD_DONE;
710 1 : ret->decision = DECISION_FAIL;
711 1 : return -1;
712 : }
713 130 : data->phase2_eap_started = 1;
714 130 : os_memset(&iret, 0, sizeof(iret));
715 130 : *resp = data->phase2_method->process(sm, data->phase2_priv,
716 : &iret, req);
717 201 : if ((iret.methodState == METHOD_DONE ||
718 199 : iret.methodState == METHOD_MAY_CONT) &&
719 201 : (iret.decision == DECISION_UNCOND_SUCC ||
720 73 : iret.decision == DECISION_COND_SUCC)) {
721 58 : data->phase2_eap_success = 1;
722 58 : data->phase2_success = 1;
723 : }
724 130 : break;
725 : }
726 :
727 222 : if (*resp == NULL &&
728 11 : (config->pending_req_identity || config->pending_req_password ||
729 5 : config->pending_req_otp || config->pending_req_new_password)) {
730 2 : wpabuf_free(data->pending_phase2_req);
731 2 : data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
732 : }
733 :
734 218 : return 0;
735 : }
736 :
737 :
738 268 : static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
739 : struct eap_method_ret *ret,
740 : const struct eap_hdr *req,
741 : const struct wpabuf *in_data,
742 : struct wpabuf **out_data)
743 : {
744 268 : struct wpabuf *in_decrypted = NULL;
745 268 : int res, skip_change = 0;
746 : struct eap_hdr *hdr, *rhdr;
747 268 : struct wpabuf *resp = NULL;
748 : size_t len;
749 :
750 268 : wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
751 : " Phase 2", (unsigned long) wpabuf_len(in_data));
752 :
753 268 : if (data->pending_phase2_req) {
754 2 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
755 : "skip decryption and use old data");
756 : /* Clear TLS reassembly state. */
757 2 : eap_peer_tls_reset_input(&data->ssl);
758 2 : in_decrypted = data->pending_phase2_req;
759 2 : data->pending_phase2_req = NULL;
760 2 : skip_change = 1;
761 2 : goto continue_req;
762 : }
763 :
764 266 : if (wpabuf_len(in_data) == 0 && sm->workaround &&
765 0 : data->phase2_success) {
766 : /*
767 : * Cisco ACS seems to be using TLS ACK to terminate
768 : * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
769 : */
770 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
771 : "expected data - acknowledge with TLS ACK since "
772 : "Phase 2 has been completed");
773 0 : ret->decision = DECISION_COND_SUCC;
774 0 : ret->methodState = METHOD_DONE;
775 0 : return 1;
776 266 : } else if (wpabuf_len(in_data) == 0) {
777 : /* Received TLS ACK - requesting more fragments */
778 0 : return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
779 : data->peap_version,
780 0 : req->identifier, NULL, out_data);
781 : }
782 :
783 266 : res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
784 266 : if (res)
785 1 : return res;
786 :
787 : continue_req:
788 267 : wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
789 : in_decrypted);
790 :
791 267 : hdr = wpabuf_mhead(in_decrypted);
792 308 : if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
793 82 : be_to_host16(hdr->length) == 5 &&
794 41 : eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
795 : /* At least FreeRADIUS seems to send full EAP header with
796 : * EAP Request Identity */
797 41 : skip_change = 1;
798 : }
799 419 : if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
800 152 : eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
801 20 : skip_change = 1;
802 : }
803 :
804 267 : if (data->peap_version == 0 && !skip_change) {
805 : struct eap_hdr *nhdr;
806 75 : struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
807 75 : wpabuf_len(in_decrypted));
808 75 : if (nmsg == NULL) {
809 1 : wpabuf_free(in_decrypted);
810 1 : return 0;
811 : }
812 74 : nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
813 74 : wpabuf_put_buf(nmsg, in_decrypted);
814 74 : nhdr->code = req->code;
815 74 : nhdr->identifier = req->identifier;
816 74 : nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
817 : wpabuf_len(in_decrypted));
818 :
819 74 : wpabuf_free(in_decrypted);
820 74 : in_decrypted = nmsg;
821 : }
822 :
823 266 : hdr = wpabuf_mhead(in_decrypted);
824 266 : if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
825 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
826 : "EAP frame (len=%lu)",
827 : (unsigned long) wpabuf_len(in_decrypted));
828 0 : wpabuf_free(in_decrypted);
829 0 : return 0;
830 : }
831 266 : len = be_to_host16(hdr->length);
832 266 : if (len > wpabuf_len(in_decrypted)) {
833 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
834 : "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
835 : (unsigned long) wpabuf_len(in_decrypted),
836 : (unsigned long) len);
837 0 : wpabuf_free(in_decrypted);
838 0 : return 0;
839 : }
840 266 : if (len < wpabuf_len(in_decrypted)) {
841 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
842 : "shorter length than full decrypted data "
843 : "(%lu < %lu)",
844 : (unsigned long) len,
845 : (unsigned long) wpabuf_len(in_decrypted));
846 : }
847 532 : wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
848 532 : "identifier=%d length=%lu", hdr->code, hdr->identifier,
849 : (unsigned long) len);
850 266 : switch (hdr->code) {
851 : case EAP_CODE_REQUEST:
852 226 : if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
853 : &resp)) {
854 4 : wpabuf_free(in_decrypted);
855 4 : wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
856 : "processing failed");
857 4 : return 0;
858 : }
859 222 : break;
860 : case EAP_CODE_SUCCESS:
861 38 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
862 38 : if (data->peap_version == 1) {
863 : /* EAP-Success within TLS tunnel is used to indicate
864 : * shutdown of the TLS channel. The authentication has
865 : * been completed. */
866 75 : if (data->phase2_eap_started &&
867 37 : !data->phase2_eap_success) {
868 0 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
869 : "Success used to indicate success, "
870 : "but Phase 2 EAP was not yet "
871 : "completed successfully");
872 0 : ret->methodState = METHOD_DONE;
873 0 : ret->decision = DECISION_FAIL;
874 0 : wpabuf_free(in_decrypted);
875 0 : return 0;
876 : }
877 38 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
878 : "EAP-Success within TLS tunnel - "
879 : "authentication completed");
880 38 : ret->decision = DECISION_UNCOND_SUCC;
881 38 : ret->methodState = METHOD_DONE;
882 38 : data->phase2_success = 1;
883 38 : if (data->peap_outer_success == 2) {
884 36 : wpabuf_free(in_decrypted);
885 36 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
886 : "to finish authentication");
887 36 : return 1;
888 2 : } else if (data->peap_outer_success == 1) {
889 : /* Reply with EAP-Success within the TLS
890 : * channel to complete the authentication. */
891 1 : resp = wpabuf_alloc(sizeof(struct eap_hdr));
892 1 : if (resp) {
893 1 : rhdr = wpabuf_put(resp, sizeof(*rhdr));
894 1 : rhdr->code = EAP_CODE_SUCCESS;
895 1 : rhdr->identifier = hdr->identifier;
896 1 : rhdr->length =
897 1 : host_to_be16(sizeof(*rhdr));
898 : }
899 : } else {
900 : /* No EAP-Success expected for Phase 1 (outer,
901 : * unencrypted auth), so force EAP state
902 : * machine to SUCCESS state. */
903 1 : sm->peap_done = TRUE;
904 : }
905 : } else {
906 : /* FIX: ? */
907 : }
908 2 : break;
909 : case EAP_CODE_FAILURE:
910 2 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
911 2 : ret->decision = DECISION_FAIL;
912 2 : ret->methodState = METHOD_MAY_CONT;
913 2 : ret->allowNotifications = FALSE;
914 : /* Reply with EAP-Failure within the TLS channel to complete
915 : * failure reporting. */
916 2 : resp = wpabuf_alloc(sizeof(struct eap_hdr));
917 2 : if (resp) {
918 2 : rhdr = wpabuf_put(resp, sizeof(*rhdr));
919 2 : rhdr->code = EAP_CODE_FAILURE;
920 2 : rhdr->identifier = hdr->identifier;
921 2 : rhdr->length = host_to_be16(sizeof(*rhdr));
922 : }
923 2 : break;
924 : default:
925 0 : wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
926 0 : "Phase 2 EAP header", hdr->code);
927 0 : break;
928 : }
929 :
930 226 : wpabuf_free(in_decrypted);
931 :
932 226 : if (resp) {
933 221 : int skip_change2 = 0;
934 : struct wpabuf *rmsg, buf;
935 :
936 221 : wpa_hexdump_buf_key(MSG_DEBUG,
937 : "EAP-PEAP: Encrypting Phase 2 data", resp);
938 : /* PEAP version changes */
939 439 : if (wpabuf_len(resp) >= 5 &&
940 436 : wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
941 218 : eap_get_type(resp) == EAP_TYPE_TLV)
942 17 : skip_change2 = 1;
943 221 : rmsg = resp;
944 221 : if (data->peap_version == 0 && !skip_change2) {
945 72 : wpabuf_set(&buf, wpabuf_head_u8(resp) +
946 : sizeof(struct eap_hdr),
947 72 : wpabuf_len(resp) - sizeof(struct eap_hdr));
948 72 : rmsg = &buf;
949 : }
950 :
951 221 : if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
952 221 : data->peap_version, req->identifier,
953 : rmsg, out_data)) {
954 1 : wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
955 : "a Phase 2 frame");
956 : }
957 221 : wpabuf_free(resp);
958 : }
959 :
960 226 : return 0;
961 : }
962 :
963 :
964 557 : static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
965 : struct eap_method_ret *ret,
966 : const struct wpabuf *reqData)
967 : {
968 : const struct eap_hdr *req;
969 : size_t left;
970 : int res;
971 : u8 flags, id;
972 : struct wpabuf *resp;
973 : const u8 *pos;
974 557 : struct eap_peap_data *data = priv;
975 : struct wpabuf msg;
976 :
977 557 : pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
978 : reqData, &left, &flags);
979 557 : if (pos == NULL)
980 0 : return NULL;
981 557 : req = wpabuf_head(reqData);
982 557 : id = req->identifier;
983 :
984 557 : if (flags & EAP_TLS_FLAGS_START) {
985 75 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
986 : "ver=%d)", flags & EAP_TLS_VERSION_MASK,
987 : data->peap_version);
988 75 : if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version)
989 2 : data->peap_version = flags & EAP_TLS_VERSION_MASK;
990 110 : if (data->force_peap_version >= 0 &&
991 35 : data->force_peap_version != data->peap_version) {
992 1 : wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
993 : "forced PEAP version %d",
994 : data->force_peap_version);
995 1 : ret->methodState = METHOD_DONE;
996 1 : ret->decision = DECISION_FAIL;
997 1 : ret->allowNotifications = FALSE;
998 1 : return NULL;
999 : }
1000 74 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
1001 : data->peap_version);
1002 74 : left = 0; /* make sure that this frame is empty, even though it
1003 : * should always be, anyway */
1004 : }
1005 :
1006 556 : wpabuf_set(&msg, pos, left);
1007 :
1008 556 : resp = NULL;
1009 824 : if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1010 268 : !data->resuming) {
1011 268 : res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
1012 : } else {
1013 288 : if (sm->waiting_ext_cert_check && data->pending_resp) {
1014 2 : struct eap_peer_config *config = eap_get_config(sm);
1015 :
1016 2 : if (config->pending_ext_cert_check ==
1017 : EXT_CERT_CHECK_GOOD) {
1018 1 : wpa_printf(MSG_DEBUG,
1019 : "EAP-PEAP: External certificate check succeeded - continue handshake");
1020 1 : resp = data->pending_resp;
1021 1 : data->pending_resp = NULL;
1022 1 : sm->waiting_ext_cert_check = 0;
1023 1 : return resp;
1024 : }
1025 :
1026 1 : if (config->pending_ext_cert_check ==
1027 : EXT_CERT_CHECK_BAD) {
1028 1 : wpa_printf(MSG_DEBUG,
1029 : "EAP-PEAP: External certificate check failed - force authentication failure");
1030 1 : ret->methodState = METHOD_DONE;
1031 1 : ret->decision = DECISION_FAIL;
1032 1 : sm->waiting_ext_cert_check = 0;
1033 1 : return NULL;
1034 : }
1035 :
1036 0 : wpa_printf(MSG_DEBUG,
1037 : "EAP-PEAP: Continuing to wait external server certificate validation");
1038 0 : return NULL;
1039 : }
1040 :
1041 286 : res = eap_peer_tls_process_helper(sm, &data->ssl,
1042 : EAP_TYPE_PEAP,
1043 : data->peap_version, id, &msg,
1044 : &resp);
1045 :
1046 286 : if (res < 0) {
1047 1 : wpa_printf(MSG_DEBUG,
1048 : "EAP-PEAP: TLS processing failed");
1049 1 : ret->methodState = METHOD_DONE;
1050 1 : ret->decision = DECISION_FAIL;
1051 1 : return resp;
1052 : }
1053 :
1054 :
1055 285 : if (sm->waiting_ext_cert_check) {
1056 2 : wpa_printf(MSG_DEBUG,
1057 : "EAP-PEAP: Waiting external server certificate validation");
1058 2 : wpabuf_free(data->pending_resp);
1059 2 : data->pending_resp = resp;
1060 2 : return NULL;
1061 : }
1062 :
1063 283 : if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
1064 : char *label;
1065 71 : wpa_printf(MSG_DEBUG,
1066 : "EAP-PEAP: TLS done, proceed to Phase 2");
1067 71 : eap_peap_free_key(data);
1068 : /* draft-josefsson-ppext-eap-tls-eap-05.txt
1069 : * specifies that PEAPv1 would use "client PEAP
1070 : * encryption" as the label. However, most existing
1071 : * PEAPv1 implementations seem to be using the old
1072 : * label, "client EAP encryption", instead. Use the old
1073 : * label by default, but allow it to be configured with
1074 : * phase1 parameter peaplabel=1. */
1075 71 : if (data->force_new_label)
1076 4 : label = "client PEAP encryption";
1077 : else
1078 67 : label = "client EAP encryption";
1079 71 : wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
1080 : "key derivation", label);
1081 71 : data->key_data =
1082 71 : eap_peer_tls_derive_key(sm, &data->ssl, label,
1083 : EAP_TLS_KEY_LEN);
1084 71 : if (data->key_data) {
1085 70 : wpa_hexdump_key(MSG_DEBUG,
1086 : "EAP-PEAP: Derived key",
1087 70 : data->key_data,
1088 : EAP_TLS_KEY_LEN);
1089 : } else {
1090 1 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
1091 : "derive key");
1092 : }
1093 :
1094 71 : os_free(data->session_id);
1095 71 : data->session_id =
1096 71 : eap_peer_tls_derive_session_id(sm, &data->ssl,
1097 : EAP_TYPE_PEAP,
1098 : &data->id_len);
1099 71 : if (data->session_id) {
1100 140 : wpa_hexdump(MSG_DEBUG,
1101 : "EAP-PEAP: Derived Session-Id",
1102 70 : data->session_id, data->id_len);
1103 : } else {
1104 1 : wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
1105 : "derive Session-Id");
1106 : }
1107 :
1108 71 : if (sm->workaround && data->resuming) {
1109 : /*
1110 : * At least few RADIUS servers (Aegis v1.1.6;
1111 : * but not v1.1.4; and Cisco ACS) seem to be
1112 : * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
1113 : * ACS) session resumption with outer
1114 : * EAP-Success. This does not seem to follow
1115 : * draft-josefsson-pppext-eap-tls-eap-05.txt
1116 : * section 4.2, so only allow this if EAP
1117 : * workarounds are enabled.
1118 : */
1119 10 : wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
1120 : "allow outer EAP-Success to "
1121 : "terminate PEAP resumption");
1122 10 : ret->decision = DECISION_COND_SUCC;
1123 10 : data->phase2_success = 1;
1124 : }
1125 :
1126 71 : data->resuming = 0;
1127 : }
1128 :
1129 283 : if (res == 2) {
1130 : /*
1131 : * Application data included in the handshake message.
1132 : */
1133 0 : wpabuf_free(data->pending_phase2_req);
1134 0 : data->pending_phase2_req = resp;
1135 0 : resp = NULL;
1136 0 : res = eap_peap_decrypt(sm, data, ret, req, &msg,
1137 : &resp);
1138 : }
1139 : }
1140 :
1141 551 : if (ret->methodState == METHOD_DONE) {
1142 60 : ret->allowNotifications = FALSE;
1143 : }
1144 :
1145 551 : if (res == 1) {
1146 175 : wpabuf_free(resp);
1147 175 : return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
1148 : data->peap_version);
1149 : }
1150 :
1151 376 : return resp;
1152 : }
1153 :
1154 :
1155 27 : static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
1156 : {
1157 27 : struct eap_peap_data *data = priv;
1158 54 : return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1159 27 : data->phase2_success;
1160 : }
1161 :
1162 :
1163 14 : static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
1164 : {
1165 14 : struct eap_peap_data *data = priv;
1166 14 : wpabuf_free(data->pending_phase2_req);
1167 14 : data->pending_phase2_req = NULL;
1168 14 : wpabuf_free(data->pending_resp);
1169 14 : data->pending_resp = NULL;
1170 14 : data->crypto_binding_used = 0;
1171 14 : }
1172 :
1173 :
1174 11 : static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
1175 : {
1176 11 : struct eap_peap_data *data = priv;
1177 11 : eap_peap_free_key(data);
1178 11 : os_free(data->session_id);
1179 11 : data->session_id = NULL;
1180 11 : if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
1181 0 : os_free(data);
1182 0 : return NULL;
1183 : }
1184 22 : if (data->phase2_priv && data->phase2_method &&
1185 11 : data->phase2_method->init_for_reauth)
1186 1 : data->phase2_method->init_for_reauth(sm, data->phase2_priv);
1187 11 : data->phase2_success = 0;
1188 11 : data->phase2_eap_success = 0;
1189 11 : data->phase2_eap_started = 0;
1190 11 : data->resuming = 1;
1191 11 : data->reauth = 1;
1192 11 : sm->peap_done = FALSE;
1193 11 : return priv;
1194 : }
1195 :
1196 :
1197 424 : static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
1198 : size_t buflen, int verbose)
1199 : {
1200 424 : struct eap_peap_data *data = priv;
1201 : int len, ret;
1202 :
1203 424 : len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
1204 424 : if (data->phase2_method) {
1205 257 : ret = os_snprintf(buf + len, buflen - len,
1206 : "EAP-PEAPv%d Phase2 method=%s\n",
1207 : data->peap_version,
1208 257 : data->phase2_method->name);
1209 257 : if (os_snprintf_error(buflen - len, ret))
1210 0 : return len;
1211 257 : len += ret;
1212 : }
1213 424 : return len;
1214 : }
1215 :
1216 :
1217 557 : static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
1218 : {
1219 557 : struct eap_peap_data *data = priv;
1220 557 : return data->key_data != NULL && data->phase2_success;
1221 : }
1222 :
1223 :
1224 145 : static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
1225 : {
1226 145 : struct eap_peap_data *data = priv;
1227 : u8 *key;
1228 :
1229 145 : if (data->key_data == NULL || !data->phase2_success)
1230 0 : return NULL;
1231 :
1232 145 : key = os_malloc(EAP_TLS_KEY_LEN);
1233 145 : if (key == NULL)
1234 1 : return NULL;
1235 :
1236 144 : *len = EAP_TLS_KEY_LEN;
1237 :
1238 144 : if (data->crypto_binding_used) {
1239 : u8 csk[128];
1240 : /*
1241 : * Note: It looks like Microsoft implementation requires null
1242 : * termination for this label while the one used for deriving
1243 : * IPMK|CMK did not use null termination.
1244 : */
1245 13 : if (peap_prfplus(data->peap_version, data->ipmk, 40,
1246 : "Session Key Generating Function",
1247 : (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
1248 1 : os_free(key);
1249 1 : return NULL;
1250 : }
1251 12 : wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
1252 12 : os_memcpy(key, csk, EAP_TLS_KEY_LEN);
1253 12 : wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1254 : key, EAP_TLS_KEY_LEN);
1255 : } else
1256 131 : os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
1257 :
1258 143 : return key;
1259 : }
1260 :
1261 :
1262 145 : static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1263 : {
1264 145 : struct eap_peap_data *data = priv;
1265 : u8 *id;
1266 :
1267 145 : if (data->session_id == NULL || !data->phase2_success)
1268 0 : return NULL;
1269 :
1270 145 : id = os_malloc(data->id_len);
1271 145 : if (id == NULL)
1272 1 : return NULL;
1273 :
1274 144 : *len = data->id_len;
1275 144 : os_memcpy(id, data->session_id, data->id_len);
1276 :
1277 144 : return id;
1278 : }
1279 :
1280 :
1281 49 : int eap_peer_peap_register(void)
1282 : {
1283 : struct eap_method *eap;
1284 :
1285 49 : eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1286 : EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
1287 49 : if (eap == NULL)
1288 0 : return -1;
1289 :
1290 49 : eap->init = eap_peap_init;
1291 49 : eap->deinit = eap_peap_deinit;
1292 49 : eap->process = eap_peap_process;
1293 49 : eap->isKeyAvailable = eap_peap_isKeyAvailable;
1294 49 : eap->getKey = eap_peap_getKey;
1295 49 : eap->get_status = eap_peap_get_status;
1296 49 : eap->has_reauth_data = eap_peap_has_reauth_data;
1297 49 : eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
1298 49 : eap->init_for_reauth = eap_peap_init_for_reauth;
1299 49 : eap->getSessionId = eap_peap_get_session_id;
1300 :
1301 49 : return eap_peer_method_register(eap);
1302 : }
|