diff -Naur ppp-2.4.8/README.eap-tls ppp-2.4.8-eaptls-mppe-1.300/README.eap-tls --- ppp-2.4.8/README.eap-tls 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/README.eap-tls 2020-04-07 10:09:50.565118206 +0200 @@ -0,0 +1,307 @@ +EAP-TLS authentication support for PPP +====================================== + +1. Intro + + The Extensible Authentication Protocol (EAP; RFC 3748) is a + security protocol that can be used with PPP. It provides a means + to plug in multiple optional authentication methods. + + Transport Level Security (TLS; RFC 5216) provides for mutual + authentication, integrity-protected ciphersuite negotiation and + key exchange between two endpoints. It also provides for optional + MPPE encryption. + + EAP-TLS (RFC 2716) incapsulates the TLS messages in EAP packets, + allowing TLS mutual authentication to be used as a generic EAP + mechanism. It also provides optional encryption using the MPPE + protocol. + + This patch provide EAP-TLS support to pppd. + This authentication method can be used in both client or server + mode. + +2. Building + + To build pppd with EAP-TLS support, OpenSSL (http://www.openssl.org) + is required. Any version from 0.9.7 should work. + + Configure, compile, and install as usual. + +3. Configuration + + On the client side there are two ways to configure EAP-TLS: + + 1. supply the appropriate 'ca', 'cert' and 'key' command-line parameters + + 2. edit the /etc/ppp/eaptls-client file. + Insert a line for each system with which you use EAP-TLS. + The line is composed of this fields separated by tab: + + - Client name + The name used by the client for authentication, can be * + - Server name + The name of the server, can be * + - Client certificate file + The file containing the certificate chain for the + client in PEM format + - Server certificate file + If you want to specify the certificate that the + server is allowed to use, put the certificate file name. + Else put a dash '-'. + - CA certificate file + The file containing the trusted CA certificates in PEM + format. + - Client private key file + The file containing the client private key in PEM format. + + + On the server side edit the /etc/ppp/eaptls-server file. + Insert a line for each system with which you use EAP-TLS. + The line is composed of this fields separated by tab: + + - Client name + The name used by the client for authentication, can be * + - Server name + The name of the server, can be * + - Client certificate file + If you want to specify the certificate that the + client is allowed to use, put the certificate file name. + Else put a dash '-'. + - Server certificate file + The file containing the certificate chain for the + server in PEM format + - CA certificate file + The file containing the trusted CA certificates in PEM format. + - Client private key file + The file containing the server private key in PEM format. + - addresses + A list of IP addresses the client is allowed to use. + + + OpenSSL engine support is included starting with v0.95 of this patch. + Currently the only engine tested is the 'pkcs11' engine (hardware token + support). To use the 'pksc11' engine: + - Use a special private key fileiname in the /etc/ppp/eaptls-client file: + : + e.g. + pkcs11:123456 + + - The certificate can also be loaded from the 'pkcs11' engine using + a special client certificate filename in the /etc/ppp/eaptls-client file: + : + e.g. + pkcs11:123456 + + - Create an /etc/ppp/openssl.cnf file to load the right OpenSSL engine prior + to starting 'pppd'. A sample openssl.cnf file is + + openssl_conf = openssl_def + + [ openssl_def ] + engines = engine_section + + [ engine_section ] + pkcs11 = pkcs11_section + + [ pkcs11_section ] + engine_id = pkcs11 + dynamic_path = /usr/lib64/openssl/engines/engine_pkcs11.so + MODULE_PATH = /usr/lib64/libeTPkcs11.so + init = 0 + + - There are two ways to specify a password/PIN for the PKCS11 engine: + - inside the openssl.cnf file using + PIN = your-secret-pin + Note The keyword 'PIN' is case sensitive! + - Using the 'password' in the ppp options file. + From v0.97 of the eap-tls patch the password can also be supplied + using the appropriate 'eaptls_passwd_hook' (see plugins/passprompt.c + for an example). + + +4. Options + + These pppd options are available: + + ca + Use the CA public certificate found in in PEM format + cert + Use the client public certificate found in in PEM format + or in engine:engine_id format + key + Use the client private key found in in PEM format + or in engine:engine_id format + crl + Use the Certificate Revocation List (CRL) file in PEM format. + crl-dir + Use CRL files from directory . It contains CRL files in PEM + format and each file contains a CRL. The files are looked up + by the issuer name hash value. Use the c_rehash utility + to create necessary links. + need-peer-eap + If the peer doesn't ask us to authenticate or doesn't use eap + to authenticate us, disconnect. + + Note: + password-encrypted certificates can be used as of v0.94 of this + patch. The password for the eap-tls.key file is specified using + the regular + password .... + statement in the ppp options file, or by using the appropriate + plugin which supplies a 'eaptls_passwd_hook' routine. + +5. Connecting + + If you're setting up a pppd server, edit the EAP-TLS configuration file + as written above and then run pppd with the 'auth' option to authenticate + the client. The EAP-TLS method will be used if the other eap methods can't + be used (no secrets). + + If you're setting up a client, edit the configuration file and then run + pppd with 'remotename' option to specify the server name. Add the + 'need-peer-eap' option if you want to be sure the peer ask you to + authenticate (and to use eap) and to disconnect if it doesn't. + +6. Example + + The following example can be used to connect a Linux client with the 'pptp' + package to a Linux server running the 'pptpd' (PoPToP) package. The server + was configured with a certificate with name (CN) 'pptp-server', the client + was configured with a certificate with name (CN) 'pptp-client', both + signed by the same Certificate Authority (CA). + + Server side: + - /etc/pptpd.conf file: + option /etc/ppp/options-pptpd-eaptls + localip 172.16.1.1 + remoteip 172.16.1.10-20 + - /etc/ppp/options-pptpd-eaptls file: + name pptp-server + lock + mtu 1500 + mru 1450 + auth + lcp-echo-failure 3 + lcp-echo-interval 5 + nodeflate + nobsdcomp + nopredictor1 + nopcomp + noaccomp + + require-eap + require-mppe-128 + + crl /home/janjust/ppp/keys/crl.pem + + debug + logfile /tmp/pppd.log + + - /etc/ppp/eaptls-server file: + * pptp-server - /etc/ppp/pptp-server.crt /etc/ppp/ca.crt /etc/ppp/pptp-server.key * + + - On the server, run + pptdp --conf /etc/pptpd.conf + + Client side: + - Run + pppd noauth require-eap require-mppe-128 \ + ipcp-accept-local ipcp-accept-remote noipdefault \ + cert /etc/ppp/keys/pptp-client.crt \ + key /etc/ppp/keys/pptp-client.key \ + ca /etc/ppp/keys/ca.crt \ + name pptp-client remotename pptp-server \ + debug logfile /tmp/pppd.log + pty "pptp pptp-server.example.com --nolaunchpppd" + + Check /var/log/messages and the files /tmp/pppd.log on both sides for debugging info. + +7. Notes + + This is experimental code. + Send suggestions and comments to Jan Just Keijser + +8. Changelog of ppp-<>-eaptls-mppe-* patches + +v0.7 (22-Nov-2005) + - First version of the patch to include MPPE support + - ppp-2.4.3 only +v0.9 (25-Jul-2006) + - Bug fixes + - First version for ppp-2.4.4 +v0.91 (03-Sep-2006) + - Added missing #include for md5.h + - Last version for ppp-2.4.3 +v0.92 (22-Apr-2008) + - Fix for openssl 0.9.8 issue with md5 function overload. +v0.93 (14-Aug-2008) + - Make sure 'noauth' option can be used to bypass server certificate verification. +v0.94 (15-Oct-2008) + - Added support for password-protected private keys by (ab)using the 'password' field. +v0.95 (23-Dec-2009) + - First version with OpenSSL engine support. +v0.96 (27-Jan-2010) + - Added fully functional support for OpenSSL engines (PKCS#11) + - First version for ppp-2.4.5 +v0.97 (20-Apr-2010) + - Some bug fixes for v0.96 + - Added support for entering the password via a plugin. The sample plugin + .../pppd/plugins/passprompt.c has been extended with EAP-TLS support. + The "old" methods using the password option or the /etc/ppp/openssl.cnf file still work. + - Added support for specifying the client CA, certificate and private key on the command-line + or via the ppp config file. +v0.98 (20-Apr-2010) + - Fix initialisation bug when using ca/cert/key command-line options. + - Last version for ppp-2.4.4 +v0.99 (05-Oct-2010) + - Fix coredump when using multilink option. +v0.991 (08-Aug-2011) + - Fix compilation issue with openssl 1.0. +v0.992 (01-Dec-2011) + - Fix compilation issue with eaptls_check_hook and passwordfd plugin. +v0.993 (24-Apr-2012) + - Fix compilation issue when EAP_TLS=n in pppd/Makefile. +v0.994 (11-Jun-2012) + - Fix compilation issue on Ubuntu 11.10. +v0.995 (27-May-2014) + - Add support for a CRL file using the command-line option 'crl' + (prior only 'crl-dir' was supported). + - Fix segfault when pkcs11 enginename was not specified correctly. + - Fix segfault when client was misconfigured. + - Disable SSL Session Ticket support as Windows 8 does not support this. +v0.996 (28-May-2014) + - Fix minor bug where SessionTicket message was printed as 'Unknown SSL3 code 4' + - Add EAP-TLS-specific options to pppd.8 manual page. + - Updated README.eap-tls file with new options and provide an example. +v0.997 (19-Jun-2014) + - Change SSL_OP_NO_TICKETS to SSL_OP_NO_TICKET + - Fix bug in initialisation code with fragmented packets. +v0.998 (13-Mar-2015) + - Add fix for https://bugzilla.redhat.com/show_bug.cgi?id=1023620 +v0.999 (11-May-2017) + - Add support for OpenSSL 1.1: the code will now compile against OpenSSL 1.0.x or 1.1.x. +v1.101 (1-Jun-2018) + - Fix vulnerabilities CVE-2018-11574. +v1.102 (2-Nov-2018) + - Add TLS 1.2 support. Windows 7/8 will connect using TLS 1.0, Windows 10 clients using TLS 1.2. + This works both when compiling against OpenSSL 1.0.1+ and 1.1+. + - Print warning when certificate is either not yet valid or has expired. + - Perform better peer certificate checks. + - Allow certificate chain files to be used. +v1.200 (28-Feb-2020) + - First version of patch that was used to create a github PR against the main ppp code base. + - Add client-side 'capath' option to allow a directory with trusted CA certificates. + - Add compile-time Makefile option to have pppd use either the internal MD5+SHA1 functions or + use the ones supplied by OpenSSL. + - Code now also builds on Solaris (x86 tested) but has not been tested yet, as the Solaris ppp + kernel driver does not support MPPE. +v1.201 (03-Apr-2020) + - Force use of TLSv1.2 even if TLSv1.3 is available (with OpenSSL 1.1.1+). This ensures that + you can compile and link against OpenSSL 1.1.1+ without breaking the TLS negotiation. +v1.300 (03-Apr-2020) + - Add (experimental) TLS 1.3 support. This is based on draft-ietf-emu-eap-tls13-05 (expired) and + requires OpenSSL 1.1.1+ to be effective. + - Add new option 'max-tls-version' to specify the highest version of the TLS protocol to use + (defaults to TLS1.2 for now - so to use TLS1.3 you need to explicitly add 'max-tls-version 1.3') + diff -Naur ppp-2.4.8/etc.ppp/eaptls-client ppp-2.4.8-eaptls-mppe-1.300/etc.ppp/eaptls-client --- ppp-2.4.8/etc.ppp/eaptls-client 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/etc.ppp/eaptls-client 2020-04-07 10:09:50.566118204 +0200 @@ -0,0 +1,10 @@ +# Parameters for authentication using EAP-TLS (client) + +# client name (can be *) +# server name (can be *) +# client certificate file (required) +# server certificate file (optional, if unused put '-') +# CA certificate file (required) +# client private key file (required) + +#client server /root/cert/client.crt - /root/cert/ca.crt /root/cert/client.key diff -Naur ppp-2.4.8/etc.ppp/eaptls-server ppp-2.4.8-eaptls-mppe-1.300/etc.ppp/eaptls-server --- ppp-2.4.8/etc.ppp/eaptls-server 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/etc.ppp/eaptls-server 2020-04-07 10:09:50.566118204 +0200 @@ -0,0 +1,11 @@ +# Parameters for authentication using EAP-TLS (server) + +# client name (can be *) +# server name (can be *) +# client certificate file (optional, if unused put '-') +# server certificate file (required) +# CA certificate file (required) +# server private key file (required) +# allowed addresses (required, can be *) + +#client server - /root/cert/server.crt /root/cert/ca.crt /root/cert/server.key 192.168.1.0/24 diff -Naur ppp-2.4.8/etc.ppp/openssl.cnf ppp-2.4.8-eaptls-mppe-1.300/etc.ppp/openssl.cnf --- ppp-2.4.8/etc.ppp/openssl.cnf 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/etc.ppp/openssl.cnf 2020-04-07 10:09:50.566118204 +0200 @@ -0,0 +1,14 @@ +openssl_conf = openssl_def + +[ openssl_def ] +engines = engine_section + +[ engine_section ] +pkcs11 = pkcs11_section + +[ pkcs11_section ] +engine_id = pkcs11 +dynamic_path = /usr/lib64/openssl/engines/engine_pkcs11.so +MODULE_PATH = /usr/lib64/libeTPkcs11.so +init = 0 + diff -Naur ppp-2.4.8/linux/Makefile.top ppp-2.4.8-eaptls-mppe-1.300/linux/Makefile.top --- ppp-2.4.8/linux/Makefile.top 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/linux/Makefile.top 2020-04-07 10:09:50.566118204 +0200 @@ -26,7 +26,7 @@ cd pppdump; $(MAKE) $(MFLAGS) install install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \ - $(ETCDIR)/chap-secrets + $(ETCDIR)/chap-secrets $(ETCDIR)/eaptls-server $(ETCDIR)/eaptls-client install-devel: cd pppd; $(MAKE) $(MFLAGS) install-devel @@ -37,6 +37,10 @@ $(INSTALL) -c -m 600 etc.ppp/pap-secrets $@ $(ETCDIR)/chap-secrets: $(INSTALL) -c -m 600 etc.ppp/chap-secrets $@ +$(ETCDIR)/eaptls-server: + $(INSTALL) -c -m 600 etc.ppp/eaptls-server $@ +$(ETCDIR)/eaptls-client: + $(INSTALL) -c -m 600 etc.ppp/eaptls-client $@ $(BINDIR): $(INSTALL) -d -m 755 $@ diff -Naur ppp-2.4.8/pppd/Makefile.linux ppp-2.4.8-eaptls-mppe-1.300/pppd/Makefile.linux --- ppp-2.4.8/pppd/Makefile.linux 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/Makefile.linux 2020-04-07 10:10:01.427104384 +0200 @@ -11,16 +11,16 @@ TARGETS = pppd -PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c md5.c ccp.c \ - ecp.c ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c \ +PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c ccp.c \ + ecp.c ipxcp.c auth.c options.c sys-linux.c chap_ms.c \ demand.c utils.c tty.c eap.c chap-md5.c session.c HEADERS = ccp.h session.h chap-new.h ecp.h fsm.h ipcp.h \ - ipxcp.h lcp.h magic.h md5.h patchlevel.h pathnames.h pppd.h \ + ipxcp.h lcp.h magic.h patchlevel.h pathnames.h pppd.h \ upap.h eap.h MANPAGES = pppd.8 -PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o md5.o ccp.o \ +PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o ccp.o \ ecp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o tty.o \ eap.o chap-md5.o session.o @@ -81,6 +81,13 @@ # Use libutil USE_LIBUTIL=y +# Enable EAP-TLS authentication (requires MPPE support, libssl and libcrypto) +USE_EAPTLS=y + +# Either use the internal {md5,sha1} routines or use the openssl versions +USE_OPENSSL_MD5=y +USE_OPENSSL_SHA1=y + MAXOCTETS=y INCLUDE_DIRS= -I../include @@ -92,8 +99,9 @@ ifdef CHAPMS CFLAGS += -DCHAPMS=1 NEEDDES=y -PPPDOBJS += md4.o chap_ms.o +PPPDSRC += md4.c chap_ms.c HEADERS += md4.h chap_ms.h +PPPDOBJS += md4.o chap_ms.o ifdef MSLANMAN CFLAGS += -DMSLANMAN=1 endif @@ -111,11 +119,31 @@ MANPAGES += srp-entry.8 EXTRACLEAN += srp-entry.o NEEDDES=y +endif + +# EAP-TLS +ifdef USE_EAPTLS +CFLAGS += -DUSE_EAPTLS=1 +LIBS += -lssl -lcrypto +PPPDSRC += eap-tls.c +HEADERS += eap-tls.h +PPPDOBJS += eap-tls.o +endif + +ifdef USE_OPENSSL_MD5 +CFLAGS += -DUSE_OPENSSL_MD5=1 +LIBS += -lcrypto +else +PPPDSRC += md5.c +HEADERS += md5.h +PPPDOBJS += md5.o +endif + +ifdef USE_OPENSSL_SHA1 +CFLAGS += -DUSE_OPENSSL_SHA1=1 +LIBS += -lcrypto else -# OpenSSL has an integrated version of SHA-1, and its implementation -# is incompatible with this local SHA-1 implementation. We must use -# one or the other, not both. -PPPDSRCS += sha1.c +PPPDSRC += sha1.c HEADERS += sha1.h PPPDOBJS += sha1.o endif diff -Naur ppp-2.4.8/pppd/Makefile.sol2 ppp-2.4.8-eaptls-mppe-1.300/pppd/Makefile.sol2 --- ppp-2.4.8/pppd/Makefile.sol2 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/Makefile.sol2 2020-04-07 10:09:50.566118204 +0200 @@ -5,10 +5,10 @@ include ../Makedefs.com -CFLAGS = -I../include -DSVR4 -DSOL2 $(COPTS) '-DDESTDIR="@DESTDIR@"' +CFLAGS = -I../include -DSVR4 -DSOL2 $(COPTS) '-DDESTDIR="/usr/local"' LIBS = -lsocket -lnsl -OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o eap.o md5.o \ +OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o eap.o \ tty.o ccp.o ecp.o auth.o options.o demand.o utils.o sys-solaris.o \ chap-md5.o session.o @@ -37,7 +37,21 @@ # Uncomment to enable MS-CHAP CFLAGS += -DUSE_CRYPT -DCHAPMS -DMSLANMAN -DHAVE_CRYPT_H -OBJS += chap_ms.o pppcrypt.o md4.o sha1.o +OBJS += chap_ms.o pppcrypt.o md4.o + +# Uncomment to enable MPPE (in both CHAP and EAP-TLS) +CFLAGS += -DMPPE + +# Uncomment to use the OpenSSL {md5,sha1} routines +#CFLAGS += -DUSE_OPENSSL_MD5 -DUSE_OPENSSL_SHA1 +#LIBS += -lcrypto +# else +OBJS += md5.o sha1.o + +# Uncomment to enable EAP-TLS +CFLAGS += -DUSE_EAPTLS +LIBS += -lcrypto -lssl +OBJS += eap-tls.o # Uncomment for CBCP #CFLAGS += -DCBCP_SUPPORT diff -Naur ppp-2.4.8/pppd/auth.c ppp-2.4.8-eaptls-mppe-1.300/pppd/auth.c --- ppp-2.4.8/pppd/auth.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/auth.c 2020-04-07 10:09:50.567118203 +0200 @@ -113,6 +113,9 @@ #include "upap.h" #include "chap-new.h" #include "eap.h" +#ifdef USE_EAPTLS +#include "eap-tls.h" +#endif #ifdef CBCP_SUPPORT #include "cbcp.h" #endif @@ -186,6 +189,11 @@ /* Hook for a plugin to get the CHAP password for authenticating us */ int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL; +#ifdef USE_EAPTLS +/* Hook for a plugin to get the EAP-TLS password for authenticating us */ +int (*eaptls_passwd_hook) __P((char *user, char *passwd)) = NULL; +#endif + /* Hook for a plugin to say whether it is OK if the peer refuses to authenticate. */ int (*null_auth_hook) __P((struct wordlist **paddrs, @@ -241,6 +249,16 @@ bool explicit_user = 0; /* Set if "user" option supplied */ bool explicit_passwd = 0; /* Set if "password" option supplied */ char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ +#ifdef USE_EAPTLS +char *cacert_file = NULL; /* CA certificate file (pem format) */ +char *ca_path = NULL; /* directory with CA certificates */ +char *cert_file = NULL; /* client certificate file (pem format) */ +char *privkey_file = NULL; /* client private key file (pem format) */ +char *crl_dir = NULL; /* directory containing CRL files */ +char *crl_file = NULL; /* Certificate Revocation List (CRL) file (pem format) */ +char *max_tls_version = NULL; /* Maximum TLS protocol version (default=1.2) */ +bool need_peer_eap = 0; /* Require peer to authenticate us */ +#endif static char *uafname; /* name of most recent +ua file */ @@ -257,6 +275,19 @@ static int have_chap_secret __P((char *, char *, int, int *)); static int have_srp_secret __P((char *client, char *server, int need_ip, int *lacks_ipp)); + +#ifdef USE_EAPTLS +static int have_eaptls_secret_server +__P((char *client, char *server, int need_ip, int *lacks_ipp)); +static int have_eaptls_secret_client __P((char *client, char *server)); +static int scan_authfile_eaptls __P((FILE * f, char *client, char *server, + char *cli_cert, char *serv_cert, + char *ca_cert, char *pk, + struct wordlist ** addrs, + struct wordlist ** opts, + char *filename, int flags)); +#endif + static int ip_addr_check __P((u_int32_t, struct permitted_ip *)); static int scan_authfile __P((FILE *, char *, char *, char *, struct wordlist **, struct wordlist **, @@ -404,6 +435,18 @@ "Set telephone number(s) which are allowed to connect", OPT_PRIV | OPT_A2LIST }, +#ifdef USE_EAPTLS + { "ca", o_string, &cacert_file, "EAP-TLS CA certificate in PEM format" }, + { "capath", o_string, &ca_path, "EAP-TLS CA certificate directory" }, + { "cert", o_string, &cert_file, "EAP-TLS client certificate in PEM format" }, + { "key", o_string, &privkey_file, "EAP-TLS client private key in PEM format" }, + { "crl-dir", o_string, &crl_dir, "Use CRLs in directory" }, + { "crl", o_string, &crl_file, "Use specific CRL file" }, + { "max-tls-version", o_string, &max_tls_version, + "Maximum TLS version (1.0/1.1/1.2 (default)/1.3)" }, + { "need-peer-eap", o_bool, &need_peer_eap, + "Require the peer to authenticate us", 1 }, +#endif /* USE_EAPTLS */ { NULL } }; @@ -737,6 +780,9 @@ lcp_options *wo = &lcp_wantoptions[unit]; lcp_options *go = &lcp_gotoptions[unit]; lcp_options *ho = &lcp_hisoptions[unit]; +#ifdef USE_EAPTLS + lcp_options *ao = &lcp_allowoptions[unit]; +#endif int i; struct protent *protp; @@ -771,6 +817,22 @@ } } +#ifdef USE_EAPTLS + if (need_peer_eap && !ao->neg_eap) { + warn("eap required to authenticate us but no suitable secrets"); + lcp_close(unit, "couldn't negotiate eap"); + status = EXIT_AUTH_TOPEER_FAILED; + return; + } + + if (need_peer_eap && !ho->neg_eap) { + warn("peer doesn't want to authenticate us with eap"); + lcp_close(unit, "couldn't negotiate eap"); + status = EXIT_PEER_AUTH_FAILED; + return; + } +#endif + new_phase(PHASE_AUTHENTICATE); auth = 0; if (go->neg_eap) { @@ -1291,6 +1353,15 @@ our_name, 1, &lacks_ip); } +#ifdef USE_EAPTLS + if (!can_auth && wo->neg_eap) { + can_auth = + have_eaptls_secret_server((explicit_remote ? remote_name : + NULL), our_name, 1, &lacks_ip); + + } +#endif + if (auth_required && !can_auth && noauth_addrs == NULL) { if (default_auth) { option_error( @@ -1345,7 +1416,11 @@ passwd[0] != 0 || (hadchap == 1 || (hadchap == -1 && have_chap_secret(user, (explicit_remote? remote_name: NULL), 0, NULL))) || - have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL)); + have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL) +#ifdef USE_EAPTLS + || have_eaptls_secret_client(user, (explicit_remote? remote_name: NULL)) +#endif + ); hadchap = -1; if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) @@ -1360,8 +1435,14 @@ !have_chap_secret((explicit_remote? remote_name: NULL), our_name, 1, NULL))) && !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1, - NULL)) + NULL) +#ifdef USE_EAPTLS + && !have_eaptls_secret_server((explicit_remote? remote_name: NULL), + our_name, 1, NULL) +#endif + ) go->neg_eap = 0; + } @@ -1721,6 +1802,7 @@ } + /* * get_secret - open the CHAP secret file and return the secret * for authenticating the given client on the given server. @@ -2373,3 +2455,345 @@ auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0); } + + +#ifdef USE_EAPTLS +static int +have_eaptls_secret_server(client, server, need_ip, lacks_ipp) + char *client; + char *server; + int need_ip; + int *lacks_ipp; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + char servcertfile[MAXWORDLEN]; + char clicertfile[MAXWORDLEN]; + char cacertfile[MAXWORDLEN]; + char pkfile[MAXWORDLEN]; + + filename = _PATH_EAPTLSSERVFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + if (client != NULL && client[0] == 0) + client = NULL; + else if (server != NULL && server[0] == 0) + server = NULL; + + ret = + scan_authfile_eaptls(f, client, server, clicertfile, servcertfile, + cacertfile, pkfile, &addrs, NULL, filename, + 0); + + fclose(f); + +/* + if (ret >= 0 && !eaptls_init_ssl(1, cacertfile, servcertfile, + clicertfile, pkfile)) + ret = -1; +*/ + + if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} + + +static int +have_eaptls_secret_client(client, server) + char *client; + char *server; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs = NULL; + char servcertfile[MAXWORDLEN]; + char clicertfile[MAXWORDLEN]; + char cacertfile[MAXWORDLEN]; + char pkfile[MAXWORDLEN]; + + if (client != NULL && client[0] == 0) + client = NULL; + else if (server != NULL && server[0] == 0) + server = NULL; + + if ((cacert_file || ca_path) && cert_file && privkey_file) + return 1; + + filename = _PATH_EAPTLSCLIFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + ret = + scan_authfile_eaptls(f, client, server, clicertfile, servcertfile, + cacertfile, pkfile, &addrs, NULL, filename, + 0); + fclose(f); + +/* + if (ret >= 0 && !eaptls_init_ssl(0, cacertfile, clicertfile, + servcertfile, pkfile)) + ret = -1; +*/ + + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} + + +static int +scan_authfile_eaptls(f, client, server, cli_cert, serv_cert, ca_cert, pk, + addrs, opts, filename, flags) + FILE *f; + char *client; + char *server; + char *cli_cert; + char *serv_cert; + char *ca_cert; + char *pk; + struct wordlist **addrs; + struct wordlist **opts; + char *filename; + int flags; +{ + int newline; + int got_flag, best_flag; + struct wordlist *ap, *addr_list, *alist, **app; + char word[MAXWORDLEN]; + + if (addrs != NULL) + *addrs = NULL; + if (opts != NULL) + *opts = NULL; + addr_list = NULL; + if (!getword(f, word, &newline, filename)) + return -1; /* file is empty??? */ + newline = 1; + best_flag = -1; + for (;;) { + /* + * Skip until we find a word at the start of a line. + */ + while (!newline && getword(f, word, &newline, filename)); + if (!newline) + break; /* got to end of file */ + + /* + * Got a client - check if it's a match or a wildcard. + */ + got_flag = 0; + if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) { + newline = 0; + continue; + } + if (!ISWILD(word)) + got_flag = NONWILD_CLIENT; + + /* + * Now get a server and check if it matches. + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + if (!ISWILD(word)) { + if (server != NULL && strcmp(word, server) != 0) + continue; + got_flag |= NONWILD_SERVER; + } + + /* + * Got some sort of a match - see if it's better than what + * we have already. + */ + if (got_flag <= best_flag) + continue; + + /* + * Get the cli_cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + if (strcmp(word, "-") != 0) { + strlcpy(cli_cert, word, MAXWORDLEN); + } else + cli_cert[0] = 0; + + /* + * Get serv_cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + if (strcmp(word, "-") != 0) { + strlcpy(serv_cert, word, MAXWORDLEN); + } else + serv_cert[0] = 0; + + /* + * Get ca_cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + strlcpy(ca_cert, word, MAXWORDLEN); + + /* + * Get pk + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + strlcpy(pk, word, MAXWORDLEN); + + + /* + * Now read address authorization info and make a wordlist. + */ + app = &alist; + for (;;) { + if (!getword(f, word, &newline, filename) || newline) + break; + ap = (struct wordlist *) + malloc(sizeof(struct wordlist) + strlen(word) + 1); + if (ap == NULL) + novm("authorized addresses"); + ap->word = (char *) (ap + 1); + strcpy(ap->word, word); + *app = ap; + app = &ap->next; + } + *app = NULL; + /* + * This is the best so far; remember it. + */ + best_flag = got_flag; + if (addr_list) + free_wordlist(addr_list); + addr_list = alist; + + if (!newline) + break; + } + + /* scan for a -- word indicating the start of options */ + for (app = &addr_list; (ap = *app) != NULL; app = &ap->next) + if (strcmp(ap->word, "--") == 0) + break; + /* ap = start of options */ + if (ap != NULL) { + ap = ap->next; /* first option */ + free(*app); /* free the "--" word */ + *app = NULL; /* terminate addr list */ + } + if (opts != NULL) + *opts = ap; + else if (ap != NULL) + free_wordlist(ap); + if (addrs != NULL) + *addrs = addr_list; + else if (addr_list != NULL) + free_wordlist(addr_list); + + return best_flag; +} + + +int +get_eaptls_secret(unit, client, server, clicertfile, servcertfile, + cacertfile, capath, pkfile, am_server) + int unit; + char *client; + char *server; + char *clicertfile; + char *servcertfile; + char *cacertfile; + char *capath; + char *pkfile; + int am_server; +{ + FILE *fp; + int ret; + char *filename = NULL; + struct wordlist *addrs = NULL; + struct wordlist *opts = NULL; + + /* maybe overkill, but it eases debugging */ + bzero(clicertfile, MAXWORDLEN); + bzero(servcertfile, MAXWORDLEN); + bzero(cacertfile, MAXWORDLEN); + bzero(capath, MAXWORDLEN); + bzero(pkfile, MAXWORDLEN); + + /* the ca+cert+privkey can also be specified as options */ + if (!am_server && (cacert_file || ca_path) && cert_file && privkey_file ) + { + strlcpy( clicertfile, cert_file, MAXWORDLEN ); + if (cacert_file) + strlcpy( cacertfile, cacert_file, MAXWORDLEN ); + if (ca_path) + strlcpy( capath, ca_path, MAXWORDLEN ); + strlcpy( pkfile, privkey_file, MAXWORDLEN ); + } + else + { + filename = (am_server ? _PATH_EAPTLSSERVFILE : _PATH_EAPTLSCLIFILE); + addrs = NULL; + + fp = fopen(filename, "r"); + if (fp == NULL) + { + error("Can't open eap-tls secret file %s: %m", filename); + return 0; + } + + check_access(fp, filename); + + ret = scan_authfile_eaptls(fp, client, server, clicertfile, servcertfile, + cacertfile, pkfile, &addrs, &opts, filename, 0); + + fclose(fp); + + if (ret < 0) return 0; + } + + if (eaptls_passwd_hook) + { + dbglog( "Calling eaptls password hook" ); + if ( (*eaptls_passwd_hook)(pkfile, passwd) < 0) + { + error("Unable to obtain EAP-TLS password for %s (%s) from plugin", + client, pkfile); + return 0; + } + } + if (am_server) + set_allowed_addrs(unit, addrs, opts); + else if (opts != NULL) + free_wordlist(opts); + if (addrs != NULL) + free_wordlist(addrs); + + return 1; +} +#endif + diff -Naur ppp-2.4.8/pppd/ccp.c ppp-2.4.8-eaptls-mppe-1.300/pppd/ccp.c --- ppp-2.4.8/pppd/ccp.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/ccp.c 2020-04-07 10:09:50.567118203 +0200 @@ -539,6 +539,9 @@ if (go->mppe) { ccp_options *ao = &ccp_allowoptions[f->unit]; int auth_mschap_bits = auth_done[f->unit]; +#ifdef USE_EAPTLS + int auth_eap_bits = auth_done[f->unit]; +#endif int numbits; /* @@ -566,8 +569,23 @@ lcp_close(f->unit, "MPPE required but not available"); return; } + +#ifdef USE_EAPTLS + /* + * MPPE is also possible in combination with EAP-TLS. + * It is not possible to detect if we're doing EAP or EAP-TLS + * at this stage, hence we accept all forms of EAP. If TLS is + * not used then the MPPE keys will not be derived anyway. + */ + /* Leave only the eap auth bits set */ + auth_eap_bits &= (EAP_WITHPEER | EAP_PEER ); + + if ((numbits == 0) && (auth_eap_bits == 0)) { + error("MPPE required, but MS-CHAP[v2] nor EAP-TLS auth are performed."); +#else if (!numbits) { - error("MPPE required, but MS-CHAP[v2] auth not performed."); + error("MPPE required, but MS-CHAP[v2] auth not performed."); +#endif lcp_close(f->unit, "MPPE required but not available"); return; } diff -Naur ppp-2.4.8/pppd/chap-md5.c ppp-2.4.8-eaptls-mppe-1.300/pppd/chap-md5.c --- ppp-2.4.8/pppd/chap-md5.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/chap-md5.c 2020-04-07 10:09:50.567118203 +0200 @@ -36,7 +36,11 @@ #include "chap-new.h" #include "chap-md5.h" #include "magic.h" +#ifdef USE_OPENSSL_MD5 +#include "openssl/md5.h" +#else #include "md5.h" +#endif /* USE_OPENSSL_MD5 */ #define MD5_HASH_SIZE 16 #define MD5_MIN_CHALLENGE 16 diff -Naur ppp-2.4.8/pppd/chap_ms.c ppp-2.4.8-eaptls-mppe-1.300/pppd/chap_ms.c --- ppp-2.4.8/pppd/chap_ms.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/chap_ms.c 2020-04-07 10:09:50.567118203 +0200 @@ -534,7 +534,7 @@ char *username, u_char Challenge[8]) { - SHA1_CTX sha1Context; + SHA_CTX sha1Context; u_char sha1Hash[SHA1_SIGNATURE_SIZE]; char *user; @@ -670,7 +670,7 @@ 0x6E }; int i; - SHA1_CTX sha1Context; + SHA_CTX sha1Context; u_char Digest[SHA1_SIGNATURE_SIZE]; u_char Challenge[8]; @@ -724,7 +724,7 @@ void mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) { - SHA1_CTX sha1Context; + SHA_CTX sha1Context; u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ SHA1_Init(&sha1Context); @@ -768,7 +768,7 @@ mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], u_char NTResponse[24], int IsServer) { - SHA1_CTX sha1Context; + SHA_CTX sha1Context; u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ diff -Naur ppp-2.4.8/pppd/eap-tls.c ppp-2.4.8-eaptls-mppe-1.300/pppd/eap-tls.c --- ppp-2.4.8/pppd/eap-tls.c 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/eap-tls.c 2020-04-07 10:09:50.568118202 +0200 @@ -0,0 +1,1560 @@ +/* * eap-tls.c - EAP-TLS implementation for PPP + * + * Copyright (c) Beniamino Galvani 2005 All rights reserved. + * Jan Just Keijser 2006-2019 All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pppd.h" +#include "eap.h" +#include "eap-tls.h" +#include "fsm.h" +#include "lcp.h" +#include "pathnames.h" + +typedef struct pw_cb_data +{ + const void *password; + const char *prompt_info; +} PW_CB_DATA; + +/* The openssl configuration file and engines can be loaded only once */ +static CONF *ssl_config = NULL; +static ENGINE *cert_engine = NULL; +static ENGINE *pkey_engine = NULL; + +/* TLSv1.3 do we have a session ticket ? */ +static int have_session_ticket = 0; + +int ssl_verify_callback(int, X509_STORE_CTX *); +void ssl_msg_callback(int write_p, int version, int ct, const void *buf, + size_t len, SSL * ssl, void *arg); +int ssl_new_session_cb(SSL *s, SSL_SESSION *sess); + +X509 *get_X509_from_file(char *filename); +int ssl_cmp_certs(char *filename, X509 * a); + +#ifdef MPPE + +#define EAPTLS_MPPE_KEY_LEN 32 + +/* + * The following stuff is only needed if SSL_export_keying_material() is not available + */ + +#if OPENSSL_VERSION_NUMBER < 0x10001000L + +/* + * https://wiki.openssl.org/index.php/1.1_API_Changes + * tries to provide some guidance but ultimately falls short. + * + */ + +static void HMAC_CTX_free(HMAC_CTX *ctx) +{ + if (ctx != NULL) { + HMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +static HMAC_CTX *HMAC_CTX_new(void) +{ + HMAC_CTX *ctx = OPENSSL_malloc(sizeof(*ctx)); + if (ctx != NULL) + HMAC_CTX_init(ctx); + return ctx; +} + +static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, + size_t outlen) +{ + if (outlen == 0) + return sizeof(ssl->s3->client_random); + if (outlen > sizeof(ssl->s3->client_random)) + outlen = sizeof(ssl->s3->client_random); + memcpy(out, ssl->s3->client_random, outlen); + return outlen; +} + +static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, + size_t outlen) +{ + if (outlen == 0) + return sizeof(ssl->s3->server_random); + if (outlen > sizeof(ssl->s3->server_random)) + outlen = sizeof(ssl->s3->server_random); + memcpy(out, ssl->s3->server_random, outlen); + return outlen; +} + +static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, + unsigned char *out, size_t outlen) +{ + if (outlen == 0) + return session->master_key_length; + if (outlen > session->master_key_length) + outlen = session->master_key_length; + memcpy(out, session->master_key, outlen); + return outlen; +} + + +/* + * TLS PRF from RFC 2246 + */ +static void P_hash(const EVP_MD *evp_md, + const unsigned char *secret, unsigned int secret_len, + const unsigned char *seed, unsigned int seed_len, + unsigned char *out, unsigned int out_len) +{ + HMAC_CTX *ctx_a, *ctx_out; + unsigned char a[HMAC_MAX_MD_CBLOCK]; + unsigned int size; + + ctx_a = HMAC_CTX_new(); + ctx_out = HMAC_CTX_new(); + HMAC_Init_ex(ctx_a, secret, secret_len, evp_md, NULL); + HMAC_Init_ex(ctx_out, secret, secret_len, evp_md, NULL); + + size = HMAC_size(ctx_out); + + /* Calculate A(1) */ + HMAC_Update(ctx_a, seed, seed_len); + HMAC_Final(ctx_a, a, NULL); + + while (1) { + /* Calculate next part of output */ + HMAC_Update(ctx_out, a, size); + HMAC_Update(ctx_out, seed, seed_len); + + /* Check if last part */ + if (out_len < size) { + HMAC_Final(ctx_out, a, NULL); + memcpy(out, a, out_len); + break; + } + + /* Place digest in output buffer */ + HMAC_Final(ctx_out, out, NULL); + HMAC_Init_ex(ctx_out, NULL, 0, NULL, NULL); + out += size; + out_len -= size; + + /* Calculate next A(i) */ + HMAC_Init_ex(ctx_a, NULL, 0, NULL, NULL); + HMAC_Update(ctx_a, a, size); + HMAC_Final(ctx_a, a, NULL); + } + + HMAC_CTX_free(ctx_a); + HMAC_CTX_free(ctx_out); + memset(a, 0, sizeof(a)); +} + +static void PRF(const unsigned char *secret, unsigned int secret_len, + const unsigned char *seed, unsigned int seed_len, + unsigned char *out, unsigned char *buf, unsigned int out_len) +{ + unsigned int i; + unsigned int len = (secret_len + 1) / 2; + const unsigned char *s1 = secret; + const unsigned char *s2 = secret + (secret_len - len); + + P_hash(EVP_md5(), s1, len, seed, seed_len, out, out_len); + P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len); + + for (i=0; i < out_len; i++) { + out[i] ^= buf[i]; + } +} + +static int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen, + const char *label, size_t llen, + const unsigned char *p, size_t plen, + int use_context) +{ + unsigned char seed[64 + 2*SSL3_RANDOM_SIZE]; + unsigned char buf[4*EAPTLS_MPPE_KEY_LEN]; + unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; + size_t master_key_length; + unsigned char *pp; + + pp = seed; + + memcpy(pp, label, llen); + pp += llen; + + llen += SSL_get_client_random(s, pp, SSL3_RANDOM_SIZE); + pp += SSL3_RANDOM_SIZE; + + llen += SSL_get_server_random(s, pp, SSL3_RANDOM_SIZE); + + master_key_length = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, + sizeof(master_key)); + PRF(master_key, master_key_length, seed, llen, out, buf, olen); + + return 1; +} + +#endif /* OPENSSL_VERSION_NUMBER < 0x10001000L */ + + +/* + * OpenSSL 1.1+ introduced a generic TLS_method() + * For older releases we substitute the appropriate method + */ + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +#define TLS_method SSLv23_method + +#define SSL3_RT_HEADER 0x100 + +#ifndef SSL_CTX_set_max_proto_version +/** Mimics SSL_CTX_set_max_proto_version for OpenSSL < 1.1 */ +static inline int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, long tls_ver_max) +{ + long sslopt = 0; + + if (tls_ver_max < TLS1_VERSION) + { + sslopt |= SSL_OP_NO_TLSv1; + } +#ifdef SSL_OP_NO_TLSv1_1 + if (tls_ver_max < TLS1_1_VERSION) + { + sslopt |= SSL_OP_NO_TLSv1_1; + } +#endif +#ifdef SSL_OP_NO_TLSv1_2 + if (tls_ver_max < TLS1_2_VERSION) + { + sslopt |= SSL_OP_NO_TLSv1_2; + } +#endif + SSL_CTX_set_options(ctx, sslopt); + + return 1; +} +#endif /* SSL_CTX_set_max_proto_version */ + +#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ + + +/* + * Generate keys according to RFC 2716 and add to reply + */ +void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client) +{ + unsigned char out[4*EAPTLS_MPPE_KEY_LEN]; + const char *prf_label; + size_t prf_size; + unsigned char eap_tls13_context[] = { EAPT_TLS }; + unsigned char *context = NULL; + size_t context_len = 0; + unsigned char *p; + + dbglog("EAP-TLS generating MPPE keys"); + if (ets->tls_v13) + { + prf_label = "EXPORTER_EAP_TLS_Key_Material"; + context = eap_tls13_context; + context_len = 1; + } + else + { + prf_label = "client EAP encryption"; + } + + dbglog("EAP-TLS PRF label = %s", prf_label); + prf_size = strlen(prf_label); + if (SSL_export_keying_material(ets->ssl, out, sizeof(out), prf_label, prf_size, + context, context_len, 0) != 1) + { + warn( "EAP-TLS: Failed generating keying material" ); + return; + } + + /* + * We now have the master send and receive keys. + * From these, generate the session send and receive keys. + * (see RFC3079 / draft-ietf-pppext-mppe-keys-03.txt for details) + */ + if (client) + { + p = out; + BCOPY( p, mppe_send_key, sizeof(mppe_send_key) ); + p += EAPTLS_MPPE_KEY_LEN; + BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) ); + } + else + { + p = out; + BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) ); + p += EAPTLS_MPPE_KEY_LEN; + BCOPY( p, mppe_send_key, sizeof(mppe_send_key) ); + } + + mppe_keys_set = 1; +} + +#endif /* MPPE */ + +void log_ssl_errors( void ) +{ + unsigned long ssl_err = ERR_get_error(); + + if (ssl_err != 0) + dbglog("EAP-TLS SSL error stack:"); + while (ssl_err != 0) { + dbglog( ERR_error_string( ssl_err, NULL ) ); + ssl_err = ERR_get_error(); + } +} + + +int password_callback (char *buf, int size, int rwflag, void *u) +{ + if (buf) + { + strncpy (buf, passwd, size); + return strlen (buf); + } + return 0; +} + + +CONF *eaptls_ssl_load_config( void ) +{ + CONF *config; + int ret_code; + long error_line = 33; + + config = NCONF_new( NULL ); + dbglog( "Loading OpenSSL config file" ); + ret_code = NCONF_load( config, _PATH_OPENSSLCONFFILE, &error_line ); + if (ret_code == 0) + { + warn( "EAP-TLS: Error in OpenSSL config file %s at line %d", _PATH_OPENSSLCONFFILE, error_line ); + NCONF_free( config ); + config = NULL; + ERR_clear_error(); + } + + dbglog( "Loading OpenSSL built-ins" ); + ENGINE_load_builtin_engines(); + OPENSSL_load_builtin_modules(); + + dbglog( "Loading OpenSSL configured modules" ); + if (CONF_modules_load( config, NULL, 0 ) <= 0 ) + { + warn( "EAP-TLS: Error loading OpenSSL modules" ); + log_ssl_errors(); + config = NULL; + } + + return config; +} + +ENGINE *eaptls_ssl_load_engine( char *engine_name ) +{ + ENGINE *e = NULL; + + dbglog( "Enabling OpenSSL auto engines" ); + ENGINE_register_all_complete(); + + dbglog( "Loading OpenSSL '%s' engine support", engine_name ); + e = ENGINE_by_id( engine_name ); + if (!e) + { + dbglog( "EAP-TLS: Cannot load '%s' engine support, trying 'dynamic'", engine_name ); + e = ENGINE_by_id( "dynamic" ); + if (e) + { + if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine_name, 0) + || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) + { + warn( "EAP-TLS: Error loading dynamic engine '%s'", engine_name ); + log_ssl_errors(); + ENGINE_free(e); + e = NULL; + } + } + else + { + warn( "EAP-TLS: Cannot load dynamic engine support" ); + } + } + + if (e) + { + dbglog( "Initialising engine" ); + if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) + { + warn( "EAP-TLS: Cannot use that engine" ); + log_ssl_errors(); + ENGINE_free(e); + e = NULL; + } + } + + return e; +} + +/* + * Initialize the SSL stacks and tests if certificates, key and crl + * for client or server use can be loaded. + */ +SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, + char *certfile, char *peer_certfile, char *privkeyfile) +{ + char *cert_engine_name = NULL; + char *cert_identifier = NULL; + char *pkey_engine_name = NULL; + char *pkey_identifier = NULL; + SSL_CTX *ctx; + SSL *ssl; + X509_STORE *certstore; + X509_LOOKUP *lookup; + X509 *tmp; + int ret; +#if defined(TLS1_2_VERSION) + long tls_version = TLS1_2_VERSION; +#elif defined(TLS1_1_VERSION) + long tls_version = TLS1_1_VERSION; +#else + long tls_version = TLS1_VERSION; +#endif + + /* + * Without these can't continue + */ + if (!(cacertfile[0] || capath[0])) + { + error("EAP-TLS: CA certificate file or path missing"); + return NULL; + } + + if (!certfile[0]) + { + error("EAP-TLS: Certificate missing"); + return NULL; + } + + if (!privkeyfile[0]) + { + error("EAP-TLS: Private key missing"); + return NULL; + } + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(TLS_method()); + + if (!ctx) { + error("EAP-TLS: Cannot initialize SSL CTX context"); + goto fail; + } + + /* if the certificate filename is of the form engine:id. e.g. + pkcs11:12345 + then we try to load and use this engine. + If the certificate filename starts with a / or . then we + ALWAYS assume it is a file and not an engine/pkcs11 identifier + */ + if ( index( certfile, '/' ) == NULL && index( certfile, '.') == NULL ) + { + cert_identifier = index( certfile, ':' ); + + if (cert_identifier) + { + cert_engine_name = certfile; + *cert_identifier = '\0'; + cert_identifier++; + + dbglog( "Found certificate engine '%s'", cert_engine_name ); + dbglog( "Found certificate identifier '%s'", cert_identifier ); + } + } + + /* if the privatekey filename is of the form engine:id. e.g. + pkcs11:12345 + then we try to load and use this engine. + If the privatekey filename starts with a / or . then we + ALWAYS assume it is a file and not an engine/pkcs11 identifier + */ + if ( index( privkeyfile, '/' ) == NULL && index( privkeyfile, '.') == NULL ) + { + pkey_identifier = index( privkeyfile, ':' ); + + if (pkey_identifier) + { + pkey_engine_name = privkeyfile; + *pkey_identifier = '\0'; + pkey_identifier++; + + dbglog( "Found privatekey engine '%s'", pkey_engine_name ); + dbglog( "Found privatekey identifier '%s'", pkey_identifier ); + } + } + + if (cert_identifier && pkey_identifier) + { + if (strlen( cert_identifier ) == 0) + { + if (strlen( pkey_identifier ) == 0) + error( "EAP-TLS: both the certificate and privatekey identifiers are missing!" ); + else + { + dbglog( "Substituting privatekey identifier for certificate identifier" ); + cert_identifier = pkey_identifier; + } + } + else + { + if (strlen( pkey_identifier ) == 0) + { + dbglog( "Substituting certificate identifier for privatekey identifier" ); + pkey_identifier = cert_identifier; + } + } + + } + + /* load the openssl config file only once */ + if (!ssl_config) + { + if (cert_engine_name || pkey_engine_name) + ssl_config = eaptls_ssl_load_config(); + + if (ssl_config && cert_engine_name) + cert_engine = eaptls_ssl_load_engine( cert_engine_name ); + + if (ssl_config && pkey_engine_name) + { + /* don't load the same engine twice */ + if ( cert_engine && strcmp( cert_engine_name, pkey_engine_name) == 0 ) + pkey_engine = cert_engine; + else + pkey_engine = eaptls_ssl_load_engine( pkey_engine_name ); + } + } + + SSL_CTX_set_default_passwd_cb (ctx, password_callback); + + if (strlen(cacertfile) == 0) cacertfile = NULL; + if (strlen(capath) == 0) capath = NULL; + + if (!SSL_CTX_load_verify_locations(ctx, cacertfile, capath)) + { + error("EAP-TLS: Cannot load verify locations"); + if (cacertfile) dbglog("CA certificate file = [%s]", cacertfile); + if (capath) dbglog("CA certificate path = [%s]", capath); + goto fail; + } + + if (init_server) + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(cacertfile)); + + if (cert_engine) + { + struct + { + const char *s_slot_cert_id; + X509 *cert; + } cert_info; + + cert_info.s_slot_cert_id = cert_identifier; + cert_info.cert = NULL; + + if (!ENGINE_ctrl_cmd( cert_engine, "LOAD_CERT_CTRL", 0, &cert_info, NULL, 0 ) ) + { + error( "EAP-TLS: Error loading certificate with id '%s' from engine", cert_identifier ); + goto fail; + } + + if (cert_info.cert) + { + dbglog( "Got the certificate, adding it to SSL context" ); + dbglog( "subject = %s", X509_NAME_oneline( X509_get_subject_name( cert_info.cert ), NULL, 0 ) ); + if (SSL_CTX_use_certificate(ctx, cert_info.cert) <= 0) + { + error("EAP-TLS: Cannot use PKCS11 certificate %s", cert_identifier); + goto fail; + } + } + else + { + warn("EAP-TLS: Cannot load PKCS11 key %s", cert_identifier); + log_ssl_errors(); + } + } + else + { + if (!SSL_CTX_use_certificate_chain_file(ctx, certfile)) + { + error( "EAP-TLS: Cannot use public certificate %s", certfile ); + goto fail; + } + } + + + /* + * Check the Before and After dates of the certificate + */ + ssl = SSL_new(ctx); + tmp = SSL_get_certificate(ssl); + + ret = X509_cmp_time(X509_get_notBefore(tmp), NULL); + if (ret == 0) + { + warn( "EAP-TLS: Failed to read certificate notBefore field."); + } + if (ret > 0) + { + warn( "EAP-TLS: Your certificate is not yet valid!"); + } + + ret = X509_cmp_time(X509_get_notAfter(tmp), NULL); + if (ret == 0) + { + warn( "EAP-TLS: Failed to read certificate notAfter field."); + } + if (ret < 0) + { + warn( "EAP-TLS: Your certificate has expired!"); + } + SSL_free(ssl); + + if (pkey_engine) + { + EVP_PKEY *pkey = NULL; + PW_CB_DATA cb_data; + + cb_data.password = passwd; + cb_data.prompt_info = pkey_identifier; + + dbglog( "Loading private key '%s' from engine", pkey_identifier ); + pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, NULL, &cb_data); + if (pkey) + { + dbglog( "Got the private key, adding it to SSL context" ); + if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0) + { + error("EAP-TLS: Cannot use PKCS11 key %s", pkey_identifier); + goto fail; + } + } + else + { + warn("EAP-TLS: Cannot load PKCS11 key %s", pkey_identifier); + log_ssl_errors(); + } + } + else + { + if (!SSL_CTX_use_PrivateKey_file(ctx, privkeyfile, SSL_FILETYPE_PEM)) + { + error("EAP-TLS: Cannot use private key %s", privkeyfile); + goto fail; + } + } + + if (SSL_CTX_check_private_key(ctx) != 1) { + error("EAP-TLS: Private key %s fails security check", privkeyfile); + goto fail; + } + + /* Explicitly set the NO_TICKETS flag to support Win7/Win8 clients */ + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 +#ifdef SSL_OP_NO_TICKET + | SSL_OP_NO_TICKET +#endif + ); + + /* OpenSSL 1.1.1+ does not include RC4 ciphers by default. + * This causes totally obsolete WinXP clients to fail. If you really + * need ppp+EAP-TLS+openssl 1.1.1+WinXP then enable RC4 cipers and + * make sure that you use an OpenSSL that supports them + + SSL_CTX_set_cipher_list(ctx, "RC4"); + */ + + + /* Set up a SSL Session cache with a callback. This is needed for TLSv1.3+. + * During the initial handshake the server signals to the client early on + * that the handshake is finished, even before the client has sent its + * credentials to the server. The actual connection (and moment that the + * client sends its credentials) only starts after the arrival of the first + * session ticket. The 'ssl_new_session_cb' catches this ticket. + */ + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); + SSL_CTX_sess_set_new_cb(ctx, ssl_new_session_cb); + + /* As EAP-TLS+TLSv1.3 is highly experimental we offer the user a chance to override */ + if (max_tls_version) + { + if (strncmp(max_tls_version, "1.0", 3) == 0) + tls_version = TLS1_VERSION; + else if (strncmp(max_tls_version, "1.1", 3) == 0) + tls_version = TLS1_1_VERSION; + else if (strncmp(max_tls_version, "1.2", 3) == 0) +#ifdef TLS1_2_VERSION + tls_version = TLS1_2_VERSION; +#else + { + warn("TLSv1.2 not available. Defaulting to TLSv1.1"); + tls_version = TLS_1_1_VERSION; + } +#endif + else if (strncmp(max_tls_version, "1.3", 3) == 0) +#ifdef TLS1_3_VERSION + tls_version = TLS1_3_VERSION; +#else + warn("TLSv1.3 not available."); +#endif + } + + dbglog("EAP-TLS: Setting max protocol version to 0x%X", tls_version); + SSL_CTX_set_max_proto_version(ctx, tls_version); + + SSL_CTX_set_verify_depth(ctx, 5); + SSL_CTX_set_verify(ctx, + SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + &ssl_verify_callback); + + if (crl_dir) { + if (!(certstore = SSL_CTX_get_cert_store(ctx))) { + error("EAP-TLS: Failed to get certificate store"); + goto fail; + } + + if (!(lookup = + X509_STORE_add_lookup(certstore, X509_LOOKUP_hash_dir()))) { + error("EAP-TLS: Store lookup for CRL failed"); + + goto fail; + } + + X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM); + X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK); + } + + if (crl_file) { + FILE *fp = NULL; + X509_CRL *crl = NULL; + + fp = fopen(crl_file, "r"); + if (!fp) { + error("EAP-TLS: Cannot open CRL file '%s'", crl_file); + goto fail; + } + + crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL); + if (!crl) { + error("EAP-TLS: Cannot read CRL file '%s'", crl_file); + goto fail; + } + + if (!(certstore = SSL_CTX_get_cert_store(ctx))) { + error("EAP-TLS: Failed to get certificate store"); + goto fail; + } + if (!X509_STORE_add_crl(certstore, crl)) { + error("EAP-TLS: Cannot add CRL to certificate store"); + goto fail; + } + X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK); + + } + + /* + * If a peer certificate file was specified, it must be valid, else fail + */ + if (peer_certfile[0]) { + if (!(tmp = get_X509_from_file(peer_certfile))) { + error("EAP-TLS: Error loading client certificate from file %s", + peer_certfile); + goto fail; + } + X509_free(tmp); + } + + return ctx; + +fail: + log_ssl_errors(); + SSL_CTX_free(ctx); + return NULL; +} + +/* + * Determine the maximum packet size by looking at the LCP handshake + */ + +int eaptls_get_mtu(int unit) +{ + int mtu, mru; + + lcp_options *wo = &lcp_wantoptions[unit]; + lcp_options *go = &lcp_gotoptions[unit]; + lcp_options *ho = &lcp_hisoptions[unit]; + lcp_options *ao = &lcp_allowoptions[unit]; + + mtu = ho->neg_mru? ho->mru: PPP_MRU; + mru = go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU; + mtu = MIN(MIN(mtu, mru), ao->mru)- PPP_HDRLEN - 10; + + dbglog("MTU = %d", mtu); + return mtu; +} + + +/* + * Init the ssl handshake (server mode) + */ +int eaptls_init_ssl_server(eap_state * esp) +{ + struct eaptls_session *ets; + char servcertfile[MAXWORDLEN]; + char clicertfile[MAXWORDLEN]; + char cacertfile[MAXWORDLEN]; + char capath[MAXWORDLEN]; + char pkfile[MAXWORDLEN]; + /* + * Allocate new eaptls session + */ + esp->es_server.ea_session = malloc(sizeof(struct eaptls_session)); + if (!esp->es_server.ea_session) + fatal("Allocation error"); + ets = esp->es_server.ea_session; + + if (!esp->es_server.ea_peer) { + error("EAP-TLS: Error: client name not set (BUG)"); + return 0; + } + + strncpy(ets->peer, esp->es_server.ea_peer, MAXWORDLEN); + + dbglog( "getting eaptls secret" ); + if (!get_eaptls_secret(esp->es_unit, esp->es_server.ea_peer, + esp->es_server.ea_name, clicertfile, + servcertfile, cacertfile, capath, pkfile, 1)) { + error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"", + esp->es_server.ea_peer, esp->es_server.ea_name ); + return 0; + } + + ets->mtu = eaptls_get_mtu(esp->es_unit); + + ets->ctx = eaptls_init_ssl(1, cacertfile, capath, servcertfile, clicertfile, pkfile); + if (!ets->ctx) + goto fail; + + if (!(ets->ssl = SSL_new(ets->ctx))) + goto fail; + + /* + * Set auto-retry to avoid timeouts on BIO_read + */ + SSL_set_mode(ets->ssl, SSL_MODE_AUTO_RETRY); + + /* + * Initialize the BIOs we use to read/write to ssl engine + */ + ets->into_ssl = BIO_new(BIO_s_mem()); + ets->from_ssl = BIO_new(BIO_s_mem()); + SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl); + + SSL_set_msg_callback(ets->ssl, ssl_msg_callback); + SSL_set_msg_callback_arg(ets->ssl, ets); + + /* + * Attach the session struct to the connection, so we can later + * retrieve it when doing certificate verification + */ + SSL_set_ex_data(ets->ssl, 0, ets); + + SSL_set_accept_state(ets->ssl); + + ets->tls_v13 = 0; + + ets->data = NULL; + ets->datalen = 0; + ets->alert_sent = 0; + ets->alert_recv = 0; + + /* + * If we specified the client certificate file, store it in ets->peercertfile, + * so we can check it later in ssl_verify_callback() + */ + if (clicertfile[0]) + strncpy(&ets->peercertfile[0], clicertfile, MAXWORDLEN); + else + ets->peercertfile[0] = 0; + + return 1; + +fail: + SSL_CTX_free(ets->ctx); + return 0; +} + +/* + * Init the ssl handshake (client mode) + */ +int eaptls_init_ssl_client(eap_state * esp) +{ + struct eaptls_session *ets; + char servcertfile[MAXWORDLEN]; + char clicertfile[MAXWORDLEN]; + char cacertfile[MAXWORDLEN]; + char capath[MAXWORDLEN]; + char pkfile[MAXWORDLEN]; + + /* + * Allocate new eaptls session + */ + esp->es_client.ea_session = malloc(sizeof(struct eaptls_session)); + if (!esp->es_client.ea_session) + fatal("Allocation error"); + ets = esp->es_client.ea_session; + + /* + * If available, copy server name in ets; it will be used in cert + * verify + */ + if (esp->es_client.ea_peer) + strncpy(ets->peer, esp->es_client.ea_peer, MAXWORDLEN); + else + ets->peer[0] = 0; + + ets->mtu = eaptls_get_mtu(esp->es_unit); + + dbglog( "calling get_eaptls_secret" ); + if (!get_eaptls_secret(esp->es_unit, esp->es_client.ea_name, + ets->peer, clicertfile, + servcertfile, cacertfile, capath, pkfile, 0)) { + error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"", + esp->es_client.ea_name, ets->peer ); + return 0; + } + + dbglog( "calling eaptls_init_ssl" ); + ets->ctx = eaptls_init_ssl(0, cacertfile, capath, clicertfile, servcertfile, pkfile); + if (!ets->ctx) + goto fail; + + ets->ssl = SSL_new(ets->ctx); + + if (!ets->ssl) + goto fail; + + /* + * Initialize the BIOs we use to read/write to ssl engine + */ + dbglog( "Initializing SSL BIOs" ); + ets->into_ssl = BIO_new(BIO_s_mem()); + ets->from_ssl = BIO_new(BIO_s_mem()); + SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl); + + SSL_set_msg_callback(ets->ssl, ssl_msg_callback); + SSL_set_msg_callback_arg(ets->ssl, ets); + + /* + * Attach the session struct to the connection, so we can later + * retrieve it when doing certificate verification + */ + SSL_set_ex_data(ets->ssl, 0, ets); + + SSL_set_connect_state(ets->ssl); + + ets->tls_v13 = 0; + + ets->data = NULL; + ets->datalen = 0; + ets->alert_sent = 0; + ets->alert_recv = 0; + + /* + * If we specified the server certificate file, store it in + * ets->peercertfile, so we can check it later in + * ssl_verify_callback() + */ + if (servcertfile[0]) + strncpy(ets->peercertfile, servcertfile, MAXWORDLEN); + else + ets->peercertfile[0] = 0; + + return 1; + +fail: + dbglog( "eaptls_init_ssl_client: fail" ); + SSL_CTX_free(ets->ctx); + return 0; + +} + +void eaptls_free_session(struct eaptls_session *ets) +{ + if (ets->ssl) + SSL_free(ets->ssl); + + if (ets->ctx) + SSL_CTX_free(ets->ctx); + + free(ets); +} + + +int eaptls_is_init_finished(struct eaptls_session *ets) +{ + if (ets->ssl && SSL_is_init_finished(ets->ssl)) + { + if (ets->tls_v13) + return have_session_ticket; + else + return 1; + } + + return 0; +} + +/* + * Handle a received packet, reassembling fragmented messages and + * passing them to the ssl engine + */ +int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len) +{ + u_char flags; + u_int tlslen = 0; + u_char dummy[65536]; + + if (len < 1) { + warn("EAP-TLS: received no or invalid data"); + return 1; + } + + GETCHAR(flags, inp); + len--; + + if (flags & EAP_TLS_FLAGS_LI && len > 4) { + /* + * LenghtIncluded flag set -> this is the first packet of a message + */ + + /* + * the first 4 octets are the length of the EAP-TLS message + */ + GETLONG(tlslen, inp); + len -= 4; + + if (!ets->data) { + + if (tlslen > EAP_TLS_MAX_LEN) { + error("EAP-TLS: TLS message length > %d, truncated", EAP_TLS_MAX_LEN); + tlslen = EAP_TLS_MAX_LEN; + } + + /* + * Allocate memory for the whole message + */ + ets->data = malloc(tlslen); + if (!ets->data) + fatal("EAP-TLS: allocation error\n"); + + ets->datalen = 0; + ets->tlslen = tlslen; + } + else + warn("EAP-TLS: non-first LI packet? that's odd..."); + } + else if (!ets->data) { + /* + * A non fragmented message without LI flag + */ + + ets->data = malloc(len); + if (!ets->data) + fatal("EAP-TLS: allocation error\n"); + + ets->datalen = 0; + ets->tlslen = len; + } + + if (flags & EAP_TLS_FLAGS_MF) + ets->frag = 1; + else + ets->frag = 0; + + if (len < 0) { + warn("EAP-TLS: received malformed data"); + return 1; + } + + if (len + ets->datalen > ets->tlslen) { + warn("EAP-TLS: received data > TLS message length"); + return 1; + } + + BCOPY(inp, ets->data + ets->datalen, len); + ets->datalen += len; + + if (!ets->frag) { + + /* + * If we have the whole message, pass it to ssl + */ + + if (ets->datalen != ets->tlslen) { + warn("EAP-TLS: received data != TLS message length"); + return 1; + } + + if (BIO_write(ets->into_ssl, ets->data, ets->datalen) == -1) + log_ssl_errors(); + + SSL_read(ets->ssl, dummy, 65536); + + free(ets->data); + ets->data = NULL; + ets->datalen = 0; + } + + return 0; +} + +/* + * Return an eap-tls packet in outp. + * A TLS message read from the ssl engine is buffered in ets->data. + * At each call we control if there is buffered data and send a + * packet of mtu bytes. + */ +int eaptls_send(struct eaptls_session *ets, u_char ** outp) +{ + bool first = 0; + int size; + u_char fromtls[65536]; + int res; + u_char *start; + + start = *outp; + + if (!ets->data) + { + if(!ets->alert_sent) + { + res = SSL_read(ets->ssl, fromtls, 65536); + } + + /* + * Read from ssl + */ + if ((res = BIO_read(ets->from_ssl, fromtls, 65536)) == -1) + { + warn("EAP-TLS send: No data from BIO_read"); + return 1; + } + + ets->datalen = res; + + ets->data = malloc(ets->datalen); + BCOPY(fromtls, ets->data, ets->datalen); + + ets->offset = 0; + first = 1; + + } + + size = ets->datalen - ets->offset; + + if (size > ets->mtu) { + size = ets->mtu; + ets->frag = 1; + } else + ets->frag = 0; + + PUTCHAR(EAPT_TLS, *outp); + + /* + * Set right flags and length if necessary + */ + if (ets->frag && first) { + PUTCHAR(EAP_TLS_FLAGS_LI | EAP_TLS_FLAGS_MF, *outp); + PUTLONG(ets->datalen, *outp); + } else if (ets->frag) { + PUTCHAR(EAP_TLS_FLAGS_MF, *outp); + } else + PUTCHAR(0, *outp); + + /* + * Copy the data in outp + */ + BCOPY(ets->data + ets->offset, *outp, size); + INCPTR(size, *outp); + + /* + * Copy the packet in retransmission buffer + */ + BCOPY(start, &ets->rtx[0], *outp - start); + ets->rtx_len = *outp - start; + + ets->offset += size; + + if (ets->offset >= ets->datalen) { + + /* + * The whole message has been sent + */ + + free(ets->data); + ets->data = NULL; + ets->datalen = 0; + ets->offset = 0; + } + + return 0; +} + +/* + * Get the sent packet from the retransmission buffer + */ +void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp) +{ + BCOPY(ets->rtx, *outp, ets->rtx_len); + INCPTR(ets->rtx_len, *outp); +} + +/* + * Verify a certificate. + * Most of the work (signatures and issuer attributes checking) + * is done by ssl; we check the CN in the peer certificate + * against the peer name. + */ +int ssl_verify_callback(int ok, X509_STORE_CTX * ctx) +{ + char subject[256]; + char cn_str[256]; + X509 *peer_cert; + int err, depth; + SSL *ssl; + struct eaptls_session *ets; + + peer_cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + dbglog("certificate verify depth: %d", depth); + + if (auth_required && !ok) { + X509_NAME_oneline(X509_get_subject_name(peer_cert), + subject, 256); + + X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert), + NID_commonName, cn_str, 256); + + dbglog("Certificate verification error:\n depth: %d CN: %s" + "\n err: %d (%s)\n", depth, cn_str, err, + X509_verify_cert_error_string(err)); + + return 0; + } + + ssl = X509_STORE_CTX_get_ex_data(ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + + ets = (struct eaptls_session *)SSL_get_ex_data(ssl, 0); + + if (ets == NULL) { + error("Error: SSL_get_ex_data returned NULL"); + return 0; + } + + log_ssl_errors(); + + if (!depth) { /* This is the peer certificate */ + + X509_NAME_oneline(X509_get_subject_name(peer_cert), + subject, 256); + + X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert), + NID_commonName, cn_str, 256); + + /* + * If acting as client and the name of the server wasn't specified + * explicitely, we can't verify the server authenticity + */ + if (!ets->peer[0]) { + warn("Peer name not specified: no check"); + return ok; + } + + /* + * Check the CN + */ + if (strcmp(cn_str, ets->peer)) { + error + ("Certificate verification error: CN (%s) != peer_name (%s)", + cn_str, ets->peer); + return 0; + } + + warn("Certificate CN: %s , peer name %s", cn_str, ets->peer); + + /* + * If a peer certificate file was specified, here we check it + */ + if (ets->peercertfile[0]) { + if (ssl_cmp_certs(&ets->peercertfile[0], peer_cert) + != 0) { + error + ("Peer certificate doesn't match stored certificate"); + return 0; + } + } + } + + return ok; +} + +/* + * Compare a certificate with the one stored in a file + */ +int ssl_cmp_certs(char *filename, X509 * a) +{ + X509 *b; + int ret; + + if (!(b = get_X509_from_file(filename))) + return 1; + + ret = X509_cmp(a, b); + X509_free(b); + + return ret; + +} + +X509 *get_X509_from_file(char *filename) +{ + FILE *fp; + X509 *ret; + + if (!(fp = fopen(filename, "r"))) + return NULL; + + ret = PEM_read_X509(fp, NULL, NULL, NULL); + + fclose(fp); + + return ret; +} + +/* + * Every sent & received message this callback function is invoked, + * so we know when alert messages have arrived or are sent and + * we can print debug information about TLS handshake. + */ +void +ssl_msg_callback(int write_p, int version, int content_type, + const void *buf, size_t len, SSL * ssl, void *arg) +{ + char string[256]; + struct eaptls_session *ets = (struct eaptls_session *)arg; + unsigned char code; + const unsigned char*msg = buf; + int hvers = msg[1] << 8 | msg[2]; + + if(write_p) + strcpy(string, " -> "); + else + strcpy(string, " <- "); + + switch(content_type) { + + case SSL3_RT_HEADER: + strcat(string, "SSL/TLS Header: "); + switch(hvers) { + case SSL3_VERSION: + strcat(string, "SSL 3.0"); + break; + case TLS1_VERSION: + strcat(string, "TLS 1.0"); + break; + case TLS1_1_VERSION: + strcat(string, "TLS 1.1"); + break; + case TLS1_2_VERSION: + strcat(string, "TLS 1.2"); + break; + default: + sprintf(string, "SSL/TLS Header: Unknown version (%d)", hvers); + } + break; + + case SSL3_RT_ALERT: + strcat(string, "Alert: "); + code = msg[1]; + + if (write_p) { + ets->alert_sent = 1; + ets->alert_sent_desc = code; + } else { + ets->alert_recv = 1; + ets->alert_recv_desc = code; + } + + strcat(string, SSL_alert_desc_string_long(code)); + break; + + case SSL3_RT_CHANGE_CIPHER_SPEC: + strcat(string, "ChangeCipherSpec"); + break; + +#ifdef SSL3_RT_INNER_CONTENT_TYPE + case SSL3_RT_INNER_CONTENT_TYPE: + strcat(string, "InnerContentType (TLS1.3)"); + break; +#endif + + case SSL3_RT_HANDSHAKE: + + strcat(string, "Handshake: "); + code = msg[0]; + + switch(code) { + case SSL3_MT_HELLO_REQUEST: + strcat(string,"Hello Request"); + break; + case SSL3_MT_CLIENT_HELLO: + strcat(string,"Client Hello"); + break; + case SSL3_MT_SERVER_HELLO: + strcat(string,"Server Hello"); + break; +#ifdef SSL3_MT_NEWSESSION_TICKET + case SSL3_MT_NEWSESSION_TICKET: + strcat(string,"New Session Ticket"); + break; +#endif +#ifdef SSL3_MT_END_OF_EARLY_DATA + case SSL3_MT_END_OF_EARLY_DATA: + strcat(string,"End of Early Data"); + break; +#endif +#ifdef SSL3_MT_ENCRYPTED_EXTENSIONS + case SSL3_MT_ENCRYPTED_EXTENSIONS: + strcat(string,"Encryped Extensions"); + break; +#endif + case SSL3_MT_CERTIFICATE: + strcat(string,"Certificate"); + break; + case SSL3_MT_SERVER_KEY_EXCHANGE: + strcat(string,"Server Key Exchange"); + break; + case SSL3_MT_CERTIFICATE_REQUEST: + strcat(string,"Certificate Request"); + break; + case SSL3_MT_SERVER_DONE: + strcat(string,"Server Hello Done"); + break; + case SSL3_MT_CERTIFICATE_VERIFY: + strcat(string,"Certificate Verify"); + break; + case SSL3_MT_CLIENT_KEY_EXCHANGE: + strcat(string,"Client Key Exchange"); + break; + case SSL3_MT_FINISHED: + strcat(string,"Finished: "); + hvers = SSL_version(ssl); + switch(hvers) { + case SSL3_VERSION: + strcat(string, "SSL 3.0"); + break; + case TLS1_VERSION: + strcat(string, "TLS 1.0"); + break; + case TLS1_1_VERSION: + strcat(string, "TLS 1.1"); + break; + case TLS1_2_VERSION: + strcat(string, "TLS 1.2"); + break; +#ifdef TLS1_3_VERSION + case TLS1_3_VERSION: + strcat(string, "TLS 1.3 (experimental)"); + ets->tls_v13 = 1; + break; +#endif + default: + strcat(string, "Unknown version"); + } + break; + default: + sprintf( string, "Handshake: Unknown SSL3 code received: %d", code ); + } + break; + + default: + sprintf( string, "SSL message contains unknown content type: %d", content_type ); + + } + + /* Alert messages must always be displayed */ + if(content_type == SSL3_RT_ALERT) + error("%s", string); + else + dbglog("%s", string); +} + +int +ssl_new_session_cb(SSL *s, SSL_SESSION *sess) +{ + dbglog("EAP-TLS: Post-Handshake New Session Ticket arrived:"); + have_session_ticket = 1; + + /* always return success */ + return 1; +} + diff -Naur ppp-2.4.8/pppd/eap-tls.h ppp-2.4.8-eaptls-mppe-1.300/pppd/eap-tls.h --- ppp-2.4.8/pppd/eap-tls.h 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/eap-tls.h 2020-04-07 10:09:50.568118202 +0200 @@ -0,0 +1,96 @@ +/* + * eap-tls.h + * + * Copyright (c) Beniamino Galvani 2005 All rights reserved. + * Jan Just Keijser 2006-2019 All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef __EAP_TLS_H__ +#define __EAP_TLS_H__ + +#include "eap.h" + +#include +#include + +#define EAP_TLS_FLAGS_LI 128 /* length included flag */ +#define EAP_TLS_FLAGS_MF 64 /* more fragments flag */ +#define EAP_TLS_FLAGS_START 32 /* start flag */ + +#define EAP_TLS_MAX_LEN 65536 /* max eap tls packet size */ + +struct eaptls_session +{ + u_char *data; /* buffered data */ + int datalen; /* buffered data len */ + int offset; /* from where to send */ + int tlslen; /* total length of tls data */ + bool frag; /* packet is fragmented */ + bool tls_v13; /* whether we've negotiated TLSv1.3 */ + SSL_CTX *ctx; + SSL *ssl; /* ssl connection */ + BIO *from_ssl; + BIO *into_ssl; + char peer[MAXWORDLEN]; /* peer name */ + char peercertfile[MAXWORDLEN]; + bool alert_sent; + u_char alert_sent_desc; + bool alert_recv; + u_char alert_recv_desc; + char rtx[EAP_TLS_MAX_LEN]; /* retransmission buffer */ + int rtx_len; + int mtu; /* unit mtu */ +}; + + +SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath, + char *certfile, char *peer_certfile, char *privkeyfile); +int eaptls_init_ssl_server(eap_state * esp); +int eaptls_init_ssl_client(eap_state * esp); +void eaptls_free_session(struct eaptls_session *ets); + +int eaptls_is_init_finished(struct eaptls_session *ets); + +int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len); +int eaptls_send(struct eaptls_session *ets, u_char ** outp); +void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp); + +int get_eaptls_secret(int unit, char *client, char *server, + char *clicertfile, char *servcertfile, char *cacertfile, + char *capath, char *pkfile, int am_server); + +#ifdef MPPE +#include "mppe.h" /* MPPE_MAX_KEY_LEN */ +extern u_char mppe_send_key[MPPE_MAX_KEY_LEN]; +extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; +extern int mppe_keys_set; + +void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client); +#endif + +#endif diff -Naur ppp-2.4.8/pppd/eap.c ppp-2.4.8-eaptls-mppe-1.300/pppd/eap.c --- ppp-2.4.8/pppd/eap.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/eap.c 2020-04-07 10:09:50.569118201 +0200 @@ -43,6 +43,11 @@ * Based on draft-ietf-pppext-eap-srp-03.txt. */ +/* + * Modification by Beniamino Galvani, Mar 2005 + * Implemented EAP-TLS authentication + */ + #define RCSID "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $" /* @@ -62,8 +67,12 @@ #include "pppd.h" #include "pathnames.h" -#include "md5.h" #include "eap.h" +#ifdef USE_OPENSSL_MD5 +#include "openssl/md5.h" +#else +#include "md5.h" +#endif /* USE_OPENSSL_MD5 */ #ifdef USE_SRP #include @@ -72,8 +81,12 @@ #include "pppcrypt.h" #endif /* USE_SRP */ -#ifndef SHA_DIGESTSIZE -#define SHA_DIGESTSIZE 20 +#ifdef USE_EAPTLS +#include "eap-tls.h" +#endif /* USE_EAPTLS */ + +#ifndef SHA_DIGEST_LENGTH +#define SHA_DIGEST_LENGTH 20 #endif @@ -208,6 +221,9 @@ esp->es_server.ea_id = (u_char)(drand48() * 0x100); esp->es_client.ea_timeout = EAP_DEFREQTIME; esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ; +#ifdef USE_EAPTLS + esp->es_client.ea_using_eaptls = 0; +#endif /* USE_EAPTLS */ } /* @@ -316,8 +332,8 @@ { struct tm *tp; char tbuf[9]; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; + SHA_CTX ctxt; + u_char dig[SHA_DIGEST_LENGTH]; time_t reftime; if (pn_secret == NULL) @@ -435,8 +451,16 @@ u_char vals[2]; struct b64state bs; #endif /* USE_SRP */ +#ifdef USE_EAPTLS + struct eaptls_session *ets; + int secret_len; + char secret[MAXWORDLEN]; +#endif /* USE_EAPTLS */ esp->es_server.ea_timeout = esp->es_savedtime; +#ifdef USE_EAPTLS + esp->es_server.ea_prev_state = esp->es_server.ea_state; +#endif /* USE_EAPTLS */ switch (esp->es_server.ea_state) { case eapBadAuth: return; @@ -561,9 +585,81 @@ break; } #endif /* USE_SRP */ +#ifdef USE_EAPTLS + if (!get_secret(esp->es_unit, esp->es_server.ea_peer, + esp->es_server.ea_name, secret, &secret_len, 1)) { + + esp->es_server.ea_state = eapTlsStart; + break; + } +#endif /* USE_EAPTLS */ + esp->es_server.ea_state = eapMD5Chall; break; +#ifdef USE_EAPTLS + case eapTlsStart: + /* Initialize ssl session */ + if(!eaptls_init_ssl_server(esp)) { + esp->es_server.ea_state = eapBadAuth; + break; + } + + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsRecv: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->alert_sent) { + esp->es_server.ea_state = eapTlsSendAlert; + break; + } + + if (status) { + esp->es_server.ea_state = eapBadAuth; + break; + } + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->frag) + esp->es_server.ea_state = eapTlsSendAck; + else + esp->es_server.ea_state = eapTlsSend; + break; + + case eapTlsSend: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->frag) + esp->es_server.ea_state = eapTlsRecvAck; + else + if(SSL_is_init_finished(ets->ssl)) + esp->es_server.ea_state = eapTlsRecvClient; + else + /* JJK Add "TLS empty record" message here ??? */ + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsSendAck: + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsRecvAck: + if (status) + { + esp->es_server.ea_state = eapBadAuth; + break; + } + + esp->es_server.ea_state = eapTlsSend; + break; + + case eapTlsSendAlert: + esp->es_server.ea_state = eapTlsRecvAlertAck; + break; +#endif /* USE_EAPTLS */ + case eapSRP1: #ifdef USE_SRP ts = (struct t_server *)esp->es_server.ea_session; @@ -629,6 +725,10 @@ } if (esp->es_server.ea_state == eapBadAuth) eap_send_failure(esp); + +#ifdef USE_EAPTLS + dbglog("EAP id=0x%2x '%s' -> '%s'", esp->es_server.ea_id, eap_state_name(esp->es_server.ea_prev_state), eap_state_name(esp->es_server.ea_state)); +#endif /* USE_EAPTLS */ } /* @@ -647,10 +747,10 @@ char *str; #ifdef USE_SRP struct t_server *ts; - u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp; + u_char clear[8], cipher[8], dig[SHA_DIGEST_LENGTH], *optr, *cp; int i, j; struct b64state b64; - SHA1_CTX ctxt; + SHA_CTX ctxt; #endif /* USE_SRP */ /* Handle both initial auth and restart */ @@ -717,6 +817,30 @@ INCPTR(esp->es_server.ea_namelen, outp); break; +#ifdef USE_EAPTLS + case eapTlsStart: + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(EAP_TLS_FLAGS_START, outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSend: + eaptls_send(esp->es_server.ea_session, &outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSendAck: + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(0, outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSendAlert: + eaptls_send(esp->es_server.ea_session, &outp); + eap_figure_next_state(esp, 0); + break; +#endif /* USE_EAPTLS */ + #ifdef USE_SRP case eapSRP1: PUTCHAR(EAPT_SRP, outp); @@ -763,8 +887,8 @@ PUTLONG(SRPVAL_EBIT, outp); ts = (struct t_server *)esp->es_server.ea_session; assert(ts != NULL); - BCOPY(t_serverresponse(ts), outp, SHA_DIGESTSIZE); - INCPTR(SHA_DIGESTSIZE, outp); + BCOPY(t_serverresponse(ts), outp, SHA_DIGEST_LENGTH); + INCPTR(SHA_DIGEST_LENGTH, outp); if (pncrypt_setkey(0)) { /* Generate pseudonym */ @@ -804,9 +928,9 @@ /* Set length and pad out to next 20 octet boundary */ i = outp - optr - 1; *optr = i; - i %= SHA_DIGESTSIZE; + i %= SHA_DIGEST_LENGTH; if (i != 0) { - while (i < SHA_DIGESTSIZE) { + while (i < SHA_DIGEST_LENGTH) { *outp++ = drand48() * 0x100; i++; } @@ -822,14 +946,14 @@ while (optr < outp) { SHA1Final(dig, &ctxt); cp = dig; - while (cp < dig + SHA_DIGESTSIZE) + while (cp < dig + SHA_DIGEST_LENGTH) *optr++ ^= *cp++; SHA1Init(&ctxt); SHA1Update(&ctxt, &esp->es_server.ea_id, 1); SHA1Update(&ctxt, esp->es_server.ea_skey, SESSION_KEY_LEN); - SHA1Update(&ctxt, optr - SHA_DIGESTSIZE, - SHA_DIGESTSIZE); + SHA1Update(&ctxt, optr - SHA_DIGEST_LENGTH, + SHA_DIGEST_LENGTH); } } break; @@ -903,11 +1027,57 @@ eap_server_timeout(arg) void *arg; { +#ifdef USE_EAPTLS + u_char *outp; + u_char *lenloc; + int outlen; +#endif /* USE_EAPTLS */ + eap_state *esp = (eap_state *) arg; if (!eap_server_active(esp)) return; +#ifdef USE_EAPTLS + switch(esp->es_server.ea_prev_state) { + + /* + * In eap-tls the state changes after a request, so we return to + * previous state ... + */ + case(eapTlsStart): + case(eapTlsSendAck): + esp->es_server.ea_state = esp->es_server.ea_prev_state; + break; + + /* + * ... or resend the stored data + */ + case(eapTlsSend): + case(eapTlsSendAlert): + outp = outpacket_buf; + MAKEHEADER(outp, PPP_EAP); + PUTCHAR(EAP_REQUEST, outp); + PUTCHAR(esp->es_server.ea_id, outp); + lenloc = outp; + INCPTR(2, outp); + + eaptls_retransmit(esp->es_server.ea_session, &outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN); + esp->es_server.ea_requests++; + + if (esp->es_server.ea_timeout > 0) + TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout); + + return; + default: + break; + } +#endif /* USE_EAPTLS */ + /* EAP ID number must not change on timeout. */ eap_send_request(esp); } @@ -1154,17 +1324,90 @@ PUTCHAR(id, outp); esp->es_client.ea_id = id; msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u_int32_t) + - SHA_DIGESTSIZE; + SHA_DIGEST_LENGTH; PUTSHORT(msglen, outp); PUTCHAR(EAPT_SRP, outp); PUTCHAR(EAPSRP_CVALIDATOR, outp); PUTLONG(flags, outp); - BCOPY(str, outp, SHA_DIGESTSIZE); + BCOPY(str, outp, SHA_DIGEST_LENGTH); output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); } #endif /* USE_SRP */ +#ifdef USE_EAPTLS +/* + * Send an EAP-TLS response message with tls data + */ +static void +eap_tls_response(esp, id) +eap_state *esp; +u_char id; +{ + u_char *outp; + int outlen; + u_char *lenloc; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + + lenloc = outp; + INCPTR(2, outp); + + /* + If the id in the request is unchanged, we must retransmit + the old data + */ + if(id == esp->es_client.ea_id) + eaptls_retransmit(esp->es_client.ea_session, &outp); + else + eaptls_send(esp->es_client.ea_session, &outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); + + esp->es_client.ea_id = id; +} + +/* + * Send an EAP-TLS ack + */ +static void +eap_tls_sendack(esp, id) +eap_state *esp; +u_char id; +{ + u_char *outp; + int outlen; + u_char *lenloc; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + esp->es_client.ea_id = id; + + lenloc = outp; + INCPTR(2, outp); + + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(0, outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); +} +#endif /* USE_EAPTLS */ + static void eap_send_nak(esp, id, type) eap_state *esp; @@ -1251,8 +1494,8 @@ { u_char val; u_char *datp, *digp; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; + SHA_CTX ctxt; + u_char dig[SHA_DIGEST_LENGTH]; int dsize, fd, olen = len; /* @@ -1261,21 +1504,21 @@ */ val = id; while (len > 0) { - if ((dsize = len % SHA_DIGESTSIZE) == 0) - dsize = SHA_DIGESTSIZE; + if ((dsize = len % SHA_DIGEST_LENGTH) == 0) + dsize = SHA_DIGEST_LENGTH; len -= dsize; datp = inp + len; SHA1Init(&ctxt); SHA1Update(&ctxt, &val, 1); SHA1Update(&ctxt, esp->es_client.ea_skey, SESSION_KEY_LEN); if (len > 0) { - SHA1Update(&ctxt, datp, SHA_DIGESTSIZE); + SHA1Update(&ctxt, datp, SHA_DIGEST_LENGTH); } else { SHA1Update(&ctxt, esp->es_client.ea_name, esp->es_client.ea_namelen); } SHA1Final(dig, &ctxt); - for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++) + for (digp = dig; digp < dig + SHA_DIGEST_LENGTH; digp++) *datp++ ^= *digp; } @@ -1319,12 +1562,17 @@ char rhostname[256]; MD5_CTX mdContext; u_char hash[MD5_SIGNATURE_SIZE]; +#ifdef USE_EAPTLS + u_char flags; + struct eaptls_session *ets = esp->es_client.ea_session; +#endif /* USE_EAPTLS */ + #ifdef USE_SRP struct t_client *tc; struct t_num sval, gval, Nval, *Ap, Bval; u_char vals[2]; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; + SHA_CTX ctxt; + u_char dig[SHA_DIGEST_LENGTH]; int fd; #endif /* USE_SRP */ @@ -1455,6 +1703,96 @@ esp->es_client.ea_namelen); break; +#ifdef USE_EAPTLS + case EAPT_TLS: + + switch(esp->es_client.ea_state) { + + case eapListen: + + if (len < 1) { + error("EAP: received EAP-TLS Listen packet with no data"); + /* Bogus request; wait for something real. */ + return; + } + GETCHAR(flags, inp); + if(flags & EAP_TLS_FLAGS_START){ + + esp->es_client.ea_using_eaptls = 1; + + if (explicit_remote){ + esp->es_client.ea_peer = strdup(remote_name); + esp->es_client.ea_peerlen = strlen(remote_name); + } else + esp->es_client.ea_peer = NULL; + + /* Init ssl session */ + if(!eaptls_init_ssl_client(esp)) { + dbglog("cannot init ssl"); + eap_send_nak(esp, id, EAPT_TLS); + esp->es_client.ea_using_eaptls = 0; + break; + } + + ets = esp->es_client.ea_session; + eap_tls_response(esp, id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + } + + /* The server has sent a bad start packet. */ + eap_send_nak(esp, id, EAPT_TLS); + break; + + case eapTlsRecvAck: + eap_tls_response(esp, id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + + case eapTlsRecv: + if (len < 1) { + error("EAP: discarding EAP-TLS Receive packet with no data"); + /* Bogus request; wait for something real. */ + return; + } + eaptls_receive(ets, inp, len); + + if(ets->frag) { + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecv; + break; + } + + if(ets->alert_recv) { + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecvFailure; + break; + } + + /* Check if TLS handshake is finished */ + if(eaptls_is_init_finished(ets)) { +#ifdef MPPE + eaptls_gen_mppe_keys(ets, 1); +#endif + eaptls_free_session(ets); + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecvSuccess; + break; + } + + eap_tls_response(esp,id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + + default: + eap_send_nak(esp, id, EAPT_TLS); + esp->es_client.ea_using_eaptls = 0; + break; + } + + break; +#endif /* USE_EAPTLS */ + #ifdef USE_SRP case EAPT_SRP: if (len < 1) { @@ -1639,7 +1977,7 @@ esp->es_client.ea_id, id); } } else { - len -= sizeof (u_int32_t) + SHA_DIGESTSIZE; + len -= sizeof (u_int32_t) + SHA_DIGEST_LENGTH; if (len < 0 || t_clientverify(tc, inp + sizeof (u_int32_t)) != 0) { error("EAP: SRP server verification " @@ -1649,7 +1987,7 @@ GETLONG(esp->es_client.ea_keyflags, inp); /* Save pseudonym if user wants it. */ if (len > 0 && esp->es_usepseudo) { - INCPTR(SHA_DIGESTSIZE, inp); + INCPTR(SHA_DIGEST_LENGTH, inp); write_pseudonym(esp, inp, len, id); } } @@ -1676,7 +2014,7 @@ esp->es_client.ea_namelen); SHA1Final(dig, &ctxt); eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig, - SHA_DIGESTSIZE); + SHA_DIGEST_LENGTH); break; default: @@ -1732,10 +2070,15 @@ #ifdef USE_SRP struct t_server *ts; struct t_num A; - SHA1_CTX ctxt; - u_char dig[SHA_DIGESTSIZE]; + eHA_CTX ctxt; + u_char dig[SHA_DIGEST_LENGTH]; #endif /* USE_SRP */ +#ifdef USE_EAPTLS + struct eaptls_session *ets; + u_char flags; +#endif /* USE_EAPTLS */ + if (esp->es_server.ea_id != id) { dbglog("EAP: discarding Response %d; expected ID %d", id, esp->es_server.ea_id); @@ -1775,6 +2118,64 @@ eap_figure_next_state(esp, 0); break; +#ifdef USE_EAPTLS + case EAPT_TLS: + switch(esp->es_server.ea_state) { + + case eapTlsRecv: + + ets = (struct eaptls_session *) esp->es_server.ea_session; + + eap_figure_next_state(esp, + eaptls_receive(esp->es_server.ea_session, inp, len)); + + if(ets->alert_recv) { + eap_send_failure(esp); + break; + } + break; + + case eapTlsRecvAck: + if(len > 1) { + dbglog("EAP-TLS ACK with extra data"); + } + eap_figure_next_state(esp, 0); + break; + + case eapTlsRecvClient: + /* Receive authentication response from client */ + if (len > 0) { + GETCHAR(flags, inp); + + if(len == 1 && !flags) { /* Ack = ok */ +#ifdef MPPE + eaptls_gen_mppe_keys( esp->es_server.ea_session, 0 ); +#endif + eap_send_success(esp); + } + else { /* failure */ + warn("Server authentication failed"); + eap_send_failure(esp); + } + } + else + warn("Bogus EAP-TLS packet received from client"); + + eaptls_free_session(esp->es_server.ea_session); + + break; + + case eapTlsRecvAlertAck: + eap_send_failure(esp); + break; + + default: + eap_figure_next_state(esp, 1); + break; + } + break; +#endif /* USE_EAPTLS */ + case EAPT_NOTIFICATION: dbglog("EAP unexpected Notification; response discarded"); break; @@ -1806,6 +2207,13 @@ esp->es_server.ea_state = eapMD5Chall; break; +#ifdef USE_EAPTLS + /* Send EAP-TLS start packet */ + case EAPT_TLS: + esp->es_server.ea_state = eapTlsStart; + break; +#endif /* USE_EAPTLS */ + default: dbglog("EAP: peer requesting unknown Type %d", vallen); switch (esp->es_server.ea_state) { @@ -1923,9 +2331,9 @@ eap_figure_next_state(esp, 1); break; } - if (len < sizeof (u_int32_t) + SHA_DIGESTSIZE) { + if (len < sizeof (u_int32_t) + SHA_DIGEST_LENGTH) { error("EAP: M1 length %d < %d", len, - sizeof (u_int32_t) + SHA_DIGESTSIZE); + sizeof (u_int32_t) + SHA_DIGEST_LENGTH); eap_figure_next_state(esp, 1); break; } @@ -1962,7 +2370,7 @@ info("EAP: unexpected SRP Subtype 4 Response"); return; } - if (len != SHA_DIGESTSIZE) { + if (len != SHA_DIGEST_LENGTH) { error("EAP: bad Lightweight rechallenge " "response"); return; @@ -1976,7 +2384,7 @@ SHA1Update(&ctxt, esp->es_server.ea_peer, esp->es_server.ea_peerlen); SHA1Final(dig, &ctxt); - if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) { + if (BCMP(dig, inp, SHA_DIGEST_LENGTH) != 0) { error("EAP: failed Lightweight rechallenge"); eap_send_failure(esp); break; @@ -2017,13 +2425,27 @@ int id; int len; { - if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)) { + if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp) +#ifdef USE_EAPTLS + && esp->es_client.ea_state != eapTlsRecvSuccess +#endif /* USE_EAPTLS */ + ) { dbglog("EAP unexpected success message in state %s (%d)", eap_state_name(esp->es_client.ea_state), esp->es_client.ea_state); return; } +#ifdef USE_EAPTLS + if(esp->es_client.ea_using_eaptls && esp->es_client.ea_state != + eapTlsRecvSuccess) { + dbglog("EAP-TLS unexpected success message in state %s (%d)", + eap_state_name(esp->es_client.ea_state), + esp->es_client.ea_state); + return; + } +#endif /* USE_EAPTLS */ + if (esp->es_client.ea_timeout > 0) { UNTIMEOUT(eap_client_timeout, (void *)esp); } @@ -2149,6 +2571,9 @@ int code, id, len, rtype, vallen; u_char *pstart; u_int32_t uval; +#ifdef USE_EAPTLS + u_char flags; +#endif /* USE_EAPTLS */ if (inlen < EAP_HEADERLEN) return (0); @@ -2213,6 +2638,24 @@ } break; +#ifdef USE_EAPTLS + case EAPT_TLS: + if (len < 1) + break; + GETCHAR(flags, inp); + len--; + + if(flags == 0 && len == 0){ + printer(arg, " Ack"); + break; + } + + printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -"); + printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); + printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); + break; +#endif /* USE_EAPTLS */ + case EAPT_SRP: if (len < 3) goto truncated; @@ -2280,10 +2723,10 @@ if (uval != 0) { printer(arg, " f<%X>", uval); } - if ((vallen = len) > SHA_DIGESTSIZE) - vallen = SHA_DIGESTSIZE; + if ((vallen = len) > SHA_DIGEST_LENGTH) + vallen = SHA_DIGEST_LENGTH; printer(arg, " ", len, inp, - len < SHA_DIGESTSIZE ? "?" : ""); + len < SHA_DIGEST_LENGTH ? "?" : ""); INCPTR(vallen, inp); len -= vallen; if (len > 0) { @@ -2324,6 +2767,25 @@ } break; +#ifdef USE_EAPTLS + case EAPT_TLS: + if (len < 1) + break; + GETCHAR(flags, inp); + len--; + + if(flags == 0 && len == 0){ + printer(arg, " Ack"); + break; + } + + printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -"); + printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); + printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); + + break; +#endif /* USE_EAPTLS */ + case EAPT_NAK: if (len <= 0) { printer(arg, " "); @@ -2387,7 +2849,7 @@ printer(arg, " f<%X>", uval); } printer(arg, " ", len, inp, - len == SHA_DIGESTSIZE ? "" : "?"); + len == SHA_DIGEST_LENGTH ? "" : "?"); INCPTR(len, inp); len = 0; break; @@ -2397,9 +2859,9 @@ case EAPSRP_LWRECHALLENGE: printer(arg, " ", len, inp, - len == SHA_DIGESTSIZE ? "" : "?"); - if ((vallen = len) > SHA_DIGESTSIZE) - vallen = SHA_DIGESTSIZE; + len == SHA_DIGEST_LENGTH ? "" : "?"); + if ((vallen = len) > SHA_DIGEST_LENGTH) + vallen = SHA_DIGEST_LENGTH; INCPTR(vallen, inp); len -= vallen; break; @@ -2425,3 +2887,4 @@ return (inp - pstart); } + diff -Naur ppp-2.4.8/pppd/eap.h ppp-2.4.8-eaptls-mppe-1.300/pppd/eap.h --- ppp-2.4.8/pppd/eap.h 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/eap.h 2020-04-07 10:09:50.569118201 +0200 @@ -84,6 +84,16 @@ eapClosed, /* Authentication not in use */ eapListen, /* Client ready (and timer running) */ eapIdentify, /* EAP Identify sent */ + eapTlsStart, /* Send EAP-TLS start packet */ + eapTlsRecv, /* Receive EAP-TLS tls data */ + eapTlsSendAck, /* Send EAP-TLS ack */ + eapTlsSend, /* Send EAP-TLS tls data */ + eapTlsRecvAck, /* Receive EAP-TLS ack */ + eapTlsRecvClient, /* Receive EAP-TLS auth response from client*/ + eapTlsSendAlert, /* Send EAP-TLS tls alert (server)*/ + eapTlsRecvAlertAck, /* Receive EAP-TLS ack after sending alert */ + eapTlsRecvSuccess, /* Receive EAP success */ + eapTlsRecvFailure, /* Receive EAP failure */ eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */ eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */ eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */ @@ -95,9 +105,18 @@ #define EAP_STATES \ "Initial", "Pending", "Closed", "Listen", "Identify", \ + "TlsStart", "TlsRecv", "TlsSendAck", "TlsSend", "TlsRecvAck", "TlsRecvClient",\ + "TlsSendAlert", "TlsRecvAlertAck" , "TlsRecvSuccess", "TlsRecvFailure", \ "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth" -#define eap_client_active(esp) ((esp)->es_client.ea_state == eapListen) +#ifdef USE_EAPTLS +#define eap_client_active(esp) ((esp)->es_client.ea_state != eapInitial &&\ + (esp)->es_client.ea_state != eapPending &&\ + (esp)->es_client.ea_state != eapClosed) +#else +#define eap_client_active(esp) ((esp)->es_client.ea_state == eapListen) +#endif /* USE_EAPTLS */ + #define eap_server_active(esp) \ ((esp)->es_server.ea_state >= eapIdentify && \ (esp)->es_server.ea_state <= eapMD5Chall) @@ -112,11 +131,17 @@ u_short ea_namelen; /* Length of our name */ u_short ea_peerlen; /* Length of peer's name */ enum eap_state_code ea_state; +#ifdef USE_EAPTLS + enum eap_state_code ea_prev_state; +#endif u_char ea_id; /* Current id */ u_char ea_requests; /* Number of Requests sent/received */ u_char ea_responses; /* Number of Responses */ u_char ea_type; /* One of EAPT_* */ u_int32_t ea_keyflags; /* SRP shared key usage flags */ +#ifdef USE_EAPTLS + bool ea_using_eaptls; +#endif }; /* @@ -139,7 +164,12 @@ * Timeouts. */ #define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */ +#ifdef USE_EAPTLS +#define EAP_DEFTRANSMITS 30 /* max # times to transmit */ + /* certificates can be long ... */ +#else #define EAP_DEFTRANSMITS 10 /* max # times to transmit */ +#endif /* USE_EAPTLS */ #define EAP_DEFREQTIME 20 /* Time to wait for peer request */ #define EAP_DEFALLOWREQ 20 /* max # times to accept requests */ diff -Naur ppp-2.4.8/pppd/pathnames.h ppp-2.4.8-eaptls-mppe-1.300/pppd/pathnames.h --- ppp-2.4.8/pppd/pathnames.h 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/pathnames.h 2020-04-07 10:09:50.569118201 +0200 @@ -21,6 +21,13 @@ #define _PATH_UPAPFILE _ROOT_PATH "/etc/ppp/pap-secrets" #define _PATH_CHAPFILE _ROOT_PATH "/etc/ppp/chap-secrets" #define _PATH_SRPFILE _ROOT_PATH "/etc/ppp/srp-secrets" + +#ifdef USE_EAPTLS +#define _PATH_EAPTLSCLIFILE _ROOT_PATH "/etc/ppp/eaptls-client" +#define _PATH_EAPTLSSERVFILE _ROOT_PATH "/etc/ppp/eaptls-server" +#define _PATH_OPENSSLCONFFILE _ROOT_PATH "/etc/ppp/openssl.cnf" +#endif /* USE_EAPTLS */ + #define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options" #define _PATH_IPUP _ROOT_PATH "/etc/ppp/ip-up" #define _PATH_IPDOWN _ROOT_PATH "/etc/ppp/ip-down" diff -Naur ppp-2.4.8/pppd/plugins/Makefile.linux ppp-2.4.8-eaptls-mppe-1.300/pppd/plugins/Makefile.linux --- ppp-2.4.8/pppd/plugins/Makefile.linux 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/plugins/Makefile.linux 2020-04-07 10:09:50.569118201 +0200 @@ -4,6 +4,9 @@ LDFLAGS_SHARED = -shared INSTALL = install +# EAP-TLS +CFLAGS += -DUSE_EAPTLS=1 + DESTDIR = $(INSTROOT)@DESTDIR@ BINDIR = $(DESTDIR)/sbin MANDIR = $(DESTDIR)/share/man/man8 diff -Naur ppp-2.4.8/pppd/plugins/passprompt.c ppp-2.4.8-eaptls-mppe-1.300/pppd/plugins/passprompt.c --- ppp-2.4.8/pppd/plugins/passprompt.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/plugins/passprompt.c 2020-04-07 10:09:50.569118201 +0200 @@ -107,4 +107,7 @@ { add_options(options); pap_passwd_hook = promptpass; +#ifdef USE_EAPTLS + eaptls_passwd_hook = promptpass; +#endif } diff -Naur ppp-2.4.8/pppd/plugins/passwordfd.c ppp-2.4.8-eaptls-mppe-1.300/pppd/plugins/passwordfd.c --- ppp-2.4.8/pppd/plugins/passwordfd.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/plugins/passwordfd.c 2020-04-07 10:09:50.569118201 +0200 @@ -79,4 +79,8 @@ chap_check_hook = pwfd_check; chap_passwd_hook = pwfd_passwd; + +#ifdef USE_EAPTLS + eaptls_passwd_hook = pwfd_passwd; +#endif } diff -Naur ppp-2.4.8/pppd/pppcrypt.c ppp-2.4.8-eaptls-mppe-1.300/pppd/pppcrypt.c --- ppp-2.4.8/pppd/pppcrypt.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/pppcrypt.c 2020-04-07 10:09:50.569118201 +0200 @@ -31,6 +31,7 @@ */ #include +#include #include "pppd.h" #include "pppcrypt.h" diff -Naur ppp-2.4.8/pppd/pppd.8 ppp-2.4.8-eaptls-mppe-1.300/pppd/pppd.8 --- ppp-2.4.8/pppd/pppd.8 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/pppd.8 2020-04-07 10:09:50.570118199 +0200 @@ -260,6 +260,12 @@ compression in the corresponding direction. Use \fInobsdcomp\fR or \fIbsdcomp 0\fR to disable BSD-Compress compression entirely. .TP +.B ca \fIca-file +(EAP-TLS) Use the file \fIca-file\fR as the X.509 Certificate Authority +(CA) file (in PEM format), needed for setting up an EAP-TLS connection. +This option is used on the client-side in conjunction with the \fBcert\fR +and \fBkey\fR options. +.TP .B cdtrcts Use a non-standard hardware flow control (i.e. DTR/CTS) to control the flow of data on the serial port. If neither the \fIcrtscts\fR, @@ -271,6 +277,12 @@ bi-directional flow control. The sacrifice is that this flow control mode does not permit using DTR as a modem control line. .TP +.B cert \fIcertfile +(EAP-TLS) Use the file \fIcertfile\fR as the X.509 certificate (in PEM +format), needed for setting up an EAP-TLS connection. This option is +used on the client-side in conjunction with the \fBca\fR and +\fBkey\fR options. +.TP .B chap\-interval \fIn If this option is given, pppd will rechallenge the peer every \fIn\fR seconds. @@ -299,6 +311,18 @@ 1000 (1 second). This wait period only applies if the \fBconnect\fR or \fBpty\fR option is used. .TP +.B crl \fIfilename +(EAP-TLS) Use the file \fIfilename\fR as the Certificate Revocation List +to check for the validity of the peer's certificate. This option is not +mandatory for setting up an EAP-TLS connection. Also see the \fBcrl-dir\fR +option. +.TP +.B crl-dir \fIdirectory +(EAP-TLS) Use the directory \fIdirectory\fR to scan for CRL files in +has format ($hash.r0) to check for the validity of the peer's certificate. +This option is not mandatory for setting up an EAP-TLS connection. +Also see the \fBcrl\fR option. +.TP .B debug Enables connection debugging facilities. If this option is given, pppd will log the contents of all @@ -563,6 +587,12 @@ the kernel are logged by syslog(1) to a file as directed in the /etc/syslog.conf configuration file. .TP +.B key \fIkeyfile +(EAP-TLS) Use the file \fIkeyfile\fR as the private key file (in PEM +format), needed for setting up an EAP-TLS connection. This option is +used on the client-side in conjunction with the \fBca\fR and +\fBcert\fR options. +.TP .B ktune Enables pppd to alter kernel settings as appropriate. Under Linux, pppd will enable IP forwarding (i.e. set /proc/sys/net/ipv4/ip_forward @@ -721,6 +751,9 @@ Disable Address/Control compression in both directions (send and receive). .TP +.B need-peer-eap +(EAP-TLS) Require the peer to verify our authentication credentials. +.TP .B noauth Do not require the peer to authenticate itself. This option is privileged. diff -Naur ppp-2.4.8/pppd/pppd.h ppp-2.4.8-eaptls-mppe-1.300/pppd/pppd.h --- ppp-2.4.8/pppd/pppd.h 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/pppd.h 2020-04-07 10:09:50.570118199 +0200 @@ -341,6 +341,12 @@ extern bool dryrun; /* check everything, print options, exit */ extern int child_wait; /* # seconds to wait for children at end */ +#ifdef USE_EAPTLS +extern char *crl_dir; +extern char *crl_file; +extern char *max_tls_version; +#endif /* USE_EAPTLS */ + #ifdef MAXOCTETS extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */ extern int maxoctets_dir; /* Direction : @@ -763,6 +769,10 @@ extern int (*chap_passwd_hook) __P((char *user, char *passwd)); extern void (*multilink_join_hook) __P((void)); +#ifdef USE_EAPTLS +extern int (*eaptls_passwd_hook) __P((char *user, char *passwd)); +#endif + /* Let a plugin snoop sent and received packets. Useful for L2TP */ extern void (*snoop_recv_hook) __P((unsigned char *p, int len)); extern void (*snoop_send_hook) __P((unsigned char *p, int len)); diff -Naur ppp-2.4.8/pppd/sha1.c ppp-2.4.8-eaptls-mppe-1.300/pppd/sha1.c --- ppp-2.4.8/pppd/sha1.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/sha1.c 2020-04-07 10:09:50.570118199 +0200 @@ -101,7 +101,7 @@ /* SHA1Init - Initialize new context */ void -SHA1_Init(SHA1_CTX *context) +SHA1_Init(SHA_CTX *context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; @@ -116,7 +116,7 @@ /* Run your data through this. */ void -SHA1_Update(SHA1_CTX *context, const unsigned char *data, unsigned int len) +SHA1_Update(SHA_CTX *context, const unsigned char *data, size_t len) { unsigned int i, j; @@ -140,7 +140,7 @@ /* Add padding and return the message digest. */ void -SHA1_Final(unsigned char digest[20], SHA1_CTX *context) +SHA1_Final(unsigned char *digest, SHA_CTX *context) { u_int32_t i, j; unsigned char finalcount[8]; diff -Naur ppp-2.4.8/pppd/sha1.h ppp-2.4.8-eaptls-mppe-1.300/pppd/sha1.h --- ppp-2.4.8/pppd/sha1.h 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/sha1.h 2020-04-07 10:09:50.570118199 +0200 @@ -1,11 +1,5 @@ /* sha1.h */ -/* If OpenSSL is in use, then use that version of SHA-1 */ -#ifdef OPENSSL -#include -#define __SHA1_INCLUDE_ -#endif - #ifndef __SHA1_INCLUDE_ #ifndef SHA1_SIGNATURE_SIZE @@ -20,11 +14,11 @@ u_int32_t state[5]; u_int32_t count[2]; unsigned char buffer[64]; -} SHA1_CTX; +} SHA_CTX; -extern void SHA1_Init(SHA1_CTX *); -extern void SHA1_Update(SHA1_CTX *, const unsigned char *, unsigned int); -extern void SHA1_Final(unsigned char[SHA1_SIGNATURE_SIZE], SHA1_CTX *); +extern void SHA1_Init(SHA_CTX *context); +extern void SHA1_Update(SHA_CTX *context, const unsigned char *data, size_t len); +extern void SHA1_Final(unsigned char *data, SHA_CTX *context); #define __SHA1_INCLUDE_ #endif /* __SHA1_INCLUDE_ */ diff -Naur ppp-2.4.8/pppd/sys-solaris.c ppp-2.4.8-eaptls-mppe-1.300/pppd/sys-solaris.c --- ppp-2.4.8/pppd/sys-solaris.c 2019-12-31 02:31:26.000000000 +0100 +++ ppp-2.4.8-eaptls-mppe-1.300/pppd/sys-solaris.c 2020-04-07 10:09:50.571118198 +0200 @@ -1550,6 +1550,26 @@ #endif /* defined(INET6) && defined(SOL2) */ } + + +/* + * netif_get_mtu - get the MTU on the PPP network interface. + */ +int +netif_get_mtu(int unit) +{ + struct ifreq ifr; + + memset (&ifr, '\0', sizeof (ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + + if (ioctl(ipfd, SIOCGIFMTU, (caddr_t) &ifr) < 0) { + error("ioctl(SIOCGIFMTU): %m (line %d)", __LINE__); + return 0; + } + return ifr.ifr_mtu; +} + /* * tty_send_config - configure the transmit characteristics of * the ppp interface.