ppp/ppp-2.4.8-eaptls-mppe-1.300...

3949 lines
107 KiB
Diff

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:
+ <engine>:<identifier>
+ 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:
+ <engine>:<identifier>
+ 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 <ca-file>
+ Use the CA public certificate found in <ca-file> in PEM format
+ cert <cert-file>
+ Use the client public certificate found in <cert-file> in PEM format
+ or in engine:engine_id format
+ key <key-file>
+ Use the client private key found in <key-file> in PEM format
+ or in engine:engine_id format
+ crl <crl-file>
+ Use the Certificate Revocation List (CRL) file <crl-file> in PEM format.
+ crl-dir <dir>
+ Use CRL files from directory <dir>. 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 <janjust@nikhef.nl>
+
+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 <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/hmac.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#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 <openssl/ssl.h>
+#include <openssl/bio.h>
+
+#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 <t_pwd.h>
@@ -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, " <M2%.*B%s>", 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, " <missing hint>");
@@ -2387,7 +2849,7 @@
printer(arg, " f<%X>", uval);
}
printer(arg, " <M1%.*B%s>", len, inp,
- len == SHA_DIGESTSIZE ? "" : "?");
+ len == SHA_DIGEST_LENGTH ? "" : "?");
INCPTR(len, inp);
len = 0;
break;
@@ -2397,9 +2859,9 @@
case EAPSRP_LWRECHALLENGE:
printer(arg, " <Response%.*B%s>", 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 <errno.h>
+#include <stdlib.h>
#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 <t_sha.h>
-#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.