Sisyphus repository
Last update: 1 october 2023 | SRPMs: 18631 | Visits: 37567377
en ru br
ALT Linux repos
S:2.5.0-alt1
5.0: 2.4.4-alt11
4.1: 2.4.4-alt10.M41.1
4.0: 2.4.4-alt10
+updates:2.4.4-alt10
3.0: 2.4.2-alt6
+updates:2.4.2-alt6.M30.1

Group :: Networking/Other
RPM: ppp

 Main   Changelog   Spec   Patches   Sources   Download   Gear   Bugs and FR  Repocop 

Patch: ppp-2.4.5-openssl+eaptls.patch
Download


 README.eap-tls              |  169 +++++++
 etc.ppp/eaptls-client       |   10 +
 etc.ppp/eaptls-server       |   11 +
 etc.ppp/openssl.cnf         |   14 +
 linux/Makefile.top          |    6 +-
 openssl.cnf                 |   14 +
 pppd/Makefile.linux         |   44 ++-
 pppd/auth.c                 |  412 +++++++++++++++-
 pppd/ccp.c                  |   20 +-
 pppd/chap-md5.c             |    8 +
 pppd/chap_ms.c              |   22 +-
 pppd/eap-tls.c              | 1177 +++++++++++++++++++++++++++++++++++++++++++
 pppd/eap-tls.h              |  107 ++++
 pppd/eap.c                  |  454 +++++++++++++++++-
 pppd/eap.h                  |   32 ++-
 pppd/md4.c                  |   22 +-
 pppd/md4.h                  |   16 +-
 pppd/md5.c                  |    5 +-
 pppd/md5.h                  |    2 +-
 pppd/options.c              |   10 +
 pppd/pathnames.h            |    7 +
 pppd/plugins/Makefile.linux |    3 +
 pppd/plugins/passprompt.c   |    3 +
 pppd/plugins/passwordfd.c   |    5 +
 pppd/pppd.h                 |    9 +
 pppd/sha1.h                 |    7 +-
 26 files changed, 2546 insertions(+), 43 deletions(-)
diff --git a/README.eap-tls b/README.eap-tls
new file mode 100644
index 0000000..0a4fee9
--- /dev/null
+++ b/README.eap-tls
@@ -0,0 +1,169 @@
+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-dir <dir>
+        	Use CRL files from 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. Notes
+
+   This is experimental code.
+   Send suggestions and comments to Jan Just Keijser <janjust@nikhef.nl>
+
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 f63d45e..894f8f3 100644
--- a/linux/Makefile.top
+++ b/linux/Makefile.top
@@ -26,7 +26,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
@@ -37,6 +37,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/openssl.cnf b/openssl.cnf
new file mode 100644
index 0000000..dd32f30
--- /dev/null
+++ b/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/pppd/Makefile.linux b/pppd/Makefile.linux
index 060db6a..74cb900 100644
--- a/pppd/Makefile.linux
+++ b/pppd/Makefile.linux
@@ -11,7 +11,7 @@ INCDIR = $(DESTDIR)/include
 
 TARGETS = pppd
 
-PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c md5.c ccp.c \
+PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c ccp.c \
 	   ecp.c ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c \
 	   demand.c utils.c tty.c eap.c chap-md5.c session.c
 
@@ -20,7 +20,7 @@ HEADERS = ccp.h session.h chap-new.h ecp.h fsm.h ipcp.h \
 	upap.h eap.h
 
 MANPAGES = pppd.8
-PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o md5.o ccp.o \
+PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o ccp.o \
 	   ecp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o tty.o \
 	   eap.o chap-md5.o session.o
 
@@ -73,6 +73,9 @@ PLUGIN=y
 # Enable EAP SRP-SHA1 authentication (requires libsrp)
 #USE_SRP=y
 
+# Enable EAP-TLS authentication (requires libssl)
+USE_EAPTLS=y
+
 MAXOCTETS=y
 
 INCLUDE_DIRS= -I../include
@@ -84,8 +87,14 @@ CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS) '-DDESTDIR="@DESTDIR@"'
 ifdef CHAPMS
 CFLAGS   += -DCHAPMS=1
 NEEDDES=y
+ifdef USE_BUILTIN_CRYPTO
 PPPDOBJS += md4.o chap_ms.o
-HEADERS	+= md4.h chap_ms.h
+HEADERS  += md4.h chap_ms.h
+else
+PPPDOBJS += chap_ms.o
+HEADERS	 += chap_ms.h
+NEED_OPENSSL=y
+endif
 ifdef MSLANMAN
 CFLAGS   += -DMSLANMAN=1
 endif
