Sisyphus repository
Last update: 1 october 2023 | SRPMs: 18631 | Visits: 37907128
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 :: System/Servers
RPM: ppp

 Main   Changelog   Spec   Patches   Sources   Download   Gear   Bugs and FR  Repocop 

Patch: ppp-2.4.4-eaptls-mppe-0.9.patch
Download


diff -Naur ppp-2.4.4/README.eap-tls ppp-2.4.4-eap-tls-mppe/README.eap-tls
--- ppp-2.4.4/README.eap-tls	1970-01-01 01:00:00.000000000 +0100
+++ ppp-2.4.4-eap-tls-mppe/README.eap-tls	2006-07-24 14:50:22.862595811 +0200
@@ -0,0 +1,150 @@
+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.
+
+    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.
+    
+    You must also have libcurl installed (used to fetch CRLs).
+    The version required is 7.9.8 or newer (because that's the one I used,
+    but an earlier version may work).
+
+    Configure, compile, and install as usual. 
+
+3. Configuration
+
+    On the client side 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.
+
+
+4. Options
+
+      These pppd options are available:
+
+      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.
+
+      auto-update-crl
+		On a new TLS handshake, try to fetch updated CRLs for the
+		trusted CAs. This is done only if the crl-dir option was used.
+		For each trusted CA, the appropriate CRL is checked and if
+		it doesn't exist or is too old, the update take place. 
+
+      crl-update-time
+		Time (in hours) after which a CRL must be updated if the option
+		auto-update-crl or only-update-crl-* were specified. Use 0 as 
+		value if you want to force update. The default value is 72
+
+      need-peer-eap
+		If the peer doesn't ask us to authenticate or doesn't use eap
+		to authenticate us, disconnect.
+
+      only-update-crl-server
+		Parse EAP-TLS server configuration file (/etc/ppp/eaptls-server)
+		and find all files containing trusted CAs; then update their CRL
+		and exit.
+		The 'crl-dir' option must be used to specify crl directory.
+
+      only-update-crl-client
+		Similar to only-update-crl-server, but uses client configuration
+		file.
+
+
+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. Updating CRLs with cron
+
+    With the 'auto-update-crl' option you can do crl updating at connect time.
+    In some situations this approach can't be used, because the download can 
+    take long time and the peer will have to wait too much, possibly going in
+    timeout.
+    In such cases, you can update crls periodically (with cron) using pppd with
+    the 'only-update-crl-client' or 'only-update-crl-server' options, as 
+    explained above.
+    Example:
+
+	pppd crl-dir /root/crldir only-update-crl-server crl-update-time 0
+
+    To show debug information add '/dev/null debug' to the command line.
+
+7. Notes
+
+   This is experimental code.
+   Send suggestions and comments to Beniamino Galvani <bengal@interfree.it>
+   or to Jan Just Keijser <janjust@nikhef.nl>
+
diff -Naur ppp-2.4.4/etc.ppp/eaptls-client ppp-2.4.4-eap-tls-mppe/etc.ppp/eaptls-client
--- ppp-2.4.4/etc.ppp/eaptls-client	1970-01-01 01:00:00.000000000 +0100
+++ ppp-2.4.4-eap-tls-mppe/etc.ppp/eaptls-client	2006-07-20 12:21:51.000000000 +0200
@@ -0,0 +1,10 @@
+# Parameters for authentication using EAP-TLS (client)
+
+# client name (can be *)
+# server name (can be *)
+# client certificate file (required)
+# server certificate file (optional, if unused put '-')
+# CA certificate file (required)
+# client private key file (required)
+
+#client	server	/root/cert/client.crt	-	/root/cert/ca.crt	/root/cert/client.key
diff -Naur ppp-2.4.4/etc.ppp/eaptls-server ppp-2.4.4-eap-tls-mppe/etc.ppp/eaptls-server
--- ppp-2.4.4/etc.ppp/eaptls-server	1970-01-01 01:00:00.000000000 +0100
+++ ppp-2.4.4-eap-tls-mppe/etc.ppp/eaptls-server	2006-07-20 12:21:51.000000000 +0200
@@ -0,0 +1,11 @@
+# Parameters for authentication using EAP-TLS (server)
+
+# client name (can be *)
+# server name (can be *)
+# client certificate file (optional, if unused put '-')
+# server certificate file (required)
+# CA certificate file (required)
+# server private key file (required)
+# allowed addresses (required, can be *)
+
+#client	server	-	/root/cert/server.crt	/root/cert/ca.crt	/root/cert/server.key	192.168.1.0/24
diff -Naur ppp-2.4.4/linux/Makefile.top ppp-2.4.4-eap-tls-mppe/linux/Makefile.top
--- ppp-2.4.4/linux/Makefile.top	2006-06-04 07:04:14.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/linux/Makefile.top	2006-07-20 12:21:51.000000000 +0200
@@ -26,7 +26,7 @@
 	cd pppdump; $(MAKE) $(MFLAGS) install
 
 install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
-	$(ETCDIR)/chap-secrets
+	$(ETCDIR)/chap-secrets $(ETCDIR)/eaptls-server $(ETCDIR)/eaptls-client
 
 install-devel:
 	cd pppd; $(MAKE) $(MFLAGS) install-devel
@@ -37,6 +37,10 @@
 	$(INSTALL) -c -m 600 etc.ppp/pap-secrets $@
 $(ETCDIR)/chap-secrets:
 	$(INSTALL) -c -m 600 etc.ppp/chap-secrets $@
+$(ETCDIR)/eaptls-server:
+	$(INSTALL) -c -m 600 etc.ppp/eaptls-server $@
+$(ETCDIR)/eaptls-client:
+	$(INSTALL) -c -m 600 etc.ppp/eaptls-client $@
 
 $(BINDIR):
 	$(INSTALL) -d -m 755 $@
