1 From 044a5b1e5d878c519143b71a44b3d5b0ca91de3b Mon Sep 17 00:00:00 2001
2 From: Michal Sekletar <msekleta@redhat.com>
3 Date: Mon, 7 Apr 2014 14:56:56 +0200
4 Subject: [PATCH 17/25] pppd: rebase EAP-TLS patch v0.994
7 README.eap-tls | 169 +++++++
8 etc.ppp/eaptls-client | 10 +
9 etc.ppp/eaptls-server | 11 +
10 etc.ppp/openssl.cnf | 14 +
11 linux/Makefile.top | 6 +-
12 pppd/Makefile.linux | 12 +
13 pppd/auth.c | 414 ++++++++++++++-
16 pppd/eap-tls.c | 1174 +++++++++++++++++++++++++++++++++++++++++++
17 pppd/eap-tls.h | 107 ++++
18 pppd/eap.c | 462 ++++++++++++++++-
23 pppd/pathnames.h | 7 +
24 pppd/plugins/Makefile.linux | 3 +
25 pppd/plugins/passprompt.c | 3 +
26 pppd/plugins/passwordfd.c | 4 +
28 21 files changed, 2461 insertions(+), 15 deletions(-)
29 create mode 100644 README.eap-tls
30 create mode 100644 etc.ppp/eaptls-client
31 create mode 100644 etc.ppp/eaptls-server
32 create mode 100644 etc.ppp/openssl.cnf
33 create mode 100644 pppd/eap-tls.c
34 create mode 100644 pppd/eap-tls.h
36 diff --git a/README.eap-tls b/README.eap-tls
38 index 0000000..0a4fee9
42 +EAP-TLS authentication support for PPP
43 +======================================
47 + The Extensible Authentication Protocol (EAP; RFC 3748) is a
48 + security protocol that can be used with PPP. It provides a means
49 + to plug in multiple optional authentication methods.
51 + Transport Level Security (TLS; RFC 2246) provides for mutual
52 + authentication, integrity-protected ciphersuite negotiation and
53 + key exchange between two endpoints. It also provides for optional
56 + EAP-TLS (RFC 2716) incapsulates the TLS messages in EAP packets,
57 + allowing TLS mutual authentication to be used as a generic EAP
58 + mechanism. It also provides optional encryption using the MPPE
61 + This patch provide EAP-TLS support to pppd.
62 + This authentication method can be used in both client or server
67 + To build pppd with EAP-TLS support, OpenSSL (http://www.openssl.org)
68 + is required. Any version from 0.9.7 should work.
70 + Configure, compile, and install as usual.
74 + On the client side there are two ways to configure EAP-TLS:
76 + 1. supply the appropriate 'ca', 'cert' and 'key' command-line parameters
78 + 2. edit the /etc/ppp/eaptls-client file.
79 + Insert a line for each system with which you use EAP-TLS.
80 + The line is composed of this fields separated by tab:
83 + The name used by the client for authentication, can be *
85 + The name of the server, can be *
86 + - Client certificate file
87 + The file containing the certificate chain for the
88 + client in PEM format
89 + - Server certificate file
90 + If you want to specify the certificate that the
91 + server is allowed to use, put the certificate file name.
92 + Else put a dash '-'.
93 + - CA certificate file
94 + The file containing the trusted CA certificates in PEM
96 + - Client private key file
97 + The file containing the client private key in PEM format.
100 + On the server side edit the /etc/ppp/eaptls-server file.
101 + Insert a line for each system with which you use EAP-TLS.
102 + The line is composed of this fields separated by tab:
105 + The name used by the client for authentication, can be *
107 + The name of the server, can be *
108 + - Client certificate file
109 + If you want to specify the certificate that the
110 + client is allowed to use, put the certificate file name.
111 + Else put a dash '-'.
112 + - Server certificate file
113 + The file containing the certificate chain for the
114 + server in PEM format
115 + - CA certificate file
116 + The file containing the trusted CA certificates in PEM
118 + - Client private key file
119 + The file containing the server private key in PEM format.
121 + A list of IP addresses the client is allowed to use.
124 + OpenSSL engine support is included starting with v0.95 of this patch.
125 + Currently the only engine tested is the 'pkcs11' engine (hardware token
126 + support). To use the 'pksc11' engine:
127 + - Use a special private key fileiname in the /etc/ppp/eaptls-client file:
128 + <engine>:<identifier>
132 + - The certificate can also be loaded from the 'pkcs11' engine using
133 + a special client certificate filename in the /etc/ppp/eaptls-client file:
134 + <engine>:<identifier>
138 + - Create an /etc/ppp/openssl.cnf file to load the right OpenSSL engine prior
139 + to starting 'pppd'. A sample openssl.cnf file is
141 + openssl_conf = openssl_def
144 + engines = engine_section
147 + pkcs11 = pkcs11_section
151 + dynamic_path = /usr/lib64/openssl/engines/engine_pkcs11.so
152 + MODULE_PATH = /usr/lib64/libeTPkcs11.so
155 + - There are two ways to specify a password/PIN for the PKCS11 engine:
156 + - inside the openssl.cnf file using
157 + PIN = your-secret-pin
158 + Note The keyword 'PIN' is case sensitive!
159 + - Using the 'password' in the ppp options file.
160 + From v0.97 of the eap-tls patch the password can also be supplied
161 + using the appropriate 'eaptls_passwd_hook' (see plugins/passprompt.c
167 + These pppd options are available:
170 + Use the CA public certificate found in <ca-file> in PEM format
172 + Use the client public certificate found in <cert-file> in PEM format
173 + or in engine:engine_id format
175 + Use the client private key found in <key-file> in PEM format
176 + or in engine:engine_id format
178 + Use CRL files from dir. It contains CRL files in PEM
179 + format and each file contains a CRL. The files are looked up
180 + by the issuer name hash value. Use the c_rehash utility
181 + to create necessary links.
183 + If the peer doesn't ask us to authenticate or doesn't use eap
184 + to authenticate us, disconnect.
187 + password-encrypted certificates can be used as of v0.94 of this
188 + patch. The password for the eap-tls.key file is specified using
191 + statement in the ppp options file, or by using the appropriate
192 + plugin which supplies a 'eaptls_passwd_hook' routine.
196 + If you're setting up a pppd server, edit the EAP-TLS configuration file
197 + as written above and then run pppd with the 'auth' option to authenticate
198 + the client. The EAP-TLS method will be used if the other eap methods can't
199 + be used (no secrets).
201 + If you're setting up a client, edit the configuration file and then run
202 + pppd with 'remotename' option to specify the server name. Add the
203 + 'need-peer-eap' option if you want to be sure the peer ask you to
204 + authenticate (and to use eap) and to disconnect if it doesn't.
208 + This is experimental code.
209 + Send suggestions and comments to Jan Just Keijser <janjust@nikhef.nl>
211 diff --git a/etc.ppp/eaptls-client b/etc.ppp/eaptls-client
213 index 0000000..7782f0e
215 +++ b/etc.ppp/eaptls-client
217 +# Parameters for authentication using EAP-TLS (client)
219 +# client name (can be *)
220 +# server name (can be *)
221 +# client certificate file (required)
222 +# server certificate file (optional, if unused put '-')
223 +# CA certificate file (required)
224 +# client private key file (required)
226 +#client server /root/cert/client.crt - /root/cert/ca.crt /root/cert/client.key
227 diff --git a/etc.ppp/eaptls-server b/etc.ppp/eaptls-server
229 index 0000000..fa53cbd
231 +++ b/etc.ppp/eaptls-server
233 +# Parameters for authentication using EAP-TLS (server)
235 +# client name (can be *)
236 +# server name (can be *)
237 +# client certificate file (optional, if unused put '-')
238 +# server certificate file (required)
239 +# CA certificate file (required)
240 +# server private key file (required)
241 +# allowed addresses (required, can be *)
243 +#client server - /root/cert/server.crt /root/cert/ca.crt /root/cert/server.key 192.168.1.0/24
244 diff --git a/etc.ppp/openssl.cnf b/etc.ppp/openssl.cnf
246 index 0000000..dd32f30
248 +++ b/etc.ppp/openssl.cnf
250 +openssl_conf = openssl_def
253 +engines = engine_section
256 +pkcs11 = pkcs11_section
260 +dynamic_path = /usr/lib64/openssl/engines/engine_pkcs11.so
261 +MODULE_PATH = /usr/lib64/libeTPkcs11.so
264 diff --git a/linux/Makefile.top b/linux/Makefile.top
265 index f42efd5..9a8945a 100644
266 --- a/linux/Makefile.top
267 +++ b/linux/Makefile.top
268 @@ -28,7 +28,7 @@ install-progs:
269 cd pppdump; $(MAKE) $(MFLAGS) install
271 install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
272 - $(ETCDIR)/chap-secrets
273 + $(ETCDIR)/chap-secrets $(ETCDIR)/eaptls-server $(ETCDIR)/eaptls-client
276 cd pppd; $(MAKE) $(MFLAGS) install-devel
277 @@ -39,6 +39,10 @@ $(ETCDIR)/pap-secrets:
278 $(INSTALL) -c -m 600 etc.ppp/pap-secrets $@
279 $(ETCDIR)/chap-secrets:
280 $(INSTALL) -c -m 600 etc.ppp/chap-secrets $@
281 +$(ETCDIR)/eaptls-server:
282 + $(INSTALL) -c -m 600 etc.ppp/eaptls-server $@
283 +$(ETCDIR)/eaptls-client:
284 + $(INSTALL) -c -m 600 etc.ppp/eaptls-client $@
287 $(INSTALL) -d -m 755 $@
288 diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux
289 index 65700fa..53df4d2 100644
290 --- a/pppd/Makefile.linux
291 +++ b/pppd/Makefile.linux
292 @@ -76,6 +76,9 @@ CBCP=y
296 +# Enable EAP-TLS authentication (requires libssl and libcrypto)
301 INCLUDE_DIRS= -I../include
302 @@ -115,6 +118,15 @@ HEADERS += sha1.h
308 +CFLAGS += -DUSE_EAPTLS=1 -I/usr/kerberos/include
309 +LIBS += -lssl -lcrypto
310 +PPPDSRC += eap-tls.c
311 +HEADERS += eap-tls.h
312 +PPPDOBJS += eap-tls.o
316 CFLAGS += -DHAS_SHADOW
317 #LIBS += -lshadow $(LIBS)
318 diff --git a/pppd/auth.c b/pppd/auth.c
319 index 9e957fa..88cbdb6 100644
324 #include "chap-new.h"
327 +#include "eap-tls.h"
332 @@ -183,6 +186,11 @@ int (*chap_check_hook) __P((void)) = NULL;
333 /* Hook for a plugin to get the CHAP password for authenticating us */
334 int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
337 +/* Hook for a plugin to get the EAP-TLS password for authenticating us */
338 +int (*eaptls_passwd_hook) __P((char *user, char *passwd)) = NULL;
341 /* Hook for a plugin to say whether it is OK if the peer
342 refuses to authenticate. */
343 int (*null_auth_hook) __P((struct wordlist **paddrs,
344 @@ -238,6 +246,13 @@ bool explicit_remote = 0; /* User specified explicit remote name */
345 bool explicit_user = 0; /* Set if "user" option supplied */
346 bool explicit_passwd = 0; /* Set if "password" option supplied */
347 char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
349 +char *cacert_file = NULL; /* CA certificate file (pem format) */
350 +char *cert_file = NULL; /* client certificate file (pem format) */
351 +char *privkey_file = NULL; /* client private key file (pem format) */
352 +char *crl_dir = NULL; /* directory containing CRL files */
353 +bool need_peer_eap = 0; /* Require peer to authenticate us */
356 static char *uafname; /* name of most recent +ua file */
358 @@ -254,6 +269,19 @@ static int have_pap_secret __P((int *));
359 static int have_chap_secret __P((char *, char *, int, int *));
360 static int have_srp_secret __P((char *client, char *server, int need_ip,
364 +static int have_eaptls_secret_server
365 +__P((char *client, char *server, int need_ip, int *lacks_ipp));
366 +static int have_eaptls_secret_client __P((char *client, char *server));
367 +static int scan_authfile_eaptls __P((FILE * f, char *client, char *server,
368 + char *cli_cert, char *serv_cert,
369 + char *ca_cert, char *pk,
370 + struct wordlist ** addrs,
371 + struct wordlist ** opts,
372 + char *filename, int flags));
375 static int ip_addr_check __P((u_int32_t, struct permitted_ip *));
376 static int scan_authfile __P((FILE *, char *, char *, char *,
377 struct wordlist **, struct wordlist **,
378 @@ -401,6 +429,14 @@ option_t auth_options[] = {
379 "Set telephone number(s) which are allowed to connect",
380 OPT_PRIV | OPT_A2LIST },
383 + { "ca", o_string, &cacert_file, "EAP-TLS CA certificate in PEM format" },
384 + { "cert", o_string, &cert_file, "EAP-TLS client certificate in PEM format" },
385 + { "key", o_string, &privkey_file, "EAP-TLS client private key in PEM format" },
386 + { "crl-dir", o_string, &crl_dir, "Use CRLs in directory" },
387 + { "need-peer-eap", o_bool, &need_peer_eap,
388 + "Require the peer to authenticate us", 1 },
389 +#endif /* USE_EAPTLS */
393 @@ -730,6 +766,9 @@ link_established(unit)
394 lcp_options *wo = &lcp_wantoptions[unit];
395 lcp_options *go = &lcp_gotoptions[unit];
396 lcp_options *ho = &lcp_hisoptions[unit];
398 + lcp_options *ao = &lcp_allowoptions[unit];
401 struct protent *protp;
403 @@ -764,6 +803,22 @@ link_established(unit)
408 + if (need_peer_eap && !ao->neg_eap) {
409 + warn("eap required to authenticate us but no suitable secrets");
410 + lcp_close(unit, "couldn't negotiate eap");
411 + status = EXIT_AUTH_TOPEER_FAILED;
415 + if (need_peer_eap && !ho->neg_eap) {
416 + warn("peer doesn't want to authenticate us with eap");
417 + lcp_close(unit, "couldn't negotiate eap");
418 + status = EXIT_PEER_AUTH_FAILED;
423 new_phase(PHASE_AUTHENTICATE);
426 @@ -1117,7 +1172,7 @@ np_down(unit, proto)
427 UNTIMEOUT(connect_time_expired, NULL);
429 UNTIMEOUT(check_maxoctets, NULL);
432 new_phase(PHASE_NETWORK);
435 @@ -1144,7 +1199,7 @@ check_maxoctets(arg)
437 update_link_stats(ifunit);
441 switch(maxoctets_dir) {
442 case PPP_OCTETS_DIRECTION_IN:
443 used = link_stats.bytes_in;
444 @@ -1277,6 +1332,15 @@ auth_check_options()
445 our_name, 1, &lacks_ip);
449 + if (!can_auth && wo->neg_eap) {
451 + have_eaptls_secret_server((explicit_remote ? remote_name :
452 + NULL), our_name, 1, &lacks_ip);
457 if (auth_required && !can_auth && noauth_addrs == NULL) {
460 @@ -1331,7 +1395,11 @@ auth_reset(unit)
462 (hadchap == 1 || (hadchap == -1 && have_chap_secret(user,
463 (explicit_remote? remote_name: NULL), 0, NULL))) ||
464 - have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL));
465 + have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL)
467 + || have_eaptls_secret_client(user, (explicit_remote? remote_name: NULL))
472 if (go->neg_upap && !uselogin && !have_pap_secret(NULL))
473 @@ -1346,8 +1414,14 @@ auth_reset(unit)
474 !have_chap_secret((explicit_remote? remote_name: NULL), our_name,
476 !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1,
480 + && !have_eaptls_secret_server((explicit_remote? remote_name: NULL),
489 @@ -1707,6 +1781,7 @@ have_srp_secret(client, server, need_ip, lacks_ipp)
495 * get_secret - open the CHAP secret file and return the secret
496 * for authenticating the given client on the given server.
497 @@ -2359,3 +2434,334 @@ auth_script(script)
499 auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0);
505 +have_eaptls_secret_server(client, server, need_ip, lacks_ipp)
514 + struct wordlist *addrs;
515 + char servcertfile[MAXWORDLEN];
516 + char clicertfile[MAXWORDLEN];
517 + char cacertfile[MAXWORDLEN];
518 + char pkfile[MAXWORDLEN];
520 + filename = _PATH_EAPTLSSERVFILE;
521 + f = fopen(filename, "r");
525 + if (client != NULL && client[0] == 0)
527 + else if (server != NULL && server[0] == 0)
531 + scan_authfile_eaptls(f, client, server, clicertfile, servcertfile,
532 + cacertfile, pkfile, &addrs, NULL, filename,
538 + if (ret >= 0 && !eaptls_init_ssl(1, cacertfile, servcertfile,
539 + clicertfile, pkfile))
543 + if (ret >= 0 && need_ip && !some_ip_ok(addrs)) {
544 + if (lacks_ipp != 0)
549 + free_wordlist(addrs);
556 +have_eaptls_secret_client(client, server)
563 + struct wordlist *addrs = NULL;
564 + char servcertfile[MAXWORDLEN];
565 + char clicertfile[MAXWORDLEN];
566 + char cacertfile[MAXWORDLEN];
567 + char pkfile[MAXWORDLEN];
569 + if (client != NULL && client[0] == 0)
571 + else if (server != NULL && server[0] == 0)
574 + if (cacert_file && cert_file && privkey_file)
577 + filename = _PATH_EAPTLSCLIFILE;
578 + f = fopen(filename, "r");
583 + scan_authfile_eaptls(f, client, server, clicertfile, servcertfile,
584 + cacertfile, pkfile, &addrs, NULL, filename,
589 + if (ret >= 0 && !eaptls_init_ssl(0, cacertfile, clicertfile,
590 + servcertfile, pkfile))
595 + free_wordlist(addrs);
602 +scan_authfile_eaptls(f, client, server, cli_cert, serv_cert, ca_cert, pk,
603 + addrs, opts, filename, flags)
611 + struct wordlist **addrs;
612 + struct wordlist **opts;
617 + int got_flag, best_flag;
618 + struct wordlist *ap, *addr_list, *alist, **app;
619 + char word[MAXWORDLEN];
626 + if (!getword(f, word, &newline, filename))
627 + return -1; /* file is empty??? */
632 + * Skip until we find a word at the start of a line.
634 + while (!newline && getword(f, word, &newline, filename));
636 + break; /* got to end of file */
639 + * Got a client - check if it's a match or a wildcard.
642 + if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) {
647 + got_flag = NONWILD_CLIENT;
650 + * Now get a server and check if it matches.
652 + if (!getword(f, word, &newline, filename))
656 + if (!ISWILD(word)) {
657 + if (server != NULL && strcmp(word, server) != 0)
659 + got_flag |= NONWILD_SERVER;
663 + * Got some sort of a match - see if it's better than what
666 + if (got_flag <= best_flag)
672 + if (!getword(f, word, &newline, filename))
676 + if (strcmp(word, "-") != 0) {
677 + strlcpy(cli_cert, word, MAXWORDLEN);
684 + if (!getword(f, word, &newline, filename))
688 + if (strcmp(word, "-") != 0) {
689 + strlcpy(serv_cert, word, MAXWORDLEN);
696 + if (!getword(f, word, &newline, filename))
700 + strlcpy(ca_cert, word, MAXWORDLEN);
705 + if (!getword(f, word, &newline, filename))
709 + strlcpy(pk, word, MAXWORDLEN);
713 + * Now read address authorization info and make a wordlist.
717 + if (!getword(f, word, &newline, filename) || newline)
719 + ap = (struct wordlist *)
720 + malloc(sizeof(struct wordlist) + strlen(word) + 1);
722 + novm("authorized addresses");
723 + ap->word = (char *) (ap + 1);
724 + strcpy(ap->word, word);
730 + * This is the best so far; remember it.
732 + best_flag = got_flag;
734 + free_wordlist(addr_list);
741 + /* scan for a -- word indicating the start of options */
742 + for (app = &addr_list; (ap = *app) != NULL; app = &ap->next)
743 + if (strcmp(ap->word, "--") == 0)
745 + /* ap = start of options */
747 + ap = ap->next; /* first option */
748 + free(*app); /* free the "--" word */
749 + *app = NULL; /* terminate addr list */
753 + else if (ap != NULL)
756 + *addrs = addr_list;
757 + else if (addr_list != NULL)
758 + free_wordlist(addr_list);
765 +get_eaptls_secret(unit, client, server, clicertfile, servcertfile,
766 + cacertfile, pkfile, am_server)
771 + char *servcertfile;
778 + char *filename = NULL;
779 + struct wordlist *addrs = NULL;
780 + struct wordlist *opts = NULL;
782 + /* in client mode the ca+cert+privkey can also be specified as options */
783 + if (!am_server && cacert_file && cert_file && privkey_file )
785 + strlcpy( clicertfile, cert_file, MAXWORDLEN );
786 + strlcpy( cacertfile, cacert_file, MAXWORDLEN );
787 + strlcpy( pkfile, privkey_file, MAXWORDLEN );
788 + servcertfile[0] = '\0';
792 + filename = (am_server ? _PATH_EAPTLSSERVFILE : _PATH_EAPTLSCLIFILE);
795 + fp = fopen(filename, "r");
798 + error("Can't open eap-tls secret file %s: %m", filename);
802 + check_access(fp, filename);
804 + ret = scan_authfile_eaptls(fp, client, server, clicertfile, servcertfile,
805 + cacertfile, pkfile, &addrs, &opts, filename, 0);
809 + if (ret < 0) return 0;
812 + if (eaptls_passwd_hook)
814 + dbglog( "Calling eaptls password hook" );
815 + if ( (*eaptls_passwd_hook)(pkfile, passwd) < 0)
817 + error("Unable to obtain EAP-TLS password for %s (%s) from plugin",
823 + set_allowed_addrs(unit, addrs, opts);
824 + else if (opts != NULL)
825 + free_wordlist(opts);
827 + free_wordlist(addrs);
832 diff --git a/pppd/ccp.c b/pppd/ccp.c
833 index 5814f35..7dead23 100644
836 @@ -540,6 +540,9 @@ ccp_resetci(f)
838 ccp_options *ao = &ccp_allowoptions[f->unit];
839 int auth_mschap_bits = auth_done[f->unit];
841 + int auth_eap_bits = auth_done[f->unit];
846 @@ -567,8 +570,23 @@ ccp_resetci(f)
847 lcp_close(f->unit, "MPPE required but not available");
853 + * MPPE is also possible in combination with EAP-TLS.
854 + * It is not possible to detect if we're doing EAP or EAP-TLS
855 + * at this stage, hence we accept all forms of EAP. If TLS is
856 + * not used then the MPPE keys will not be derived anyway.
858 + /* Leave only the eap auth bits set */
859 + auth_eap_bits &= (EAP_WITHPEER | EAP_PEER );
861 + if ((numbits == 0) && (auth_eap_bits == 0)) {
862 + error("MPPE required, but MS-CHAP[v2] nor EAP-TLS auth are performed.");
865 - error("MPPE required, but MS-CHAP[v2] auth not performed.");
866 + error("MPPE required, but MS-CHAP[v2] auth not performed.");
868 lcp_close(f->unit, "MPPE required but not available");
871 diff --git a/pppd/chap-md5.c b/pppd/chap-md5.c
872 index 77dd4ec..269b52c 100644
873 --- a/pppd/chap-md5.c
874 +++ b/pppd/chap-md5.c
876 #include "chap-new.h"
877 #include "chap-md5.h"
880 +#include "eap-tls.h"
883 +#endif /* USE_EAPTLS */
885 #define MD5_HASH_SIZE 16
886 #define MD5_MIN_CHALLENGE 16
887 diff --git a/pppd/eap-tls.c b/pppd/eap-tls.c
889 index 0000000..a3aea5a
894 + * eap-tls.c - EAP-TLS implementation for PPP
896 + * Copyright (c) Beniamino Galvani 2005 All rights reserved.
898 + * Redistribution and use in source and binary forms, with or without
899 + * modification, are permitted provided that the following conditions
902 + * 1. Redistributions of source code must retain the above copyright
903 + * notice, this list of conditions and the following disclaimer.
905 + * 2. Redistributions in binary form must reproduce the above copyright
906 + * notice, this list of conditions and the following disclaimer in
907 + * the documentation and/or other materials provided with the
910 + * 3. The name(s) of the authors of this software must not be used to
911 + * endorse or promote products derived from this software without
912 + * prior written permission.
914 + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
915 + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
916 + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
917 + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
918 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
919 + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
920 + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
926 +#include <sys/types.h>
927 +#include <sys/stat.h>
930 +#include <openssl/conf.h>
931 +#include <openssl/engine.h>
932 +#include <openssl/hmac.h>
933 +#include <openssl/err.h>
934 +#include <openssl/x509v3.h>
938 +#include "eap-tls.h"
941 +#include "pathnames.h"
943 +/* The openssl configuration file and engines can be loaded only once */
944 +static CONF *ssl_config = NULL;
945 +static ENGINE *cert_engine = NULL;
946 +static ENGINE *pkey_engine = NULL;
951 + * TLS PRF from RFC 2246
953 +static void P_hash(const EVP_MD *evp_md,
954 + const unsigned char *secret, unsigned int secret_len,
955 + const unsigned char *seed, unsigned int seed_len,
956 + unsigned char *out, unsigned int out_len)
958 + HMAC_CTX ctx_a, ctx_out;
959 + unsigned char a[HMAC_MAX_MD_CBLOCK];
962 + HMAC_CTX_init(&ctx_a);
963 + HMAC_CTX_init(&ctx_out);
964 + HMAC_Init_ex(&ctx_a, secret, secret_len, evp_md, NULL);
965 + HMAC_Init_ex(&ctx_out, secret, secret_len, evp_md, NULL);
967 + size = HMAC_size(&ctx_out);
969 + /* Calculate A(1) */
970 + HMAC_Update(&ctx_a, seed, seed_len);
971 + HMAC_Final(&ctx_a, a, NULL);
974 + /* Calculate next part of output */
975 + HMAC_Update(&ctx_out, a, size);
976 + HMAC_Update(&ctx_out, seed, seed_len);
978 + /* Check if last part */
979 + if (out_len < size) {
980 + HMAC_Final(&ctx_out, a, NULL);
981 + memcpy(out, a, out_len);
985 + /* Place digest in output buffer */
986 + HMAC_Final(&ctx_out, out, NULL);
987 + HMAC_Init_ex(&ctx_out, NULL, 0, NULL, NULL);
991 + /* Calculate next A(i) */
992 + HMAC_Init_ex(&ctx_a, NULL, 0, NULL, NULL);
993 + HMAC_Update(&ctx_a, a, size);
994 + HMAC_Final(&ctx_a, a, NULL);
997 + HMAC_CTX_cleanup(&ctx_a);
998 + HMAC_CTX_cleanup(&ctx_out);
999 + memset(a, 0, sizeof(a));
1002 +static void PRF(const unsigned char *secret, unsigned int secret_len,
1003 + const unsigned char *seed, unsigned int seed_len,
1004 + unsigned char *out, unsigned char *buf, unsigned int out_len)
1007 + unsigned int len = (secret_len + 1) / 2;
1008 + const unsigned char *s1 = secret;
1009 + const unsigned char *s2 = secret + (secret_len - len);
1011 + P_hash(EVP_md5(), s1, len, seed, seed_len, out, out_len);
1012 + P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len);
1014 + for (i=0; i < out_len; i++) {
1019 +#define EAPTLS_MPPE_KEY_LEN 32
1022 + * Generate keys according to RFC 2716 and add to reply
1024 +void eaptls_gen_mppe_keys(struct eaptls_session *ets, const char *prf_label,
1027 + unsigned char out[4*EAPTLS_MPPE_KEY_LEN], buf[4*EAPTLS_MPPE_KEY_LEN];
1028 + unsigned char seed[64 + 2*SSL3_RANDOM_SIZE];
1029 + unsigned char *p = seed;
1030 + SSL *s = ets->ssl;
1033 + prf_size = strlen(prf_label);
1035 + memcpy(p, prf_label, prf_size);
1038 + memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
1039 + p += SSL3_RANDOM_SIZE;
1040 + prf_size += SSL3_RANDOM_SIZE;
1042 + memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
1043 + prf_size += SSL3_RANDOM_SIZE;
1045 + PRF(s->session->master_key, s->session->master_key_length,
1046 + seed, prf_size, out, buf, sizeof(out));
1049 + * We now have the master send and receive keys.
1050 + * From these, generate the session send and receive keys.
1051 + * (see RFC3079 / draft-ietf-pppext-mppe-keys-03.txt for details)
1056 + BCOPY( p, mppe_send_key, sizeof(mppe_send_key) );
1057 + p += EAPTLS_MPPE_KEY_LEN;
1058 + BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) );
1063 + BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) );
1064 + p += EAPTLS_MPPE_KEY_LEN;
1065 + BCOPY( p, mppe_send_key, sizeof(mppe_send_key) );
1068 + mppe_keys_set = 1;
1073 +void log_ssl_errors( void )
1075 + unsigned long ssl_err = ERR_get_error();
1078 + dbglog("EAP-TLS SSL error stack:");
1079 + while (ssl_err != 0) {
1080 + dbglog( ERR_error_string( ssl_err, NULL ) );
1081 + ssl_err = ERR_get_error();
1086 +int password_callback (char *buf, int size, int rwflag, void *u)
1090 + strncpy (buf, passwd, size);
1091 + return strlen (buf);
1097 +CONF *eaptls_ssl_load_config( void )
1101 + long error_line = 33;
1103 + config = NCONF_new( NULL );
1104 + dbglog( "Loading OpenSSL config file" );
1105 + ret_code = NCONF_load( config, _PATH_OPENSSLCONFFILE, &error_line );
1106 + if (ret_code == 0)
1108 + warn( "EAP-TLS: Error in OpenSSL config file %s at line %d", _PATH_OPENSSLCONFFILE, error_line );
1109 + NCONF_free( config );
1111 + ERR_clear_error();
1114 + dbglog( "Loading OpenSSL built-ins" );
1115 + ENGINE_load_builtin_engines();
1116 + OPENSSL_load_builtin_modules();
1118 + dbglog( "Loading OpenSSL configured modules" );
1119 + if (CONF_modules_load( config, NULL, 0 ) <= 0 )
1121 + warn( "EAP-TLS: Error loading OpenSSL modules" );
1129 +ENGINE *eaptls_ssl_load_engine( char *engine_name )
1133 + dbglog( "Enabling OpenSSL auto engines" );
1134 + ENGINE_register_all_complete();
1136 + dbglog( "Loading OpenSSL '%s' engine support", engine_name );
1137 + e = ENGINE_by_id( engine_name );
1140 + dbglog( "EAP-TLS: Cannot load '%s' engine support, trying 'dynamic'", engine_name );
1141 + e = ENGINE_by_id( "dynamic" );
1144 + if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine_name, 0)
1145 + || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
1147 + warn( "EAP-TLS: Error loading dynamic engine '%s'", engine_name );
1155 + warn( "EAP-TLS: Cannot load dynamic engine support" );
1161 + dbglog( "Initialising engine" );
1162 + if(!ENGINE_set_default(e, ENGINE_METHOD_ALL))
1164 + warn( "EAP-TLS: Cannot use that engine" );
1175 + * Initialize the SSL stacks and tests if certificates, key and crl
1176 + * for client or server use can be loaded.
1178 +SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile,
1179 + char *certfile, char *peer_certfile, char *privkeyfile)
1181 + char *cert_engine_name = NULL;
1182 + char *cert_identifier = NULL;
1183 + char *pkey_engine_name = NULL;
1184 + char *pkey_identifier = NULL;
1186 + X509_STORE *certstore;
1187 + X509_LOOKUP *lookup;
1191 + * Without these can't continue
1193 + if (!cacertfile[0])
1195 + error("EAP-TLS: CA certificate missing");
1201 + error("EAP-TLS: User certificate missing");
1205 + if (!privkeyfile[0])
1207 + error("EAP-TLS: User private key missing");
1211 + SSL_library_init();
1212 + SSL_load_error_strings();
1214 + ctx = SSL_CTX_new(TLSv1_method());
1217 + error("EAP-TLS: Cannot initialize SSL CTX context");
1221 + /* if the certificate filename is of the form engine:id. e.g.
1223 + then we try to load and use this engine.
1224 + If the certificate filename starts with a / or . then we
1225 + ALWAYS assume it is a file and not an engine/pkcs11 identifier
1227 + if ( index( certfile, '/' ) == NULL && index( certfile, '.') == NULL )
1229 + cert_identifier = index( certfile, ':' );
1231 + if (cert_identifier)
1233 + cert_engine_name = certfile;
1234 + *cert_identifier = '\0';
1235 + cert_identifier++;
1237 + dbglog( "Found certificate engine '%s'", cert_engine_name );
1238 + dbglog( "Found certificate identifier '%s'", cert_identifier );
1242 + /* if the privatekey filename is of the form engine:id. e.g.
1244 + then we try to load and use this engine.
1245 + If the privatekey filename starts with a / or . then we
1246 + ALWAYS assume it is a file and not an engine/pkcs11 identifier
1248 + if ( index( privkeyfile, '/' ) == NULL && index( privkeyfile, '.') == NULL )
1250 + pkey_identifier = index( privkeyfile, ':' );
1252 + if (pkey_identifier)
1254 + pkey_engine_name = privkeyfile;
1255 + *pkey_identifier = '\0';
1256 + pkey_identifier++;
1258 + dbglog( "Found privatekey engine '%s'", pkey_engine_name );
1259 + dbglog( "Found privatekey identifier '%s'", pkey_identifier );
1263 + if (cert_identifier && pkey_identifier)
1265 + if (strlen( cert_identifier ) == 0)
1267 + if (strlen( pkey_identifier ) == 0)
1268 + error( "EAP-TLS: both the certificate and privatekey identifiers are missing!" );
1271 + dbglog( "Substituting privatekey identifier for certificate identifier" );
1272 + cert_identifier = pkey_identifier;
1277 + if (strlen( pkey_identifier ) == 0)
1279 + dbglog( "Substituting certificate identifier for privatekey identifier" );
1280 + pkey_identifier = cert_identifier;
1286 + /* load the openssl config file only once */
1289 + if (cert_engine_name || pkey_engine_name)
1290 + ssl_config = eaptls_ssl_load_config();
1292 + if (ssl_config && cert_engine_name)
1293 + cert_engine = eaptls_ssl_load_engine( cert_engine_name );
1295 + if (ssl_config && pkey_engine_name)
1297 + /* don't load the same engine twice */
1298 + if ( strcmp( cert_engine_name, pkey_engine_name) == 0 )
1299 + pkey_engine = cert_engine;
1301 + pkey_engine = eaptls_ssl_load_engine( pkey_engine_name );
1305 + SSL_CTX_set_default_passwd_cb (ctx, password_callback);
1307 + if (!SSL_CTX_load_verify_locations(ctx, cacertfile, NULL))
1309 + error("EAP-TLS: Cannot load or verify CA file %s", cacertfile);
1314 + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(cacertfile));
1320 + const char *s_slot_cert_id;
1324 + cert_info.s_slot_cert_id = cert_identifier;
1325 + cert_info.cert = NULL;
1327 + if (!ENGINE_ctrl_cmd( cert_engine, "LOAD_CERT_CTRL", 0, &cert_info, NULL, 0 ) )
1329 + error( "EAP-TLS: Error loading certificate with id '%s' from engine", cert_identifier );
1333 + if (cert_info.cert)
1335 + dbglog( "Got the certificate, adding it to SSL context" );
1336 + dbglog( "subject = %s", X509_NAME_oneline( X509_get_subject_name( cert_info.cert ), NULL, 0 ) );
1337 + if (SSL_CTX_use_certificate(ctx, cert_info.cert) <= 0)
1339 + error("EAP-TLS: Cannot use PKCS11 certificate %s", cert_identifier);
1345 + warn("EAP-TLS: Cannot load PKCS11 key %s", cert_identifier);
1351 + if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
1353 + error( "EAP-TLS: Cannot use public certificate %s", certfile );
1360 + EVP_PKEY *pkey = NULL;
1361 + PW_CB_DATA cb_data;
1363 + cb_data.password = passwd;
1364 + cb_data.prompt_info = pkey_identifier;
1366 + dbglog( "Loading private key '%s' from engine", pkey_identifier );
1367 + pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, NULL, &cb_data);
1370 + dbglog( "Got the private key, adding it to SSL context" );
1371 + if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0)
1373 + error("EAP-TLS: Cannot use PKCS11 key %s", pkey_identifier);
1379 + warn("EAP-TLS: Cannot load PKCS11 key %s", pkey_identifier);
1385 + if (!SSL_CTX_use_PrivateKey_file(ctx, privkeyfile, SSL_FILETYPE_PEM))
1387 + error("EAP-TLS: Cannot use private key %s", privkeyfile);
1392 + if (SSL_CTX_check_private_key(ctx) != 1) {
1393 + error("EAP-TLS: Private key %s fails security check", privkeyfile);
1397 + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
1398 + SSL_CTX_set_verify_depth(ctx, 5);
1399 + SSL_CTX_set_verify(ctx,
1401 + SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1402 + &ssl_verify_callback);
1405 + if (!(certstore = SSL_CTX_get_cert_store(ctx))) {
1406 + error("EAP-TLS: Failed to get certificate store");
1411 + X509_STORE_add_lookup(certstore, X509_LOOKUP_hash_dir()))) {
1412 + error("EAP-TLS: Store lookup for CRL failed");
1417 + X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM);
1418 + X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
1422 + * If a peer certificate file was specified, it must be valid, else fail
1424 + if (peer_certfile[0]) {
1425 + if (!(tmp = get_X509_from_file(peer_certfile))) {
1426 + error("EAP-TLS: Error loading client certificate from file %s",
1437 + SSL_CTX_free(ctx);
1442 + * Determine the maximum packet size by looking at the LCP handshake
1445 +int eaptls_get_mtu(int unit)
1449 + lcp_options *wo = &lcp_wantoptions[unit];
1450 + lcp_options *go = &lcp_gotoptions[unit];
1451 + lcp_options *ho = &lcp_hisoptions[unit];
1452 + lcp_options *ao = &lcp_allowoptions[unit];
1454 + mtu = ho->neg_mru? ho->mru: PPP_MRU;
1455 + mru = go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU;
1456 + mtu = MIN(MIN(mtu, mru), ao->mru)- PPP_HDRLEN - 10;
1458 + dbglog("MTU = %d", mtu);
1464 + * Init the ssl handshake (server mode)
1466 +int eaptls_init_ssl_server(eap_state * esp)
1468 + struct eaptls_session *ets;
1469 + char servcertfile[MAXWORDLEN];
1470 + char clicertfile[MAXWORDLEN];
1471 + char cacertfile[MAXWORDLEN];
1472 + char pkfile[MAXWORDLEN];
1474 + * Allocate new eaptls session
1476 + esp->es_server.ea_session = malloc(sizeof(struct eaptls_session));
1477 + if (!esp->es_server.ea_session)
1478 + fatal("Allocation error");
1479 + ets = esp->es_server.ea_session;
1481 + if (!esp->es_server.ea_peer) {
1482 + error("EAP-TLS: Error: client name not set (BUG)");
1486 + strncpy(ets->peer, esp->es_server.ea_peer, MAXWORDLEN);
1488 + dbglog( "getting eaptls secret" );
1489 + if (!get_eaptls_secret(esp->es_unit, esp->es_server.ea_peer,
1490 + esp->es_server.ea_name, clicertfile,
1491 + servcertfile, cacertfile, pkfile, 1)) {
1492 + error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
1493 + esp->es_server.ea_peer, esp->es_server.ea_name );
1497 + ets->mtu = eaptls_get_mtu(esp->es_unit);
1499 + ets->ctx = eaptls_init_ssl(1, cacertfile, servcertfile, clicertfile, pkfile);
1503 + if (!(ets->ssl = SSL_new(ets->ctx)))
1507 + * Set auto-retry to avoid timeouts on BIO_read
1509 + SSL_set_mode(ets->ssl, SSL_MODE_AUTO_RETRY);
1512 + * Initialize the BIOs we use to read/write to ssl engine
1514 + ets->into_ssl = BIO_new(BIO_s_mem());
1515 + ets->from_ssl = BIO_new(BIO_s_mem());
1516 + SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl);
1518 + SSL_set_msg_callback(ets->ssl, ssl_msg_callback);
1519 + SSL_set_msg_callback_arg(ets->ssl, ets);
1522 + * Attach the session struct to the connection, so we can later
1523 + * retrieve it when doing certificate verification
1525 + SSL_set_ex_data(ets->ssl, 0, ets);
1527 + SSL_set_accept_state(ets->ssl);
1531 + ets->alert_sent = 0;
1532 + ets->alert_recv = 0;
1535 + * If we specified the client certificate file, store it in ets->peercertfile,
1536 + * so we can check it later in ssl_verify_callback()
1538 + if (clicertfile[0])
1539 + strncpy(&ets->peercertfile[0], clicertfile, MAXWORDLEN);
1541 + ets->peercertfile[0] = 0;
1546 + SSL_CTX_free(ets->ctx);
1551 + * Init the ssl handshake (client mode)
1553 +int eaptls_init_ssl_client(eap_state * esp)
1555 + struct eaptls_session *ets;
1556 + char servcertfile[MAXWORDLEN];
1557 + char clicertfile[MAXWORDLEN];
1558 + char cacertfile[MAXWORDLEN];
1559 + char pkfile[MAXWORDLEN];
1562 + * Allocate new eaptls session
1564 + esp->es_client.ea_session = malloc(sizeof(struct eaptls_session));
1565 + if (!esp->es_client.ea_session)
1566 + fatal("Allocation error");
1567 + ets = esp->es_client.ea_session;
1570 + * If available, copy server name in ets; it will be used in cert
1573 + if (esp->es_client.ea_peer)
1574 + strncpy(ets->peer, esp->es_client.ea_peer, MAXWORDLEN);
1578 + ets->mtu = eaptls_get_mtu(esp->es_unit);
1580 + dbglog( "calling get_eaptls_secret" );
1581 + if (!get_eaptls_secret(esp->es_unit, esp->es_client.ea_name,
1582 + esp->es_client.ea_peer, clicertfile,
1583 + servcertfile, cacertfile, pkfile, 0)) {
1584 + error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
1585 + esp->es_client.ea_name, esp->es_client.ea_peer );
1589 + dbglog( "calling eaptls_init_ssl" );
1590 + ets->ctx = eaptls_init_ssl(0, cacertfile, clicertfile, servcertfile, pkfile);
1594 + ets->ssl = SSL_new(ets->ctx);
1600 + * Initialize the BIOs we use to read/write to ssl engine
1602 + dbglog( "Initializing SSL BIOs" );
1603 + ets->into_ssl = BIO_new(BIO_s_mem());
1604 + ets->from_ssl = BIO_new(BIO_s_mem());
1605 + SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl);
1607 + SSL_set_msg_callback(ets->ssl, ssl_msg_callback);
1608 + SSL_set_msg_callback_arg(ets->ssl, ets);
1611 + * Attach the session struct to the connection, so we can later
1612 + * retrieve it when doing certificate verification
1614 + SSL_set_ex_data(ets->ssl, 0, ets);
1616 + SSL_set_connect_state(ets->ssl);
1620 + ets->alert_sent = 0;
1621 + ets->alert_recv = 0;
1624 + * If we specified the server certificate file, store it in
1625 + * ets->peercertfile, so we can check it later in
1626 + * ssl_verify_callback()
1628 + if (servcertfile[0])
1629 + strncpy(ets->peercertfile, servcertfile, MAXWORDLEN);
1631 + ets->peercertfile[0] = 0;
1636 + dbglog( "eaptls_init_ssl_client: fail" );
1637 + SSL_CTX_free(ets->ctx);
1642 +void eaptls_free_session(struct eaptls_session *ets)
1645 + SSL_free(ets->ssl);
1648 + SSL_CTX_free(ets->ctx);
1654 + * Handle a received packet, reassembling fragmented messages and
1655 + * passing them to the ssl engine
1657 +int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len)
1661 + u_char dummy[65536];
1663 + GETCHAR(flags, inp);
1666 + if (flags & EAP_TLS_FLAGS_LI && !ets->data) {
1669 + * This is the first packet of a message
1672 + GETLONG(tlslen, inp);
1675 + if (tlslen > EAP_TLS_MAX_LEN) {
1676 + error("Error: tls message length > %d, truncated",
1678 + tlslen = EAP_TLS_MAX_LEN;
1682 + * Allocate memory for the whole message
1684 + ets->data = malloc(tlslen);
1686 + fatal("EAP TLS: allocation error\n");
1689 + ets->tlslen = tlslen;
1692 + else if (flags & EAP_TLS_FLAGS_LI && ets->data) {
1694 + * Non first with LI (strange...)
1697 + GETLONG(tlslen, inp);
1701 + else if (!ets->data) {
1703 + * A non fragmented message without LI flag
1706 + ets->data = malloc(len);
1708 + fatal("EAP TLS: allocation error\n");
1711 + ets->tlslen = len;
1714 + if (flags & EAP_TLS_FLAGS_MF)
1719 + if (len + ets->datalen > ets->tlslen) {
1720 + warn("EAP TLS: received data > TLS message length");
1724 + BCOPY(inp, ets->data + ets->datalen, len);
1725 + ets->datalen += len;
1730 + * If we have the whole message, pass it to ssl
1733 + if (ets->datalen != ets->tlslen) {
1734 + warn("EAP TLS: received data != TLS message length");
1738 + if (BIO_write(ets->into_ssl, ets->data, ets->datalen) == -1)
1741 + SSL_read(ets->ssl, dummy, 65536);
1752 + * Return an eap-tls packet in outp.
1753 + * A TLS message read from the ssl engine is buffered in ets->data.
1754 + * At each call we control if there is buffered data and send a
1755 + * packet of mtu bytes.
1757 +int eaptls_send(struct eaptls_session *ets, u_char ** outp)
1761 + u_char fromtls[65536];
1769 + if(!ets->alert_sent)
1770 + SSL_read(ets->ssl, fromtls, 65536);
1775 + if ((res = BIO_read(ets->from_ssl, fromtls, 65536)) == -1)
1776 + fatal("No data from BIO_read");
1778 + ets->datalen = res;
1780 + ets->data = malloc(ets->datalen);
1781 + BCOPY(fromtls, ets->data, ets->datalen);
1788 + size = ets->datalen - ets->offset;
1790 + if (size > ets->mtu) {
1796 + PUTCHAR(EAPT_TLS, *outp);
1799 + * Set right flags and length if necessary
1801 + if (ets->frag && first) {
1802 + PUTCHAR(EAP_TLS_FLAGS_LI | EAP_TLS_FLAGS_MF, *outp);
1803 + PUTLONG(ets->datalen, *outp);
1804 + } else if (ets->frag) {
1805 + PUTCHAR(EAP_TLS_FLAGS_MF, *outp);
1807 + PUTCHAR(0, *outp);
1810 + * Copy the data in outp
1812 + BCOPY(ets->data + ets->offset, *outp, size);
1813 + INCPTR(size, *outp);
1816 + * Copy the packet in retransmission buffer
1818 + BCOPY(start, &ets->rtx[0], *outp - start);
1819 + ets->rtx_len = *outp - start;
1821 + ets->offset += size;
1823 + if (ets->offset >= ets->datalen) {
1826 + * The whole message has been sent
1839 + * Get the sent packet from the retransmission buffer
1841 +void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp)
1843 + BCOPY(ets->rtx, *outp, ets->rtx_len);
1844 + INCPTR(ets->rtx_len, *outp);
1848 + * Verify a certificate.
1849 + * Most of the work (signatures and issuer attributes checking)
1850 + * is done by ssl; we check the CN in the peer certificate
1851 + * against the peer name.
1853 +int ssl_verify_callback(int preverify_ok, X509_STORE_CTX * ctx)
1855 + char subject[256];
1859 + int ok = preverify_ok;
1861 + struct eaptls_session *ets;
1863 + peer_cert = X509_STORE_CTX_get_current_cert(ctx);
1864 + err = X509_STORE_CTX_get_error(ctx);
1865 + depth = X509_STORE_CTX_get_error_depth(ctx);
1867 + dbglog("certificate verify depth: %d", depth);
1869 + if (auth_required && !ok) {
1870 + X509_NAME_oneline(X509_get_subject_name(peer_cert),
1873 + X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
1874 + NID_commonName, cn_str, 256);
1876 + dbglog("Certificate verification error:\n depth: %d CN: %s"
1877 + "\n err: %d (%s)\n", depth, cn_str, err,
1878 + X509_verify_cert_error_string(err));
1883 + ssl = X509_STORE_CTX_get_ex_data(ctx,
1884 + SSL_get_ex_data_X509_STORE_CTX_idx());
1886 + ets = (struct eaptls_session *)SSL_get_ex_data(ssl, 0);
1888 + if (ets == NULL) {
1889 + error("Error: SSL_get_ex_data returned NULL");
1895 + if (!depth) { /* This is the peer certificate */
1897 + X509_NAME_oneline(X509_get_subject_name(peer_cert),
1900 + X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
1901 + NID_commonName, cn_str, 256);
1904 + * If acting as client and the name of the server wasn't specified
1905 + * explicitely, we can't verify the server authenticity
1907 + if (!ets->peer[0]) {
1908 + warn("Peer name not specified: no check");
1915 + if (strcmp(cn_str, ets->peer)) {
1917 + ("Certificate verification error: CN (%s) != peer_name (%s)",
1918 + cn_str, ets->peer);
1922 + warn("Certificate CN: %s , peer name %s", cn_str, ets->peer);
1925 + * If a peer certificate file was specified, here we check it
1927 + if (ets->peercertfile[0]) {
1928 + if (ssl_cmp_certs(&ets->peercertfile[0], peer_cert)
1931 + ("Peer certificate doesn't match stored certificate");
1941 + * Compare a certificate with the one stored in a file
1943 +int ssl_cmp_certs(char *filename, X509 * a)
1948 + if (!(b = get_X509_from_file(filename)))
1951 + ret = X509_cmp(a, b);
1958 +X509 *get_X509_from_file(char *filename)
1963 + if (!(fp = fopen(filename, "r")))
1966 + ret = PEM_read_X509(fp, NULL, NULL, NULL);
1974 + * Every sent & received message this callback function is invoked,
1975 + * so we know when alert messages have arrived or are sent and
1976 + * we can print debug information about TLS handshake.
1979 +ssl_msg_callback(int write_p, int version, int content_type,
1980 + const void *buf, size_t len, SSL * ssl, void *arg)
1983 + struct eaptls_session *ets = (struct eaptls_session *)arg;
1984 + unsigned char code;
1987 + strcpy(string, " -> ");
1989 + strcpy(string, " <- ");
1992 + switch(content_type) {
1994 + case SSL3_RT_ALERT:
1995 + strcat(string, "Alert: ");
1996 + code = ((const unsigned char *)buf)[1];
1999 + ets->alert_sent = 1;
2000 + ets->alert_sent_desc = code;
2002 + ets->alert_recv = 1;
2003 + ets->alert_recv_desc = code;
2006 + strcat(string, SSL_alert_desc_string_long(code));
2009 + case SSL3_RT_CHANGE_CIPHER_SPEC:
2010 + strcat(string, "ChangeCipherSpec");
2013 + case SSL3_RT_HANDSHAKE:
2015 + strcat(string, "Handshake: ");
2016 + code = ((const unsigned char *)buf)[0];
2019 + case SSL3_MT_HELLO_REQUEST:
2020 + strcat(string,"Hello Request");
2022 + case SSL3_MT_CLIENT_HELLO:
2023 + strcat(string,"Client Hello");
2025 + case SSL3_MT_SERVER_HELLO:
2026 + strcat(string,"Server Hello");
2028 + case SSL3_MT_CERTIFICATE:
2029 + strcat(string,"Certificate");
2031 + case SSL3_MT_SERVER_KEY_EXCHANGE:
2032 + strcat(string,"Server Key Exchange");
2034 + case SSL3_MT_CERTIFICATE_REQUEST:
2035 + strcat(string,"Certificate Request");
2037 + case SSL3_MT_SERVER_DONE:
2038 + strcat(string,"Server Hello Done");
2040 + case SSL3_MT_CERTIFICATE_VERIFY:
2041 + strcat(string,"Certificate Verify");
2043 + case SSL3_MT_CLIENT_KEY_EXCHANGE:
2044 + strcat(string,"Client Key Exchange");
2046 + case SSL3_MT_FINISHED:
2047 + strcat(string,"Finished");
2051 + sprintf( string, "Handshake: Unknown SSL3 code received: %d", code );
2056 + sprintf( string, "SSL message contains unknown content type: %d", content_type );
2060 + /* Alert messages must always be displayed */
2061 + if(content_type == SSL3_RT_ALERT)
2062 + error("%s", string);
2064 + dbglog("%s", string);
2067 diff --git a/pppd/eap-tls.h b/pppd/eap-tls.h
2068 new file mode 100644
2069 index 0000000..2d45a0b
2071 +++ b/pppd/eap-tls.h
2076 + * Copyright (c) Beniamino Galvani 2005 All rights reserved.
2078 + * Redistribution and use in source and binary forms, with or without
2079 + * modification, are permitted provided that the following conditions
2082 + * 1. Redistributions of source code must retain the above copyright
2083 + * notice, this list of conditions and the following disclaimer.
2085 + * 2. Redistributions in binary form must reproduce the above copyright
2086 + * notice, this list of conditions and the following disclaimer in
2087 + * the documentation and/or other materials provided with the
2090 + * 3. The name(s) of the authors of this software must not be used to
2091 + * endorse or promote products derived from this software without
2092 + * prior written permission.
2094 + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
2095 + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
2096 + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
2097 + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2098 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
2099 + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
2100 + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2104 +#ifndef __EAP_TLS_H__
2105 +#define __EAP_TLS_H__
2109 +#include <openssl/ssl.h>
2110 +#include <openssl/bio.h>
2111 +#include <openssl/md5.h>
2113 +#define EAP_TLS_FLAGS_LI 128 /* length included flag */
2114 +#define EAP_TLS_FLAGS_MF 64 /* more fragments flag */
2115 +#define EAP_TLS_FLAGS_START 32 /* start flag */
2117 +#define EAP_TLS_MAX_LEN 65536 /* max eap tls packet size */
2119 +struct eaptls_session
2121 + u_char *data; /* buffered data */
2122 + int datalen; /* buffered data len */
2123 + int offset; /* from where to send */
2124 + int tlslen; /* total length of tls data */
2125 + bool frag; /* packet is fragmented */
2127 + SSL *ssl; /* ssl connection */
2130 + char peer[MAXWORDLEN]; /* peer name */
2131 + char peercertfile[MAXWORDLEN];
2133 + u_char alert_sent_desc;
2135 + u_char alert_recv_desc;
2136 + char rtx[65536]; /* retransmission buffer */
2138 + int mtu; /* unit mtu */
2141 +typedef struct pw_cb_data
2143 + const void *password;
2144 + const char *prompt_info;
2148 +int ssl_verify_callback(int, X509_STORE_CTX *);
2149 +void ssl_msg_callback(int write_p, int version, int ct, const void *buf,
2150 + size_t len, SSL * ssl, void *arg);
2152 +X509 *get_X509_from_file(char *filename);
2153 +int ssl_cmp_certs(char *filename, X509 * a);
2155 +SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile,
2156 + char *certfile, char *peer_certfile, char *privkeyfile);
2157 +int eaptls_init_ssl_server(eap_state * esp);
2158 +int eaptls_init_ssl_client(eap_state * esp);
2159 +void eaptls_free_session(struct eaptls_session *ets);
2161 +int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len);
2162 +int eaptls_send(struct eaptls_session *ets, u_char ** outp);
2163 +void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp);
2165 +int get_eaptls_secret(int unit, char *client, char *server,
2166 + char *clicertfile, char *servcertfile, char *cacertfile,
2167 + char *pkfile, int am_server);
2170 +#include "mppe.h" /* MPPE_MAX_KEY_LEN */
2171 +extern u_char mppe_send_key[MPPE_MAX_KEY_LEN];
2172 +extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
2173 +extern int mppe_keys_set;
2175 +void eaptls_gen_mppe_keys(struct eaptls_session *ets, const char *prf_label, int client);
2180 diff --git a/pppd/eap.c b/pppd/eap.c
2181 index faced53..e2270af 100644
2185 * Based on draft-ietf-pppext-eap-srp-03.txt.
2189 + * Modification by Beniamino Galvani, Mar 2005
2190 + * Implemented EAP-TLS authentication
2193 #define RCSID "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $"
2199 #include "pathnames.h"
2203 +#include "eap-tls.h"
2206 +#endif /* USE_EAPTLS */
2210 @@ -209,6 +218,9 @@ int unit;
2211 esp->es_server.ea_id = (u_char)(drand48() * 0x100);
2212 esp->es_client.ea_timeout = EAP_DEFREQTIME;
2213 esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ;
2215 + esp->es_client.ea_using_eaptls = 0;
2216 +#endif /* USE_EAPTLS */
2220 @@ -268,7 +280,7 @@ eap_state *esp;
2223 outp = outpacket_buf;
2226 MAKEHEADER(outp, PPP_EAP);
2228 PUTCHAR(EAP_FAILURE, outp);
2229 @@ -293,7 +305,7 @@ eap_state *esp;
2232 outp = outpacket_buf;
2235 MAKEHEADER(outp, PPP_EAP);
2237 PUTCHAR(EAP_SUCCESS, outp);
2238 @@ -436,8 +448,16 @@ int status;
2241 #endif /* USE_SRP */
2243 + struct eaptls_session *ets;
2245 + char secret[MAXWORDLEN];
2246 +#endif /* USE_EAPTLS */
2248 esp->es_server.ea_timeout = esp->es_savedtime;
2250 + esp->es_server.ea_prev_state = esp->es_server.ea_state;
2251 +#endif /* USE_EAPTLS */
2252 switch (esp->es_server.ea_state) {
2255 @@ -562,9 +582,81 @@ int status;
2258 #endif /* USE_SRP */
2260 + if (!get_secret(esp->es_unit, esp->es_server.ea_peer,
2261 + esp->es_server.ea_name, secret, &secret_len, 1)) {
2263 + esp->es_server.ea_state = eapTlsStart;
2266 +#endif /* USE_EAPTLS */
2268 esp->es_server.ea_state = eapMD5Chall;
2273 + /* Initialize ssl session */
2274 + if(!eaptls_init_ssl_server(esp)) {
2275 + esp->es_server.ea_state = eapBadAuth;
2279 + esp->es_server.ea_state = eapTlsRecv;
2283 + ets = (struct eaptls_session *) esp->es_server.ea_session;
2285 + if(ets->alert_sent) {
2286 + esp->es_server.ea_state = eapTlsSendAlert;
2291 + esp->es_server.ea_state = eapBadAuth;
2294 + ets = (struct eaptls_session *) esp->es_server.ea_session;
2297 + esp->es_server.ea_state = eapTlsSendAck;
2299 + esp->es_server.ea_state = eapTlsSend;
2303 + ets = (struct eaptls_session *) esp->es_server.ea_session;
2305 + if(SSL_is_init_finished(ets->ssl)) {
2306 + esp->es_server.ea_state = eapTlsRecvClient;
2311 + esp->es_server.ea_state = eapTlsRecvAck;
2313 + esp->es_server.ea_state = eapTlsRecv;
2316 + case eapTlsSendAck:
2317 + esp->es_server.ea_state = eapTlsRecv;
2320 + case eapTlsRecvAck:
2322 + esp->es_server.ea_state = eapBadAuth;
2326 + esp->es_server.ea_state = eapTlsSend;
2329 + case eapTlsSendAlert:
2330 + esp->es_server.ea_state = eapTlsRecvAlertAck;
2332 +#endif /* USE_EAPTLS */
2336 ts = (struct t_server *)esp->es_server.ea_session;
2337 @@ -681,7 +773,7 @@ eap_state *esp;
2340 outp = outpacket_buf;
2343 MAKEHEADER(outp, PPP_EAP);
2345 PUTCHAR(EAP_REQUEST, outp);
2346 @@ -718,6 +810,30 @@ eap_state *esp;
2347 INCPTR(esp->es_server.ea_namelen, outp);
2352 + PUTCHAR(EAPT_TLS, outp);
2353 + PUTCHAR(EAP_TLS_FLAGS_START, outp);
2354 + eap_figure_next_state(esp, 0);
2358 + eaptls_send(esp->es_server.ea_session, &outp);
2359 + eap_figure_next_state(esp, 0);
2362 + case eapTlsSendAck:
2363 + PUTCHAR(EAPT_TLS, outp);
2365 + eap_figure_next_state(esp, 0);
2368 + case eapTlsSendAlert:
2369 + eaptls_send(esp->es_server.ea_session, &outp);
2370 + eap_figure_next_state(esp, 0);
2372 +#endif /* USE_EAPTLS */
2376 PUTCHAR(EAPT_SRP, outp);
2377 @@ -904,11 +1020,57 @@ static void
2378 eap_server_timeout(arg)
2385 +#endif /* USE_EAPTLS */
2387 eap_state *esp = (eap_state *) arg;
2389 if (!eap_server_active(esp))
2393 + switch(esp->es_server.ea_prev_state) {
2396 + * In eap-tls the state changes after a request, so we return to
2397 + * previous state ...
2399 + case(eapTlsStart):
2400 + case(eapTlsSendAck):
2401 + esp->es_server.ea_state = esp->es_server.ea_prev_state;
2405 + * ... or resend the stored data
2408 + case(eapTlsSendAlert):
2409 + outp = outpacket_buf;
2410 + MAKEHEADER(outp, PPP_EAP);
2411 + PUTCHAR(EAP_REQUEST, outp);
2412 + PUTCHAR(esp->es_server.ea_id, outp);
2416 + eaptls_retransmit(esp->es_server.ea_session, &outp);
2418 + outlen = (outp - outpacket_buf) - PPP_HDRLEN;
2419 + PUTSHORT(outlen, lenloc);
2420 + output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN);
2421 + esp->es_server.ea_requests++;
2423 + if (esp->es_server.ea_timeout > 0)
2424 + TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout);
2430 +#endif /* USE_EAPTLS */
2432 /* EAP ID number must not change on timeout. */
2433 eap_send_request(esp);
2435 @@ -1081,7 +1243,7 @@ int namelen;
2438 outp = outpacket_buf;
2441 MAKEHEADER(outp, PPP_EAP);
2443 PUTCHAR(EAP_RESPONSE, outp);
2444 @@ -1117,7 +1279,7 @@ int lenstr;
2447 outp = outpacket_buf;
2450 MAKEHEADER(outp, PPP_EAP);
2452 PUTCHAR(EAP_RESPONSE, outp);
2453 @@ -1148,7 +1310,7 @@ u_char *str;
2456 outp = outpacket_buf;
2459 MAKEHEADER(outp, PPP_EAP);
2461 PUTCHAR(EAP_RESPONSE, outp);
2462 @@ -1166,6 +1328,81 @@ u_char *str;
2464 #endif /* USE_SRP */
2468 + * Send an EAP-TLS response message with tls data
2471 +eap_tls_response(esp, id)
2479 + outp = outpacket_buf;
2481 + MAKEHEADER(outp, PPP_EAP);
2483 + PUTCHAR(EAP_RESPONSE, outp);
2484 + PUTCHAR(id, outp);
2490 + If the id in the request is unchanged, we must retransmit
2493 + if(id == esp->es_client.ea_id)
2494 + eaptls_retransmit(esp->es_client.ea_session, &outp);
2496 + eaptls_send(esp->es_client.ea_session, &outp);
2498 + outlen = (outp - outpacket_buf) - PPP_HDRLEN;
2499 + PUTSHORT(outlen, lenloc);
2501 + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen);
2503 + esp->es_client.ea_id = id;
2508 + * Send an EAP-TLS ack
2511 +eap_tls_sendack(esp, id)
2519 + outp = outpacket_buf;
2521 + MAKEHEADER(outp, PPP_EAP);
2523 + PUTCHAR(EAP_RESPONSE, outp);
2524 + PUTCHAR(id, outp);
2525 + esp->es_client.ea_id = id;
2530 + PUTCHAR(EAPT_TLS, outp);
2533 + outlen = (outp - outpacket_buf) - PPP_HDRLEN;
2534 + PUTSHORT(outlen, lenloc);
2536 + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen);
2539 +#endif /* USE_EAPTLS */
2542 eap_send_nak(esp, id, type)
2544 @@ -1320,6 +1557,11 @@ int len;
2545 char rhostname[256];
2547 u_char hash[MD5_SIGNATURE_SIZE];
2550 + struct eaptls_session *ets = esp->es_client.ea_session;
2551 +#endif /* USE_EAPTLS */
2554 struct t_client *tc;
2555 struct t_num sval, gval, Nval, *Ap, Bval;
2556 @@ -1456,6 +1698,90 @@ int len;
2557 esp->es_client.ea_namelen);
2563 + switch(esp->es_client.ea_state) {
2567 + GETCHAR(flags, inp);
2568 + if(flags & EAP_TLS_FLAGS_START){
2570 + esp->es_client.ea_using_eaptls = 1;
2572 + if (explicit_remote){
2573 + esp->es_client.ea_peer = strdup(remote_name);
2574 + esp->es_client.ea_peerlen = strlen(remote_name);
2576 + esp->es_client.ea_peer = NULL;
2578 + /* Init ssl session */
2579 + if(!eaptls_init_ssl_client(esp)) {
2580 + dbglog("cannot init ssl");
2581 + eap_send_nak(esp, id, EAPT_TLS);
2582 + esp->es_client.ea_using_eaptls = 0;
2586 + ets = esp->es_client.ea_session;
2587 + eap_tls_response(esp, id);
2588 + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck :
2593 + /* The server has sent a bad start packet. */
2594 + eap_send_nak(esp, id, EAPT_TLS);
2597 + case eapTlsRecvAck:
2598 + eap_tls_response(esp, id);
2599 + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck :
2604 + eaptls_receive(ets, inp, len);
2607 + eap_tls_sendack(esp, id);
2608 + esp->es_client.ea_state = eapTlsRecv;
2612 + if(ets->alert_recv) {
2613 + eap_tls_sendack(esp, id);
2614 + esp->es_client.ea_state = eapTlsRecvFailure;
2618 + /* Check if TLS handshake is finished */
2619 + if(SSL_is_init_finished(ets->ssl)){
2621 + eaptls_gen_mppe_keys( ets, "client EAP encryption", 1 );
2623 + eaptls_free_session(ets);
2624 + eap_tls_sendack(esp, id);
2625 + esp->es_client.ea_state = eapTlsRecvSuccess;
2629 + eap_tls_response(esp,id);
2630 + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck :
2636 + eap_send_nak(esp, id, EAPT_TLS);
2637 + esp->es_client.ea_using_eaptls = 0;
2642 +#endif /* USE_EAPTLS */
2647 @@ -1737,6 +2063,11 @@ int len;
2648 u_char dig[SHA_DIGESTSIZE];
2649 #endif /* USE_SRP */
2652 + struct eaptls_session *ets;
2654 +#endif /* USE_EAPTLS */
2656 if (esp->es_server.ea_id != id) {
2657 dbglog("EAP: discarding Response %d; expected ID %d", id,
2658 esp->es_server.ea_id);
2659 @@ -1776,6 +2107,60 @@ int len;
2660 eap_figure_next_state(esp, 0);
2665 + switch(esp->es_server.ea_state) {
2668 + ets = (struct eaptls_session *) esp->es_server.ea_session;
2669 + eap_figure_next_state(esp,
2670 + eaptls_receive(esp->es_server.ea_session, inp, len));
2672 + if(ets->alert_recv) {
2673 + eap_send_failure(esp);
2678 + case eapTlsRecvAck:
2680 + dbglog("EAP-TLS ACK with extra data");
2682 + eap_figure_next_state(esp, 0);
2685 + case eapTlsRecvClient:
2686 + /* Receive authentication response from client */
2688 + GETCHAR(flags, inp);
2690 + if(len == 1 && !flags) { /* Ack = ok */
2692 + eaptls_gen_mppe_keys( esp->es_server.ea_session, "client EAP encryption", 0 );
2694 + eap_send_success(esp);
2696 + else { /* failure */
2697 + eaptls_receive(esp->es_server.ea_session, inp, len);
2698 + warn("Server authentication failed");
2699 + eap_send_failure(esp);
2702 + eaptls_free_session(esp->es_server.ea_session);
2706 + case eapTlsRecvAlertAck:
2707 + eap_send_failure(esp);
2711 + eap_figure_next_state(esp, 1);
2715 +#endif /* USE_EAPTLS */
2717 case EAPT_NOTIFICATION:
2718 dbglog("EAP unexpected Notification; response discarded");
2720 @@ -1807,6 +2192,13 @@ int len;
2721 esp->es_server.ea_state = eapMD5Chall;
2725 + /* Send EAP-TLS start packet */
2727 + esp->es_server.ea_state = eapTlsStart;
2729 +#endif /* USE_EAPTLS */
2732 dbglog("EAP: peer requesting unknown Type %d", vallen);
2733 switch (esp->es_server.ea_state) {
2734 @@ -2018,13 +2410,27 @@ u_char *inp;
2738 - if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)) {
2739 + if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)
2741 + && esp->es_client.ea_state != eapTlsRecvSuccess
2742 +#endif /* USE_EAPTLS */
2744 dbglog("EAP unexpected success message in state %s (%d)",
2745 eap_state_name(esp->es_client.ea_state),
2746 esp->es_client.ea_state);
2751 + if(esp->es_client.ea_using_eaptls && esp->es_client.ea_state !=
2752 + eapTlsRecvSuccess) {
2753 + dbglog("EAP-TLS unexpected success message in state %s (%d)",
2754 + eap_state_name(esp->es_client.ea_state),
2755 + esp->es_client.ea_state);
2758 +#endif /* USE_EAPTLS */
2760 if (esp->es_client.ea_timeout > 0) {
2761 UNTIMEOUT(eap_client_timeout, (void *)esp);
2763 @@ -2150,6 +2556,9 @@ void *arg;
2764 int code, id, len, rtype, vallen;
2769 +#endif /* USE_EAPTLS */
2771 if (inlen < EAP_HEADERLEN)
2773 @@ -2214,6 +2623,24 @@ void *arg;
2781 + GETCHAR(flags, inp);
2784 + if(flags == 0 && len == 0){
2785 + printer(arg, " Ack");
2789 + printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -");
2790 + printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-");
2791 + printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- ");
2793 +#endif /* USE_EAPTLS */
2798 @@ -2325,6 +2752,25 @@ void *arg;
2806 + GETCHAR(flags, inp);
2809 + if(flags == 0 && len == 0){
2810 + printer(arg, " Ack");
2814 + printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -");
2815 + printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-");
2816 + printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- ");
2819 +#endif /* USE_EAPTLS */
2823 printer(arg, " <missing hint>");
2824 diff --git a/pppd/eap.h b/pppd/eap.h
2825 index 199d184..3fa5391 100644
2828 @@ -84,6 +84,16 @@ enum eap_state_code {
2829 eapClosed, /* Authentication not in use */
2830 eapListen, /* Client ready (and timer running) */
2831 eapIdentify, /* EAP Identify sent */
2832 + eapTlsStart, /* Send EAP-TLS start packet */
2833 + eapTlsRecv, /* Receive EAP-TLS tls data */
2834 + eapTlsSendAck, /* Send EAP-TLS ack */
2835 + eapTlsSend, /* Send EAP-TLS tls data */
2836 + eapTlsRecvAck, /* Receive EAP-TLS ack */
2837 + eapTlsRecvClient, /* Receive EAP-TLS auth response from client*/
2838 + eapTlsSendAlert, /* Send EAP-TLS tls alert (server)*/
2839 + eapTlsRecvAlertAck, /* Receive EAP-TLS ack after sending alert */
2840 + eapTlsRecvSuccess, /* Receive EAP success */
2841 + eapTlsRecvFailure, /* Receive EAP failure */
2842 eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */
2843 eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */
2844 eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */
2845 @@ -95,9 +105,18 @@ enum eap_state_code {
2847 #define EAP_STATES \
2848 "Initial", "Pending", "Closed", "Listen", "Identify", \
2849 + "TlsStart", "TlsRecv", "TlsSendAck", "TlsSend", "TlsRecvAck", "TlsRecvClient",\
2850 + "TlsSendAlert", "TlsRecvAlertAck" , "TlsRecvSuccess", "TlsRecvFailure", \
2851 "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth"
2853 -#define eap_client_active(esp) ((esp)->es_client.ea_state == eapListen)
2855 +#define eap_client_active(esp) ((esp)->es_client.ea_state != eapInitial ||\
2856 + (esp)->es_client.ea_state != eapPending ||\
2857 + (esp)->es_client.ea_state != eapClosed)
2859 +#define eap_client_active(esp) ((esp)->es_client.ea_state == eapListen)
2860 +#endif /* USE_EAPTLS */
2862 #define eap_server_active(esp) \
2863 ((esp)->es_server.ea_state >= eapIdentify && \
2864 (esp)->es_server.ea_state <= eapMD5Chall)
2865 @@ -112,11 +131,17 @@ struct eap_auth {
2866 u_short ea_namelen; /* Length of our name */
2867 u_short ea_peerlen; /* Length of peer's name */
2868 enum eap_state_code ea_state;
2870 + enum eap_state_code ea_prev_state;
2872 u_char ea_id; /* Current id */
2873 u_char ea_requests; /* Number of Requests sent/received */
2874 u_char ea_responses; /* Number of Responses */
2875 u_char ea_type; /* One of EAPT_* */
2876 u_int32_t ea_keyflags; /* SRP shared key usage flags */
2878 + bool ea_using_eaptls;
2883 @@ -139,7 +164,12 @@ typedef struct eap_state {
2886 #define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */
2888 +#define EAP_DEFTRANSMITS 30 /* max # times to transmit */
2889 + /* certificates can be long ... */
2891 #define EAP_DEFTRANSMITS 10 /* max # times to transmit */
2892 +#endif /* USE_EAPTLS */
2893 #define EAP_DEFREQTIME 20 /* Time to wait for peer request */
2894 #define EAP_DEFALLOWREQ 20 /* max # times to accept requests */
2896 diff --git a/pppd/md5.c b/pppd/md5.c
2897 index f1291ce..2ee0c80 100644
2901 ***********************************************************************
2909 @@ -305,3 +307,4 @@ UINT4 *in;
2911 ******************************** (cut) ********************************
2913 +#endif /* USE_EAPTLS */
2914 diff --git a/pppd/md5.h b/pppd/md5.h
2915 index 71e8b00..14d7121 100644
2919 ** documentation and/or software. **
2920 ***********************************************************************
2924 #ifndef __MD5_INCLUDE__
2926 @@ -63,3 +64,5 @@ void MD5_Final (unsigned char hash[], MD5_CTX *mdContext);
2928 #define __MD5_INCLUDE__
2929 #endif /* __MD5_INCLUDE__ */
2931 +#endif /* USE_EAPTLS */
2932 diff --git a/pppd/options.c b/pppd/options.c
2933 index 8e62635..6915b2d 100644
2934 --- a/pppd/options.c
2935 +++ b/pppd/options.c
2936 @@ -120,6 +120,10 @@ bool dump_options; /* print out option values */
2937 bool dryrun; /* print out option values and exit */
2938 char *domain; /* domain name set by domain option */
2939 int child_wait = 5; /* # seconds to wait for children at exit */
2941 +bool only_update_crl_server = 0; /* update server crl and exit */
2942 +bool only_update_crl_client = 0; /* update client crl and exit */
2943 +#endif /* USE_EAPTLS */
2944 struct userenv *userenv_list; /* user environment variables */
2947 @@ -338,6 +342,12 @@ option_t general_options[] = {
2948 { "mo-timeout", o_int, &maxoctets_timeout,
2949 "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 },
2952 + { "only-update-crl-server", o_bool, &only_update_crl_server,
2953 + "Update server CA CRLs and exit", 1 },
2954 + { "only-update-crl-client", o_bool, &only_update_crl_client,
2955 + "Update client CA CRLs and exit", 1 },
2956 +#endif /* USE_EAPTLS */
2960 diff --git a/pppd/pathnames.h b/pppd/pathnames.h
2961 index 24e010c..6275df6 100644
2962 --- a/pppd/pathnames.h
2963 +++ b/pppd/pathnames.h
2965 #define _PATH_UPAPFILE _ROOT_PATH "/etc/ppp/pap-secrets"
2966 #define _PATH_CHAPFILE _ROOT_PATH "/etc/ppp/chap-secrets"
2967 #define _PATH_SRPFILE _ROOT_PATH "/etc/ppp/srp-secrets"
2970 +#define _PATH_EAPTLSCLIFILE _ROOT_PATH "/etc/ppp/eaptls-client"
2971 +#define _PATH_EAPTLSSERVFILE _ROOT_PATH "/etc/ppp/eaptls-server"
2972 +#define _PATH_OPENSSLCONFFILE _ROOT_PATH "/etc/ppp/openssl.cnf"
2973 +#endif /* USE_EAPTLS */
2975 #define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options"
2976 #define _PATH_IPUP _ROOT_PATH "/etc/ppp/ip-up"
2977 #define _PATH_IPDOWN _ROOT_PATH "/etc/ppp/ip-down"
2978 diff --git a/pppd/plugins/Makefile.linux b/pppd/plugins/Makefile.linux
2979 index b474a19..760cad4 100644
2980 --- a/pppd/plugins/Makefile.linux
2981 +++ b/pppd/plugins/Makefile.linux
2982 @@ -4,6 +4,9 @@ CFLAGS = $(COPTS) -I.. -I../../include -fPIC
2987 +CFLAGS += -DUSE_EAPTLS=1
2989 DESTDIR = $(INSTROOT)@DESTDIR@
2990 BINDIR = $(DESTDIR)/sbin
2991 MANDIR = $(DESTDIR)/share/man/man8
2992 diff --git a/pppd/plugins/passprompt.c b/pppd/plugins/passprompt.c
2993 index babb6dc..6ba73ca 100644
2994 --- a/pppd/plugins/passprompt.c
2995 +++ b/pppd/plugins/passprompt.c
2996 @@ -107,4 +107,7 @@ void plugin_init(void)
2998 add_options(options);
2999 pap_passwd_hook = promptpass;
3001 + eaptls_passwd_hook = promptpass;
3004 diff --git a/pppd/plugins/passwordfd.c b/pppd/plugins/passwordfd.c
3005 index d718f3b..c3f9793 100644
3006 --- a/pppd/plugins/passwordfd.c
3007 +++ b/pppd/plugins/passwordfd.c
3008 @@ -79,4 +79,8 @@ void plugin_init (void)
3010 chap_check_hook = pwfd_check;
3011 chap_passwd_hook = pwfd_passwd;
3014 + eaptls_passwd_hook = pwfd_passwd;
3017 diff --git a/pppd/pppd.h b/pppd/pppd.h
3018 index 47e4d9a..de271c1 100644
3021 @@ -324,6 +324,10 @@ extern bool dump_options; /* print out option values */
3022 extern bool dryrun; /* check everything, print options, exit */
3023 extern int child_wait; /* # seconds to wait for children at end */
3026 +extern char *crl_dir;
3027 +#endif /* USE_EAPTLS */
3030 extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */
3031 extern int maxoctets_dir; /* Direction :
3032 @@ -738,6 +742,10 @@ extern int (*chap_check_hook) __P((void));
3033 extern int (*chap_passwd_hook) __P((char *user, char *passwd));
3034 extern void (*multilink_join_hook) __P((void));
3037 +extern int (*eaptls_passwd_hook) __P((char *user, char *passwd));
3040 /* Let a plugin snoop sent and received packets. Useful for L2TP */
3041 extern void (*snoop_recv_hook) __P((unsigned char *p, int len));
3042 extern void (*snoop_send_hook) __P((unsigned char *p, int len));