@@ -96,20 +105,45 @@ endif
 
 # EAP SRP-SHA1
 ifdef USE_SRP
-CFLAGS	+= -DUSE_SRP -DOPENSSL -I/usr/local/ssl/include
-LIBS	+= -lsrp -L/usr/local/ssl/lib -lcrypto
+CFLAGS	+= -DUSE_SRP
 TARGETS	+= srp-entry
 EXTRAINSTALL = $(INSTALL) -s -c -m 555 srp-entry $(BINDIR)/srp-entry
 MANPAGES += srp-entry.8
 EXTRACLEAN += srp-entry.o
 NEEDDES=y
+NEED_OPENSSL=y
 else
 # OpenSSL has an integrated version of SHA-1, and its implementation
 # is incompatible with this local SHA-1 implementation.  We must use
 # one or the other, not both.
+ifdef USE_BUILTIN_CRYPTO
 PPPDSRCS += sha1.c
 HEADERS += sha1.h
 PPPDOBJS += sha1.o
+else
+NEED_OPENSSL=y
+endif
+endif
+
+ifdef USE_BUILTIN_CRYPTO
+PPPDSRCS += md5.c
+PPPDOBJS += md5.o
+else
+NEED_OPENSSL=y
+endif
+
+ifdef NEED_OPENSSL
+CFLAGS += -DUSE_OPENSSL
+LIBS   += -lcrypto
+endif
+
+# EAP-TLS
+ifdef USE_EAPTLS
+CFLAGS += -DUSE_EAPTLS=1
+LIBS += -lssl -lcrypt
+PPPDSRC += eap-tls.c
+HEADERS += eap-tls.h
+PPPDOBJS += eap-tls.o
 endif
 
 ifdef HAS_SHADOW
diff --git a/pppd/auth.c b/pppd/auth.c
index fb71944..eddebb7 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,12 @@ 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_check_hook) __P((void)) = NULL;
+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 +247,13 @@ 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 */
+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,14 @@ 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" },
+    { "need-peer-eap", o_bool, &need_peer_eap,
+      "Require the peer to authenticate us", 1 },
+#endif /* USE_EAPTLS */
     { NULL }
 };
 
@@ -731,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;
 
@@ -765,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) {
@@ -1278,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(
@@ -1332,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))
@@ -1347,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;
+
 }
 
 
@@ -1706,6 +1781,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.
@@ -2358,3 +2434,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..275bcce 100644
--- a/pppd/chap-md5.c
+++ b/pppd/chap-md5.c
@@ -36,7 +36,15 @@
 #include "chap-new.h"
 #include "chap-md5.h"
 #include "magic.h"
+#ifdef USE_EAPTLS
+#include "eap-tls.h"
+#else
+#ifdef USE_OPENSSL
+#include <openssl/md5.h>
+#else
 #include "md5.h"
+#endif /* USE_OPENSSL */
+#endif /* USE_EAPTLS */
 
 #define MD5_HASH_SIZE		16
 #define MD5_MIN_CHALLENGE	16
diff --git a/pppd/chap_ms.c b/pppd/chap_ms.c
index aec1226..210036e 100644
--- a/pppd/chap_ms.c
+++ b/pppd/chap_ms.c
@@ -89,8 +89,18 @@
 #include "pppd.h"
 #include "chap-new.h"
 #include "chap_ms.h"
+#ifdef USE_OPENSSL
+#include <openssl/md4.h>
+#else
 #include "md4.h"
+#endif
+#ifdef USE_OPENSSL
+#include <openssl/sha.h>
+#define SHA1_SIGNATURE_SIZE SHA_DIGEST_LENGTH
+#define SHA1_CTX SHA_CTX
+#else
 #include "sha1.h"
+#endif
 #include "pppcrypt.h"
 #include "magic.h"
 
@@ -509,7 +519,7 @@ ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
 static void
 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
 {
-#ifdef __NetBSD__
+#if defined __NetBSD__ || defined USE_OPENSSL
     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
     int			mdlen = secret_len;
 #else
@@ -517,15 +527,15 @@ NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
 #endif
     MD4_CTX		md4Context;
 
-    MD4Init(&md4Context);
-    /* MD4Update can take at most 64 bytes at a time */
+    MD4_Init(&md4Context);
+    /* MD4_Update can take at most 64 bytes at a time */
     while (mdlen > 512) {
-	MD4Update(&md4Context, secret, 512);
+	MD4_Update(&md4Context, secret, 512);
 	secret += 64;
 	mdlen -= 512;
     }
-    MD4Update(&md4Context, secret, mdlen);
-    MD4Final(hash, &md4Context);
+    MD4_Update(&md4Context, secret, mdlen);
+    MD4_Final(hash, &md4Context);
 
 }
 
