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