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