diff --git a/pppd/eap-tls.c b/pppd/eap-tls.c
new file mode 100644
index 0000000..e539f91
--- /dev/null
+++ b/pppd/eap-tls.c
@@ -0,0 +1,1177 @@
+/*
+ * 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;
+    }
+
+	ENGINE_cleanup();
+
+	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 ( 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;
+	}
+
+	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+	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 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,
+			       esp->es_client.ea_peer, clicertfile,
+			       servcertfile, cacertfile, pkfile, 0)) {
+		error( "EAP-TLS: Cannot get secret/password" );
+		error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
+				esp->es_client.ea_name, esp->es_client.ea_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;
+			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 6ea6c1f..4e346c8 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,15 @@
 
 #include "pppd.h"
 #include "pathnames.h"
+#ifdef USE_EAPTLS
+#include "eap-tls.h"
+#else
+#ifdef USE_OPENSSL
+#include <openssl/md5.h>
+#else
 #include "md5.h"
-#include "eap.h"
+#endif /* USE_OPENSSL */
+#endif /* USE_EAPTLS */
 
 #ifdef USE_SRP
 #include <t_pwd.h>
@@ -209,6 +221,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 +451,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 +585,81 @@ 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(SSL_is_init_finished(ets->ssl)) {
+			esp->es_server.ea_state = eapTlsRecvClient; 
+			break;
+		}
+
+		if(ets->frag)
+			esp->es_server.ea_state = eapTlsRecvAck;
+		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 +813,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 +1023,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 +1331,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 +1560,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 +1701,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 +2066,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 +2110,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 +2195,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 +2413,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 +2559,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 +2626,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 +2755,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 +2875,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/md4.c b/pppd/md4.c
index d943e88..9cbffca 100644
--- a/pppd/md4.c
+++ b/pppd/md4.c
@@ -13,10 +13,10 @@
 **          computation.
 **   -- Initialize MD using MDbegin(&MD)
 **   -- For each full block (64 bytes) X you wish to process, call
-**          MD4Update(&MD,X,512)
+**          MD4_Update(&MD,X,512)
 **      (512 is the number of bits in a full block.)
 **   -- For the last block (less than 64 bytes) you wish to process,
-**          MD4Update(&MD,X,n)
+**          MD4_Update(&MD,X,n)
 **      where n is the number of bits in the partial block. A partial
 **      block terminates the computation, so every MD computation
 **      should terminate by processing a partial block, even if it
@@ -96,12 +96,12 @@ MD4_CTX *MDp;
       printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
 }
 
-/* MD4Init(MDp)
+/* MD4_Init(MDp)
 ** Initialize message digest buffer MDp.
 ** This is a user-callable routine.
 */
 void
-MD4Init(MDp)
+MD4_Init(MDp)
 MD4_CTX *MDp;
 {
   int i;
@@ -192,21 +192,21 @@ unsigned char *Xb;
   MDp->buffer[3] += D;
 }
 
-/* MD4Update(MDp,X,count)
+/* MD4_Update(MDp,X,count)
 ** Input: X -- a pointer to an array of unsigned characters.
 **        count -- the number of bits of X to use.
 **          (if not a multiple of 8, uses high bits of last byte.)
 ** Update MDp using the number of bits of X given by count.
 ** This is the basic input routine for an MD4 user.
 ** The routine completes the MD computation when count < 512, so
-** every MD computation should end with one call to MD4Update with a
+** every MD computation should end with one call to MD4_Update with a
 ** count less than 512.  A call with count 0 will be ignored if the
 ** MD has already been terminated (done != 0), so an extra call with
 ** count 0 can be given as a "courtesy close" to force termination
 ** if desired.
 */
 void
-MD4Update(MDp,X,count)
+MD4_Update(MDp,X,count)
 MD4_CTX *MDp;
 unsigned char *X;
 unsigned int count;
@@ -221,7 +221,7 @@ unsigned int count;
   if (count == 0 && MDp->done) return;
   /* check to see if MD is already done and report error */
   if (MDp->done)
-  { printf("\nError: MD4Update MD already done."); return; }
+  { printf("\nError: MD4_Update MD already done."); return; }
 
   /* Add count to MDp->count */
   tmp = count;
