Home | History | Annotate | Line # | Download | only in pppd
      1 /*
      2  * Copyright (c) 2011 Rustam Kovhaev. All rights reserved.
      3  * Copyright (c) 2021 Eivind Nss. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  *
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in
     14  *    the documentation and/or other materials provided with the
     15  *    distribution.
     16  *
     17  * 3. The name(s) of the authors of this software must not be used to
     18  *    endorse or promote products derived from this software without
     19  *    prior written permission.
     20  *
     21  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
     22  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     23  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
     24  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     25  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     26  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     27  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     28  *
     29  * NOTES:
     30  *
     31  * PEAP has 2 phases,
     32  * 1 - Outer EAP, where TLS session gets established
     33  * 2 - Inner EAP, where inside TLS session with EAP MSCHAPV2 auth, or any other auth
     34  *
     35  * And so protocols encapsulation looks like this:
     36  * Outer EAP -> TLS -> Inner EAP -> MSCHAPV2
     37  * PEAP can compress an inner EAP packet prior to encapsulating it within
     38  * the Data field of a PEAP packet by removing its Code, Identifier,
     39  * and Length fields, and Microsoft PEAP server/client always does that
     40  *
     41  * Current implementation does not support:
     42  * a) Fast reconnect
     43  * b) Inner EAP fragmentation
     44  * c) Any other auth other than MSCHAPV2
     45  *
     46  * For details on the PEAP protocol, look to Microsoft:
     47  *    https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-peap
     48  */
     49 
     50 #ifdef HAVE_CONFIG_H
     51 #include "config.h"
     52 #endif
     53 
     54 #include <stdio.h>
     55 #include <stdlib.h>
     56 #include <string.h>
     57 #include <errno.h>
     58 #include <openssl/opensslv.h>
     59 #include <openssl/ssl.h>
     60 #include <openssl/hmac.h>
     61 #include <openssl/rand.h>
     62 #include <openssl/err.h>
     63 
     64 #include "pppd-private.h"
     65 #include "eap.h"
     66 #include "tls.h"
     67 #include "chap.h"
     68 #include "chap_ms.h"
     69 #include "mppe.h"
     70 #include "peap.h"
     71 
     72 #ifdef UNIT_TEST
     73 #define novm(x)
     74 #endif
     75 
     76 struct peap_state {
     77 	SSL_CTX *ctx;
     78 	SSL *ssl;
     79 	BIO *in_bio;
     80 	BIO *out_bio;
     81 
     82 	int phase;
     83 	int written, read;
     84 	u_char *in_buf;
     85 	u_char *out_buf;
     86 
     87 	u_char ipmk[PEAP_TLV_IPMK_LEN];
     88 	u_char tk[PEAP_TLV_TK_LEN];
     89 	u_char nonce[PEAP_TLV_NONCE_LEN];
     90 	struct tls_info *info;
     91 #ifdef PPP_WITH_CHAPMS
     92 	struct chap_digest_type *chap;
     93 #endif
     94 };
     95 
     96 /*
     97  * K = Key, S = Seed, LEN = output length
     98  * PRF+(K, S, LEN) = T1 | T2 | ... |Tn
     99  * Where:
    100  * T1 = HMAC-SHA1 (K, S | 0x01 | 0x00 | 0x00)
    101  * T2 = HMAC-SHA1 (K, T1 | S | 0x02 | 0x00 | 0x00)
    102  * ...
    103  * Tn = HMAC-SHA1 (K, Tn-1 | S | n | 0x00 | 0x00)
    104  * As shown, PRF+ is computed in iterations. The number of iterations (n)
    105  * depends on the output length (LEN).
    106  */
    107 static void peap_prfplus(u_char *seed, size_t seed_len, u_char *key, size_t key_len, u_char *out_buf, size_t pfr_len)
    108 {
    109 	int pos;
    110 	u_char *buf, *hash;
    111 	size_t max_iter, i, j, k;
    112 	u_int len;
    113 
    114 	max_iter = (pfr_len + SHA_DIGEST_LENGTH - 1) / SHA_DIGEST_LENGTH;
    115 	buf = malloc(seed_len + max_iter * SHA_DIGEST_LENGTH);
    116 	if (!buf)
    117 		novm("pfr buffer");
    118 	hash = malloc(pfr_len + SHA_DIGEST_LENGTH);
    119 	if (!hash)
    120 		novm("hash buffer");
    121 
    122 	for (i = 0; i < max_iter; i++) {
    123 		j = 0;
    124 		k = 0;
    125 
    126 		if (i > 0)
    127 			j = SHA_DIGEST_LENGTH;
    128 		for (k = 0; k < seed_len; k++)
    129 			buf[j + k] = seed[k];
    130 		pos = j + k;
    131 		buf[pos] = i + 1;
    132 		pos++;
    133 		buf[pos] = 0x00;
    134 		pos++;
    135 		buf[pos] = 0x00;
    136 		pos++;
    137 		if (!HMAC(EVP_sha1(), key, key_len, buf, pos, (hash + i * SHA_DIGEST_LENGTH), &len))
    138 			fatal("HMAC() failed");
    139 		for (j = 0; j < SHA_DIGEST_LENGTH; j++)
    140 			buf[j] = hash[i * SHA_DIGEST_LENGTH + j];
    141 	}
    142 	BCOPY(hash, out_buf, pfr_len);
    143 	free(hash);
    144 	free(buf);
    145 }
    146 
    147 static void generate_cmk(u_char *ipmk, u_char *tempkey, u_char *nonce, u_char *tlv_response_out, int client)
    148 {
    149 	const char *label = PEAP_TLV_IPMK_SEED_LABEL;
    150 	u_char data_tlv[PEAP_TLV_DATA_LEN] = {0};
    151 	u_char isk[PEAP_TLV_ISK_LEN] = {0};
    152 	u_char ipmkseed[PEAP_TLV_IPMKSEED_LEN] = {0};
    153 	u_char cmk[PEAP_TLV_CMK_LEN] = {0};
    154 	u_char buf[PEAP_TLV_CMK_LEN + PEAP_TLV_IPMK_LEN] = {0};
    155 	u_char compound_mac[PEAP_TLV_COMP_MAC_LEN] = {0};
    156 	u_int len;
    157 
    158 	/* format outgoing CB TLV response packet */
    159 	data_tlv[1] = PEAP_TLV_TYPE;
    160 	data_tlv[3] = PEAP_TLV_LENGTH_FIELD;
    161 	if (client)
    162 		data_tlv[7] = PEAP_TLV_SUBTYPE_RESPONSE;
    163 	else
    164 		data_tlv[7] = PEAP_TLV_SUBTYPE_REQUEST;
    165 	BCOPY(nonce, (data_tlv + PEAP_TLV_HEADERLEN), PEAP_TLV_NONCE_LEN);
    166 	data_tlv[60] = EAPT_PEAP;
    167 
    168 #ifdef PPP_WITH_MPPE
    169 	mppe_get_send_key(isk, MPPE_MAX_KEY_LEN);
    170 	mppe_get_recv_key(isk + MPPE_MAX_KEY_LEN, MPPE_MAX_KEY_LEN);
    171 #endif
    172 
    173 	BCOPY(label, ipmkseed, strlen(label));
    174 	BCOPY(isk, ipmkseed + strlen(label), PEAP_TLV_ISK_LEN);
    175 	peap_prfplus(ipmkseed, PEAP_TLV_IPMKSEED_LEN,
    176 			tempkey, PEAP_TLV_TEMPKEY_LEN, buf, PEAP_TLV_CMK_LEN + PEAP_TLV_IPMK_LEN);
    177 
    178 	BCOPY(buf, ipmk, PEAP_TLV_IPMK_LEN);
    179 	BCOPY(buf + PEAP_TLV_IPMK_LEN, cmk, PEAP_TLV_CMK_LEN);
    180 	if (!HMAC(EVP_sha1(), cmk, PEAP_TLV_CMK_LEN, data_tlv, PEAP_TLV_DATA_LEN, compound_mac, &len))
    181 		fatal("HMAC() failed");
    182 	BCOPY(compound_mac, data_tlv + PEAP_TLV_HEADERLEN + PEAP_TLV_NONCE_LEN, PEAP_TLV_COMP_MAC_LEN);
    183 	/* do not copy last byte to response packet */
    184 	BCOPY(data_tlv, tlv_response_out, PEAP_TLV_DATA_LEN - 1);
    185 }
    186 
    187 static void verify_compound_mac(struct peap_state *psm, u_char *in_buf)
    188 {
    189 	u_char nonce[PEAP_TLV_NONCE_LEN] = {0};
    190 	u_char out_buf[PEAP_TLV_LEN] = {0};
    191 
    192 	BCOPY(in_buf, nonce, PEAP_TLV_NONCE_LEN);
    193 	generate_cmk(psm->ipmk, psm->tk, nonce, out_buf, 0);
    194 	if (memcmp((in_buf + PEAP_TLV_NONCE_LEN), (out_buf + PEAP_TLV_HEADERLEN + PEAP_TLV_NONCE_LEN), PEAP_TLV_CMK_LEN))
    195 			fatal("server's CMK does not match client's CMK, potential MiTM");
    196 }
    197 
    198 #ifdef PPP_WITH_MPPE
    199 #define PEAP_MPPE_KEY_LEN 32
    200 
    201 static void generate_mppe_keys(u_char *ipmk, int client)
    202 {
    203 	const char *label = PEAP_TLV_CSK_SEED_LABEL;
    204 	u_char csk[PEAP_TLV_CSK_LEN] = {0};
    205 	size_t len;
    206 
    207 	dbglog("PEAP CB: generate mppe keys");
    208 	len = strlen(label);
    209 	len++; /* CSK requires NULL byte in seed */
    210 	peap_prfplus((u_char *)label, len, ipmk, PEAP_TLV_IPMK_LEN, csk, PEAP_TLV_CSK_LEN);
    211 
    212 	/*
    213 	 * The first 64 bytes of the CSK are split into two MPPE keys, as follows.
    214 	 *
    215 	 * +-----------------------+------------------------+
    216 	 * | First 32 bytes of CSK | Second 32 bytes of CSK |
    217 	 * +-----------------------+------------------------+
    218 	 * | MS-MPPE-Send-Key      | MS-MPPE-Recv-Key       |
    219 	 * +-----------------------+------------------------+
    220 	 */
    221 	if (client) {
    222 		mppe_set_keys(csk, csk + PEAP_MPPE_KEY_LEN, PEAP_MPPE_KEY_LEN);
    223 	} else {
    224 		mppe_set_keys(csk + PEAP_MPPE_KEY_LEN, csk, PEAP_MPPE_KEY_LEN);
    225 	}
    226 }
    227 
    228 #endif
    229 
    230 #ifndef UNIT_TEST
    231 
    232 static void peap_ack(eap_state *esp, u_char id)
    233 {
    234 	u_char *outp;
    235 
    236 	outp = outpacket_buf;
    237 	MAKEHEADER(outp, PPP_EAP);
    238 	PUTCHAR(EAP_RESPONSE, outp);
    239 	PUTCHAR(id, outp);
    240 	esp->es_client.ea_id = id;
    241 	PUTSHORT(PEAP_HEADERLEN, outp);
    242 	PUTCHAR(EAPT_PEAP, outp);
    243 	PUTCHAR(PEAP_FLAGS_ACK, outp);
    244 	output(esp->es_unit, outpacket_buf, PPP_HDRLEN + PEAP_HEADERLEN);
    245 }
    246 
    247 static void peap_response(eap_state *esp, u_char id, u_char *buf, int len)
    248 {
    249 	struct peap_state *psm = esp->ea_peap;
    250 	u_char *outp;
    251 	int peap_len;
    252 
    253 	outp = outpacket_buf;
    254 	MAKEHEADER(outp, PPP_EAP);
    255 	PUTCHAR(EAP_RESPONSE, outp);
    256 	PUTCHAR(id, outp);
    257 	esp->es_client.ea_id = id;
    258 
    259 	if (psm->phase == PEAP_PHASE_1)
    260 		peap_len = PEAP_HEADERLEN + PEAP_FRAGMENT_LENGTH_FIELD + len;
    261 	else
    262 		peap_len = PEAP_HEADERLEN + len;
    263 
    264 	PUTSHORT(peap_len, outp);
    265 	PUTCHAR(EAPT_PEAP, outp);
    266 
    267 	if (psm->phase == PEAP_PHASE_1) {
    268 		PUTCHAR(PEAP_L_FLAG_SET, outp);
    269 		PUTLONG(len, outp);
    270 	} else
    271 		PUTCHAR(PEAP_NO_FLAGS, outp);
    272 
    273 	BCOPY(buf, outp, len);
    274 	output(esp->es_unit, outpacket_buf, PPP_HDRLEN + peap_len);
    275 }
    276 
    277 static void peap_do_inner_eap(u_char *in_buf, int in_len, eap_state *esp, int id,
    278 		u_char *out_buf, int *out_len)
    279 {
    280 	struct peap_state *psm = esp->ea_peap;
    281 	int used = 0;
    282 	int typenum;
    283 	int secret_len;
    284 	char secret[MAXSECRETLEN + 1];
    285 	char rhostname[MAXWORDLEN];
    286 	u_char *outp = out_buf;
    287 
    288 	dbglog("PEAP: EAP (in): %.*B", in_len, in_buf);
    289 
    290 	if (*(in_buf + EAP_HEADERLEN) == PEAP_CAPABILITIES_TYPE &&
    291 			in_len  == (EAP_HEADERLEN + PEAP_CAPABILITIES_LEN)) {
    292 		/* use original packet as template for response */
    293 		BCOPY(in_buf, outp, EAP_HEADERLEN + PEAP_CAPABILITIES_LEN);
    294 		PUTCHAR(EAP_RESPONSE, outp);
    295 		PUTCHAR(id, outp);
    296 		/* change last byte to 0 to disable fragmentation */
    297 		*(outp + PEAP_CAPABILITIES_LEN + 1) = 0x00;
    298 		used = EAP_HEADERLEN + PEAP_CAPABILITIES_LEN;
    299 		goto done;
    300 	}
    301 	if (*(in_buf + EAP_HEADERLEN + PEAP_TLV_HEADERLEN) == PEAP_TLV_TYPE &&
    302 			in_len == PEAP_TLV_LEN) {
    303 		/* PEAP TLV message, do cryptobinding */
    304 		SSL_export_keying_material(psm->ssl, psm->tk, PEAP_TLV_TK_LEN,
    305 				PEAP_TLV_TK_SEED_LABEL, strlen(PEAP_TLV_TK_SEED_LABEL), NULL, 0, 0);
    306 		/* verify server's CMK */
    307 		verify_compound_mac(psm, in_buf + EAP_HEADERLEN + PEAP_TLV_RESULT_LEN + PEAP_TLV_HEADERLEN);
    308 		/* generate client's CMK with new nonce */
    309 		PUTCHAR(EAP_RESPONSE, outp);
    310 		PUTCHAR(id, outp);
    311 		PUTSHORT(PEAP_TLV_LEN, outp);
    312 		BCOPY(in_buf + EAP_HEADERLEN, outp, PEAP_TLV_RESULT_LEN);
    313 		outp = outp + PEAP_TLV_RESULT_LEN;
    314 		RAND_bytes(psm->nonce, PEAP_TLV_NONCE_LEN);
    315 		generate_cmk(psm->ipmk, psm->tk, psm->nonce, outp, 1);
    316 #ifdef PPP_WITH_MPPE
    317 		/* set mppe keys */
    318 		generate_mppe_keys(psm->ipmk, 1);
    319 #endif
    320 		used = PEAP_TLV_LEN;
    321 		goto done;
    322 	}
    323 
    324 	GETCHAR(typenum, in_buf);
    325 	in_len--;
    326 
    327 	switch (typenum) {
    328 	case EAPT_IDENTITY:
    329 		/* Respond with our identity to the peer */
    330 		PUTCHAR(EAPT_IDENTITY, outp);
    331 		BCOPY(esp->es_client.ea_name, outp,
    332 				esp->es_client.ea_namelen);
    333 		used += (esp->es_client.ea_namelen + 1);
    334 		break;
    335 
    336 	case EAPT_TLS:
    337 		/* Send NAK to EAP_TLS request */
    338 		PUTCHAR(EAPT_NAK, outp);
    339 		PUTCHAR(EAPT_MSCHAPV2, outp);
    340 		used += 2;
    341 		break;
    342 
    343 #if PPP_WITH_CHAPMS
    344 	case EAPT_MSCHAPV2: {
    345 
    346 		// Must have at least 4 more bytes to process CHAP header
    347 		if (in_len < 4) {
    348 			error("PEAP: received invalid MSCHAPv2 packet, too short");
    349 			break;
    350 		}
    351 
    352 		u_char opcode;
    353 		GETCHAR(opcode, in_buf);
    354 
    355 		u_char chap_id;
    356 		GETCHAR(chap_id, in_buf);
    357 
    358 		short mssize;
    359 		GETSHORT(mssize, in_buf);
    360 
    361 		// Validate the CHAP packet (including header)
    362 		if (in_len != mssize) {
    363 			error("PEAP: received invalid MSCHAPv2 packet, invalid length");
    364 			break;
    365 		}
    366 		in_len -= 4;
    367 
    368 		switch (opcode) {
    369 		case CHAP_CHALLENGE: {
    370 
    371 			u_char *challenge = in_buf;	// VLEN + VALUE
    372 			u_char vsize;
    373 
    374 			GETCHAR(vsize, in_buf);
    375 			in_len -= 1;
    376 
    377 			if (vsize != MS_CHAP2_PEER_CHAL_LEN || in_len < MS_CHAP2_PEER_CHAL_LEN) {
    378 				error("PEAP: received invalid MSCHAPv2 packet, invalid value-length: %d", vsize);
    379 				goto done;
    380 			}
    381 
    382 			INCPTR(MS_CHAP2_PEER_CHAL_LEN, in_buf);
    383 			in_len -= MS_CHAP2_PEER_CHAL_LEN;
    384 
    385 			// Copy the provided remote host name
    386 			rhostname[0] = '\0';
    387 			if (in_len > 0) {
    388 				if (in_len >= sizeof(rhostname)) {
    389 					dbglog("PEAP: trimming really long peer name down");
    390 					in_len = sizeof(rhostname) - 1;
    391 				}
    392 				BCOPY(in_buf, rhostname, in_len);
    393 				rhostname[in_len] = '\0';
    394 			}
    395 
    396 			// In case the remote doesn't give us his name, or user explictly specified remotename is config
    397 			if (explicit_remote || (remote_name[0] != '\0' && in_len == 0))
    398 				strlcpy(rhostname, remote_name, sizeof(rhostname));
    399 
    400 			// Get the scrert for authenticating ourselves with the specified host
    401 			if (get_secret(esp->es_unit, esp->es_client.ea_name,
    402 						rhostname, secret, &secret_len, 0)) {
    403 
    404 				u_char response[MS_CHAP2_RESPONSE_LEN+1];
    405 				u_char user_len = esp->es_client.ea_namelen;
    406 				char *user = esp->es_client.ea_name;
    407 
    408 				psm->chap->make_response(response, chap_id, user,
    409 						challenge, secret, secret_len, NULL);
    410 
    411 				PUTCHAR(EAPT_MSCHAPV2, outp);
    412 				PUTCHAR(CHAP_RESPONSE, outp);
    413 				PUTCHAR(chap_id, outp);
    414 				PUTCHAR(0, outp);
    415 				PUTCHAR(5 + user_len + MS_CHAP2_RESPONSE_LEN, outp);
    416 				BCOPY(response, outp, MS_CHAP2_RESPONSE_LEN+1);	// VLEN + VALUE
    417 				INCPTR(MS_CHAP2_RESPONSE_LEN+1, outp);
    418 				BCOPY(user, outp, user_len);
    419 				used = 5 + user_len + MS_CHAP2_RESPONSE_LEN + 1;
    420 
    421 			} else {
    422 				dbglog("PEAP: no CHAP secret for auth to %q", rhostname);
    423 				PUTCHAR(EAPT_NAK, outp);
    424 				++used;
    425 			}
    426 			break;
    427 		}
    428 		case CHAP_SUCCESS: {
    429 
    430 			u_char status = CHAP_FAILURE;
    431 			if (psm->chap->check_success(chap_id, in_buf, in_len)) {
    432 				info("Chap authentication succeeded! %.*v", in_len, in_buf);
    433 				status = CHAP_SUCCESS;
    434 			}
    435 
    436 			PUTCHAR(EAPT_MSCHAPV2, outp);
    437 			PUTCHAR(status, outp);
    438 			used += 2;
    439 			break;
    440 		}
    441 		case CHAP_FAILURE: {
    442 
    443 			u_char status = CHAP_FAILURE;
    444 			psm->chap->handle_failure(in_buf, in_len);
    445 			PUTCHAR(EAPT_MSCHAPV2, outp);
    446 			PUTCHAR(status, outp);
    447 			used += 2;
    448 			break;
    449 		}
    450 		default:
    451 			break;
    452 		}
    453 		break;
    454 	}	// EAPT_MSCHAPv2
    455 #endif
    456 	default:
    457 
    458 		/* send compressed EAP NAK for any unknown packet */
    459 		PUTCHAR(EAPT_NAK, outp);
    460 		++used;
    461 	}
    462 
    463 done:
    464 
    465 	dbglog("PEAP: EAP (out): %.*B", used, psm->out_buf);
    466 	*out_len = used;
    467 }
    468 
    469 int peap_init(struct peap_state **ctx, const char *rhostname)
    470 {
    471 	const SSL_METHOD *method;
    472 
    473 	if (!ctx)
    474 		return -1;
    475 
    476 	tls_init();
    477 
    478 	struct peap_state *psm = malloc(sizeof(*psm));
    479 	if (!psm)
    480 		novm("peap psm struct");
    481 	psm->in_buf = malloc(TLS_RECORD_MAX_SIZE);
    482 	if (!psm->in_buf)
    483 		novm("peap tls buffer");
    484 	psm->out_buf = malloc(TLS_RECORD_MAX_SIZE);
    485 	if (!psm->out_buf)
    486 		novm("peap tls buffer");
    487 	method = tls_method();
    488 	if (!method)
    489 		novm("TLS_method() failed");
    490 	psm->ctx = SSL_CTX_new(method);
    491 	if (!psm->ctx)
    492 		novm("SSL_CTX_new() failed");
    493 
    494 	/* Configure the default options */
    495 	tls_set_opts(psm->ctx);
    496 
    497 	/* Configure the max TLS version */
    498 	tls_set_version(psm->ctx, max_tls_version);
    499 
    500 	/* Configure the peer certificate callback */
    501 	tls_set_verify(psm->ctx, 5);
    502 
    503 	/* Configure CA locations */
    504 	if (tls_set_ca(psm->ctx, ca_path, cacert_file)) {
    505 		fatal("Could not set CA verify locations");
    506 	}
    507 
    508 	/* Configure CRL check (if any) */
    509 	if (tls_set_crl(psm->ctx, crl_dir, crl_file)) {
    510 		fatal("Could not set CRL verify locations");
    511 	}
    512 
    513 	psm->out_bio = BIO_new(BIO_s_mem());
    514 	psm->in_bio = BIO_new(BIO_s_mem());
    515 	BIO_set_mem_eof_return(psm->out_bio, -1);
    516 	BIO_set_mem_eof_return(psm->in_bio, -1);
    517 	psm->ssl = SSL_new(psm->ctx);
    518 	SSL_set_bio(psm->ssl, psm->in_bio, psm->out_bio);
    519 	SSL_set_connect_state(psm->ssl);
    520 	psm->phase = PEAP_PHASE_1;
    521 	tls_set_verify_info(psm->ssl, explicit_remote ? rhostname : NULL, NULL, 1, &psm->info);
    522 	psm->chap = chap_find_digest(CHAP_MICROSOFT_V2);
    523 	*ctx = psm;
    524 	return 0;
    525 }
    526 
    527 void peap_finish(struct peap_state **psm) {
    528 
    529 	if (psm && *psm) {
    530 		struct peap_state *tmp = *psm;
    531 
    532 		if (tmp->ssl)
    533 			SSL_free(tmp->ssl);
    534 
    535 		if (tmp->ctx)
    536 			SSL_CTX_free(tmp->ctx);
    537 
    538 		if (tmp->info)
    539 			tls_free_verify_info(&tmp->info);
    540 
    541 		// NOTE: BIO and memory is freed as a part of SSL_free()
    542 
    543 		free(*psm);
    544 		*psm = NULL;
    545 	}
    546 }
    547 
    548 int peap_process(eap_state *esp, u_char id, u_char *inp, int len)
    549 {
    550 	int ret;
    551 	int out_len;
    552 
    553 	struct peap_state *psm = esp->ea_peap;
    554 
    555 	if (esp->es_client.ea_id == id) {
    556 		info("PEAP: retransmits are not supported..");
    557 		return -1;
    558 	}
    559 
    560 	switch (*inp) {
    561 	case PEAP_S_FLAG_SET:
    562 		dbglog("PEAP: S bit is set, starting PEAP phase 1");
    563 		ret = SSL_do_handshake(psm->ssl);
    564 		if (ret != 1) {
    565 			ret = SSL_get_error(psm->ssl, ret);
    566 			if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE)
    567 				fatal("SSL_do_handshake(): %s", ERR_error_string(ret, NULL));
    568 
    569 		}
    570 		psm->read = BIO_read(psm->out_bio, psm->out_buf, TLS_RECORD_MAX_SIZE);
    571 		peap_response(esp, id, psm->out_buf, psm->read);
    572 		break;
    573 
    574 	case PEAP_LM_FLAG_SET:
    575 		dbglog("PEAP TLS: LM bits are set, need to get more TLS fragments");
    576 		inp = inp + PEAP_FRAGMENT_LENGTH_FIELD + PEAP_FLAGS_FIELD;
    577 		psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FRAGMENT_LENGTH_FIELD - PEAP_FLAGS_FIELD);
    578 		peap_ack(esp, id);
    579 		break;
    580 
    581 	case PEAP_M_FLAG_SET:
    582 		dbglog("PEAP TLS: M bit is set, need to get more TLS fragments");
    583 		inp = inp + PEAP_FLAGS_FIELD;
    584 		psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FLAGS_FIELD);
    585 		peap_ack(esp, id);
    586 		break;
    587 
    588 	case PEAP_L_FLAG_SET:
    589 	case PEAP_NO_FLAGS:
    590 		if (*inp == PEAP_L_FLAG_SET) {
    591 			dbglog("PEAP TLS: L bit is set");
    592 			inp = inp + PEAP_FRAGMENT_LENGTH_FIELD + PEAP_FLAGS_FIELD;
    593 			psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FRAGMENT_LENGTH_FIELD - PEAP_FLAGS_FIELD);
    594 		} else {
    595 			dbglog("PEAP TLS: all bits are off");
    596 			inp = inp + PEAP_FLAGS_FIELD;
    597 			psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FLAGS_FIELD);
    598 		}
    599 
    600 		if (psm->phase == PEAP_PHASE_1) {
    601 			dbglog("PEAP TLS: continue handshake");
    602 			ret = SSL_do_handshake(psm->ssl);
    603 			if (ret != 1) {
    604 				ret = SSL_get_error(psm->ssl, ret);
    605 				if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE)
    606 					fatal("SSL_do_handshake(): %s", ERR_error_string(ret, NULL));
    607 			}
    608 			if (SSL_is_init_finished(psm->ssl))
    609 				psm->phase = PEAP_PHASE_2;
    610 			if (BIO_ctrl_pending(psm->out_bio) == 0) {
    611 				peap_ack(esp, id);
    612 				break;
    613 			}
    614 			psm->read = 0;
    615 			psm->read = BIO_read(psm->out_bio, psm->out_buf,
    616 					TLS_RECORD_MAX_SIZE);
    617 			peap_response(esp, id, psm->out_buf, psm->read);
    618 			break;
    619 		}
    620 		psm->read = SSL_read(psm->ssl, psm->in_buf,
    621 				TLS_RECORD_MAX_SIZE);
    622 		out_len = TLS_RECORD_MAX_SIZE;
    623 		peap_do_inner_eap(psm->in_buf, psm->read, esp, id,
    624 				psm->out_buf, &out_len);
    625 		if (out_len > 0) {
    626 			psm->written = SSL_write(psm->ssl, psm->out_buf, out_len);
    627 			psm->read = BIO_read(psm->out_bio, psm->out_buf,
    628 				TLS_RECORD_MAX_SIZE);
    629 			peap_response(esp, id, psm->out_buf, psm->read);
    630 		}
    631 		break;
    632 	}
    633 	return 0;
    634 }
    635 
    636 #else
    637 
    638 u_char outpacket_buf[255];
    639 int debug = 1;
    640 int error_count = 0;
    641 int unsuccess = 0;
    642 
    643 /**
    644  * Using the example in MS-PEAP, section 4.4.1.
    645  *	see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-peap/5308642b-90c9-4cc4-beec-fb367325c0f9
    646  */
    647 int test_cmk(u_char *ipmk) {
    648 	u_char nonce[PEAP_TLV_NONCE_LEN] = {
    649 		0x6C, 0x6B, 0xA3, 0x87, 0x84, 0x23, 0x74, 0x57,
    650 		0xCC, 0xC9, 0x0B, 0x1A, 0x90, 0x8C, 0xBD, 0xF4,
    651 		0x71, 0x1B, 0x69, 0x99, 0x4D, 0x0C, 0xFE, 0x8D,
    652 		0x3D, 0xB4, 0x4E, 0xCB, 0xCD, 0xAD, 0x37, 0xE9
    653 	};
    654 
    655 	u_char tmpkey[PEAP_TLV_TEMPKEY_LEN] = {
    656 		0x73, 0x8B, 0xB5, 0xF4, 0x62, 0xD5, 0x8E, 0x7E,
    657 		0xD8, 0x44, 0xE1, 0xF0, 0x0D, 0x0E, 0xBE, 0x50,
    658 		0xC5, 0x0A, 0x20, 0x50, 0xDE, 0x11, 0x99, 0x77,
    659 		0x10, 0xD6, 0x5F, 0x45, 0xFB, 0x5F, 0xBA, 0xB7,
    660 		0xE3, 0x18, 0x1E, 0x92, 0x4F, 0x42, 0x97, 0x38,
    661 		// 0xDE, 0x40, 0xC8, 0x46, 0xCD, 0xF5, 0x0B, 0xCB,
    662 		// 0xF9, 0xCE, 0xDB, 0x1E, 0x85, 0x1D, 0x22, 0x52,
    663 		// 0x45, 0x3B, 0xDF, 0x63
    664 	};
    665 
    666 	u_char expected[60] = {
    667 		0x00, 0x0C, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01,
    668 		0x6C, 0x6B, 0xA3, 0x87, 0x84, 0x23, 0x74, 0x57,
    669 		0xCC, 0xC9, 0x0B, 0x1A, 0x90, 0x8C, 0xBD, 0xF4,
    670 		0x71, 0x1B, 0x69, 0x99, 0x4D, 0x0C, 0xFE, 0x8D,
    671 		0x3D, 0xB4, 0x4E, 0xCB, 0xCD, 0xAD, 0x37, 0xE9,
    672 		0x42, 0xE0, 0x86, 0x07, 0x1D, 0x1C, 0x8B, 0x8C,
    673 		0x8E, 0x45, 0x8F, 0x70, 0x21, 0xF0, 0x6A, 0x6E,
    674 		0xAB, 0x16, 0xB6, 0x46
    675 	};
    676 
    677 	u_char inner_mppe_keys[32] = {
    678 		0x67, 0x3E, 0x96, 0x14, 0x01, 0xBE, 0xFB, 0xA5,
    679 		0x60, 0x71, 0x7B, 0x3B, 0x5D, 0xDD, 0x40, 0x38,
    680 		0x65, 0x67, 0xF9, 0xF4, 0x16, 0xFD, 0x3E, 0x9D,
    681 		0xFC, 0x71, 0x16, 0x3B, 0xDF, 0xF2, 0xFA, 0x95
    682 	};
    683 
    684 	u_char response[60] = {};
    685 
    686 	// Set the inner MPPE keys (e.g. from CHAPv2)
    687 	mppe_set_keys(inner_mppe_keys, inner_mppe_keys + 16, 16);
    688 
    689 	// Generate and compare the response
    690 	generate_cmk(ipmk, tmpkey, nonce, response, 1);
    691 	if (memcmp(expected, response, sizeof(response)) != 0) {
    692 		dbglog("Failed CMK key generation\n");
    693 		dbglog("%.*B", sizeof(response), response);
    694 		dbglog("%.*B", sizeof(expected), expected);
    695 		return -1;
    696 	}
    697 
    698 	return 0;
    699 }
    700 
    701 int test_mppe(u_char *ipmk) {
    702 	u_char outer_mppe_send_key[MPPE_MAX_KEY_SIZE] = {
    703 		0x6A, 0x02, 0xD7, 0x82, 0x20, 0x1B, 0xC7, 0x13,
    704 		0x8B, 0xF8, 0xEF, 0xF7, 0x33, 0xB4, 0x96, 0x97,
    705 		0x0D, 0x7C, 0xAB, 0x30, 0x0A, 0xC9, 0x57, 0x72,
    706 		0x78, 0xE1, 0xDD, 0xD5, 0xAE, 0xF7, 0x66, 0x97
    707 	};
    708 
    709 	u_char outer_mppe_recv_key[MPPE_MAX_KEY_SIZE] = {
    710 		0x17, 0x52, 0xD4, 0xE5, 0x84, 0xA1, 0xC8, 0x95,
    711 		0x03, 0x9B, 0x4D, 0x05, 0xE3, 0xBC, 0x9A, 0x84,
    712 		0x84, 0xDD, 0xC2, 0xAA, 0x6E, 0x2C, 0xE1, 0x62,
    713 		0x76, 0x5C, 0x40, 0x68, 0xBF, 0xF6, 0x5A, 0x45
    714 	};
    715 
    716 	u_char result[MPPE_MAX_KEY_SIZE];
    717 	int len;
    718 
    719 	mppe_clear_keys();
    720 
    721 	generate_mppe_keys(ipmk, 1);
    722 
    723 	len = mppe_get_recv_key(result, sizeof(result));
    724 	if (len != sizeof(result)) {
    725 		dbglog("Invalid length of resulting MPPE recv key");
    726 		return -1;
    727 	}
    728 
    729 	if (memcmp(result, outer_mppe_recv_key, len) != 0) {
    730 		dbglog("Invalid result for outer mppe recv key");
    731 		return -1;
    732 	}
    733 
    734 	len = mppe_get_send_key(result, sizeof(result));
    735 	if (len != sizeof(result)) {
    736 		dbglog("Invalid length of resulting MPPE send key");
    737 		return -1;
    738 	}
    739 
    740 	if (memcmp(result, outer_mppe_send_key, len) != 0) {
    741 		dbglog("Invalid result for outer mppe send key");
    742 		return -1;
    743 	}
    744 
    745 	return 0;
    746 }
    747 
    748 int main(int argc, char *argv[])
    749 {
    750 	 u_char ipmk[PEAP_TLV_IPMK_LEN] = {
    751 		0x3A, 0x91, 0x1C, 0x25, 0x54, 0x73, 0xE8, 0x3E,
    752 		0x9A, 0x0C, 0xC3, 0x33, 0xAE, 0x1F, 0x8A, 0x35,
    753 		0xCD, 0xC7, 0x41, 0x63, 0xE7, 0xF6, 0x0F, 0x6C,
    754 		0x65, 0xEF, 0x71, 0xC2, 0x64, 0x42, 0xAA, 0xAC,
    755 		0xA2, 0xB6, 0xF1, 0xEB, 0x4F, 0x25, 0xEC, 0xA3,
    756 	};
    757 	int ret = -1;
    758 
    759 	ret = test_cmk(ipmk);
    760 	if (ret != 0) {
    761 		return -1;
    762 	}
    763 
    764 	ret = test_mppe(ipmk);
    765 	if (ret != 0) {
    766 		return -1;
    767 	}
    768 
    769 	return 0;
    770 }
    771 
    772 #endif
    773