diff -Naur ppp-2.4.4/pppd/Makefile.linux ppp-2.4.4-eap-tls-mppe/pppd/Makefile.linux
--- ppp-2.4.4/pppd/Makefile.linux	2006-06-04 07:07:46.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/pppd/Makefile.linux	2006-07-24 15:39:35.138053142 +0200
@@ -73,6 +73,9 @@
 # Enable EAP SRP-SHA1 authentication (requires libsrp)
 #USE_SRP=y
 
+# Enable EAP-TLS authentication (requires libssl and libcurl)
+USE_EAPTLS=y
+
 MAXOCTETS=y
 
 INCLUDE_DIRS= -I../include
@@ -112,6 +115,15 @@
 PPPDOBJS += sha1.o
 endif
 
+# EAP-TLS
+ifdef USE_EAPTLS
+CFLAGS += -DUSE_EAPTLS=1 -I/usr/kerberos/include
+LIBS += -lssl -lcurl
+PPPDSRC += eap-tls.c
+HEADERS += eap-tls.h
+PPPDOBJS += eap-tls.o
+endif
+
 ifdef HAS_SHADOW
 CFLAGS   += -DHAS_SHADOW
 #LIBS     += -lshadow $(LIBS)
diff -Naur ppp-2.4.4/pppd/auth.c ppp-2.4.4-eap-tls-mppe/pppd/auth.c
--- ppp-2.4.4/pppd/auth.c	2006-06-18 13:26:00.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/pppd/auth.c	2006-07-24 15:38:34.070498062 +0200
@@ -112,6 +112,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
@@ -237,6 +240,9 @@
 bool allow_any_ip = 0;		/* Allow peer to use any IP address */
 bool explicit_remote = 0;	/* User specified explicit remote name */
 char remote_name[MAXNAMELEN];	/* Peer's name for authentication */
+#ifdef USE_EAPTLS
+bool need_peer_eap = 0;		/* Require peer to authenticate us */
+#endif
 
 static char *uafname;		/* name of most recent +ua file */
 
@@ -255,6 +261,19 @@
 static int  have_chap_secret __P((char *, char *, int, int *));
 static int  have_srp_secret __P((char *client, char *server, int need_ip,
     int *lacks_ipp));
+
+#ifdef USE_EAPTLS
+static int  have_eaptls_secret_server
+__P((char *client, char *server, int need_ip, int *lacks_ipp));
+static int  have_eaptls_secret_client __P((char *client, char *server));
+static int  scan_authfile_eaptls __P((FILE * f, char *client, char *server,
+			       char *cli_cert, char *serv_cert,
+			       char *ca_cert, char *pk,
+			       struct wordlist ** addrs,
+			       struct wordlist ** opts,
+			       char *filename, int flags));
+#endif
+
 static int  ip_addr_check __P((u_int32_t, struct permitted_ip *));
 static int  scan_authfile __P((FILE *, char *, char *, char *,
 			       struct wordlist **, struct wordlist **,
@@ -396,7 +415,10 @@
     { "allow-number", o_special, (void *)set_permitted_number,
       "Set telephone number(s) which are allowed to connect",
       OPT_PRIV | OPT_A2LIST },
-
+#ifdef USE_EAPTLS
+    { "need-peer-eap", o_bool, &need_peer_eap,
+      "Require the peer to authenticate us", 1 },
+#endif
     { NULL }
 };
 
@@ -724,6 +746,9 @@
     lcp_options *wo = &lcp_wantoptions[unit];
     lcp_options *go = &lcp_gotoptions[unit];
     lcp_options *ho = &lcp_hisoptions[unit];
+#ifdef USE_EAPTLS
+    lcp_options *ao = &lcp_allowoptions[unit];
+#endif
     int i;
     struct protent *protp;
 
@@ -758,6 +783,22 @@
 	}
     }
 
+#ifdef USE_EAPTLS
+    if (need_peer_eap && !ao->neg_eap) {
+	warn("eap required to authenticate us but no suitable secrets");
+	lcp_close(unit, "couldn't negotiate eap");
+	status = EXIT_AUTH_TOPEER_FAILED;
+	return;
+    }
+
+    if (need_peer_eap && !ho->neg_eap) {
+	warn("peer doesn't want to authenticate us with eap");
+	lcp_close(unit, "couldn't negotiate eap");
+	status = EXIT_PEER_AUTH_FAILED;
+	return;
+    }
+#endif
+
     new_phase(PHASE_AUTHENTICATE);
     used_login = 0;
     auth = 0;
@@ -1268,6 +1309,15 @@
 				    our_name, 1, &lacks_ip);
     }
 
+#ifdef USE_EAPTLS
+    if (!can_auth && wo->neg_eap) {
+	can_auth =
+	    have_eaptls_secret_server((explicit_remote ? remote_name :
+				       NULL), our_name, 1, &lacks_ip);
+
+    }
+#endif
+
     if (auth_required && !can_auth && noauth_addrs == NULL) {
 	if (default_auth) {
 	    option_error(
@@ -1322,7 +1372,11 @@
 	passwd[0] != 0 ||
 	(hadchap == 1 || (hadchap == -1 && have_chap_secret(user,
 	    (explicit_remote? remote_name: NULL), 0, NULL))) ||
-	have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL));
+	have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL)
+#ifdef USE_EAPTLS
+		|| have_eaptls_secret_client(user, (explicit_remote? remote_name: NULL)))
+#endif
+	;
 
     hadchap = -1;
     if (go->neg_upap && !uselogin && !have_pap_secret(NULL))
@@ -1337,8 +1391,14 @@
 	    !have_chap_secret((explicit_remote? remote_name: NULL), our_name,
 		1, NULL))) &&
 	!have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1,
-	    NULL))
+	    NULL)
+#ifdef USE_EAPTLS
+	 && !have_eaptls_secret_server((explicit_remote? remote_name: NULL),
+				   our_name, 1, NULL)
+#endif
+		)
 	go->neg_eap = 0;