@@ -239,7 +239,7 @@ unsigned int count;
   }
   else if (count > 512) /* Check for count too large */
   {
-    printf("\nError: MD4Update called with illegal count value %d.",
+    printf("\nError: MD4_Update called with illegal count value %d.",
 	   count);
     return;
   }
@@ -277,14 +277,14 @@ unsigned int count;
 ** Finish up MD4 computation and return message digest.
 */
 void
-MD4Final(buf, MD)
+MD4_Final(buf, MD)
 unsigned char *buf;
 MD4_CTX *MD;
 {
   int i, j;
   unsigned int w;
 
-  MD4Update(MD, NULL, 0);
+  MD4_Update(MD, NULL, 0);
   for (i = 0; i < 4; ++i) {
     w = MD->buffer[i];
     for (j = 0; j < 4; ++j) {
diff --git a/pppd/md4.h b/pppd/md4.h
index 80e8f9a..344f62d 100644
--- a/pppd/md4.h
+++ b/pppd/md4.h
@@ -25,25 +25,25 @@ typedef struct {
 	unsigned int done;      /* Nonzero means MD computation finished */
 } MD4_CTX;
 
-/* MD4Init(MD4_CTX *)
+/* MD4_Init(MD4_CTX *)
 ** Initialize the MD4_CTX prepatory to doing a message digest
 ** computation.
 */
-extern void MD4Init __P((MD4_CTX *MD));
+extern void MD4_Init __P((MD4_CTX *MD));
 
-/* MD4Update(MD,X,count)
+/* MD4_Update(MD,X,count)
 ** Input: X -- a pointer to an array of unsigned characters.
 **        count -- the number of bits of X to use (an unsigned int).
 ** Updates MD using the first "count" bits of X.
 ** The array pointed to by X is not modified.
-** If count is not a multiple of 8, MD4Update uses high bits of
+** If count is not a multiple of 8, MD4_Update uses high bits of
 ** last byte.
 ** This is the basic input routine for a user.
 ** The routine terminates the MD computation when count < 512, so
-** every MD computation should end with one call to MD4Update with a
+** every MD computation should end with one call to MD4_Update with a
 ** count less than 512.  Zero is OK for a count.
 */
-extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count));
+extern void MD4_Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count));
 
 /* MD4Print(MD)
 ** Prints message digest buffer MD as 32 hexadecimal digits.
@@ -53,11 +53,11 @@ extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count));
 */
 extern void MD4Print __P((MD4_CTX *));
 
-/* MD4Final(buf, MD)
+/* MD4_Final(buf, MD)
 ** Returns message digest from MD and terminates the message
 ** digest computation.
 */
-extern void MD4Final __P((unsigned char *, MD4_CTX *));
+extern void MD4_Final __P((unsigned char *, MD4_CTX *));
 
 /*
 ** End of md4.h
diff --git a/pppd/md5.c b/pppd/md5.c
index f1291ce..df0716e 100644
--- a/pppd/md5.c
+++ b/pppd/md5.c
@@ -115,7 +115,7 @@ MD5_CTX *mdContext;
   mdContext->buf[3] = (UINT4)0x10325476;
 }
 
-/* The routine MD5Update updates the message-digest context to
+/* The routine MD5_Update updates the message-digest context to
    account for the presence of each of the characters inBuf[0..inLen-1]
    in the message whose digest is being computed.
  */
@@ -154,7 +154,7 @@ unsigned int inLen;
   }
 }
 
-/* The routine MD5Final terminates the message-digest computation and
+/* The routine MD5_Final terminates the message-digest computation and
    ends with the desired message digest in mdContext->digest[0...15].
  */
 void MD5_Final (hash, mdContext)
@@ -305,3 +305,4 @@ UINT4 *in;
  ** End of md5.c                                                      **
  ******************************** (cut) ********************************
  */
+
diff --git a/pppd/md5.h b/pppd/md5.h
index 71e8b00..6cbe543 100644
--- a/pppd/md5.h
+++ b/pppd/md5.h
@@ -54,7 +54,7 @@ typedef struct {
   UINT4 i[2];                   /* number of _bits_ handled mod 2^64 */
   UINT4 buf[4];                                    /* scratch buffer */
   unsigned char in[64];                              /* input buffer */
-  unsigned char digest[16];     /* actual digest after MD5Final call */
+  unsigned char digest[16];     /* actual digest after MD5_Final call */
 } MD5_CTX;
 
 void MD5_Init (MD5_CTX *mdContext);
diff --git a/pppd/options.c b/pppd/options.c
index 482eab9..b591adb 100644
--- a/pppd/options.c
+++ b/pppd/options.c
@@ -119,6 +119,10 @@ bool	dump_options;		/* print out option values */
 bool	dryrun;			/* print out option values and exit */
 char	*domain;		/* domain name set by domain option */
 int	child_wait = 5;		/* # seconds to wait for children at exit */
