d2e1ce41ee
Regenerated all patches from ppp-2.4.6-fedora git repo See: http://www.nikhef.nl/~janjust/ppp/download.html See: https://github.com/msekletar/ppp-2.4.6-fedora
3176 lines
84 KiB
Diff
3176 lines
84 KiB
Diff
From 7887b3d84468e1ebfbe5adc373f0816eda2b995a Mon Sep 17 00:00:00 2001
|
|
From: Michal Sekletar <msekleta@redhat.com>
|
|
Date: Fri, 20 Jun 2014 10:31:43 +0200
|
|
Subject: [PATCH 27/27] pppd: EAP-TLS patch v0.997
|
|
|
|
See: http://www.nikhef.nl/~janjust/ppp/download.html
|
|
---
|
|
README.eap-tls | 280 ++++++++++
|
|
etc.ppp/eaptls-client | 10 +
|
|
etc.ppp/eaptls-server | 11 +
|
|
etc.ppp/openssl.cnf | 14 +
|
|
linux/Makefile.top | 6 +-
|
|
pppd/Makefile.linux | 12 +
|
|
pppd/auth.c | 413 ++++++++++++++-
|
|
pppd/ccp.c | 20 +-
|
|
pppd/chap-md5.c | 4 +
|
|
pppd/eap-tls.c | 1212 +++++++++++++++++++++++++++++++++++++++++++
|
|
pppd/eap-tls.h | 107 ++++
|
|
pppd/eap.c | 449 +++++++++++++++-
|
|
pppd/eap.h | 32 +-
|
|
pppd/md5.c | 4 +
|
|
pppd/md5.h | 3 +
|
|
pppd/pathnames.h | 7 +
|
|
pppd/plugins/Makefile.linux | 3 +
|
|
pppd/plugins/passprompt.c | 3 +
|
|
pppd/plugins/passwordfd.c | 4 +
|
|
pppd/pppd.8 | 33 ++
|
|
pppd/pppd.h | 9 +
|
|
21 files changed, 2629 insertions(+), 7 deletions(-)
|
|
create mode 100644 README.eap-tls
|
|
create mode 100644 etc.ppp/eaptls-client
|
|
create mode 100644 etc.ppp/eaptls-server
|
|
create mode 100644 etc.ppp/openssl.cnf
|
|
create mode 100644 pppd/eap-tls.c
|
|
create mode 100644 pppd/eap-tls.h
|
|
|
|
diff --git a/README.eap-tls b/README.eap-tls
|
|
new file mode 100644
|
|
index 0000000..037be0a
|
|
--- /dev/null
|
|
+++ b/README.eap-tls
|
|
@@ -0,0 +1,280 @@
|
|
+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 2246) 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 option 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.
|
|
+
|
|
diff --git a/etc.ppp/eaptls-client b/etc.ppp/eaptls-client
|
|
new file mode 100644
|
|
index 0000000..7782f0e
|
|
--- /dev/null
|
|
+++ b/etc.ppp/eaptls-client
|
|
@@ -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 --git a/etc.ppp/eaptls-server b/etc.ppp/eaptls-server
|
|
new file mode 100644
|
|
index 0000000..fa53cbd
|
|
--- /dev/null
|
|
+++ b/etc.ppp/eaptls-server
|
|
@@ -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 --git a/etc.ppp/openssl.cnf b/etc.ppp/openssl.cnf
|
|
new file mode 100644
|
|
index 0000000..dd32f30
|
|
--- /dev/null
|
|
+++ b/etc.ppp/openssl.cnf
|
|
@@ -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 --git a/linux/Makefile.top b/linux/Makefile.top
|
|
index f42efd5..9a8945a 100644
|
|
--- a/linux/Makefile.top
|
|
+++ b/linux/Makefile.top
|
|
@@ -28,7 +28,7 @@ install-progs:
|
|
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
|
|
@@ -39,6 +39,10 @@ $(ETCDIR)/pap-secrets:
|
|
$(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 --git a/pppd/Makefile.linux b/pppd/Makefile.linux
|
|
index 943cf83..534ccc2 100644
|
|
--- a/pppd/Makefile.linux
|
|
+++ b/pppd/Makefile.linux
|
|
@@ -79,6 +79,9 @@ CBCP=y
|
|
# Use libutil
|
|
USE_LIBUTIL=y
|
|
|
|
+# Enable EAP-TLS authentication (requires libssl and libcrypto)
|
|
+USE_EAPTLS=y
|
|
+
|
|
MAXOCTETS=y
|
|
|
|
INCLUDE_DIRS= -I../include
|
|
@@ -118,6 +121,15 @@ HEADERS += sha1.h
|
|
PPPDOBJS += sha1.o
|
|
endif
|
|
|
|
+# EAP-TLS
|
|
+ifdef USE_EAPTLS
|
|
+CFLAGS += -DUSE_EAPTLS=1 -I/usr/kerberos/include
|
|
+LIBS += -lssl -lcrypto
|
|
+PPPDSRC += eap-tls.c
|
|
+HEADERS += eap-tls.h
|
|
+PPPDOBJS += eap-tls.o
|
|
+endif
|
|
+
|
|
ifdef HAS_SHADOW
|
|
CFLAGS += -DHAS_SHADOW
|
|
#LIBS += -lshadow $(LIBS)
|
|
diff --git a/pppd/auth.c b/pppd/auth.c
|
|
index 9e957fa..656ffe9 100644
|
|
--- a/pppd/auth.c
|
|
+++ b/pppd/auth.c
|
|
@@ -109,6 +109,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
|
|
@@ -183,6 +186,11 @@ int (*chap_check_hook) __P((void)) = NULL;
|
|
/* 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,
|
|
@@ -238,6 +246,14 @@ bool explicit_remote = 0; /* User specified explicit remote name */
|
|
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 *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) */
|
|
+bool need_peer_eap = 0; /* Require peer to authenticate us */
|
|
+#endif
|
|
|
|
static char *uafname; /* name of most recent +ua file */
|
|
|
|
@@ -254,6 +270,19 @@ static int have_pap_secret __P((int *));
|
|
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 **,
|
|
@@ -401,6 +430,15 @@ option_t auth_options[] = {
|
|
"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" },
|
|
+ { "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" },
|
|
+ { "need-peer-eap", o_bool, &need_peer_eap,
|
|
+ "Require the peer to authenticate us", 1 },
|
|
+#endif /* USE_EAPTLS */
|
|
{ NULL }
|
|
};
|
|
|
|
@@ -730,6 +768,9 @@ link_established(unit)
|
|
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;
|
|
|
|
@@ -764,6 +805,22 @@ link_established(unit)
|
|
}
|
|
}
|
|
|
|
+#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) {
|
|
@@ -1277,6 +1334,15 @@ auth_check_options()
|
|
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(
|
|
@@ -1331,7 +1397,11 @@ auth_reset(unit)
|
|
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))
|
|
@@ -1346,8 +1416,14 @@ auth_reset(unit)
|
|
!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;
|
|
+
|
|
}
|
|
|
|
|
|
@@ -1707,6 +1783,7 @@ have_srp_secret(client, server, need_ip, lacks_ipp)
|
|
}
|
|
|
|
|
|
+
|
|
/*
|
|
* get_secret - open the CHAP secret file and return the secret
|
|
* for authenticating the given client on the given server.
|
|
@@ -2359,3 +2436,335 @@ auth_script(script)
|
|
|
|
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 && 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, pkfile, am_server)
|
|
+ int unit;
|
|
+ char *client;
|
|
+ char *server;
|
|
+ char *clicertfile;
|
|
+ char *servcertfile;
|
|
+ char *cacertfile;
|
|
+ char *pkfile;
|
|
+ int am_server;
|
|
+{
|
|
+ FILE *fp;
|
|
+ int ret;
|
|
+ char *filename = NULL;
|
|
+ struct wordlist *addrs = NULL;
|
|
+ struct wordlist *opts = NULL;
|
|
+
|
|
+ /* in client mode the ca+cert+privkey can also be specified as options */
|
|
+ if (!am_server && cacert_file && cert_file && privkey_file )
|
|
+ {
|
|
+ strlcpy( clicertfile, cert_file, MAXWORDLEN );
|
|
+ strlcpy( cacertfile, cacert_file, MAXWORDLEN );
|
|
+ strlcpy( pkfile, privkey_file, MAXWORDLEN );
|
|
+ servcertfile[0] = '\0';
|
|
+ }
|
|
+ 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 --git a/pppd/ccp.c b/pppd/ccp.c
|
|
index 5814f35..7dead23 100644
|
|
--- a/pppd/ccp.c
|
|
+++ b/pppd/ccp.c
|
|
@@ -540,6 +540,9 @@ ccp_resetci(f)
|
|
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;
|
|
|
|
/*
|
|
@@ -567,8 +570,23 @@ ccp_resetci(f)
|
|
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 --git a/pppd/chap-md5.c b/pppd/chap-md5.c
|
|
index 77dd4ec..269b52c 100644
|
|
--- a/pppd/chap-md5.c
|
|
+++ b/pppd/chap-md5.c
|
|
@@ -36,7 +36,11 @@
|
|
#include "chap-new.h"
|
|
#include "chap-md5.h"
|
|
#include "magic.h"
|
|
+#ifdef USE_EAPTLS
|
|
+#include "eap-tls.h"
|
|
+#else
|
|
#include "md5.h"
|
|
+#endif /* USE_EAPTLS */
|
|
|
|
#define MD5_HASH_SIZE 16
|
|
#define MD5_MIN_CHALLENGE 16
|
|
diff --git a/pppd/eap-tls.c b/pppd/eap-tls.c
|
|
new file mode 100644
|
|
index 0000000..edcb0cb
|
|
--- /dev/null
|
|
+++ b/pppd/eap-tls.c
|
|
@@ -0,0 +1,1212 @@
|
|
+/*
|
|
+ * eap-tls.c - EAP-TLS implementation for PPP
|
|
+ *
|
|
+ * Copyright (c) Beniamino Galvani 2005 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 <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"
|
|
+
|
|
+/* 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;
|
|
+
|
|
+#ifdef MPPE
|
|
+
|
|
+/*
|
|
+ * 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;
|
|
+
|
|
+ HMAC_CTX_init(&ctx_a);
|
|
+ HMAC_CTX_init(&ctx_out);
|
|
+ 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_cleanup(&ctx_a);
|
|
+ HMAC_CTX_cleanup(&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];
|
|
+ }
|
|
+}
|
|
+
|
|
+#define EAPTLS_MPPE_KEY_LEN 32
|
|
+
|
|
+/*
|
|
+ * Generate keys according to RFC 2716 and add to reply
|
|
+ */
|
|
+void eaptls_gen_mppe_keys(struct eaptls_session *ets, const char *prf_label,
|
|
+ int client)
|
|
+{
|
|
+ unsigned char out[4*EAPTLS_MPPE_KEY_LEN], buf[4*EAPTLS_MPPE_KEY_LEN];
|
|
+ unsigned char seed[64 + 2*SSL3_RANDOM_SIZE];
|
|
+ unsigned char *p = seed;
|
|
+ SSL *s = ets->ssl;
|
|
+ size_t prf_size;
|
|
+
|
|
+ prf_size = strlen(prf_label);
|
|
+
|
|
+ memcpy(p, prf_label, prf_size);
|
|
+ p += prf_size;
|
|
+
|
|
+ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
|
|
+ p += SSL3_RANDOM_SIZE;
|
|
+ prf_size += SSL3_RANDOM_SIZE;
|
|
+
|
|
+ memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
|
|
+ prf_size += SSL3_RANDOM_SIZE;
|
|
+
|
|
+ PRF(s->session->master_key, s->session->master_key_length,
|
|
+ seed, prf_size, out, buf, sizeof(out));
|
|
+
|
|
+ /*
|
|
+ * 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
|
|
+
|
|
+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 *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;
|
|
+ X509_STORE *certstore;
|
|
+ X509_LOOKUP *lookup;
|
|
+ X509 *tmp;
|
|
+
|
|
+ /*
|
|
+ * Without these can't continue
|
|
+ */
|
|
+ if (!cacertfile[0])
|
|
+ {
|
|
+ error("EAP-TLS: CA certificate missing");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!certfile[0])
|
|
+ {
|
|
+ error("EAP-TLS: User certificate missing");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!privkeyfile[0])
|
|
+ {
|
|
+ error("EAP-TLS: User private key missing");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ SSL_library_init();
|
|
+ SSL_load_error_strings();
|
|
+
|
|
+ ctx = SSL_CTX_new(TLSv1_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 (!SSL_CTX_load_verify_locations(ctx, cacertfile, NULL))
|
|
+ {
|
|
+ error("EAP-TLS: Cannot load or verify CA file %s", cacertfile);
|
|
+ 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_file(ctx, certfile, SSL_FILETYPE_PEM))
|
|
+ {
|
|
+ error( "EAP-TLS: Cannot use public certificate %s", certfile );
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 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
|
|
+);
|
|
+ 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 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, 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, 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->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 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, 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, 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->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);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * 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;
|
|
+ u_char dummy[65536];
|
|
+
|
|
+ GETCHAR(flags, inp);
|
|
+ len--;
|
|
+
|
|
+ if (flags & EAP_TLS_FLAGS_LI && !ets->data) {
|
|
+
|
|
+ /*
|
|
+ * This is the first packet of a message
|
|
+ */
|
|
+
|
|
+ GETLONG(tlslen, inp);
|
|
+ len -= 4;
|
|
+
|
|
+ if (tlslen > EAP_TLS_MAX_LEN) {
|
|
+ error("Error: 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 if (flags & EAP_TLS_FLAGS_LI && ets->data) {
|
|
+ /*
|
|
+ * Non first with LI (strange...)
|
|
+ */
|
|
+
|
|
+ GETLONG(tlslen, inp);
|
|
+ len -= 4;
|
|
+
|
|
+ }
|
|
+ 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 + 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)
|
|
+ SSL_read(ets->ssl, fromtls, 65536);
|
|
+
|
|
+ /*
|
|
+ * Read from ssl
|
|
+ */
|
|
+ if ((res = BIO_read(ets->from_ssl, fromtls, 65536)) == -1)
|
|
+ fatal("No data from BIO_read");
|
|
+
|
|
+ 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 preverify_ok, X509_STORE_CTX * ctx)
|
|
+{
|
|
+ char subject[256];
|
|
+ char cn_str[256];
|
|
+ X509 *peer_cert;
|
|
+ int err, depth;
|
|
+ int ok = preverify_ok;
|
|
+ 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 1;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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 1;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * 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;
|
|
+
|
|
+ if(write_p)
|
|
+ strcpy(string, " -> ");
|
|
+ else
|
|
+ strcpy(string, " <- ");
|
|
+
|
|
+
|
|
+ switch(content_type) {
|
|
+
|
|
+ case SSL3_RT_ALERT:
|
|
+ strcat(string, "Alert: ");
|
|
+ code = ((const unsigned char *)buf)[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;
|
|
+
|
|
+ case SSL3_RT_HANDSHAKE:
|
|
+
|
|
+ strcat(string, "Handshake: ");
|
|
+ code = ((const unsigned char *)buf)[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
|
|
+ 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");
|
|
+ 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);
|
|
+}
|
|
+
|
|
diff --git a/pppd/eap-tls.h b/pppd/eap-tls.h
|
|
new file mode 100644
|
|
index 0000000..2d45a0b
|
|
--- /dev/null
|
|
+++ b/pppd/eap-tls.h
|
|
@@ -0,0 +1,107 @@
|
|
+/*
|
|
+ * eap-tls.h
|
|
+ *
|
|
+ * Copyright (c) Beniamino Galvani 2005 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>
|
|
+#include <openssl/md5.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 */
|
|
+ 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[65536]; /* retransmission buffer */
|
|
+ int rtx_len;
|
|
+ int mtu; /* unit mtu */
|
|
+};
|
|
+
|
|
+typedef struct pw_cb_data
|
|
+{
|
|
+ const void *password;
|
|
+ const char *prompt_info;
|
|
+} PW_CB_DATA;
|
|
+
|
|
+
|
|
+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);
|
|
+
|
|
+X509 *get_X509_from_file(char *filename);
|
|
+int ssl_cmp_certs(char *filename, X509 * a);
|
|
+
|
|
+SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile,
|
|
+ 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_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 *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, const char *prf_label, int client);
|
|
+
|
|
+#endif
|
|
+
|
|
+#endif
|
|
diff --git a/pppd/eap.c b/pppd/eap.c
|
|
index faced53..bfbce95 100644
|
|
--- a/pppd/eap.c
|
|
+++ b/pppd/eap.c
|
|
@@ -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_EAPTLS
|
|
+#include "eap-tls.h"
|
|
+#else
|
|
+#include "md5.h"
|
|
+#endif /* USE_EAPTLS */
|
|
|
|
#ifdef USE_SRP
|
|
#include <t_pwd.h>
|
|
@@ -209,6 +218,9 @@ int unit;
|
|
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 */
|
|
}
|
|
|
|
/*
|
|
@@ -436,8 +448,16 @@ int status;
|
|
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;
|
|
@@ -562,9 +582,79 @@ int status;
|
|
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
|
|
+ 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;
|
|
@@ -718,6 +808,30 @@ eap_state *esp;
|
|
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);
|
|
@@ -904,11 +1018,57 @@ static void
|
|
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);
|
|
}
|
|
@@ -1166,6 +1326,81 @@ u_char *str;
|
|
}
|
|
#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;
|
|
@@ -1320,6 +1555,11 @@ int len;
|
|
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;
|
|
@@ -1456,6 +1696,90 @@ int len;
|
|
esp->es_client.ea_namelen);
|
|
break;
|
|
|
|
+#ifdef USE_EAPTLS
|
|
+ case EAPT_TLS:
|
|
+
|
|
+ switch(esp->es_client.ea_state) {
|
|
+
|
|
+ case eapListen:
|
|
+
|
|
+ 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:
|
|
+ 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(SSL_is_init_finished(ets->ssl)){
|
|
+#ifdef MPPE
|
|
+ eaptls_gen_mppe_keys( ets, "client EAP encryption", 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) {
|
|
@@ -1737,6 +2061,11 @@ int len;
|
|
u_char dig[SHA_DIGESTSIZE];
|
|
#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);
|
|
@@ -1776,6 +2105,60 @@ int len;
|
|
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 */
|
|
+
|
|
+ GETCHAR(flags, inp);
|
|
+
|
|
+ if(len == 1 && !flags) { /* Ack = ok */
|
|
+#ifdef MPPE
|
|
+ eaptls_gen_mppe_keys( esp->es_server.ea_session, "client EAP encryption", 0 );
|
|
+#endif
|
|
+ eap_send_success(esp);
|
|
+ }
|
|
+ else { /* failure */
|
|
+ eaptls_receive(esp->es_server.ea_session, inp, len);
|
|
+ warn("Server authentication failed");
|
|
+ eap_send_failure(esp);
|
|
+ }
|
|
+
|
|
+ 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;
|
|
@@ -1807,6 +2190,13 @@ int len;
|
|
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) {
|
|
@@ -2018,13 +2408,27 @@ u_char *inp;
|
|
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);
|
|
}
|
|
@@ -2150,6 +2554,9 @@ void *arg;
|
|
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);
|
|
@@ -2214,6 +2621,24 @@ void *arg;
|
|
}
|
|
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;
|
|
@@ -2325,6 +2750,25 @@ void *arg;
|
|
}
|
|
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>");
|
|
@@ -2426,3 +2870,4 @@ void *arg;
|
|
|
|
return (inp - pstart);
|
|
}
|
|
+
|
|
diff --git a/pppd/eap.h b/pppd/eap.h
|
|
index 199d184..3fa5391 100644
|
|
--- a/pppd/eap.h
|
|
+++ b/pppd/eap.h
|
|
@@ -84,6 +84,16 @@ enum eap_state_code {
|
|
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 @@ enum eap_state_code {
|
|
|
|
#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 @@ struct eap_auth {
|
|
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 @@ typedef struct eap_state {
|
|
* 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 --git a/pppd/md5.c b/pppd/md5.c
|
|
index f1291ce..6f8f720 100644
|
|
--- a/pppd/md5.c
|
|
+++ b/pppd/md5.c
|
|
@@ -33,6 +33,8 @@
|
|
***********************************************************************
|
|
*/
|
|
|
|
+#ifndef USE_EAPTLS
|
|
+
|
|
#include <string.h>
|
|
#include "md5.h"
|
|
|
|
@@ -305,3 +307,5 @@ UINT4 *in;
|
|
** End of md5.c **
|
|
******************************** (cut) ********************************
|
|
*/
|
|
+#endif /* USE_EAPTLS */
|
|
+
|
|
diff --git a/pppd/md5.h b/pppd/md5.h
|
|
index 71e8b00..14d7121 100644
|
|
--- a/pppd/md5.h
|
|
+++ b/pppd/md5.h
|
|
@@ -36,6 +36,7 @@
|
|
** documentation and/or software. **
|
|
***********************************************************************
|
|
*/
|
|
+#ifndef USE_EAPTLS
|
|
|
|
#ifndef __MD5_INCLUDE__
|
|
|
|
@@ -63,3 +64,5 @@ void MD5_Final (unsigned char hash[], MD5_CTX *mdContext);
|
|
|
|
#define __MD5_INCLUDE__
|
|
#endif /* __MD5_INCLUDE__ */
|
|
+
|
|
+#endif /* USE_EAPTLS */
|
|
diff --git a/pppd/pathnames.h b/pppd/pathnames.h
|
|
index 24e010c..6275df6 100644
|
|
--- a/pppd/pathnames.h
|
|
+++ b/pppd/pathnames.h
|
|
@@ -22,6 +22,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 --git a/pppd/plugins/Makefile.linux b/pppd/plugins/Makefile.linux
|
|
index b474a19..760cad4 100644
|
|
--- a/pppd/plugins/Makefile.linux
|
|
+++ b/pppd/plugins/Makefile.linux
|
|
@@ -4,6 +4,9 @@ CFLAGS = $(COPTS) -I.. -I../../include -fPIC
|
|
LDFLAGS = -shared
|
|
INSTALL = install
|
|
|
|
+# EAP-TLS
|
|
+CFLAGS += -DUSE_EAPTLS=1
|
|
+
|
|
DESTDIR = $(INSTROOT)@DESTDIR@
|
|
BINDIR = $(DESTDIR)/sbin
|
|
MANDIR = $(DESTDIR)/share/man/man8
|
|
diff --git a/pppd/plugins/passprompt.c b/pppd/plugins/passprompt.c
|
|
index babb6dc..6ba73ca 100644
|
|
--- a/pppd/plugins/passprompt.c
|
|
+++ b/pppd/plugins/passprompt.c
|
|
@@ -107,4 +107,7 @@ void plugin_init(void)
|
|
{
|
|
add_options(options);
|
|
pap_passwd_hook = promptpass;
|
|
+#ifdef USE_EAPTLS
|
|
+ eaptls_passwd_hook = promptpass;
|
|
+#endif
|
|
}
|
|
diff --git a/pppd/plugins/passwordfd.c b/pppd/plugins/passwordfd.c
|
|
index d718f3b..c3f9793 100644
|
|
--- a/pppd/plugins/passwordfd.c
|
|
+++ b/pppd/plugins/passwordfd.c
|
|
@@ -79,4 +79,8 @@ void plugin_init (void)
|
|
|
|
chap_check_hook = pwfd_check;
|
|
chap_passwd_hook = pwfd_passwd;
|
|
+
|
|
+#ifdef USE_EAPTLS
|
|
+ eaptls_passwd_hook = pwfd_passwd;
|
|
+#endif
|
|
}
|
|
diff --git a/pppd/pppd.8 b/pppd/pppd.8
|
|
index 2dd6e1a..75dd6f3 100644
|
|
--- a/pppd/pppd.8
|
|
+++ b/pppd/pppd.8
|
|
@@ -248,6 +248,12 @@ Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
|
|
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,
|
|
@@ -259,6 +265,12 @@ RTS output. Such serial ports use this mode to implement true
|
|
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.
|
|
@@ -287,6 +299,18 @@ negotiation by sending its first LCP packet. The default value is
|
|
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
|
|
@@ -551,6 +575,12 @@ transmitted packets be printed. On most systems, messages printed by
|
|
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
|
|
@@ -709,6 +739,9 @@ name to \fIname\fR.)
|
|
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 --git a/pppd/pppd.h b/pppd/pppd.h
|
|
index 5f72f72..523f226 100644
|
|
--- a/pppd/pppd.h
|
|
+++ b/pppd/pppd.h
|
|
@@ -324,6 +324,11 @@ extern bool dump_options; /* print out option values */
|
|
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;
|
|
+#endif /* USE_EAPTLS */
|
|
+
|
|
#ifdef MAXOCTETS
|
|
extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */
|
|
extern int maxoctets_dir; /* Direction :
|
|
@@ -738,6 +743,10 @@ extern int (*chap_check_hook) __P((void));
|
|
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));
|
|
--
|
|
1.8.3.1
|
|
|