+
 }
 
 
@@ -1916,6 +1976,7 @@
 }
 
 
+
 /*
  * get_secret - open the CHAP secret file and return the secret
  * for authenticating the given client on the given server.
@@ -2568,3 +2629,307 @@
 
     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;
+    char servcertfile[MAXWORDLEN];
+    char clicertfile[MAXWORDLEN];
+    char cacertfile[MAXWORDLEN];
+    char pkfile[MAXWORDLEN];
+
+    filename = _PATH_EAPTLSCLIFILE;
+    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(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;
+    struct wordlist *addrs, *opts;
+
+    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 (am_server)
+	set_allowed_addrs(unit, addrs, opts);
+    else if (opts != NULL)
+	free_wordlist(opts);
+    if (addrs != NULL)
+	free_wordlist(addrs);
+
+    return 1;
+}
+#endif
+
diff -Naur ppp-2.4.4/pppd/ccp.c ppp-2.4.4-eap-tls-mppe/pppd/ccp.c
--- ppp-2.4.4/pppd/ccp.c	2005-07-09 02:23:05.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/pppd/ccp.c	2006-07-24 15:41:53.429251910 +0200
@@ -540,6 +540,9 @@
     if (go->mppe) {
 	ccp_options *ao = &ccp_allowoptions[f->unit];
 	int auth_mschap_bits = auth_done[f->unit];
+#ifdef USE_EAPTLS
+	int auth_eap_bits = auth_done[f->unit];
+#endif
 	int numbits;
 
 	/*
@@ -567,8 +570,23 @@
 	    lcp_close(f->unit, "MPPE required but not available");
 	    return;
 	}
+
+#ifdef USE_EAPTLS
+    /*
+     * MPPE is also possible in combination with EAP-TLS.
+     * It is not possible to detect if we're doing EAP or EAP-TLS
+     * at this stage, hence we accept all forms of EAP. If TLS is
+     * not used then the MPPE keys will not be derived anyway.
+     */
+	/* Leave only the eap auth bits set */
+	auth_eap_bits &= (EAP_WITHPEER | EAP_PEER );
+
+	if ((numbits == 0) && (auth_eap_bits == 0)) {
+	    error("MPPE required, but MS-CHAP[v2] nor EAP-TLS auth are performed.");
+#else
 	if (!numbits) {
-	    error("MPPE required, but MS-CHAP[v2] auth not performed.");
+		error("MPPE required, but MS-CHAP[v2] auth not performed.");
+#endif
 	    lcp_close(f->unit, "MPPE required but not available");
 	    return;
 	}
diff -Naur ppp-2.4.4/pppd/eap-tls.c ppp-2.4.4-eap-tls-mppe/pppd/eap-tls.c
--- ppp-2.4.4/pppd/eap-tls.c	1970-01-01 01:00:00.000000000 +0100
+++ ppp-2.4.4-eap-tls-mppe/pppd/eap-tls.c	2006-07-24 13:49:08.515871696 +0200
@@ -0,0 +1,1276 @@
+/*
+ * 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/hmac.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+#include <curl/curl.h>
+
+#include "pppd.h"
+#include "eap.h"
+#include "eap-tls.h"
+#include "pathnames.h"
+
+extern char *crl_dir;
+extern bool auto_update_crl;
+extern int crl_update_time;
+
+static int search_wordlist(struct wordlist *wl, char *word);
+static void add_wordlist(struct wordlist *wl, char *word);
+static void destroy_wordlist(struct wordlist *wl);
+
+#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();
+	}
+}
+
+/*
+ * 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)
+{
+	SSL_CTX		*ctx;
+	X509_STORE	*certstore;
+	X509_LOOKUP	*lookup;
+	X509		*tmp;
+
+	/*
+	 * Without these can't continue 
+	 */
+	if (!cacertfile[0] || !privkeyfile[0] || !certfile[0] )
+		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 (!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 (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM)) {
+		error("EAP-TLS: Cannot use public certificate %s", certfile);
+		goto fail;
+	}
+
+	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;
+}
+
+/*
+ * 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];
+	struct wordlist updatedfiles;
+
+	updatedfiles.next = NULL;
+	updatedfiles.word = NULL;
+
+	/*
+	 * 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("Error: client name not set (BUG)");
+		return 0;
+	}
+
+	strncpy(ets->peer, esp->es_server.ea_peer, MAXWORDLEN);
+
+	if (!get_eaptls_secret(esp->es_unit, esp->es_server.ea_peer,
+			       esp->es_server.ea_name, clicertfile,
+			       servcertfile, cacertfile, pkfile, 1)) {
+		dbglog("get_eaptls_secret error");
+		return 0;
+	}
+
+	ets->mtu = netif_get_mtu(esp->es_unit) - PPP_HDRLEN - 10;
+
+	ets->ctx = eaptls_init_ssl(1, cacertfile, servcertfile, clicertfile, pkfile);
+	if (!ets->ctx)
+		goto fail;
+
+	if (crl_dir) {
+		if (auto_update_crl)
+			eaptls_update_crls(crl_dir, cacertfile, &updatedfiles);
+
+		destroy_wordlist(&updatedfiles);
+	}
+
+	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];
+	struct wordlist updatedfiles;
+
+	updatedfiles.next = NULL;
+	updatedfiles.word = NULL;
+
+	/*
+	 * 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 = netif_get_mtu(esp->es_unit) - PPP_HDRLEN - 10;
+
+	if (!get_eaptls_secret(esp->es_unit, esp->es_client.ea_name,
+			       esp->es_client.ea_peer, clicertfile,
+			       servcertfile, cacertfile, pkfile, 0)) {
+		dbglog("get_eaptls_secret error");
+		return 0;
+	}
+
+	ets->ctx = eaptls_init_ssl(0, cacertfile, clicertfile, servcertfile, pkfile);
+	if (!ets->ctx)
+		goto fail;
+
+	if (crl_dir) {
+		if (auto_update_crl)
+			eaptls_update_crls(crl_dir, cacertfile, &updatedfiles);
+
+		destroy_wordlist(&updatedfiles);
+	}
+
+	ets->ssl = SSL_new(ets->ctx);
+
+	if (!ets->ssl)
+		goto fail;
+
+	/*
+	 * 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_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:
+	SSL_CTX_free(ets->ctx);
+	return 0;
+
+}
+
+/*
+ * Updates the CA CRL
+ */
+void eaptls_update_crls(char *crldir, char *cacertfile, struct wordlist *uf)
+{
+	FILE *file;
+	X509 *cert;
+	char *filename;
+
+	if (!(file = fopen(cacertfile, "r")))
+		return;
+
+	filename = malloc(strlen(crldir) + 15);
+
+	/*
+	 * for each CA certificate, control if the CRL must be updated 
+	 */
+	while ((cert = PEM_read_X509(file, NULL, NULL, NULL))) {
+
+		if (eaptls_must_update(cert, crldir, filename, uf) == 1) {
+
+			eaptls_get_crl(cert, filename);
+			add_wordlist(uf, filename);
+		}
+
+	}
+
+	free(filename);
+	fclose(file);
+}
+
+/*
+ * Control if the CA CRL must be updated
+ * Return in filename the file to be updated 
+ */
+int eaptls_must_update(X509 * cert, char *crldir, char *filename,
+		   struct wordlist *uf)
+{
+	X509_NAME *xn;
+	unsigned long hash;
+	int found = 0, i, hours;
+	FILE *file;
+	X509_CRL *crl;
+	time_t curr_time, mod_time;
+	struct stat file_stat;
+	char tmpname[15];
+	char subject[256];
+	char cn_str[256];
+
+	/*
+	 * Get CA subject name and calculate its hash 
+	 */
+	xn = X509_get_subject_name(cert);
+	hash = X509_NAME_hash(xn);
+
+	X509_NAME_oneline(xn, subject, 256);
+	X509_NAME_get_text_by_NID(xn, NID_commonName, cn_str, 256);
+	dbglog("  -> processing CA: %s", cn_str);
+
+	/*
+	 * Search a CRL for this CA in crldir 
+	 */
+	for (i = 0; i < 10; i++) {
+		sprintf(tmpname, "%08lx.r%1d", hash, i);
+		strcpy(filename, crldir);
+		strcat(filename, "/");
+		strcat(filename, tmpname);
+
+		if (!(file = fopen(filename, "r")))
+			break;	/* CRL not found */
+
+		if (!(crl = PEM_read_X509_CRL(file, NULL, NULL, NULL))) {
+			fclose(file);
+			continue;
+		}
+		fclose(file);
+
+		/*
+		 * test if it's the right CRL 
+		 */
+		if (X509_NAME_cmp(xn, X509_CRL_get_issuer(crl)) == 0) {
+			found = 1;
+			X509_CRL_free(crl);
+			break;
+		}
+		X509_CRL_free(crl);
+	}
+
+	/*
+	 * If file already in list, we've already updated it 
+	 */
+	if (search_wordlist(uf, filename) == 1)
+		return 0;
+
+	/*
+	 * If CRL file for this CA not found, need update 
+	 */
+	if (!found)
+		return 1;
+
+	curr_time = time(NULL);
+	stat(filename, &file_stat);
+	mod_time = file_stat.st_mtime;
+	hours = (curr_time - mod_time) / 3600;
+
+	/*
+	 * If file too old, need update 
+	 */
+	if (hours >= crl_update_time) {
+		dbglog("        file %s is %d hours old, need update",
+		       filename, hours);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Extract CDPs from certificate 
+ */
+void eaptls_get_crl(X509 * cert, char *filename)
+{
+	STACK_OF(DIST_POINT) * distpoints = NULL;
+	DIST_POINT *dp;
+	DIST_POINT_NAME *dpn;
+	STACK_OF(GENERAL_NAME) * names;
+	GENERAL_NAME *name;
+	ASN1_IA5STRING *uri_asn;
+	char *uri;
+	int num_dp, i;
+	int num_name, j;
+
+	distpoints = X509_get_ext_d2i(cert, 
+			NID_crl_distribution_points, NULL, NULL);
+	num_dp = sk_DIST_POINT_num(distpoints);
+
+	dbglog("        CA certificate contains %d CDP", num_dp);
+
+	for (i = 0; i < num_dp; i++) {
+
+		dp = sk_DIST_POINT_value(distpoints, i);
+		dpn = dp->distpoint;
+		names = dpn->name.fullname;
+		num_name = sk_GENERAL_NAME_num(names);
+
+		for (j = 0; j < num_name; j++) {
+
+			name = sk_GENERAL_NAME_value(names, j);
+
+			if (name->type == GEN_URI) {
+				uri_asn = name->d.uniformResourceIdentifier;
+				uri = ASN1_STRING_data(uri_asn);
+
+				if (eaptls_download_crl(uri, filename)) {
+					dbglog
+					    ("          * %s successfully loaded",
+					     uri);
+					return;
+				}
+
+			}
+
+		}
+	}
+}
+
+/*
+ * Download a CRL from uri into file 
+ */
+int eaptls_download_crl(char *uri, char *filename)
+{
+	FILE *tmpfile;
+	FILE *destfile;
+	int tmpfd;
+	char tmpname[30];
+	CURL *curl;
+	int res;
+	X509_CRL *crl;
+
+	strcpy(tmpname, "/tmp/ppp-tmp-XXXXXX");
+
+	if ((tmpfd = mkstemp(tmpname)) == -1) {
+		error("error creating temp file /tmp/ppp-tmp-*");
+		return 0;
+	}
+
+	tmpfile = fdopen(tmpfd, "w");
+	if (!tmpfile) {
+		error("error fdopen");
+		close(tmpfd);
+		return 0;
+	}
+
+	/*
+	 * download in temp file using libcurl 
+	 */
+	curl_global_init(CURL_GLOBAL_NOTHING);
+	curl = curl_easy_init();
+	curl_easy_setopt(curl, CURLOPT_URL, uri);
+	curl_easy_setopt(curl, CURLOPT_WRITEDATA, tmpfile);
+
+	res = curl_easy_perform(curl);
+
+	curl_easy_cleanup(curl);
+	curl_global_cleanup();
+
+	if (res != CURLE_OK) {
+		dbglog("          * %s download failed", uri);
+		fclose(tmpfile);
+		unlink(tmpname);
+		return 0;
+	}
+
+	fclose(tmpfile);
+	tmpfile = fopen(tmpname, "r");
+	if(!tmpfile)
+		return 0;
+
+	/*
+	 * load CRL from temp file 
+	 */
+	crl = d2i_X509_CRL_fp(tmpfile, NULL);
+
+	fclose(tmpfile);
+	unlink(tmpname);
+
+	if (!crl) {
+		warn("cannot load DER CRL");
+		return 0;
+	}
+
+	destfile = fopen(filename, "w");
+	if (!destfile) {
+		X509_CRL_free(crl);
+		return 0;
+	}
+
+	/*
+	 * write CRL in PEM format to destination file 
+	 */
+	PEM_write_X509_CRL(destfile, crl);
+
+	X509_CRL_free(crl);
+	fclose(destfile);
+
+	return 1;
+}
+
+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 (!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;
+		}
+		break;
+	}
+
+	/* Alert messages must always be displayed */
+	if(content_type == SSL3_RT_ALERT)
+		error("%s", string);
+	else
+		dbglog("%s", string);
+}
+
+/*
+ * Extract all CA files from conf file 'filename' and update crl
+ */
+void eaptls_do_update(char *filename, struct wordlist *updatedfiles)
+{
+	int newline;
+	FILE *f;
+	char word[MAXWORDLEN];
+
+	if (!(f = fopen(filename, "r"))) {
+		fprintf(stderr, "can't open %s", filename);
+		die(1);
+	}
+
+	if (!getword(f, word, &newline, filename))
+		return;		/* file is empty??? */
+
+	newline = 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 */
+
+		/*
+		 * server 
+		 */
+		if (!getword(f, word, &newline, filename))
+			break;
+		if (newline)
+			continue;
+
+		/*
+		 * client cert 
+		 */
+		if (!getword(f, word, &newline, filename))
+			break;
+		if (newline)
+			continue;
+
+		/*
+		 * server cert 
+		 */
+		if (!getword(f, word, &newline, filename))
+			break;
+		if (newline)
+			continue;
+
+		/*
+		 * ca cert 
+		 */
+		if (!getword(f, word, &newline, filename))
+			break;
+		if (newline)
+			continue;
+
+		printf("Updating CRLs for CA file %s\n", word);
+
+		eaptls_update_crls(crl_dir, word, updatedfiles);
+	}
+
+	fclose(f);
+}
+
+void eaptls_only_update_crl(int server, int client)
+{
+	/*
+	 * mantain a list of updated crl files, so if a CA appears more
+	 * times, it is updated once 
+	 */
+	struct wordlist updatedfiles;
+
+	updatedfiles.next = NULL;
+	updatedfiles.word = NULL;
+
+	if (server)
+		eaptls_do_update(_PATH_EAPTLSSERVFILE, &updatedfiles);
+
+	if (client)
+		eaptls_do_update(_PATH_EAPTLSCLIFILE, &updatedfiles);
+
+	destroy_wordlist(&updatedfiles);
+}
+
+static int search_wordlist(struct wordlist *wl, char *word)
+{
+	struct wordlist *tmp = wl->next;
+
+	while (tmp) {
+		if (strcmp(tmp->word, word) == 0)
+			return 1;
+		tmp = tmp->next;
+	}
+	return 0;
+}
+
+static void add_wordlist(struct wordlist *wl, char *word)
+{
+	struct wordlist *tmp = wl;
+
+	while (tmp->next)
+		tmp = tmp->next;
+
+	tmp->next = malloc(sizeof(struct wordlist));
+	tmp->next->word = strdup(word);
+	tmp->next->next = NULL;
+
+}
+
+static void destroy_wordlist(struct wordlist *wl)
+{
+	struct wordlist *tmp = wl->next;
+	struct wordlist *next;
+
+	while (tmp) {
+		next = tmp->next;
+
+		if (tmp->word)
+			free(tmp->word);
+
+		free(tmp);
+		tmp = next;
+	}
+
+}
diff -Naur ppp-2.4.4/pppd/eap-tls.h ppp-2.4.4-eap-tls-mppe/pppd/eap-tls.h
--- ppp-2.4.4/pppd/eap-tls.h	1970-01-01 01:00:00.000000000 +0100
+++ ppp-2.4.4-eap-tls-mppe/pppd/eap-tls.h	2006-07-24 12:36:35.240447056 +0200
@@ -0,0 +1,106 @@
+/*
+ * 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>
+
+#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 */
+
+#define CRL_UPDATE_TIME         72	/* update time for crl: 72 hours */
+
+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 */
+};
+
+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);
+
+void eaptls_update_crls(char *crldir, char *cacertfile, struct wordlist *wl);
+int eaptls_must_update(X509 * cert, char *crldir, char *filename,
+		       struct wordlist *wl);
+void eaptls_get_crl(X509 * cert, char *filename);
+int eaptls_download_crl(char *uri, char *filename);
+
+#ifdef MPPE
+#include <net/ppp-comp.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 -Naur ppp-2.4.4/pppd/eap.c ppp-2.4.4-eap-tls-mppe/pppd/eap.c
--- ppp-2.4.4/pppd/eap.c	2004-11-09 23:39:25.000000000 +0100
+++ ppp-2.4.4-eap-tls-mppe/pppd/eap.c	2006-07-24 16:07:52.889280229 +0200
@@ -43,6 +43,11 @@
  * Based on draft-ietf-pppext-eap-srp-03.txt.
  */
 
