]> git.ozlabs.org Git - ppp.git/blob - pppd/peap.c
pppd man page: Update header to refer to pppd 2.5.x
[ppp.git] / pppd / peap.c
1 /*
2  * Copyright (c) 2011 Rustam Kovhaev. All rights reserved.
3  * Copyright (c) 2021 Eivind Næss. 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 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <errno.h>
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>
60
61 #include "pppd.h"
62 #include "eap.h"
63 #include "tls.h"
64 #include "chap-new.h"
65 #include "chap_ms.h"
66 #include "mppe.h"
67 #include "peap.h"
68
69 #ifdef UNIT_TEST
70 #define novm(x)
71 #endif
72
73 struct peap_state {
74         SSL_CTX *ctx;
75         SSL *ssl;
76         BIO *in_bio;
77         BIO *out_bio;
78
79         int phase;
80         int written, read;
81         u_char *in_buf;
82         u_char *out_buf;
83
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;
88 #ifdef CHAPMS
89         struct chap_digest_type *chap;
90 #endif
91 };
92
93 /*
94  * K = Key, S = Seed, LEN = output length
95  * PRF+(K, S, LEN) = T1 | T2 | ... |Tn
96  * Where:
97  * T1 = HMAC-SHA1 (K, S | 0x01 | 0x00 | 0x00)
98  * T2 = HMAC-SHA1 (K, T1 | S | 0x02 | 0x00 | 0x00)
99  * ...
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).
103  */
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)
105 {
106         int pos;
107         u_char *buf, *hash;
108         size_t max_iter, i, j, k;
109         u_int len;
110
111         max_iter = (pfr_len + SHA_DIGEST_LENGTH - 1) / SHA_DIGEST_LENGTH;
112         buf = malloc(seed_len + max_iter * SHA_DIGEST_LENGTH);
113         if (!buf)
114                 novm("pfr buffer");
115         hash = malloc(pfr_len + SHA_DIGEST_LENGTH);
116         if (!hash)
117                 novm("hash buffer");
118
119         for (i = 0; i < max_iter; i++) {
120                 j = 0;
121                 k = 0;
122
123                 if (i > 0)
124                         j = SHA_DIGEST_LENGTH;
125                 for (k = 0; k < seed_len; k++)
126                         buf[j + k] = seed[k];
127                 pos = j + k;
128                 buf[pos] = i + 1;
129                 pos++;
130                 buf[pos] = 0x00;
131                 pos++;
132                 buf[pos] = 0x00;
133                 pos++;
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];
138         }
139         BCOPY(hash, out_buf, pfr_len);
140         free(hash);
141         free(buf);
142 }
143
144 static void generate_cmk(u_char *ipmk, u_char *tempkey, u_char *nonce, u_char *tlv_response_out, int client)
145 {
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};
153         u_int len;
154
155         /* format outgoing CB TLV response packet */
156         data_tlv[1] = PEAP_TLV_TYPE;
157         data_tlv[3] = PEAP_TLV_LENGTH_FIELD;
158         if (client)
159                 data_tlv[7] = PEAP_TLV_SUBTYPE_RESPONSE;
160         else
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;
164
165 #ifdef MPPE
166         mppe_get_send_key(isk, MPPE_MAX_KEY_LEN);
167         mppe_get_recv_key(isk + MPPE_MAX_KEY_LEN, MPPE_MAX_KEY_LEN);
168 #endif
169
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);
174
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);
182 }
183
184 static void verify_compound_mac(struct peap_state *psm, u_char *in_buf)
185 {
186         u_char nonce[PEAP_TLV_NONCE_LEN] = {0};
187         u_char out_buf[PEAP_TLV_LEN] = {0};
188
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");
193 }
194
195 #ifdef MPPE
196 #define PEAP_MPPE_KEY_LEN 32
197
198 static void generate_mppe_keys(u_char *ipmk, int client)
199 {
200         const char *label = PEAP_TLV_CSK_SEED_LABEL;
201         u_char csk[PEAP_TLV_CSK_LEN] = {0};
202         size_t len;
203
204         dbglog("PEAP CB: generate mppe keys");
205         len = strlen(label);
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);
208
209         /*
210          * The first 64 bytes of the CSK are split into two MPPE keys, as follows.
211          *
212          * +-----------------------+------------------------+
213          * | First 32 bytes of CSK | Second 32 bytes of CSK |
214          * +-----------------------+------------------------+
215          * | MS-MPPE-Send-Key      | MS-MPPE-Recv-Key       |
216          * +-----------------------+------------------------+
217          */
218         if (client) {
219                 mppe_set_keys(csk, csk + PEAP_MPPE_KEY_LEN, PEAP_MPPE_KEY_LEN);
220         } else {
221                 mppe_set_keys(csk + PEAP_MPPE_KEY_LEN, csk, PEAP_MPPE_KEY_LEN);
222         }
223 }
224
225 #endif
226
227 #ifndef UNIT_TEST
228
229 static void peap_ack(eap_state *esp, u_char id)
230 {
231         u_char *outp;
232
233         outp = outpacket_buf;
234         MAKEHEADER(outp, PPP_EAP);
235         PUTCHAR(EAP_RESPONSE, outp);
236         PUTCHAR(id, 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);
242 }
243
244 static void peap_response(eap_state *esp, u_char id, u_char *buf, int len)
245 {
246         struct peap_state *psm = esp->ea_peap;
247         u_char *outp;
248         int peap_len;
249
250         outp = outpacket_buf;
251         MAKEHEADER(outp, PPP_EAP);
252         PUTCHAR(EAP_RESPONSE, outp);
253         PUTCHAR(id, outp);
254         esp->es_client.ea_id = id;
255
256         if (psm->phase == PEAP_PHASE_1)
257                 peap_len = PEAP_HEADERLEN + PEAP_FRAGMENT_LENGTH_FIELD + len;
258         else
259                 peap_len = PEAP_HEADERLEN + len;
260
261         PUTSHORT(peap_len, outp);
262         PUTCHAR(EAPT_PEAP, outp);
263
264         if (psm->phase == PEAP_PHASE_1) {
265                 PUTCHAR(PEAP_L_FLAG_SET, outp);
266                 PUTLONG(len, outp);
267         } else
268                 PUTCHAR(PEAP_NO_FLAGS, outp);
269
270         BCOPY(buf, outp, len);
271         output(esp->es_unit, outpacket_buf, PPP_HDRLEN + peap_len);
272 }
273
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)
276 {
277         struct peap_state *psm = esp->ea_peap;
278         int used = 0;
279         int typenum;
280         int secret_len;
281         char secret[MAXSECRETLEN + 1];
282         char rhostname[MAXWORDLEN];
283         u_char *outp = out_buf;
284
285         dbglog("PEAP: EAP (in): %.*B", in_len, in_buf);
286
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);
292                 PUTCHAR(id, outp);
293                 /* change last byte to 0 to disable fragmentation */
294                 *(outp + PEAP_CAPABILITIES_LEN + 1) = 0x00;
295                 used = EAP_HEADERLEN + PEAP_CAPABILITIES_LEN;
296                 goto done;
297         }
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);
307                 PUTCHAR(id, 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);
313 #ifdef MPPE
314                 /* set mppe keys */
315                 generate_mppe_keys(psm->ipmk, 1);
316 #endif
317                 used = PEAP_TLV_LEN;
318                 goto done;
319         }
320
321         GETCHAR(typenum, in_buf);
322         in_len--;
323
324         switch (typenum) {
325         case EAPT_IDENTITY:
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);
331                 break;
332
333         case EAPT_TLS:
334                 /* Send NAK to EAP_TLS request */
335                 PUTCHAR(EAPT_NAK, outp);
336                 PUTCHAR(EAPT_MSCHAPV2, outp);
337                 used += 2;
338                 break;
339
340 #if CHAPMS
341         case EAPT_MSCHAPV2: {
342
343                 // Must have at least 4 more bytes to process CHAP header
344                 if (in_len < 4) {
345                         error("PEAP: received invalid MSCHAPv2 packet, too short");
346                         break;
347                 }
348
349                 u_char opcode;
350                 GETCHAR(opcode, in_buf);
351
352                 u_char chap_id;
353                 GETCHAR(chap_id, in_buf);
354
355                 short mssize;
356                 GETSHORT(mssize, in_buf);
357
358                 // Validate the CHAP packet (including header)
359                 if (in_len != mssize) {
360                         error("PEAP: received invalid MSCHAPv2 packet, invalid length");
361                         break;
362                 }
363                 in_len -= 4;
364
365                 switch (opcode) {
366                 case CHAP_CHALLENGE: {
367
368                         u_char *challenge = in_buf;     // VLEN + VALUE
369                         u_char vsize;
370
371                         GETCHAR(vsize, in_buf);
372                         in_len -= 1;
373
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);
376                                 goto done;
377                         }
378
379                         INCPTR(MS_CHAP2_PEER_CHAL_LEN, in_buf);
380                         in_len -= MS_CHAP2_PEER_CHAL_LEN;
381
382                         // Copy the provided remote host name
383                         rhostname[0] = '\0';
384                         if (in_len > 0) {
385                                 if (in_len >= sizeof(rhostname)) {
386                                         dbglog("PEAP: trimming really long peer name down");
387                                         in_len = sizeof(rhostname) - 1;
388                                 }
389                                 BCOPY(in_buf, rhostname, in_len);
390                                 rhostname[in_len] = '\0';
391                         }
392
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));
396
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)) {
400
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;
404
405                                 psm->chap->make_response(response, chap_id, user,
406                                                 challenge, secret, secret_len, NULL);
407
408                                 PUTCHAR(EAPT_MSCHAPV2, outp);
409                                 PUTCHAR(CHAP_RESPONSE, outp);
410                                 PUTCHAR(chap_id, outp);
411                                 PUTCHAR(0, 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;
417
418                         } else {
419                                 dbglog("PEAP: no CHAP secret for auth to %q", rhostname);
420                                 PUTCHAR(EAPT_NAK, outp);
421                                 ++used;
422                         }
423                         break;
424                 }
425                 case CHAP_SUCCESS: {
426
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;
431                         }
432
433                         PUTCHAR(EAPT_MSCHAPV2, outp);
434                         PUTCHAR(status, outp);
435                         used += 2;
436                         break;
437                 }
438                 case CHAP_FAILURE: {
439
440                         psm->chap->handle_failure(in_buf, in_len);
441                         PUTCHAR(EAPT_MSCHAPV2, outp);
442                         PUTCHAR(status, outp);
443                         used += 2;
444                         break;
445                 }
446                 default:
447                         break;
448                 }
449                 break;
450         }       // EAPT_MSCHAPv2
451 #endif
452         default:
453
454                 /* send compressed EAP NAK for any unknown packet */
455                 PUTCHAR(EAPT_NAK, outp);
456                 ++used;
457         }
458
459 done:
460
461         dbglog("PEAP: EAP (out): %.*B", used, psm->out_buf);
462         *out_len = used;
463 }
464
465 int peap_init(struct peap_state **ctx, const char *rhostname)
466 {
467         const SSL_METHOD *method;
468
469         if (!ctx)
470                 return -1;
471
472         tls_init();
473
474         struct peap_state *psm = malloc(sizeof(*psm));
475         if (!psm)
476                 novm("peap psm struct");
477         psm->in_buf = malloc(TLS_RECORD_MAX_SIZE);
478         if (!psm->in_buf)
479                 novm("peap tls buffer");
480         psm->out_buf = malloc(TLS_RECORD_MAX_SIZE);
481         if (!psm->out_buf)
482                 novm("peap tls buffer");
483         method = tls_method();
484         if (!method)
485                 novm("TLS_method() failed");
486         psm->ctx = SSL_CTX_new(method);
487         if (!psm->ctx)
488                 novm("SSL_CTX_new() failed");
489
490         /* Configure the default options */
491         tls_set_opts(psm->ctx);
492
493         /* Configure the max TLS version */
494         tls_set_version(psm->ctx, max_tls_version);
495
496         /* Configure the peer certificate callback */
497         tls_set_verify(psm->ctx, 5);
498
499         /* Configure CA locations */
500         if (tls_set_ca(psm->ctx, ca_path, cacert_file)) {
501                 fatal("Could not set CA verify locations");
502         }
503
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");
507         }
508
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);
519         *ctx = psm;
520         return 0;
521 }
522
523 void peap_finish(struct peap_state **psm) {
524
525         if (psm && *psm) {
526                 struct peap_state *tmp = *psm;
527
528                 if (tmp->ssl)
529                         SSL_free(tmp->ssl);
530
531                 if (tmp->ctx)
532                         SSL_CTX_free(tmp->ctx);
533
534                 if (tmp->info)
535                         tls_free_verify_info(&tmp->info);
536
537                 // NOTE: BIO and memory is freed as a part of SSL_free()
538
539                 free(*psm);
540                 *psm = NULL;
541         }
542 }
543
544 int peap_process(eap_state *esp, u_char id, u_char *inp, int len)
545 {
546         int ret;
547         int out_len;
548
549         struct peap_state *psm = esp->ea_peap;
550
551         if (esp->es_client.ea_id == id) {
552                 info("PEAP: retransmits are not supported..");
553                 return -1;
554         }
555
556         switch (*inp) {
557         case PEAP_S_FLAG_SET:
558                 dbglog("PEAP: S bit is set, starting PEAP phase 1");
559                 ret = SSL_do_handshake(psm->ssl);
560                 if (ret != 1) {
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));
564
565                 }
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);
568                 break;
569
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);
574                 peap_ack(esp, id);
575                 break;
576
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);
581                 peap_ack(esp, id);
582                 break;
583
584         case PEAP_L_FLAG_SET:
585         case PEAP_NO_FLAGS:
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);
590                 } else {
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);
594                 }
595
596                 if (psm->phase == PEAP_PHASE_1) {
597                         dbglog("PEAP TLS: continue handshake");
598                         ret = SSL_do_handshake(psm->ssl);
599                         if (ret != 1) {
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));
603                         }
604                         if (SSL_is_init_finished(psm->ssl))
605                                 psm->phase = PEAP_PHASE_2;
606                         if (BIO_ctrl_pending(psm->out_bio) == 0) {
607                                 peap_ack(esp, id);
608                                 break;
609                         }
610                         psm->read = 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);
614                         break;
615                 }
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);
621                 if (out_len > 0) {
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);
626                 }
627                 break;
628         }
629         return 0;
630 }
631
632 #else
633
634 u_char outpacket_buf[255];
635 int debug = 1;
636 int error_count = 0;
637 int unsuccess = 0;
638
639 /**
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
642  */
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
649         };
650
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
660         };
661
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
671         };
672
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
678         };
679
680         u_char response[60] = {};
681
682         // Set the inner MPPE keys (e.g. from CHAPv2)
683         mppe_set_keys(inner_mppe_keys, inner_mppe_keys + 16, 16);
684
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);
691                 return -1;
692         }
693
694         return 0;
695 }
696
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
703         };
704
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
710         };
711
712         u_char result[MPPE_MAX_KEY_SIZE];
713         int len;
714
715         mppe_clear_keys();
716
717         generate_mppe_keys(ipmk, 1);
718
719         len = mppe_get_recv_key(result, sizeof(result));
720         if (len != sizeof(result)) {
721                 dbglog("Invalid length of resulting MPPE recv key");
722                 return -1;
723         }
724
725         if (memcmp(result, outer_mppe_recv_key, len) != 0) {
726                 dbglog("Invalid result for outer mppe recv key");
727                 return -1;
728         }
729
730         len = mppe_get_send_key(result, sizeof(result));
731         if (len != sizeof(result)) {
732                 dbglog("Invalid length of resulting MPPE send key");
733                 return -1;
734         }
735
736         if (memcmp(result, outer_mppe_send_key, len) != 0) {
737                 dbglog("Invalid result for outer mppe send key");
738                 return -1;
739         }
740
741         return 0;
742 }
743
744 int main(int argc, char *argv[])
745 {
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,
752         };
753         int ret = -1;
754
755         ret = test_cmk(ipmk);
756         if (ret != 0) {
757                 return -1;
758         }
759
760         ret = test_mppe(ipmk);
761         if (ret != 0) {
762                 return -1;
763         }
764
765         return 0;
766 }
767
768 #endif