]> git.ozlabs.org Git - ppp.git/blob - pppd/peap.c
pppd: add experimental support for PEAP protocol, an extension of EAP
[ppp.git] / pppd / peap.c
1 /*
2  *      Copyright (c) 2011
3  *
4  * Authors:
5  *
6  *      Rustam Kovhaev <rkovhaev@gmail.com>
7  *
8  * PEAP has 2 phases,
9  * 1 - Outer EAP, where TLS session gets established
10  * 2 - Inner EAP, where inside TLS session with EAP MSCHAPV2 auth, or any
11  * other auth
12  *
13  * And so protocols encapsulation looks like this:
14  * Outer EAP -> TLS -> Inner EAP -> MSCHAPV2
15  * PEAP can compress an inner EAP packet prior to encapsulating it within
16  * the Data field of a PEAP packet by removing its Code, Identifier,
17  * and Length fields, and Microsoft PEAP server/client always does that
18  *
19  * Current implementation does not support:
20  * a) Fast reconnect
21  * b) Inner EAP fragmentation
22  * c) Any other auth other than MSCHAPV2
23  *
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <openssl/opensslv.h>
31 #include <openssl/ssl.h>
32 #include <openssl/hmac.h>
33 #include <openssl/rand.h>
34 #include <openssl/err.h>
35 #include "pppd.h"
36 #include "eap.h"
37 #include "chap-new.h"
38 #include "chap_ms.h"
39 #include "peap.h"
40
41 struct peap_state {
42         SSL_CTX *ctx;
43         SSL *ssl;
44         BIO *in_bio;
45         BIO *out_bio;
46
47         int written, read;
48         u_char *in_buf;
49         u_char *out_buf;
50
51         u_char ipmk[PEAP_TLV_IPMK_LEN];
52         u_char tk[PEAP_TLV_TK_LEN];
53         u_char nonce[PEAP_TLV_NONCE_LEN];
54 };
55
56 static struct peap_state *psm;
57 static int peap_phase;
58 extern bool tls_verify_cert;
59 static bool init;
60
61 static void ssl_init()
62 {
63 #if OPENSSL_VERSION_NUMBER < 0x10100000L
64         SSL_library_init();
65         SSL_load_error_strings();
66 #endif
67         init = 1;
68 }
69
70 /*
71  * K = Key, S = Seed, LEN = output length
72  * PRF+(K, S, LEN) = T1 | T2 | ... |Tn
73  * Where:
74  * T1 = HMAC-SHA1 (K, S | 0x01 | 0x00 | 0x00)
75  * T2 = HMAC-SHA1 (K, T1 | S | 0x02 | 0x00 | 0x00)
76  * ...
77  * Tn = HMAC-SHA1 (K, Tn-1 | S | n | 0x00 | 0x00)
78  * As shown, PRF+ is computed in iterations. The number of iterations (n)
79  * depends on the output length (LEN).
80  */
81 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)
82 {
83         int pos;
84         u_char *buf, *hash;
85         size_t max_iter, i, j, k;
86         u_int len;
87
88         max_iter = (pfr_len + SHA_HASH_LEN - 1) / SHA_HASH_LEN;
89         buf = malloc(seed_len + max_iter * SHA_HASH_LEN);
90         if (!buf)
91                 novm("pfr buffer");
92         hash = malloc(pfr_len + SHA_HASH_LEN);
93         if (!hash)
94                 novm("hash buffer");
95
96         for (i = 0; i < max_iter; i++) {
97                 j = 0;
98                 k = 0;
99
100                 if (i > 0)
101                         j = SHA_HASH_LEN;
102                 for (k = 0; k < seed_len; k++)
103                         buf[j + k] = seed[k];
104                 pos = j + k;
105                 buf[pos] = i + 1;
106                 pos++;
107                 buf[pos] = 0x00;
108                 pos++;
109                 buf[pos] = 0x00;
110                 pos++;
111                 if (!HMAC(EVP_sha1(), key, key_len, buf, pos, (hash + i * SHA_HASH_LEN), &len))
112                         fatal("HMAC() failed");
113                 for (j = 0; j < SHA_HASH_LEN; j++)
114                         buf[j] = hash[i * SHA_HASH_LEN + j];
115         }
116         BCOPY(hash, out_buf, pfr_len);
117         free(hash);
118         free(buf);
119 }
120
121 static void generate_cmk(u_char *tempkey, u_char *nonce, u_char *tlv_response_out, int client)
122 {
123         const char *label = PEAP_TLV_IPMK_SEED_LABEL;
124         u_char data_tlv[PEAP_TLV_DATA_LEN] = {0};
125         u_char isk[PEAP_TLV_ISK_LEN] = {0};
126         u_char ipmkseed[PEAP_TLV_IPMKSEED_LEN] = {0};
127         u_char cmk[PEAP_TLV_CMK_LEN] = {0};
128         u_char buf[PEAP_TLV_CMK_LEN + PEAP_TLV_IPMK_LEN] = {0};
129         u_char compound_mac[PEAP_TLV_COMP_MAC_LEN] = {0};
130         u_int len;
131
132         if (debug)
133                 info("PEAP CB: generate compound mac");
134         /* format outgoing CB TLV response packet */
135         data_tlv[1] = PEAP_TLV_TYPE;
136         data_tlv[3] = PEAP_TLV_LENGTH_FIELD;
137         if (client)
138                 data_tlv[7] = PEAP_TLV_SUBTYPE_RESPONSE;
139         else
140                 data_tlv[7] = PEAP_TLV_SUBTYPE_REQUEST;
141         BCOPY(nonce, (data_tlv + PEAP_TLV_HEADERLEN), PEAP_TLV_NONCE_LEN);
142         data_tlv[60] = EAPT_PEAP;
143
144         BCOPY(mppe_send_key, isk, MPPE_MAX_KEY_LEN);
145         BCOPY(mppe_recv_key, isk + MPPE_MAX_KEY_LEN, MPPE_MAX_KEY_LEN);
146
147         BCOPY(label, ipmkseed, strlen(label));
148         BCOPY(isk, ipmkseed + strlen(label), PEAP_TLV_ISK_LEN);
149         peap_prfplus(ipmkseed, PEAP_TLV_IPMKSEED_LEN,
150                         tempkey, PEAP_TLV_TEMPKEY_LEN, buf, PEAP_TLV_CMK_LEN + PEAP_TLV_IPMK_LEN);
151
152         BCOPY(buf, psm->ipmk, PEAP_TLV_IPMK_LEN);
153         BCOPY(buf + PEAP_TLV_IPMK_LEN, cmk, PEAP_TLV_CMK_LEN);
154         if (!HMAC(EVP_sha1(), cmk, PEAP_TLV_CMK_LEN, data_tlv, PEAP_TLV_DATA_LEN, compound_mac, &len))
155                 fatal("HMAC() failed");
156         BCOPY(compound_mac, data_tlv + PEAP_TLV_HEADERLEN + PEAP_TLV_NONCE_LEN, PEAP_TLV_COMP_MAC_LEN);
157         /* do not copy last byte to response packet */
158         BCOPY(data_tlv, tlv_response_out, PEAP_TLV_DATA_LEN - 1);
159 }
160
161 static void verify_compound_mac(u_char *in_buf)
162 {
163         u_char nonce[PEAP_TLV_NONCE_LEN] = {0};
164         u_char out_buf[PEAP_TLV_LEN] = {0};
165
166         BCOPY(in_buf, nonce, PEAP_TLV_NONCE_LEN);
167         generate_cmk(psm->tk, nonce, out_buf, 0);
168         if (memcmp((in_buf + PEAP_TLV_NONCE_LEN), (out_buf + PEAP_TLV_HEADERLEN + PEAP_TLV_NONCE_LEN), PEAP_TLV_CMK_LEN))
169                         fatal("server's CMK does not match client's CMK, potential MiTM");
170 }
171
172 static void generate_mppe_keys(void)
173 {
174         const char *label = PEAP_TLV_CSK_SEED_LABEL;
175         u_char csk[PEAP_TLV_CSK_LEN] = {0};
176         size_t len;
177
178         if (debug)
179                 info("PEAP CB: generate mppe keys");
180         len = strlen(label);
181         len++; /* CSK requires NULL byte in seed */
182         peap_prfplus((u_char *)label, len, psm->ipmk, PEAP_TLV_IPMK_LEN, csk, PEAP_TLV_CSK_LEN);
183
184         /*
185          * The first 64 bytes of the CSK are split into two MPPE keys, as follows.
186          *
187          * +-----------------------+------------------------+
188          * | First 32 bytes of CSK | Second 32 bytes of CSK |
189          * +-----------------------+------------------------+
190          * | MS-MPPE-Send-Key      | MS-MPPE-Recv-Key       |
191          * +-----------------------+------------------------+
192          */
193         BCOPY(csk, mppe_send_key, MPPE_MAX_KEY_LEN);
194         BCOPY(csk + 32, mppe_recv_key, MPPE_MAX_KEY_LEN);
195 }
196
197 static void dump(u_char *buf, int len)
198 {
199         int i = 0;
200
201         dbglog("len: %d bytes", len);
202         for (i = 0; i < len; i++)
203                 printf("%02x ", buf[i]);
204         printf("\n");
205 }
206
207 static void peap_ack(eap_state *esp, u_char id)
208 {
209         u_char *outp;
210
211         outp = outpacket_buf;
212         MAKEHEADER(outp, PPP_EAP);
213         PUTCHAR(EAP_RESPONSE, outp);
214         PUTCHAR(id, outp);
215         esp->es_client.ea_id = id;
216         PUTSHORT(PEAP_HEADERLEN, outp);
217         PUTCHAR(EAPT_PEAP, outp);
218         PUTCHAR(PEAP_FLAGS_ACK, outp);
219         output(esp->es_unit, outpacket_buf, PPP_HDRLEN + PEAP_HEADERLEN);
220 }
221
222 static void peap_response(eap_state *esp, u_char id, u_char *buf, int len)
223 {
224         u_char *outp;
225         int peap_len;
226
227         outp = outpacket_buf;
228         MAKEHEADER(outp, PPP_EAP);
229         PUTCHAR(EAP_RESPONSE, outp);
230         PUTCHAR(id, outp);
231         esp->es_client.ea_id = id;
232
233         if (peap_phase == PEAP_PHASE_1)
234                 peap_len = PEAP_HEADERLEN + PEAP_FRAGMENT_LENGTH_FIELD + len;
235         else
236                 peap_len = PEAP_HEADERLEN + len;
237
238         PUTSHORT(peap_len, outp);
239         PUTCHAR(EAPT_PEAP, outp);
240
241         if (peap_phase == PEAP_PHASE_1) {
242                 PUTCHAR(PEAP_L_FLAG_SET, outp);
243                 PUTLONG(len, outp);
244         } else
245                 PUTCHAR(PEAP_NO_FLAGS, outp);
246
247         BCOPY(buf, outp, len);
248         output(esp->es_unit, outpacket_buf, PPP_HDRLEN + peap_len);
249 }
250
251 void do_inner_eap(u_char *in_buf, int in_len, eap_state *esp, int id,
252                 char *rhostname, u_char *out_buf, int *out_len)
253 {
254         if (debug)
255                 dump(in_buf, in_len);
256         int used;
257         u_char *outp;
258
259         used = 0;
260         outp = out_buf;
261
262         if (*in_buf == EAPT_IDENTITY && in_len == 1) {
263                 PUTCHAR(EAPT_IDENTITY, outp);
264                 used++;
265                 BCOPY(esp->es_client.ea_name, outp,
266                                 esp->es_client.ea_namelen);
267                 used += esp->es_client.ea_namelen;
268         } else if (*(in_buf + EAP_HEADERLEN) == PEAP_CAPABILITIES_TYPE &&
269                         in_len  == (EAP_HEADERLEN + PEAP_CAPABILITIES_LEN)) {
270                 /* use original packet as template for response */
271                 BCOPY(in_buf, outp, EAP_HEADERLEN + PEAP_CAPABILITIES_LEN);
272                 PUTCHAR(EAP_RESPONSE, outp);
273                 PUTCHAR(id, outp);
274                 /* change last byte to 0 to disable fragmentation */
275                 *(outp + PEAP_CAPABILITIES_LEN + 1) = 0x00;
276                 used = EAP_HEADERLEN + PEAP_CAPABILITIES_LEN;
277         } else if (*in_buf == EAPT_TLS && in_len  == 2) {
278                 /* send NAK to EAP_TLS request */
279                 PUTCHAR(EAPT_NAK, outp);
280                 used++;
281                 PUTCHAR(EAPT_MSCHAPV2, outp);
282                 used++;
283         } else if (*in_buf == EAPT_MSCHAPV2 && *(in_buf + 1) == CHAP_CHALLENGE) {
284                 /* MSCHAPV2 auth */
285                 int secret_len;
286                 char secret[MAXSECRETLEN + 1];
287                 char *user;
288                 u_char user_len;
289                 u_char response[MS_CHAP2_RESPONSE_LEN];
290                 u_char auth_response[MS_AUTH_RESPONSE_LENGTH + 1];
291                 u_char chap_id;
292                 u_char rchallenge[MS_CHAP2_PEER_CHAL_LEN];
293
294                 user = esp->es_client.ea_name;
295                 user_len = esp->es_client.ea_namelen;
296                 chap_id = *(in_buf + 2);
297                 BCOPY((in_buf + 6), rchallenge, MS_CHAP2_PEER_CHAL_LEN);
298                 if (!get_secret(esp->es_unit, esp->es_client.ea_name,
299                                         rhostname, secret, &secret_len, 0))
300                         fatal("Can't read password file");
301                 /* MSCHAPV2 response */
302                 ChapMS2(rchallenge, NULL, esp->es_client.ea_name,
303                                 secret, secret_len, response, auth_response, MS_CHAP2_AUTHENTICATEE);
304                 PUTCHAR(EAPT_MSCHAPV2, outp);
305                 PUTCHAR(CHAP_RESPONSE, outp);
306                 PUTCHAR(chap_id, outp);
307                 PUTCHAR(0, outp);
308                 PUTCHAR(5 + user_len + MS_CHAP2_RESPONSE_LEN, outp);
309                 PUTCHAR(MS_CHAP2_RESPONSE_LEN, outp)
310                 BCOPY(response, outp, MS_CHAP2_RESPONSE_LEN);
311                 outp = outp + MS_CHAP2_RESPONSE_LEN;
312                 BCOPY(user, outp, user_len);
313                 used = 5 + user_len + MS_CHAP2_RESPONSE_LEN + 1;
314         } else if (*in_buf == EAPT_MSCHAPV2 && *(in_buf + 1) == CHAP_SUCCESS) {
315                 PUTCHAR(EAPT_MSCHAPV2, outp);
316                 used++;
317                 PUTCHAR(CHAP_SUCCESS, outp);
318                 used++;
319                 auth_peer_success(esp->es_unit, PPP_CHAP, CHAP_MICROSOFT_V2,
320                                 esp->es_server.ea_peer, esp->es_server.ea_peerlen);
321         } else if (*(in_buf + EAP_HEADERLEN + PEAP_TLV_HEADERLEN) == PEAP_TLV_TYPE &&
322                         in_len == PEAP_TLV_LEN) {
323                 /* PEAP TLV message, do cryptobinding */
324                 SSL_export_keying_material(psm->ssl, psm->tk, PEAP_TLV_TK_LEN,
325                                 PEAP_TLV_TK_SEED_LABEL, strlen(PEAP_TLV_TK_SEED_LABEL), NULL, 0, 0);
326                 /* verify server's CMK */
327                 verify_compound_mac(in_buf + EAP_HEADERLEN + PEAP_TLV_RESULT_LEN + PEAP_TLV_HEADERLEN);
328                 /* generate client's CMK with new nonce */
329                 PUTCHAR(EAP_RESPONSE, outp);
330                 PUTCHAR(id, outp);
331                 PUTSHORT(PEAP_TLV_LEN, outp);
332                 BCOPY(in_buf + EAP_HEADERLEN, outp, PEAP_TLV_RESULT_LEN);
333                 outp = outp + PEAP_TLV_RESULT_LEN;
334                 RAND_bytes(psm->nonce, PEAP_TLV_NONCE_LEN);
335                 generate_cmk(psm->tk, psm->nonce, outp, 1);
336                 /* set mppe keys */
337                 generate_mppe_keys();
338                 used = PEAP_TLV_LEN;
339         } else {
340                 /* send compressed EAP NAK for any unknown packet */
341                 PUTCHAR(EAPT_NAK, outp);
342                 ++used;
343         }
344
345         if (debug)
346                 dump(psm->out_buf, used);
347         *out_len = used;
348 }
349
350 void allocate_buffers(void)
351 {
352         const SSL_METHOD *method;
353
354         psm = malloc(sizeof(*psm));
355         if (!psm)
356                 novm("peap psm struct");
357         psm->in_buf = malloc(TLS_RECORD_MAX_SIZE);
358         if (!psm->in_buf)
359                 novm("peap tls buffer");
360         psm->out_buf = malloc(TLS_RECORD_MAX_SIZE);
361         if (!psm->out_buf)
362                 novm("peap tls buffer");
363         method = TLS_method();
364         if (!method)
365                 novm("TLS_method() failed");
366         psm->ctx = SSL_CTX_new(method);
367         if (!psm->ctx)
368                 novm("SSL_CTX_new() failed");
369
370         if (!tls_verify_cert)
371                 SSL_CTX_set_verify(psm->ctx, SSL_VERIFY_NONE, NULL);
372         else
373                 SSL_CTX_set_verify(psm->ctx, SSL_VERIFY_PEER, NULL);
374         info("PEAP: SSL certificate validation is %s", tls_verify_cert ? "enabled" : "disabled");
375
376         SSL_CTX_set_options(psm->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
377
378         psm->out_bio = BIO_new(BIO_s_mem());
379         psm->in_bio = BIO_new(BIO_s_mem());
380         BIO_set_mem_eof_return(psm->out_bio, -1);
381         BIO_set_mem_eof_return(psm->in_bio, -1);
382         psm->ssl = SSL_new(psm->ctx);
383         SSL_set_bio(psm->ssl, psm->in_bio, psm->out_bio);
384         SSL_set_connect_state(psm->ssl);
385         peap_phase = PEAP_PHASE_1;
386 }
387
388 void peap_process(eap_state *esp, u_char id, u_char *inp, int len, char *rhostname)
389 {
390         int ret;
391         int out_len;
392
393         if (!init)
394                 ssl_init();
395
396         if (esp->es_client.ea_id == id) {
397                 info("PEAP: retransmits are not supported..");
398                 return;
399         }
400
401         switch (*inp) {
402         case PEAP_S_FLAG_SET:
403                 allocate_buffers();
404                 if (debug)
405                         info("PEAP: S bit is set, starting PEAP phase 1");
406                 ret = SSL_do_handshake(psm->ssl);
407                 if (ret != 1) {
408                         ret = SSL_get_error(psm->ssl, ret);
409                         if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE)
410                                 fatal("SSL_do_handshake(): %s", ERR_error_string(ret, NULL));
411
412                 }
413                 psm->read = BIO_read(psm->out_bio, psm->out_buf, TLS_RECORD_MAX_SIZE);
414                 peap_response(esp, id, psm->out_buf, psm->read);
415                 break;
416
417         case PEAP_LM_FLAG_SET:
418                 if (debug)
419                         info("PEAP TLS: LM bits are set, need to get more TLS fragments");
420                 inp = inp + PEAP_FRAGMENT_LENGTH_FIELD + PEAP_FLAGS_FIELD;
421                 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FRAGMENT_LENGTH_FIELD - PEAP_FLAGS_FIELD);
422                 peap_ack(esp, id);
423                 break;
424
425         case PEAP_M_FLAG_SET:
426                 if (debug)
427                         info("PEAP TLS: M bit is set, need to get more TLS fragments");
428                 inp = inp + PEAP_FLAGS_FIELD;
429                 psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FLAGS_FIELD);
430                 peap_ack(esp, id);
431                 break;
432
433         case PEAP_L_FLAG_SET:
434         case PEAP_NO_FLAGS:
435                 if (*inp == PEAP_L_FLAG_SET) {
436                         if (debug)
437                                 info("PEAP TLS: L bit is set");
438                         inp = inp + PEAP_FRAGMENT_LENGTH_FIELD + PEAP_FLAGS_FIELD;
439                         psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FRAGMENT_LENGTH_FIELD - PEAP_FLAGS_FIELD);
440                 } else {
441                         if (debug)
442                                 info("PEAP TLS: all bits are off");
443                         inp = inp + PEAP_FLAGS_FIELD;
444                         psm->written = BIO_write(psm->in_bio, inp, len - PEAP_FLAGS_FIELD);
445                 }
446
447                 if (peap_phase == PEAP_PHASE_1) {
448                         if (debug)
449                                 info("PEAP TLS: continue handshake");
450                         ret = SSL_do_handshake(psm->ssl);
451                         if (ret != 1) {
452                                 ret = SSL_get_error(psm->ssl, ret);
453                                 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE)
454                                         fatal("SSL_do_handshake(): %s", ERR_error_string(ret, NULL));
455                         }
456                         if (SSL_is_init_finished(psm->ssl))
457                                 peap_phase = PEAP_PHASE_2;
458                         if (BIO_ctrl_pending(psm->out_bio) == 0) {
459                                 peap_ack(esp, id);
460                                 break;
461                         }
462                         psm->read = 0;
463                         psm->read = BIO_read(psm->out_bio, psm->out_buf,
464                                         TLS_RECORD_MAX_SIZE);
465                         peap_response(esp, id, psm->out_buf, psm->read);
466                         break;
467                 }
468                 psm->read = SSL_read(psm->ssl, psm->in_buf,
469                                 TLS_RECORD_MAX_SIZE);
470                 out_len = TLS_RECORD_MAX_SIZE;
471                 do_inner_eap(psm->in_buf, psm->read, esp, id, rhostname,
472                                 psm->out_buf, &out_len);
473                 psm->written = SSL_write(psm->ssl, psm->out_buf, out_len);
474                 psm->read = BIO_read(psm->out_bio, psm->out_buf,
475                                 TLS_RECORD_MAX_SIZE);
476                 peap_response(esp, id, psm->out_buf, psm->read);
477                 break;
478         }
479 }