+/*
+ * Modification by Beniamino Galvani, Mar 2005
+ * Implemented EAP-TLS authentication
+ */
+
 #define RCSID	"$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $"
 
 /*
@@ -73,9 +73,14 @@
 #define MD5Update MD5_Update
 #define MD5Final MD5_Final
 #else
+#ifndef USE_EAPTLS
 #include "md5.h"
-#endif
+#endif /* USE_EAPTLS */
+#endif /* USE_OPENSSL */
 #include "eap.h"
+#ifdef USE_EAPTLS
+#include "eap-tls.h"
+#endif /* USE_EAPTLS */
 
 #ifdef USE_SRP
 #include <t_pwd.h>
@@ -83,6 +92,12 @@
 static char *pn_secret = NULL;		/* Pseudonym generating secret */
 #endif
 
+#ifdef USE_EAPTLS
+char *crl_dir = NULL;
+bool auto_update_crl = 0;
+int crl_update_time = CRL_UPDATE_TIME;
+#endif /* USE_EAPTLS */
+
 /*
  * Command-line options.
  */
@@ -105,6 +120,14 @@
     { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo,
       "Use pseudonym if offered one by server", 1 },
 #endif
+#ifdef USE_EAPTLS
+    { "crl-dir", o_string, &crl_dir,
+      "Use CRLs in directory" },
+    { "auto-update-crl", o_bool, &auto_update_crl,
+      "Automatically download CA CRL if old or non existent", 1 },
+    { "crl-update-time", o_int, &crl_update_time,
+      "Time (in hours) after which reload CA CRL" },
+#endif /* USE_EAPTLS */
     { NULL }
 };
 
