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>
59 #include <net/ppp_defs.h>
84 u_char ipmk[PEAP_TLV_IPMK_LEN];
85 u_char tk[PEAP_TLV_TK_LEN];
86 u_char nonce[PEAP_TLV_NONCE_LEN];
87 struct tls_info *info;
89 struct chap_digest_type *chap;
94 * K = Key, S = Seed, LEN = output length
95 * PRF+(K, S, LEN) = T1 | T2 | ... |Tn
97 * T1 = HMAC-SHA1 (K, S | 0x01 | 0x00 | 0x00)
98 * T2 = HMAC-SHA1 (K, T1 | S | 0x02 | 0x00 | 0x00)
100 * Tn = HMAC-SHA1 (K, Tn-1 | S | n | 0x00 | 0x00)
101 * As shown, PRF+ is computed in iterations. The number of iterations (n)
102 * depends on the output length (LEN).
104 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 size_t max_iter, i, j, k;
111 max_iter = (pfr_len + SHA_DIGEST_LENGTH - 1) / SHA_DIGEST_LENGTH;
112 buf = malloc(seed_len + max_iter * SHA_DIGEST_LENGTH);
115 hash = malloc(pfr_len + SHA_DIGEST_LENGTH);
119 for (i = 0; i < max_iter; i++) {
124 j = SHA_DIGEST_LENGTH;
125 for (k = 0; k < seed_len; k++)
126 buf[j + k] = seed[k];
134 if (!HMAC(EVP_sha1(), key, key_len, buf, pos, (hash + i * SHA_DIGEST_LENGTH), &len))
135 fatal("HMAC() failed");
136 for (j = 0; j < SHA_DIGEST_LENGTH; j++)
137 buf[j] = hash[i * SHA_DIGEST_LENGTH + j];
139 BCOPY(hash, out_buf, pfr_len);
144 static void generate_cmk(u_char *ipmk, u_char *tempkey, u_char *nonce, u_char *tlv_response_out, int client)
146 const char *label = PEAP_TLV_IPMK_SEED_LABEL;
147 u_char data_tlv[PEAP_TLV_DATA_LEN] = {0};
148 u_char isk[PEAP_TLV_ISK_LEN] = {0};
149 u_char ipmkseed[PEAP_TLV_IPMKSEED_LEN] = {0};
150 u_char cmk[PEAP_TLV_CMK_LEN] = {0};
151 u_char buf[PEAP_TLV_CMK_LEN + PEAP_TLV_IPMK_LEN] = {0};
152 u_char compound_mac[PEAP_TLV_COMP_MAC_LEN] = {0};
155 /* format outgoing CB TLV response packet */
156 data_tlv[1] = PEAP_TLV_TYPE;
157 data_tlv[3] = PEAP_TLV_LENGTH_FIELD;
159 data_tlv[7] = PEAP_TLV_SUBTYPE_RESPONSE;
161 data_tlv[7] = PEAP_TLV_SUBTYPE_REQUEST;
162 BCOPY(nonce, (data_tlv + PEAP_TLV_HEADERLEN), PEAP_TLV_NONCE_LEN);
163 data_tlv[60] = EAPT_PEAP;
166 mppe_get_send_key(isk, MPPE_MAX_KEY_LEN);
167 mppe_get_recv_key(isk + MPPE_MAX_KEY_LEN, MPPE_MAX_KEY_LEN);
170 BCOPY(label, ipmkseed, strlen(label));
171 BCOPY(isk, ipmkseed + strlen(label), PEAP_TLV_ISK_LEN);
172 peap_prfplus(ipmkseed, PEAP_TLV_IPMKSEED_LEN,
173 tempkey, PEAP_TLV_TEMPKEY_LEN, buf, PEAP_TLV_CMK_LEN + PEAP_TLV_IPMK_LEN);
175 BCOPY(buf, ipmk, PEAP_TLV_IPMK_LEN);
176 BCOPY(buf + PEAP_TLV_IPMK_LEN, cmk, PEAP_TLV_CMK_LEN);
177 if (!HMAC(EVP_sha1(), cmk, PEAP_TLV_CMK_LEN, data_tlv, PEAP_TLV_DATA_LEN, compound_mac, &len))
178 fatal("HMAC() failed");
179 BCOPY(compound_mac, data_tlv + PEAP_TLV_HEADERLEN + PEAP_TLV_NONCE_LEN, PEAP_TLV_COMP_MAC_LEN);
180 /* do not copy last byte to response packet */
181 BCOPY(data_tlv, tlv_response_out, PEAP_TLV_DATA_LEN - 1);
184 static void verify_compound_mac(struct peap_state *psm, u_char *in_buf)
186 u_char nonce[PEAP_TLV_NONCE_LEN] = {0};
187 u_char out_buf[PEAP_TLV_LEN] = {0};
189 BCOPY(in_buf, nonce, PEAP_TLV_NONCE_LEN);
190 generate_cmk(psm->ipmk, psm->tk, nonce, out_buf, 0);
191 if (memcmp((in_buf + PEAP_TLV_NONCE_LEN), (out_buf + PEAP_TLV_HEADERLEN + PEAP_TLV_NONCE_LEN), PEAP_TLV_CMK_LEN))
192 fatal("server's CMK does not match client's CMK, potential MiTM");
196 #define PEAP_MPPE_KEY_LEN 32
198 static void generate_mppe_keys(u_char *ipmk, int client)
200 const char *label = PEAP_TLV_CSK_SEED_LABEL;
201 u_char csk[PEAP_TLV_CSK_LEN] = {0};
204 dbglog("PEAP CB: generate mppe keys");
206 len++; /* CSK requires NULL byte in seed */
207 peap_prfplus((u_char *)label, len, ipmk, PEAP_TLV_IPMK_LEN, csk, PEAP_TLV_CSK_LEN);
210 * The first 64 bytes of the CSK are split into two MPPE keys, as follows.
212 * +-----------------------+------------------------+
213 * | First 32 bytes of CSK | Second 32 bytes of CSK |
214 * +-----------------------+------------------------+
215 * | MS-MPPE-Send-Key | MS-MPPE-Recv-Key |
216 * +-----------------------+------------------------+
219 mppe_set_keys(csk, csk + PEAP_MPPE_KEY_LEN, PEAP_MPPE_KEY_LEN);
221 mppe_set_keys(csk + PEAP_MPPE_KEY_LEN, csk, PEAP_MPPE_KEY_LEN);
229 static void peap_ack(eap_state *esp, u_char id)
233 outp = outpacket_buf;
234 MAKEHEADER(outp, PPP_EAP);
235 PUTCHAR(EAP_RESPONSE, outp);
237 esp->es_client.ea_id = id;
238 PUTSHORT(PEAP_HEADERLEN, outp);
239 PUTCHAR(EAPT_PEAP, outp);
240 PUTCHAR(PEAP_FLAGS_ACK, outp);
241 output(esp->es_unit, outpacket_buf, PPP_HDRLEN + PEAP_HEADERLEN);
244 static void peap_response(eap_state *esp, u_char id, u_char *buf, int len)
246 struct peap_state *psm = esp->ea_peap;
250 outp = outpacket_buf;
251 MAKEHEADER(outp, PPP_EAP);
252 PUTCHAR(EAP_RESPONSE, outp);
254 esp->es_client.ea_id = id;
256 if (psm->phase == PEAP_PHASE_1)
257 peap_len = PEAP_HEADERLEN + PEAP_FRAGMENT_LENGTH_FIELD + len;
259 peap_len = PEAP_HEADERLEN + len;
261 PUTSHORT(peap_len, outp);
262 PUTCHAR(EAPT_PEAP, outp);
264 if (psm->phase == PEAP_PHASE_1) {
265 PUTCHAR(PEAP_L_FLAG_SET, outp);
268 PUTCHAR(PEAP_NO_FLAGS, outp);
270 BCOPY(buf, outp, len);
271 output(esp->es_unit, outpacket_buf, PPP_HDRLEN + peap_len);
274 void peap_do_inner_eap(u_char *in_buf, int in_len, eap_state *esp, int id,
275 u_char *out_buf, int *out_len)
277 struct peap_state *psm = esp->ea_peap;
281 char secret[MAXSECRETLEN + 1];
282 char rhostname[MAXWORDLEN];
283 u_char *outp = out_buf;
285 dbglog("PEAP: EAP (in): %.*B", in_len, in_buf);
287 if (*(in_buf + EAP_HEADERLEN) == PEAP_CAPABILITIES_TYPE &&
288 in_len == (EAP_HEADERLEN + PEAP_CAPABILITIES_LEN)) {
289 /* use original packet as template for response */
290 BCOPY(in_buf, outp, EAP_HEADERLEN + PEAP_CAPABILITIES_LEN);
291 PUTCHAR(EAP_RESPONSE, outp);
293 /* change last byte to 0 to disable fragmentation */
294 *(outp + PEAP_CAPABILITIES_LEN + 1) = 0x00;
295 used = EAP_HEADERLEN + PEAP_CAPABILITIES_LEN;
298 if (*(in_buf + EAP_HEADERLEN + PEAP_TLV_HEADERLEN) == PEAP_TLV_TYPE &&
299 in_len == PEAP_TLV_LEN) {
300 /* PEAP TLV message, do cryptobinding */
301 SSL_export_keying_material(psm->ssl, psm->tk, PEAP_TLV_TK_LEN,
302 PEAP_TLV_TK_SEED_LABEL, strlen(PEAP_TLV_TK_SEED_LABEL), NULL, 0, 0);
303 /* verify server's CMK */
304 verify_compound_mac(psm, in_buf + EAP_HEADERLEN + PEAP_TLV_RESULT_LEN + PEAP_TLV_HEADERLEN);
305 /* generate client's CMK with new nonce */
306 PUTCHAR(EAP_RESPONSE, outp);
308 PUTSHORT(PEAP_TLV_LEN, outp);
309 BCOPY(in_buf + EAP_HEADERLEN, outp, PEAP_TLV_RESULT_LEN);
310 outp = outp + PEAP_TLV_RESULT_LEN;
311 RAND_bytes(psm->nonce, PEAP_TLV_NONCE_LEN);
312 generate_cmk(psm->ipmk, psm->tk, psm->nonce, outp, 1);
315 generate_mppe_keys(psm->ipmk, 1);
321 GETCHAR(typenum, in_buf);
326 /* Respond with our identity to the peer */
327 PUTCHAR(EAPT_IDENTITY, outp);
328 BCOPY(esp->es_client.ea_name, outp,
329 esp->es_client.ea_namelen);
330 used += (esp->es_client.ea_namelen + 1);
334 /* Send NAK to EAP_TLS request */
335 PUTCHAR(EAPT_NAK, outp);
336 PUTCHAR(EAPT_MSCHAPV2, outp);
341 case EAPT_MSCHAPV2: {
343 // Must have at least 4 more bytes to process CHAP header
345 error("PEAP: received invalid MSCHAPv2 packet, too short");
350 GETCHAR(opcode, in_buf);
353 GETCHAR(chap_id, in_buf);
356 GETSHORT(mssize, in_buf);
358 // Validate the CHAP packet (including header)
359 if (in_len != mssize) {
360 error("PEAP: received invalid MSCHAPv2 packet, invalid length");
366 case CHAP_CHALLENGE: {
368 u_char *challenge = in_buf; // VLEN + VALUE
371 GETCHAR(vsize, in_buf);
374 if (vsize != MS_CHAP2_PEER_CHAL_LEN || in_len < MS_CHAP2_PEER_CHAL_LEN) {
375 error("PEAP: received invalid MSCHAPv2 packet, invalid value-length: %d", vsize);
379 INCPTR(MS_CHAP2_PEER_CHAL_LEN, in_buf);
380 in_len -= MS_CHAP2_PEER_CHAL_LEN;
382 // Copy the provided remote host name
385 if (in_len >= sizeof(rhostname)) {
386 dbglog("PEAP: trimming really long peer name down");
387 in_len = sizeof(rhostname) - 1;
389 BCOPY(in_buf, rhostname, in_len);
390 rhostname[in_len] = '\0';
393 // In case the remote doesn't give us his name, or user explictly specified remotename is config
394 if (explicit_remote || (remote_name[0] != '\0' && in_len == 0))
395 strlcpy(rhostname, remote_name, sizeof(rhostname));
397 // Get the scrert for authenticating ourselves with the specified host
398 if (get_secret(esp->es_unit, esp->es_client.ea_name,
399 rhostname, secret, &secret_len, 0)) {
401 u_char response[MS_CHAP2_RESPONSE_LEN+1];
402 u_char user_len = esp->es_client.ea_namelen;
403 char *user = esp->es_client.ea_name;
405 psm->chap->make_response(response, chap_id, user,
406 challenge, secret, secret_len, NULL);
408 PUTCHAR(EAPT_MSCHAPV2, outp);
409 PUTCHAR(CHAP_RESPONSE, outp);
410 PUTCHAR(chap_id, outp);
412 PUTCHAR(5 + user_len + MS_CHAP2_RESPONSE_LEN, outp);
413 BCOPY(response, outp, MS_CHAP2_RESPONSE_LEN+1); // VLEN + VALUE
414 INCPTR(MS_CHAP2_RESPONSE_LEN+1, outp);
415 BCOPY(user, outp, user_len);
416 used = 5 + user_len + MS_CHAP2_RESPONSE_LEN + 1;
419 dbglog("PEAP: no CHAP secret for auth to %q", rhostname);
420 PUTCHAR(EAPT_NAK, outp);
427 u_char status = CHAP_FAILURE;
428 if (psm->chap->check_success(chap_id, in_buf, in_len)) {
429 info("Chap authentication succeeded! %.*v", in_len, in_buf);
430 status = CHAP_SUCCESS;
433 PUTCHAR(EAPT_MSCHAPV2, outp);
434 PUTCHAR(status, outp);
440 psm->chap->handle_failure(in_buf, in_len);
441 PUTCHAR(EAPT_MSCHAPV2, outp);
442 PUTCHAR(status, outp);
454 /* send compressed EAP NAK for any unknown packet */
455 PUTCHAR(EAPT_NAK, outp);
461 dbglog("PEAP: EAP (out): %.*B", used, psm->out_buf);
465 int peap_init(struct peap_state **ctx, const char *rhostname)
467 const SSL_METHOD *method;
474 struct peap_state *psm = malloc(sizeof(*psm));
476 novm("peap psm struct");
477 psm->in_buf = malloc(TLS_RECORD_MAX_SIZE);
479 novm("peap tls buffer");
480 psm->out_buf = malloc(TLS_RECORD_MAX_SIZE);
482 novm("peap tls buffer");
483 method = tls_method();
485 novm("TLS_method() failed");
486 psm->ctx = SSL_CTX_new(method);
488 novm("SSL_CTX_new() failed");
490 /* Configure the default options */
491 tls_set_opts(psm->ctx);
493 /* Configure the max TLS version */
494 tls_set_version(psm->ctx, max_tls_version);
496 /* Configure the peer certificate callback */
497 tls_set_verify(psm->ctx, 5);
499 /* Configure CA locations */
500 if (tls_set_ca(psm->ctx, ca_path, cacert_file)) {
501 fatal("Could not set CA verify locations");
504 /* Configure CRL check (if any) */
505 if (tls_set_crl(psm->ctx, crl_dir, crl_file)) {
506 fatal("Could not set CRL verify locations");
509 psm->out_bio = BIO_new(BIO_s_mem());
510 psm->in_bio = BIO_new(BIO_s_mem());
511 BIO_set_mem_eof_return(psm->out_bio, -1);
512 BIO_set_mem_eof_return(psm->in_bio, -1);
513 psm->ssl = SSL_new(psm->ctx);
514 SSL_set_bio(psm->ssl, psm->in_bio, psm->out_bio);
515 SSL_set_connect_state(psm->ssl);
516 psm->phase = PEAP_PHASE_1;
517 tls_set_verify_info(psm->ssl, explicit_remote ? rhostname : NULL, NULL, 1, &psm->info);
518 psm->chap = chap_find_digest(CHAP_MICROSOFT_V2);
523 void peap_finish(struct peap_state **psm) {
526 struct peap_state *tmp = *psm;
532 SSL_CTX_free(tmp->ctx);
535 tls_free_verify_info(&tmp->info);
537 // NOTE: BIO and memory is freed as a part of SSL_free()
544 int peap_process(eap_state *esp, u_char id, u_char *inp, int len)
549 struct peap_state *psm = esp->ea_peap;
551 if (esp->es_client.ea_id == id) {
552 info("PEAP: retransmits are not supported..");
557 case PEAP_S_FLAG_SET:
558 dbglog("PEAP: S bit is set, starting PEAP phase 1");
559 ret = SSL_do_handshake(psm->ssl);
561 ret = SSL_get_error(psm->ssl, ret);
562 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE)
563 fatal("SSL_do_handshake(): %s", ERR_error_string(ret, NULL));
566 psm->read = BIO_read(psm->out_bio, psm->out_buf, TLS_RECORD_MAX_SIZE);
567 peap_response(esp, id, psm->out_buf, psm->read);
570 case PEAP_LM_FLAG_SET:
571 dbglog("PEAP TLS: LM bits are set, need to get more TLS fragments");
572 inp = inp + PEAP_FRAGMENT_LENGTH_FIELD + PEAP_FLAGS_FIELD;
573 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FRAGMENT_LENGTH_FIELD - PEAP_FLAGS_FIELD);
577 case PEAP_M_FLAG_SET:
578 dbglog("PEAP TLS: M bit is set, need to get more TLS fragments");
579 inp = inp + PEAP_FLAGS_FIELD;
580 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FLAGS_FIELD);
584 case PEAP_L_FLAG_SET:
586 if (*inp == PEAP_L_FLAG_SET) {
587 dbglog("PEAP TLS: L bit is set");
588 inp = inp + PEAP_FRAGMENT_LENGTH_FIELD + PEAP_FLAGS_FIELD;
589 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FRAGMENT_LENGTH_FIELD - PEAP_FLAGS_FIELD);
591 dbglog("PEAP TLS: all bits are off");
592 inp = inp + PEAP_FLAGS_FIELD;
593 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FLAGS_FIELD);
596 if (psm->phase == PEAP_PHASE_1) {
597 dbglog("PEAP TLS: continue handshake");
598 ret = SSL_do_handshake(psm->ssl);
600 ret = SSL_get_error(psm->ssl, ret);
601 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE)
602 fatal("SSL_do_handshake(): %s", ERR_error_string(ret, NULL));
604 if (SSL_is_init_finished(psm->ssl))
605 psm->phase = PEAP_PHASE_2;
606 if (BIO_ctrl_pending(psm->out_bio) == 0) {
611 psm->read = BIO_read(psm->out_bio, psm->out_buf,
612 TLS_RECORD_MAX_SIZE);
613 peap_response(esp, id, psm->out_buf, psm->read);
616 psm->read = SSL_read(psm->ssl, psm->in_buf,
617 TLS_RECORD_MAX_SIZE);
618 out_len = TLS_RECORD_MAX_SIZE;
619 peap_do_inner_eap(psm->in_buf, psm->read, esp, id,
620 psm->out_buf, &out_len);
622 psm->written = SSL_write(psm->ssl, psm->out_buf, out_len);
623 psm->read = BIO_read(psm->out_bio, psm->out_buf,
624 TLS_RECORD_MAX_SIZE);
625 peap_response(esp, id, psm->out_buf, psm->read);
634 u_char outpacket_buf[255];
640 * Using the example in MS-PEAP, section 4.4.1.
641 * see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-peap/5308642b-90c9-4cc4-beec-fb367325c0f9
643 int test_cmk(u_char *ipmk) {
644 u_char nonce[PEAP_TLV_NONCE_LEN] = {
645 0x6C, 0x6B, 0xA3, 0x87, 0x84, 0x23, 0x74, 0x57,
646 0xCC, 0xC9, 0x0B, 0x1A, 0x90, 0x8C, 0xBD, 0xF4,
647 0x71, 0x1B, 0x69, 0x99, 0x4D, 0x0C, 0xFE, 0x8D,
648 0x3D, 0xB4, 0x4E, 0xCB, 0xCD, 0xAD, 0x37, 0xE9
651 u_char tmpkey[PEAP_TLV_TEMPKEY_LEN] = {
652 0x73, 0x8B, 0xB5, 0xF4, 0x62, 0xD5, 0x8E, 0x7E,
653 0xD8, 0x44, 0xE1, 0xF0, 0x0D, 0x0E, 0xBE, 0x50,
654 0xC5, 0x0A, 0x20, 0x50, 0xDE, 0x11, 0x99, 0x77,
655 0x10, 0xD6, 0x5F, 0x45, 0xFB, 0x5F, 0xBA, 0xB7,
656 0xE3, 0x18, 0x1E, 0x92, 0x4F, 0x42, 0x97, 0x38,
657 // 0xDE, 0x40, 0xC8, 0x46, 0xCD, 0xF5, 0x0B, 0xCB,
658 // 0xF9, 0xCE, 0xDB, 0x1E, 0x85, 0x1D, 0x22, 0x52,
659 // 0x45, 0x3B, 0xDF, 0x63
662 u_char expected[60] = {
663 0x00, 0x0C, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01,
664 0x6C, 0x6B, 0xA3, 0x87, 0x84, 0x23, 0x74, 0x57,
665 0xCC, 0xC9, 0x0B, 0x1A, 0x90, 0x8C, 0xBD, 0xF4,
666 0x71, 0x1B, 0x69, 0x99, 0x4D, 0x0C, 0xFE, 0x8D,
667 0x3D, 0xB4, 0x4E, 0xCB, 0xCD, 0xAD, 0x37, 0xE9,
668 0x42, 0xE0, 0x86, 0x07, 0x1D, 0x1C, 0x8B, 0x8C,
669 0x8E, 0x45, 0x8F, 0x70, 0x21, 0xF0, 0x6A, 0x6E,
670 0xAB, 0x16, 0xB6, 0x46
673 u_char inner_mppe_keys[32] = {
674 0x67, 0x3E, 0x96, 0x14, 0x01, 0xBE, 0xFB, 0xA5,
675 0x60, 0x71, 0x7B, 0x3B, 0x5D, 0xDD, 0x40, 0x38,
676 0x65, 0x67, 0xF9, 0xF4, 0x16, 0xFD, 0x3E, 0x9D,
677 0xFC, 0x71, 0x16, 0x3B, 0xDF, 0xF2, 0xFA, 0x95
680 u_char response[60] = {};
682 // Set the inner MPPE keys (e.g. from CHAPv2)
683 mppe_set_keys(inner_mppe_keys, inner_mppe_keys + 16, 16);
685 // Generate and compare the response
686 generate_cmk(ipmk, tmpkey, nonce, response, 1);
687 if (memcmp(expected, response, sizeof(response)) != 0) {
688 dbglog("Failed CMK key generation\n");
689 dbglog("%.*B", sizeof(response), response);
690 dbglog("%.*B", sizeof(expected), expected);
697 int test_mppe(u_char *ipmk) {
698 u_char outer_mppe_send_key[MPPE_MAX_KEY_SIZE] = {
699 0x6A, 0x02, 0xD7, 0x82, 0x20, 0x1B, 0xC7, 0x13,
700 0x8B, 0xF8, 0xEF, 0xF7, 0x33, 0xB4, 0x96, 0x97,
701 0x0D, 0x7C, 0xAB, 0x30, 0x0A, 0xC9, 0x57, 0x72,
702 0x78, 0xE1, 0xDD, 0xD5, 0xAE, 0xF7, 0x66, 0x97
705 u_char outer_mppe_recv_key[MPPE_MAX_KEY_SIZE] = {
706 0x17, 0x52, 0xD4, 0xE5, 0x84, 0xA1, 0xC8, 0x95,
707 0x03, 0x9B, 0x4D, 0x05, 0xE3, 0xBC, 0x9A, 0x84,
708 0x84, 0xDD, 0xC2, 0xAA, 0x6E, 0x2C, 0xE1, 0x62,
709 0x76, 0x5C, 0x40, 0x68, 0xBF, 0xF6, 0x5A, 0x45
712 u_char result[MPPE_MAX_KEY_SIZE];
717 generate_mppe_keys(ipmk, 1);
719 len = mppe_get_recv_key(result, sizeof(result));
720 if (len != sizeof(result)) {
721 dbglog("Invalid length of resulting MPPE recv key");
725 if (memcmp(result, outer_mppe_recv_key, len) != 0) {
726 dbglog("Invalid result for outer mppe recv key");
730 len = mppe_get_send_key(result, sizeof(result));
731 if (len != sizeof(result)) {
732 dbglog("Invalid length of resulting MPPE send key");
736 if (memcmp(result, outer_mppe_send_key, len) != 0) {
737 dbglog("Invalid result for outer mppe send key");
744 int main(int argc, char *argv[])
746 u_char ipmk[PEAP_TLV_IPMK_LEN] = {
747 0x3A, 0x91, 0x1C, 0x25, 0x54, 0x73, 0xE8, 0x3E,
748 0x9A, 0x0C, 0xC3, 0x33, 0xAE, 0x1F, 0x8A, 0x35,
749 0xCD, 0xC7, 0x41, 0x63, 0xE7, 0xF6, 0x0F, 0x6C,
750 0x65, 0xEF, 0x71, 0xC2, 0x64, 0x42, 0xAA, 0xAC,
751 0xA2, 0xB6, 0xF1, 0xEB, 0x4F, 0x25, 0xEC, 0xA3,
755 ret = test_cmk(ipmk);
760 ret = test_mppe(ipmk);