2 * Copyright (c) 2011 Rustam Kovhaev. All rights reserved.
3 * Copyright (c) 2021 Eivind Næss. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
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.
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
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
41 * Current implementation does not support:
43 * b) Inner EAP fragmentation
44 * c) Any other auth other than MSCHAPV2
46 * For details on the PEAP protocol, look to Microsoft:
47 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-peap
54 #include <openssl/opensslv.h>
55 #include <openssl/ssl.h>
56 #include <openssl/hmac.h>
57 #include <openssl/rand.h>
58 #include <openssl/err.h>
83 u_char ipmk[PEAP_TLV_IPMK_LEN];
84 u_char tk[PEAP_TLV_TK_LEN];
85 u_char nonce[PEAP_TLV_NONCE_LEN];
86 struct tls_info *info;
87 #ifdef PPP_WITH_CHAPMS
88 struct chap_digest_type *chap;
93 * K = Key, S = Seed, LEN = output length
94 * PRF+(K, S, LEN) = T1 | T2 | ... |Tn
96 * T1 = HMAC-SHA1 (K, S | 0x01 | 0x00 | 0x00)
97 * T2 = HMAC-SHA1 (K, T1 | S | 0x02 | 0x00 | 0x00)
99 * Tn = HMAC-SHA1 (K, Tn-1 | S | n | 0x00 | 0x00)
100 * As shown, PRF+ is computed in iterations. The number of iterations (n)
101 * depends on the output length (LEN).
103 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)
107 size_t max_iter, i, j, k;
110 max_iter = (pfr_len + SHA_DIGEST_LENGTH - 1) / SHA_DIGEST_LENGTH;
111 buf = malloc(seed_len + max_iter * SHA_DIGEST_LENGTH);
114 hash = malloc(pfr_len + SHA_DIGEST_LENGTH);
118 for (i = 0; i < max_iter; i++) {
123 j = SHA_DIGEST_LENGTH;
124 for (k = 0; k < seed_len; k++)
125 buf[j + k] = seed[k];
133 if (!HMAC(EVP_sha1(), key, key_len, buf, pos, (hash + i * SHA_DIGEST_LENGTH), &len))
134 fatal("HMAC() failed");
135 for (j = 0; j < SHA_DIGEST_LENGTH; j++)
136 buf[j] = hash[i * SHA_DIGEST_LENGTH + j];
138 BCOPY(hash, out_buf, pfr_len);
143 static void generate_cmk(u_char *ipmk, u_char *tempkey, u_char *nonce, u_char *tlv_response_out, int client)
145 const char *label = PEAP_TLV_IPMK_SEED_LABEL;
146 u_char data_tlv[PEAP_TLV_DATA_LEN] = {0};
147 u_char isk[PEAP_TLV_ISK_LEN] = {0};
148 u_char ipmkseed[PEAP_TLV_IPMKSEED_LEN] = {0};
149 u_char cmk[PEAP_TLV_CMK_LEN] = {0};
150 u_char buf[PEAP_TLV_CMK_LEN + PEAP_TLV_IPMK_LEN] = {0};
151 u_char compound_mac[PEAP_TLV_COMP_MAC_LEN] = {0};
154 /* format outgoing CB TLV response packet */
155 data_tlv[1] = PEAP_TLV_TYPE;
156 data_tlv[3] = PEAP_TLV_LENGTH_FIELD;
158 data_tlv[7] = PEAP_TLV_SUBTYPE_RESPONSE;
160 data_tlv[7] = PEAP_TLV_SUBTYPE_REQUEST;
161 BCOPY(nonce, (data_tlv + PEAP_TLV_HEADERLEN), PEAP_TLV_NONCE_LEN);
162 data_tlv[60] = EAPT_PEAP;
165 mppe_get_send_key(isk, MPPE_MAX_KEY_LEN);
166 mppe_get_recv_key(isk + MPPE_MAX_KEY_LEN, MPPE_MAX_KEY_LEN);
169 BCOPY(label, ipmkseed, strlen(label));
170 BCOPY(isk, ipmkseed + strlen(label), PEAP_TLV_ISK_LEN);
171 peap_prfplus(ipmkseed, PEAP_TLV_IPMKSEED_LEN,
172 tempkey, PEAP_TLV_TEMPKEY_LEN, buf, PEAP_TLV_CMK_LEN + PEAP_TLV_IPMK_LEN);
174 BCOPY(buf, ipmk, PEAP_TLV_IPMK_LEN);
175 BCOPY(buf + PEAP_TLV_IPMK_LEN, cmk, PEAP_TLV_CMK_LEN);
176 if (!HMAC(EVP_sha1(), cmk, PEAP_TLV_CMK_LEN, data_tlv, PEAP_TLV_DATA_LEN, compound_mac, &len))
177 fatal("HMAC() failed");
178 BCOPY(compound_mac, data_tlv + PEAP_TLV_HEADERLEN + PEAP_TLV_NONCE_LEN, PEAP_TLV_COMP_MAC_LEN);
179 /* do not copy last byte to response packet */
180 BCOPY(data_tlv, tlv_response_out, PEAP_TLV_DATA_LEN - 1);
183 static void verify_compound_mac(struct peap_state *psm, u_char *in_buf)
185 u_char nonce[PEAP_TLV_NONCE_LEN] = {0};
186 u_char out_buf[PEAP_TLV_LEN] = {0};
188 BCOPY(in_buf, nonce, PEAP_TLV_NONCE_LEN);
189 generate_cmk(psm->ipmk, psm->tk, nonce, out_buf, 0);
190 if (memcmp((in_buf + PEAP_TLV_NONCE_LEN), (out_buf + PEAP_TLV_HEADERLEN + PEAP_TLV_NONCE_LEN), PEAP_TLV_CMK_LEN))
191 fatal("server's CMK does not match client's CMK, potential MiTM");
195 #define PEAP_MPPE_KEY_LEN 32
197 static void generate_mppe_keys(u_char *ipmk, int client)
199 const char *label = PEAP_TLV_CSK_SEED_LABEL;
200 u_char csk[PEAP_TLV_CSK_LEN] = {0};
203 dbglog("PEAP CB: generate mppe keys");
205 len++; /* CSK requires NULL byte in seed */
206 peap_prfplus((u_char *)label, len, ipmk, PEAP_TLV_IPMK_LEN, csk, PEAP_TLV_CSK_LEN);
209 * The first 64 bytes of the CSK are split into two MPPE keys, as follows.
211 * +-----------------------+------------------------+
212 * | First 32 bytes of CSK | Second 32 bytes of CSK |
213 * +-----------------------+------------------------+
214 * | MS-MPPE-Send-Key | MS-MPPE-Recv-Key |
215 * +-----------------------+------------------------+
218 mppe_set_keys(csk, csk + PEAP_MPPE_KEY_LEN, PEAP_MPPE_KEY_LEN);
220 mppe_set_keys(csk + PEAP_MPPE_KEY_LEN, csk, PEAP_MPPE_KEY_LEN);
228 static void peap_ack(eap_state *esp, u_char id)
232 outp = outpacket_buf;
233 MAKEHEADER(outp, PPP_EAP);
234 PUTCHAR(EAP_RESPONSE, outp);
236 esp->es_client.ea_id = id;
237 PUTSHORT(PEAP_HEADERLEN, outp);
238 PUTCHAR(EAPT_PEAP, outp);
239 PUTCHAR(PEAP_FLAGS_ACK, outp);
240 output(esp->es_unit, outpacket_buf, PPP_HDRLEN + PEAP_HEADERLEN);
243 static void peap_response(eap_state *esp, u_char id, u_char *buf, int len)
245 struct peap_state *psm = esp->ea_peap;
249 outp = outpacket_buf;
250 MAKEHEADER(outp, PPP_EAP);
251 PUTCHAR(EAP_RESPONSE, outp);
253 esp->es_client.ea_id = id;
255 if (psm->phase == PEAP_PHASE_1)
256 peap_len = PEAP_HEADERLEN + PEAP_FRAGMENT_LENGTH_FIELD + len;
258 peap_len = PEAP_HEADERLEN + len;
260 PUTSHORT(peap_len, outp);
261 PUTCHAR(EAPT_PEAP, outp);
263 if (psm->phase == PEAP_PHASE_1) {
264 PUTCHAR(PEAP_L_FLAG_SET, outp);
267 PUTCHAR(PEAP_NO_FLAGS, outp);
269 BCOPY(buf, outp, len);
270 output(esp->es_unit, outpacket_buf, PPP_HDRLEN + peap_len);
273 void peap_do_inner_eap(u_char *in_buf, int in_len, eap_state *esp, int id,
274 u_char *out_buf, int *out_len)
276 struct peap_state *psm = esp->ea_peap;
280 char secret[MAXSECRETLEN + 1];
281 char rhostname[MAXWORDLEN];
282 u_char *outp = out_buf;
284 dbglog("PEAP: EAP (in): %.*B", in_len, in_buf);
286 if (*(in_buf + EAP_HEADERLEN) == PEAP_CAPABILITIES_TYPE &&
287 in_len == (EAP_HEADERLEN + PEAP_CAPABILITIES_LEN)) {
288 /* use original packet as template for response */
289 BCOPY(in_buf, outp, EAP_HEADERLEN + PEAP_CAPABILITIES_LEN);
290 PUTCHAR(EAP_RESPONSE, outp);
292 /* change last byte to 0 to disable fragmentation */
293 *(outp + PEAP_CAPABILITIES_LEN + 1) = 0x00;
294 used = EAP_HEADERLEN + PEAP_CAPABILITIES_LEN;
297 if (*(in_buf + EAP_HEADERLEN + PEAP_TLV_HEADERLEN) == PEAP_TLV_TYPE &&
298 in_len == PEAP_TLV_LEN) {
299 /* PEAP TLV message, do cryptobinding */
300 SSL_export_keying_material(psm->ssl, psm->tk, PEAP_TLV_TK_LEN,
301 PEAP_TLV_TK_SEED_LABEL, strlen(PEAP_TLV_TK_SEED_LABEL), NULL, 0, 0);
302 /* verify server's CMK */
303 verify_compound_mac(psm, in_buf + EAP_HEADERLEN + PEAP_TLV_RESULT_LEN + PEAP_TLV_HEADERLEN);
304 /* generate client's CMK with new nonce */
305 PUTCHAR(EAP_RESPONSE, outp);
307 PUTSHORT(PEAP_TLV_LEN, outp);
308 BCOPY(in_buf + EAP_HEADERLEN, outp, PEAP_TLV_RESULT_LEN);
309 outp = outp + PEAP_TLV_RESULT_LEN;
310 RAND_bytes(psm->nonce, PEAP_TLV_NONCE_LEN);
311 generate_cmk(psm->ipmk, psm->tk, psm->nonce, outp, 1);
314 generate_mppe_keys(psm->ipmk, 1);
320 GETCHAR(typenum, in_buf);
325 /* Respond with our identity to the peer */
326 PUTCHAR(EAPT_IDENTITY, outp);
327 BCOPY(esp->es_client.ea_name, outp,
328 esp->es_client.ea_namelen);
329 used += (esp->es_client.ea_namelen + 1);
333 /* Send NAK to EAP_TLS request */
334 PUTCHAR(EAPT_NAK, outp);
335 PUTCHAR(EAPT_MSCHAPV2, outp);
340 case EAPT_MSCHAPV2: {
342 // Must have at least 4 more bytes to process CHAP header
344 error("PEAP: received invalid MSCHAPv2 packet, too short");
349 GETCHAR(opcode, in_buf);
352 GETCHAR(chap_id, in_buf);
355 GETSHORT(mssize, in_buf);
357 // Validate the CHAP packet (including header)
358 if (in_len != mssize) {
359 error("PEAP: received invalid MSCHAPv2 packet, invalid length");
365 case CHAP_CHALLENGE: {
367 u_char *challenge = in_buf; // VLEN + VALUE
370 GETCHAR(vsize, in_buf);
373 if (vsize != MS_CHAP2_PEER_CHAL_LEN || in_len < MS_CHAP2_PEER_CHAL_LEN) {
374 error("PEAP: received invalid MSCHAPv2 packet, invalid value-length: %d", vsize);
378 INCPTR(MS_CHAP2_PEER_CHAL_LEN, in_buf);
379 in_len -= MS_CHAP2_PEER_CHAL_LEN;
381 // Copy the provided remote host name
384 if (in_len >= sizeof(rhostname)) {
385 dbglog("PEAP: trimming really long peer name down");
386 in_len = sizeof(rhostname) - 1;
388 BCOPY(in_buf, rhostname, in_len);
389 rhostname[in_len] = '\0';
392 // In case the remote doesn't give us his name, or user explictly specified remotename is config
393 if (explicit_remote || (remote_name[0] != '\0' && in_len == 0))
394 strlcpy(rhostname, remote_name, sizeof(rhostname));
396 // Get the scrert for authenticating ourselves with the specified host
397 if (get_secret(esp->es_unit, esp->es_client.ea_name,
398 rhostname, secret, &secret_len, 0)) {
400 u_char response[MS_CHAP2_RESPONSE_LEN+1];
401 u_char user_len = esp->es_client.ea_namelen;
402 char *user = esp->es_client.ea_name;
404 psm->chap->make_response(response, chap_id, user,
405 challenge, secret, secret_len, NULL);
407 PUTCHAR(EAPT_MSCHAPV2, outp);
408 PUTCHAR(CHAP_RESPONSE, outp);
409 PUTCHAR(chap_id, outp);
411 PUTCHAR(5 + user_len + MS_CHAP2_RESPONSE_LEN, outp);
412 BCOPY(response, outp, MS_CHAP2_RESPONSE_LEN+1); // VLEN + VALUE
413 INCPTR(MS_CHAP2_RESPONSE_LEN+1, outp);
414 BCOPY(user, outp, user_len);
415 used = 5 + user_len + MS_CHAP2_RESPONSE_LEN + 1;
418 dbglog("PEAP: no CHAP secret for auth to %q", rhostname);
419 PUTCHAR(EAPT_NAK, outp);
426 u_char status = CHAP_FAILURE;
427 if (psm->chap->check_success(chap_id, in_buf, in_len)) {
428 info("Chap authentication succeeded! %.*v", in_len, in_buf);
429 status = CHAP_SUCCESS;
432 PUTCHAR(EAPT_MSCHAPV2, outp);
433 PUTCHAR(status, outp);
439 psm->chap->handle_failure(in_buf, in_len);
440 PUTCHAR(EAPT_MSCHAPV2, outp);
441 PUTCHAR(status, outp);
453 /* send compressed EAP NAK for any unknown packet */
454 PUTCHAR(EAPT_NAK, outp);
460 dbglog("PEAP: EAP (out): %.*B", used, psm->out_buf);
464 int peap_init(struct peap_state **ctx, const char *rhostname)
466 const SSL_METHOD *method;
473 struct peap_state *psm = malloc(sizeof(*psm));
475 novm("peap psm struct");
476 psm->in_buf = malloc(TLS_RECORD_MAX_SIZE);
478 novm("peap tls buffer");
479 psm->out_buf = malloc(TLS_RECORD_MAX_SIZE);
481 novm("peap tls buffer");
482 method = tls_method();
484 novm("TLS_method() failed");
485 psm->ctx = SSL_CTX_new(method);
487 novm("SSL_CTX_new() failed");
489 /* Configure the default options */
490 tls_set_opts(psm->ctx);
492 /* Configure the max TLS version */
493 tls_set_version(psm->ctx, max_tls_version);
495 /* Configure the peer certificate callback */
496 tls_set_verify(psm->ctx, 5);
498 /* Configure CA locations */
499 if (tls_set_ca(psm->ctx, ca_path, cacert_file)) {
500 fatal("Could not set CA verify locations");
503 /* Configure CRL check (if any) */
504 if (tls_set_crl(psm->ctx, crl_dir, crl_file)) {
505 fatal("Could not set CRL verify locations");
508 psm->out_bio = BIO_new(BIO_s_mem());
509 psm->in_bio = BIO_new(BIO_s_mem());
510 BIO_set_mem_eof_return(psm->out_bio, -1);
511 BIO_set_mem_eof_return(psm->in_bio, -1);
512 psm->ssl = SSL_new(psm->ctx);
513 SSL_set_bio(psm->ssl, psm->in_bio, psm->out_bio);
514 SSL_set_connect_state(psm->ssl);
515 psm->phase = PEAP_PHASE_1;
516 tls_set_verify_info(psm->ssl, explicit_remote ? rhostname : NULL, NULL, 1, &psm->info);
517 psm->chap = chap_find_digest(CHAP_MICROSOFT_V2);
522 void peap_finish(struct peap_state **psm) {
525 struct peap_state *tmp = *psm;
531 SSL_CTX_free(tmp->ctx);
534 tls_free_verify_info(&tmp->info);
536 // NOTE: BIO and memory is freed as a part of SSL_free()
543 int peap_process(eap_state *esp, u_char id, u_char *inp, int len)
548 struct peap_state *psm = esp->ea_peap;
550 if (esp->es_client.ea_id == id) {
551 info("PEAP: retransmits are not supported..");
556 case PEAP_S_FLAG_SET:
557 dbglog("PEAP: S bit is set, starting PEAP phase 1");
558 ret = SSL_do_handshake(psm->ssl);
560 ret = SSL_get_error(psm->ssl, ret);
561 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE)
562 fatal("SSL_do_handshake(): %s", ERR_error_string(ret, NULL));
565 psm->read = BIO_read(psm->out_bio, psm->out_buf, TLS_RECORD_MAX_SIZE);
566 peap_response(esp, id, psm->out_buf, psm->read);
569 case PEAP_LM_FLAG_SET:
570 dbglog("PEAP TLS: LM bits are set, need to get more TLS fragments");
571 inp = inp + PEAP_FRAGMENT_LENGTH_FIELD + PEAP_FLAGS_FIELD;
572 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FRAGMENT_LENGTH_FIELD - PEAP_FLAGS_FIELD);
576 case PEAP_M_FLAG_SET:
577 dbglog("PEAP TLS: M bit is set, need to get more TLS fragments");
578 inp = inp + PEAP_FLAGS_FIELD;
579 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FLAGS_FIELD);
583 case PEAP_L_FLAG_SET:
585 if (*inp == PEAP_L_FLAG_SET) {
586 dbglog("PEAP TLS: L bit is set");
587 inp = inp + PEAP_FRAGMENT_LENGTH_FIELD + PEAP_FLAGS_FIELD;
588 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FRAGMENT_LENGTH_FIELD - PEAP_FLAGS_FIELD);
590 dbglog("PEAP TLS: all bits are off");
591 inp = inp + PEAP_FLAGS_FIELD;
592 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FLAGS_FIELD);
595 if (psm->phase == PEAP_PHASE_1) {
596 dbglog("PEAP TLS: continue handshake");
597 ret = SSL_do_handshake(psm->ssl);
599 ret = SSL_get_error(psm->ssl, ret);
600 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE)
601 fatal("SSL_do_handshake(): %s", ERR_error_string(ret, NULL));
603 if (SSL_is_init_finished(psm->ssl))
604 psm->phase = PEAP_PHASE_2;
605 if (BIO_ctrl_pending(psm->out_bio) == 0) {
610 psm->read = BIO_read(psm->out_bio, psm->out_buf,
611 TLS_RECORD_MAX_SIZE);
612 peap_response(esp, id, psm->out_buf, psm->read);
615 psm->read = SSL_read(psm->ssl, psm->in_buf,
616 TLS_RECORD_MAX_SIZE);
617 out_len = TLS_RECORD_MAX_SIZE;
618 peap_do_inner_eap(psm->in_buf, psm->read, esp, id,
619 psm->out_buf, &out_len);
621 psm->written = SSL_write(psm->ssl, psm->out_buf, out_len);
622 psm->read = BIO_read(psm->out_bio, psm->out_buf,
623 TLS_RECORD_MAX_SIZE);
624 peap_response(esp, id, psm->out_buf, psm->read);
633 u_char outpacket_buf[255];
639 * Using the example in MS-PEAP, section 4.4.1.
640 * see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-peap/5308642b-90c9-4cc4-beec-fb367325c0f9
642 int test_cmk(u_char *ipmk) {
643 u_char nonce[PEAP_TLV_NONCE_LEN] = {
644 0x6C, 0x6B, 0xA3, 0x87, 0x84, 0x23, 0x74, 0x57,
645 0xCC, 0xC9, 0x0B, 0x1A, 0x90, 0x8C, 0xBD, 0xF4,
646 0x71, 0x1B, 0x69, 0x99, 0x4D, 0x0C, 0xFE, 0x8D,
647 0x3D, 0xB4, 0x4E, 0xCB, 0xCD, 0xAD, 0x37, 0xE9
650 u_char tmpkey[PEAP_TLV_TEMPKEY_LEN] = {
651 0x73, 0x8B, 0xB5, 0xF4, 0x62, 0xD5, 0x8E, 0x7E,
652 0xD8, 0x44, 0xE1, 0xF0, 0x0D, 0x0E, 0xBE, 0x50,
653 0xC5, 0x0A, 0x20, 0x50, 0xDE, 0x11, 0x99, 0x77,
654 0x10, 0xD6, 0x5F, 0x45, 0xFB, 0x5F, 0xBA, 0xB7,
655 0xE3, 0x18, 0x1E, 0x92, 0x4F, 0x42, 0x97, 0x38,
656 // 0xDE, 0x40, 0xC8, 0x46, 0xCD, 0xF5, 0x0B, 0xCB,
657 // 0xF9, 0xCE, 0xDB, 0x1E, 0x85, 0x1D, 0x22, 0x52,
658 // 0x45, 0x3B, 0xDF, 0x63
661 u_char expected[60] = {
662 0x00, 0x0C, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01,
663 0x6C, 0x6B, 0xA3, 0x87, 0x84, 0x23, 0x74, 0x57,
664 0xCC, 0xC9, 0x0B, 0x1A, 0x90, 0x8C, 0xBD, 0xF4,
665 0x71, 0x1B, 0x69, 0x99, 0x4D, 0x0C, 0xFE, 0x8D,
666 0x3D, 0xB4, 0x4E, 0xCB, 0xCD, 0xAD, 0x37, 0xE9,
667 0x42, 0xE0, 0x86, 0x07, 0x1D, 0x1C, 0x8B, 0x8C,
668 0x8E, 0x45, 0x8F, 0x70, 0x21, 0xF0, 0x6A, 0x6E,
669 0xAB, 0x16, 0xB6, 0x46
672 u_char inner_mppe_keys[32] = {
673 0x67, 0x3E, 0x96, 0x14, 0x01, 0xBE, 0xFB, 0xA5,
674 0x60, 0x71, 0x7B, 0x3B, 0x5D, 0xDD, 0x40, 0x38,
675 0x65, 0x67, 0xF9, 0xF4, 0x16, 0xFD, 0x3E, 0x9D,
676 0xFC, 0x71, 0x16, 0x3B, 0xDF, 0xF2, 0xFA, 0x95
679 u_char response[60] = {};
681 // Set the inner MPPE keys (e.g. from CHAPv2)
682 mppe_set_keys(inner_mppe_keys, inner_mppe_keys + 16, 16);
684 // Generate and compare the response
685 generate_cmk(ipmk, tmpkey, nonce, response, 1);
686 if (memcmp(expected, response, sizeof(response)) != 0) {
687 dbglog("Failed CMK key generation\n");
688 dbglog("%.*B", sizeof(response), response);
689 dbglog("%.*B", sizeof(expected), expected);
696 int test_mppe(u_char *ipmk) {
697 u_char outer_mppe_send_key[MPPE_MAX_KEY_SIZE] = {
698 0x6A, 0x02, 0xD7, 0x82, 0x20, 0x1B, 0xC7, 0x13,
699 0x8B, 0xF8, 0xEF, 0xF7, 0x33, 0xB4, 0x96, 0x97,
700 0x0D, 0x7C, 0xAB, 0x30, 0x0A, 0xC9, 0x57, 0x72,
701 0x78, 0xE1, 0xDD, 0xD5, 0xAE, 0xF7, 0x66, 0x97
704 u_char outer_mppe_recv_key[MPPE_MAX_KEY_SIZE] = {
705 0x17, 0x52, 0xD4, 0xE5, 0x84, 0xA1, 0xC8, 0x95,
706 0x03, 0x9B, 0x4D, 0x05, 0xE3, 0xBC, 0x9A, 0x84,
707 0x84, 0xDD, 0xC2, 0xAA, 0x6E, 0x2C, 0xE1, 0x62,
708 0x76, 0x5C, 0x40, 0x68, 0xBF, 0xF6, 0x5A, 0x45
711 u_char result[MPPE_MAX_KEY_SIZE];
716 generate_mppe_keys(ipmk, 1);
718 len = mppe_get_recv_key(result, sizeof(result));
719 if (len != sizeof(result)) {
720 dbglog("Invalid length of resulting MPPE recv key");
724 if (memcmp(result, outer_mppe_recv_key, len) != 0) {
725 dbglog("Invalid result for outer mppe recv key");
729 len = mppe_get_send_key(result, sizeof(result));
730 if (len != sizeof(result)) {
731 dbglog("Invalid length of resulting MPPE send key");
735 if (memcmp(result, outer_mppe_send_key, len) != 0) {
736 dbglog("Invalid result for outer mppe send key");
743 int main(int argc, char *argv[])
745 u_char ipmk[PEAP_TLV_IPMK_LEN] = {
746 0x3A, 0x91, 0x1C, 0x25, 0x54, 0x73, 0xE8, 0x3E,
747 0x9A, 0x0C, 0xC3, 0x33, 0xAE, 0x1F, 0x8A, 0x35,
748 0xCD, 0xC7, 0x41, 0x63, 0xE7, 0xF6, 0x0F, 0x6C,
749 0x65, 0xEF, 0x71, 0xC2, 0x64, 0x42, 0xAA, 0xAC,
750 0xA2, 0xB6, 0xF1, 0xEB, 0x4F, 0x25, 0xEC, 0xA3,
754 ret = test_cmk(ipmk);
759 ret = test_mppe(ipmk);