@@ -209,6 +232,9 @@
 	esp->es_server.ea_id = (u_char)(drand48() * 0x100);
 	esp->es_client.ea_timeout = EAP_DEFREQTIME;
 	esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ;
+#ifdef USE_EAPTLS
+	esp->es_client.ea_using_eaptls = 0;
+#endif /* USE_EAPTLS */
 }
 
 /*
@@ -436,8 +462,16 @@
 	u_char vals[2];
 	struct b64state bs;
 #endif /* USE_SRP */
+#ifdef USE_EAPTLS
+	struct eaptls_session *ets;
+	int secret_len;
+	char secret[MAXWORDLEN];
+#endif /* USE_EAPTLS */
 
 	esp->es_server.ea_timeout = esp->es_savedtime;
+#ifdef USE_EAPTLS
+	esp->es_server.ea_prev_state = esp->es_server.ea_state;
+#endif /* USE_EAPTLS */
 	switch (esp->es_server.ea_state) {
 	case eapBadAuth:
 		return;
@@ -562,9 +596,81 @@
 			break;
 		}
 #endif /* USE_SRP */
+#ifdef USE_EAPTLS
+                if (!get_secret(esp->es_unit, esp->es_server.ea_peer,
+                    esp->es_server.ea_name, secret, &secret_len, 1)) {
+
+			esp->es_server.ea_state = eapTlsStart;
+			break;
+		}
+#endif /* USE_EAPTLS */
+
 		esp->es_server.ea_state = eapMD5Chall;
 		break;
 