+#ifdef USE_EAPTLS
+bool	only_update_crl_server = 0;	/* update server crl and exit */
+bool	only_update_crl_client = 0;	/* update client crl and exit */
+#endif /* USE_EAPTLS */
 
 #ifdef MAXOCTETS
 unsigned int  maxoctets = 0;    /* default - no limit */
@@ -320,6 +324,12 @@ option_t general_options[] = {
     { "mo-timeout", o_int, &maxoctets_timeout,
       "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 },
 #endif
+#ifdef USE_EAPTLS
+    { "only-update-crl-server", o_bool, &only_update_crl_server,
+      "Update server CA CRLs and exit", 1 },
+    { "only-update-crl-client", o_bool, &only_update_crl_client,
+      "Update client CA CRLs and exit", 1 },
+#endif /* USE_EAPTLS */
 
     { NULL }
 };
diff --git a/pppd/pathnames.h b/pppd/pathnames.h
index a33f046..5c8cfe8 100644
--- a/pppd/pathnames.h
+++ b/pppd/pathnames.h
@@ -21,6 +21,13 @@
 #define _PATH_UPAPFILE 	 _ROOT_PATH "/etc/ppp/pap-secrets"
 #define _PATH_CHAPFILE 	 _ROOT_PATH "/etc/ppp/chap-secrets"
 #define _PATH_SRPFILE 	 _ROOT_PATH "/etc/ppp/srp-secrets"
+
+#ifdef USE_EAPTLS
+#define _PATH_EAPTLSCLIFILE	_ROOT_PATH "/etc/ppp/eaptls-client"
+#define _PATH_EAPTLSSERVFILE	_ROOT_PATH "/etc/ppp/eaptls-server"
+#define _PATH_OPENSSLCONFFILE	_ROOT_PATH "/etc/ppp/openssl.cnf"
+#endif /* USE_EAPTLS */
+
 #define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options"
 #define _PATH_IPUP	 _ROOT_PATH "/etc/ppp/ip-up"
 #define _PATH_IPDOWN	 _ROOT_PATH "/etc/ppp/ip-down"
diff --git a/pppd/plugins/Makefile.linux b/pppd/plugins/Makefile.linux
index 0a7ec7b..182d4ce 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 1d885fc..83a7790 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..05cb410 100644
--- a/pppd/plugins/passwordfd.c
+++ b/pppd/plugins/passwordfd.c
@@ -79,4 +79,9 @@ void plugin_init (void)
 
     chap_check_hook = pwfd_check;
     chap_passwd_hook = pwfd_passwd;
+
+#ifdef USE_EAPTLS
+    eaptls_check_hook = pwfd_check;
+    eaptls_passwd_hook = pwfd_passwd;
+#endif
 }
diff --git a/pppd/pppd.h b/pppd/pppd.h
index cf9840a..299517e 100644
--- a/pppd/pppd.h
+++ b/pppd/pppd.h
@@ -320,6 +320,10 @@ 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;
+#endif /* USE_EAPTLS */
+
 #ifdef MAXOCTETS
 extern unsigned int maxoctets;	     /* Maximum octetes per session (in bytes) */
 extern int       maxoctets_dir;      /* Direction :
@@ -717,6 +721,11 @@ 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_check_hook) __P((void));
+extern int (*eaptls_passwd_hook) __P((char *user, char *passwd));
+#endif
+
 /* Let a plugin snoop sent and received packets.  Useful for L2TP */
 extern void (*snoop_recv_hook) __P((unsigned char *p, int len));
 extern void (*snoop_send_hook) __P((unsigned char *p, int len));
diff --git a/pppd/sha1.h b/pppd/sha1.h
index 83f64df..d824a3b 100644
--- a/pppd/sha1.h
+++ b/pppd/sha1.h
@@ -2,12 +2,11 @@
 
 /* If OpenSSL is in use, then use that version of SHA-1 */
 #ifdef OPENSSL
-#include <t_sha.h>
+#include <openssl/sha.h>
+#define SHA1_CTX SHA_CTX
 #define __SHA1_INCLUDE_
 #endif
 
-#ifndef __SHA1_INCLUDE_
-
 #ifndef SHA1_SIGNATURE_SIZE
 #ifdef SHA_DIGESTSIZE
 #define SHA1_SIGNATURE_SIZE SHA_DIGESTSIZE
@@ -16,6 +15,8 @@
 #endif
 #endif
 
+#ifndef __SHA1_INCLUDE_
+
 typedef struct {
     u_int32_t state[5];
     u_int32_t count[2];
 
design & coding: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
current maintainer: Michael Shigorin