+#ifdef USE_EAPTLS
+	case eapTlsStart:
+		/* Initialize ssl session */
+		if(!eaptls_init_ssl_server(esp)) {
+			esp->es_server.ea_state = eapBadAuth;
+			break;
+		}
+
+		esp->es_server.ea_state = eapTlsRecv;
+		break;
+
+	case eapTlsRecv:
+		ets = (struct eaptls_session *) esp->es_server.ea_session;
+		
+		if(ets->alert_sent) {
+			esp->es_server.ea_state = eapTlsSendAlert;
+			break;
+		}
+
+		if (status) {
+			esp->es_server.ea_state = eapBadAuth;
+			break;	
+		}
+		ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+		if(ets->frag)
+			esp->es_server.ea_state = eapTlsSendAck;
+		else
+			esp->es_server.ea_state = eapTlsSend;
+		break;
+
+	case eapTlsSend:
+		ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+		if(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 +824,30 @@
 		INCPTR(esp->es_server.ea_namelen, outp);
 		break;
 
+#ifdef USE_EAPTLS
+	case eapTlsStart:
+		PUTCHAR(EAPT_TLS, outp);
+		PUTCHAR(EAP_TLS_FLAGS_START, outp);
+		eap_figure_next_state(esp, 0);
+		break;
+
+	case eapTlsSend:
+		eaptls_send(esp->es_server.ea_session, &outp);
+		eap_figure_next_state(esp, 0);
+		break;
+
+	case eapTlsSendAck:
+		PUTCHAR(EAPT_TLS, outp);
+		PUTCHAR(0, outp);
+		eap_figure_next_state(esp, 0);
+		break;
+
+	case eapTlsSendAlert:
+		eaptls_send(esp->es_server.ea_session, &outp);
+		eap_figure_next_state(esp, 0);
+		break;
+#endif /* USE_EAPTLS */
+
 #ifdef USE_SRP
 	case eapSRP1:
 		PUTCHAR(EAPT_SRP, outp);
@@ -904,11 +1034,57 @@
 eap_server_timeout(arg)
 void *arg;
 {
+#ifdef USE_EAPTLS
+	u_char *outp;
+	u_char *lenloc;
+	int outlen;
+#endif /* USE_EAPTLS */
+
 	eap_state *esp = (eap_state *) arg;
 
 	if (!eap_server_active(esp))
 		return;
 
+#ifdef USE_EAPTLS
+	switch(esp->es_server.ea_prev_state) {
+
+	/* 
+	 *  In eap-tls the state changes after a request, so we return to
+	 *  previous state ...
+	 */	
+	case(eapTlsStart):
+	case(eapTlsSendAck):
+		esp->es_server.ea_state = esp->es_server.ea_prev_state;
+		break;
+
+	/*
+	 *  ... or resend the stored data
+	 */
+	case(eapTlsSend):
+	case(eapTlsSendAlert):
+		outp = outpacket_buf;
+		MAKEHEADER(outp, PPP_EAP);
+		PUTCHAR(EAP_REQUEST, outp);
+		PUTCHAR(esp->es_server.ea_id, outp);
+		lenloc = outp;
+		INCPTR(2, outp);
+
+		eaptls_retransmit(esp->es_server.ea_session, &outp);
+
+		outlen = (outp - outpacket_buf) - PPP_HDRLEN;
+		PUTSHORT(outlen, lenloc);
+		output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN);
+		esp->es_server.ea_requests++;
+
+		if (esp->es_server.ea_timeout > 0)
+			TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout);
+
+		return;
+	default:
+		break;
+	}
+#endif /* USE_EAPTLS */
+
 	/* EAP ID number must not change on timeout. */
 	eap_send_request(esp);
 }
@@ -1166,6 +1342,81 @@
 }
 #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 +1571,11 @@
 	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 +1712,90 @@
 		    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 +2077,11 @@
 	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 +2121,60 @@
 		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 +2206,13 @@
 			esp->es_server.ea_state = eapMD5Chall;
 			break;
 
+#ifdef USE_EAPTLS
+			/* Send EAP-TLS start packet */
+		case EAPT_TLS:
+			esp->es_server.ea_state = eapTlsStart;
+			break;
+#endif /* USE_EAPTLS */
+			
 		default:
 			dbglog("EAP: peer requesting unknown Type %d", vallen);
 			switch (esp->es_server.ea_state) {
@@ -2018,13 +2424,27 @@
 int id;
 int len;
 {
-	if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)) {
+	if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)
+#ifdef USE_EAPTLS
+		&& esp->es_client.ea_state != eapTlsRecvSuccess
+#endif /* USE_EAPTLS */
+		) {
 		dbglog("EAP unexpected success message in state %s (%d)",
 		    eap_state_name(esp->es_client.ea_state),
 		    esp->es_client.ea_state);
 		return;
 	}
 
+#ifdef USE_EAPTLS
+	if(esp->es_client.ea_using_eaptls && esp->es_client.ea_state != 
+		eapTlsRecvSuccess) {
+		dbglog("EAP-TLS unexpected success message in state %s (%d)",
+                    eap_state_name(esp->es_client.ea_state),
+                    esp->es_client.ea_state);
+		return;
+	}
+#endif /* USE_EAPTLS */
+
 	if (esp->es_client.ea_timeout > 0) {
 		UNTIMEOUT(eap_client_timeout, (void *)esp);
 	}
@@ -2150,6 +2570,9 @@
 	int code, id, len, rtype, vallen;
 	u_char *pstart;
 	u_int32_t uval;
+#ifdef USE_EAPTLS
+	u_char flags;
+#endif /* USE_EAPTLS */
 
 	if (inlen < EAP_HEADERLEN)
 		return (0);
@@ -2214,6 +2637,24 @@
 			}
 			break;
 
+#ifdef USE_EAPTLS
+		case EAPT_TLS:
+			if (len < 1)
+				break;
+			GETCHAR(flags, inp);
+			len--;
+
+                        if(flags == 0 && len == 0){
+                                printer(arg, " Ack");
+                                break;
+                        }
+
+			printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -");
+			printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-");
+			printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- ");
+			break;
+#endif /* USE_EAPTLS */
+
 		case EAPT_SRP:
 			if (len < 3)
 				goto truncated;
@@ -2325,6 +2766,25 @@
 			}
 			break;
 
+#ifdef USE_EAPTLS
+		case EAPT_TLS:
+			if (len < 1)
+				break;
+			GETCHAR(flags, inp);
+			len--;
+
+                        if(flags == 0 && len == 0){
+                                printer(arg, " Ack");
+                                break;
+                        }
+
+			printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -");
+			printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-");
+			printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- ");
+			
+			break;												
+#endif /* USE_EAPTLS */
+
 		case EAPT_NAK:
 			if (len <= 0) {
 				printer(arg, " <missing hint>");
@@ -2426,3 +2886,4 @@
 
 	return (inp - pstart);
 }
+
diff -Naur ppp-2.4.4/pppd/eap.h ppp-2.4.4-eap-tls-mppe/pppd/eap.h
--- ppp-2.4.4/pppd/eap.h	2003-06-12 01:56:26.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/pppd/eap.h	2006-07-24 16:03:38.142650902 +0200
@@ -84,6 +84,16 @@
 	eapClosed,	/* Authentication not in use */
 	eapListen,	/* Client ready (and timer running) */
 	eapIdentify,	/* EAP Identify sent */
+	eapTlsStart,	/* Send EAP-TLS start packet */
+	eapTlsRecv,	/* Receive EAP-TLS tls data */
+	eapTlsSendAck,	/* Send EAP-TLS ack */
+	eapTlsSend,	/* Send EAP-TLS tls data */
+	eapTlsRecvAck,	/* Receive EAP-TLS ack */
+	eapTlsRecvClient, 	/* Receive EAP-TLS auth response from client*/
+	eapTlsSendAlert,	/* Send EAP-TLS tls alert (server)*/
+	eapTlsRecvAlertAck,	/* Receive EAP-TLS ack after sending alert */
+	eapTlsRecvSuccess,	/* Receive EAP success */
+	eapTlsRecvFailure,	/* Receive EAP failure */
 	eapSRP1,	/* Sent EAP SRP-SHA1 Subtype 1 */
 	eapSRP2,	/* Sent EAP SRP-SHA1 Subtype 2 */
 	eapSRP3,	/* Sent EAP SRP-SHA1 Subtype 3 */
@@ -95,9 +105,18 @@
 
 #define	EAP_STATES	\
 	"Initial", "Pending", "Closed", "Listen", "Identify", \
+	"TlsStart", "TlsRecv", "TlsSendAck", "TlsSend", "TlsRecvAck", "TlsRecvClient",\
+	"TlsSendAlert", "TlsRecvAlertAck" , "TlsRecvSuccess", "TlsRecvFailure", \
 	"SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth"
 
-#define	eap_client_active(esp)	((esp)->es_client.ea_state == eapListen)
+#ifdef USE_EAPTLS
+#define	eap_client_active(esp)	((esp)->es_client.ea_state != eapInitial ||\
+				 (esp)->es_client.ea_state != eapPending ||\
+				 (esp)->es_client.ea_state != eapClosed)
+#else
+#define eap_client_active(esp)	((esp)->es_client.ea_state == eapListen)
+#endif /* USE_EAPTLS */
+
 #define	eap_server_active(esp)	\
 	((esp)->es_server.ea_state >= eapIdentify && \
 	 (esp)->es_server.ea_state <= eapMD5Chall)
@@ -112,11 +131,17 @@
 	u_short ea_namelen;	/* Length of our name */
 	u_short ea_peerlen;	/* Length of peer's name */
 	enum eap_state_code ea_state;
+#ifdef USE_EAPTLS
+	enum eap_state_code ea_prev_state;
+#endif
 	u_char ea_id;		/* Current id */
 	u_char ea_requests;	/* Number of Requests sent/received */
 	u_char ea_responses;	/* Number of Responses */
 	u_char ea_type;		/* One of EAPT_* */
 	u_int32_t ea_keyflags;	/* SRP shared key usage flags */
+#ifdef USE_EAPTLS
+	bool ea_using_eaptls;
+#endif
 };
 
 /*
@@ -139,7 +164,12 @@
  * Timeouts.
  */
 #define	EAP_DEFTIMEOUT		3	/* Timeout (seconds) for rexmit */
+#ifdef USE_EAPTLS
+#define	EAP_DEFTRANSMITS	30	/* max # times to transmit */
+					/* certificates can be long ... */
+#else
 #define	EAP_DEFTRANSMITS	10	/* max # times to transmit */
+#endif /* USE_EAPTLS */
 #define	EAP_DEFREQTIME		20	/* Time to wait for peer request */
 #define	EAP_DEFALLOWREQ		20	/* max # times to accept requests */
 
diff -Naur ppp-2.4.4/pppd/main.c ppp-2.4.4-eap-tls-mppe/pppd/main.c
--- ppp-2.4.4/pppd/main.c	2006-06-04 05:52:50.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/pppd/main.c	2006-07-24 16:09:38.714310467 +0200
@@ -260,6 +260,10 @@
 extern	char	*getlogin __P((void));
 int main __P((int, char *[]));
 
+#ifdef USE_EAPTLS
+void eaptls_only_update_crl(int serv, int cli);
+#endif
+
 #ifdef ultrix
 #undef	O_NONBLOCK
 #define	O_NONBLOCK	O_NDELAY
@@ -418,6 +422,19 @@
     if (dryrun)
 	die(0);
 
+#ifdef USE_EAPTLS
+	if(only_update_crl_server || only_update_crl_client) {
+		if(!crl_dir){
+			fprintf(stderr, "You must specify a crl dir\n");
+			die(1);
+		}
+
+		eaptls_only_update_crl(only_update_crl_server, only_update_crl_client);
+
+        die(0);
+    }
+#endif /* USE_EAPTLS */
+
     /* Make sure fds 0, 1, 2 are open to somewhere. */
     fd_devnull = open(_PATH_DEVNULL, O_RDWR);
     if (fd_devnull < 0)
diff -Naur ppp-2.4.4/pppd/options.c ppp-2.4.4-eap-tls-mppe/pppd/options.c
--- ppp-2.4.4/pppd/options.c	2006-06-18 13:26:00.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/pppd/options.c	2006-07-24 16:10:16.075202878 +0200
@@ -119,6 +119,10 @@
 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 @@
     { "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 -Naur ppp-2.4.4/pppd/pathnames.h ppp-2.4.4-eap-tls-mppe/pppd/pathnames.h
--- ppp-2.4.4/pppd/pathnames.h	2005-08-26 01:59:34.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/pppd/pathnames.h	2006-07-24 16:10:41.665759273 +0200
@@ -21,6 +21,12 @@
 #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"
+#endif /* USE_EAPTLS */
+
 #define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options"
 #define _PATH_IPUP	 _ROOT_PATH "/etc/ppp/ip-up"
 #define _PATH_IPDOWN	 _ROOT_PATH "/etc/ppp/ip-down"
diff -Naur ppp-2.4.4/pppd/pppd.h ppp-2.4.4-eap-tls-mppe/pppd/pppd.h
--- ppp-2.4.4/pppd/pppd.h	2005-08-26 01:59:34.000000000 +0200
+++ ppp-2.4.4-eap-tls-mppe/pppd/pppd.h	2006-07-24 16:11:03.272540399 +0200
@@ -319,6 +319,12 @@
 extern bool	dryrun;		/* check everything, print options, exit */
 extern int	child_wait;	/* # seconds to wait for children at end */
 
+#ifdef USE_EAPTLS
+extern bool	only_update_crl_server;	/* update server crls and exit */
+extern bool	only_update_crl_client;	/* update client crls and exit */
+extern char	*crl_dir;
+#endif /* USE_EAPTLS */
+
 #ifdef MAXOCTETS
 extern unsigned int maxoctets;	     /* Maximum octetes per session (in bytes) */
 extern int       maxoctets_dir;      /* Direction :
 
design & coding: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
current maintainer: Michael Shigorin