]> git.ozlabs.org Git - ppp.git/commitdiff
Add support for EAP-TLS (including experimental TLS v1.3 support).
authorJan Just Keijser <jan.just.keijser@gmail.com>
Mon, 19 Oct 2020 15:57:36 +0000 (17:57 +0200)
committerJan Just Keijser <jan.just.keijser@gmail.com>
Mon, 19 Oct 2020 16:00:54 +0000 (18:00 +0200)
Signed-off-by: Jan Just Keijser <jan.just.keijser@gmail.com>
21 files changed:
README.eap-tls [new file with mode: 0644]
etc.ppp/eaptls-client [new file with mode: 0644]
etc.ppp/eaptls-server [new file with mode: 0644]
etc.ppp/openssl.cnf [new file with mode: 0644]
linux/Makefile.top
pppd/Makefile.linux
pppd/Makefile.sol2
pppd/auth.c
pppd/ccp.c
pppd/eap-tls.c [new file with mode: 0644]
pppd/eap-tls.c.rej [new file with mode: 0644]
pppd/eap-tls.h [new file with mode: 0644]
pppd/eap.c
pppd/eap.h
pppd/pathnames.h
pppd/plugins/Makefile.linux
pppd/plugins/passprompt.c
pppd/plugins/passwordfd.c
pppd/pppd.8
pppd/pppd.h
pppd/sys-solaris.c

diff --git a/README.eap-tls b/README.eap-tls
new file mode 100644 (file)
index 0000000..ab3794e
--- /dev/null
@@ -0,0 +1,229 @@
+EAP-TLS authentication support for PPP
+======================================
+
+1. Intro
+
+    The Extensible Authentication Protocol (EAP; RFC 3748) is a
+    security protocol that can be used with PPP.  It provides a means
+    to plug in multiple optional authentication methods.
+
+    Transport Level Security (TLS; RFC 5216) provides for mutual 
+    authentication, integrity-protected ciphersuite negotiation and 
+    key exchange between two endpoints.  It also provides for optional
+    MPPE encryption.
+
+    EAP-TLS (RFC 2716) incapsulates the TLS messages in EAP packets,
+    allowing TLS mutual authentication to be used as a generic EAP
+    mechanism. It also provides optional encryption using the MPPE
+    protocol.
+
+    This patch provide EAP-TLS support to pppd.
+    This authentication method can be used in both client or server
+    mode.
+
+2. Building
+
+    To build pppd with EAP-TLS support, OpenSSL (http://www.openssl.org)
+    is required. Any version from 0.9.7 should work.
+    
+    Configure, compile, and install as usual. 
+
+3. Configuration
+
+    On the client side there are two ways to configure EAP-TLS:
+
+    1. supply the appropriate 'ca', 'cert' and 'key' command-line parameters
+
+    2. edit the /etc/ppp/eaptls-client file.
+    Insert a line for each system with which you use EAP-TLS.
+    The line is composed of this fields separated by tab:
+
+      - Client name 
+        The name used by the client for authentication, can be *
+      - Server name
+        The name of the server, can be *
+      - Client certificate file 
+        The file containing the certificate chain for the 
+        client in PEM format
+      - Server certificate file
+        If you want to specify the certificate that the 
+        server is allowed to use, put the certificate file name.
+        Else put a dash '-'.
+      - CA certificate file
+        The file containing the trusted CA certificates in PEM
+        format.
+      - Client private key file
+        The file containing the client private key in PEM format.
+
+
+    On the server side edit the /etc/ppp/eaptls-server file.
+    Insert a line for each system with which you use EAP-TLS.
+    The line is composed of this fields separated by tab:
+
+      - Client name
+        The name used by the client for authentication, can be *
+      - Server name
+        The name of the server, can be *
+      - Client certificate file
+        If you want to specify the certificate that the
+        client is allowed to use, put the certificate file name.
+        Else put a dash '-'.
+      - Server certificate file
+        The file containing the certificate chain for the
+        server in PEM format
+      - CA certificate file
+        The file containing the trusted CA certificates in PEM format.
+      - Client private key file
+        The file containing the server private key in PEM format.
+      - addresses
+        A list of IP addresses the client is allowed to use.
+
+
+    OpenSSL engine support is included starting with v0.95 of this patch. 
+    Currently the only engine tested is the 'pkcs11' engine (hardware token
+    support). To use the 'pksc11' engine:
+      - Use a special private key fileiname in the /etc/ppp/eaptls-client file:
+          <engine>:<identifier>
+        e.g.
+          pkcs11:123456
+
+      - The certificate can also be loaded from the 'pkcs11' engine using
+        a special client certificate filename in the /etc/ppp/eaptls-client file:
+          <engine>:<identifier>
+        e.g.
+          pkcs11:123456
+
+      - Create an /etc/ppp/openssl.cnf file to load the right OpenSSL engine prior
+        to starting 'pppd'. A sample openssl.cnf file is
+
+        openssl_conf = openssl_def
+
+        [ openssl_def ]
+        engines = engine_section
+
+        [ engine_section ]
+        pkcs11 = pkcs11_section
+
+        [ pkcs11_section ]
+        engine_id = pkcs11
+        dynamic_path = /usr/lib64/openssl/engines/engine_pkcs11.so
+        MODULE_PATH = /usr/lib64/libeTPkcs11.so
+        init = 0
+
+      - There are two ways to specify a password/PIN for the PKCS11 engine:
+          - inside the openssl.cnf file using
+              PIN = your-secret-pin
+            Note The keyword 'PIN' is case sensitive!
+          - Using the 'password' in the ppp options file.
+        From v0.97 of the eap-tls patch the password can also be supplied
+        using the appropriate 'eaptls_passwd_hook' (see plugins/passprompt.c
+        for an example).
+
+
+4. Options
+
+    These pppd options are available:
+
+      ca <ca-file>
+        Use the CA public certificate found in <ca-file> in PEM format
+      ca-path <directory>
+        Use the directory <directory> as the CA public certificate directory
+      cert <cert-file>
+        Use the client public certificate found in <cert-file> in PEM format
+        or in engine:engine_id format
+      key <key-file>
+        Use the client private key found in <key-file> in PEM format
+        or in engine:engine_id format
+      crl <crl-file>
+        Use the Certificate Revocation List (CRL) file <crl-file> in PEM format.
+      crl-dir <dir>
+        Use CRL files from directory <dir>. It contains CRL files in PEM
+        format and each file contains a CRL. The files are looked up 
+        by the issuer name hash value. Use the c_rehash utility 
+        to create necessary links.
+      need-peer-eap
+        If the peer doesn't ask us to authenticate or doesn't use eap
+        to authenticate us, disconnect.
+      max-tls-version <1.0|1.1|1.2 (default)|1.3>
+        Specify the maximum TLS protocol version to negotiate with peers. Defaults
+        to TLSv1.2 as the TLSv1.3 code is experimental.
+
+    Note: 
+      password-encrypted certificates can be used as of v0.94 of this 
+      patch. The password for the eap-tls.key file is specified using 
+      the regular
+          password ....
+      statement in the ppp options file, or by using the appropriate
+      plugin which supplies a 'eaptls_passwd_hook' routine.
+
+5. Connecting
+
+    If you're setting up a pppd server, edit the EAP-TLS configuration file 
+    as written above and then run pppd with the 'auth' option to authenticate
+    the client. The EAP-TLS method will be used if the other eap methods can't
+    be used (no secrets).
+
+    If you're setting up a client, edit the configuration file and then run
+    pppd with 'remotename' option to specify the server name. Add the 
+    'need-peer-eap' option if you want to be sure the peer ask you to
+    authenticate (and to use eap) and to disconnect if it doesn't.
+
+6. Example
+
+    The following example can be used to connect a Linux client with the 'pptp'
+    package to a Linux server running the 'pptpd' (PoPToP) package. The server
+    was configured with a certificate with name (CN) 'pptp-server', the client
+    was configured with a certificate with name (CN) 'pptp-client', both 
+    signed by the same Certificate Authority (CA).
+
+    Server side:
+      - /etc/pptpd.conf file:
+          option /etc/ppp/options-pptpd-eaptls
+          localip 172.16.1.1
+          remoteip 172.16.1.10-20 
+      - /etc/ppp/options-pptpd-eaptls file:
+          name pptp-server
+          lock 
+          mtu 1500 
+          mru 1450
+          auth 
+          lcp-echo-failure 3 
+          lcp-echo-interval 5 
+          nodeflate 
+          nobsdcomp
+          nopredictor1
+          nopcomp
+          noaccomp
+          
+          require-eap
+          require-mppe-128
+          
+          crl /home/janjust/ppp/keys/crl.pem
+          
+          debug
+          logfile /tmp/pppd.log
+
+      - /etc/ppp/eaptls-server file:
+           * pptp-server - /etc/ppp/pptp-server.crt /etc/ppp/ca.crt /etc/ppp/pptp-server.key *
+
+      - On the server, run 
+          pptdp --conf /etc/pptpd.conf
+       
+    Client side:
+      - Run
+          pppd noauth require-eap require-mppe-128 \
+            ipcp-accept-local ipcp-accept-remote noipdefault \
+            cert  /etc/ppp/keys/pptp-client.crt \
+            key   /etc/ppp/keys/pptp-client.key \
+            ca    /etc/ppp/keys/ca.crt \
+            name pptp-client remotename pptp-server \
+            debug logfile /tmp/pppd.log
+            pty "pptp pptp-server.example.com --nolaunchpppd"
+
+    Check /var/log/messages and the files /tmp/pppd.log on both sides for debugging info.
+
+7. Notes
+
+    This is experimental code.
+    Send suggestions and comments to Jan Just Keijser <janjust@nikhef.nl>
+
diff --git a/etc.ppp/eaptls-client b/etc.ppp/eaptls-client
new file mode 100644 (file)
index 0000000..7782f0e
--- /dev/null
@@ -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 (file)
index 0000000..fa53cbd
--- /dev/null
@@ -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 (file)
index 0000000..dd32f30
--- /dev/null
@@ -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
+
index f63d45e58a78ab2e275c8dbffbac8469126ed8a4..894f8f32c9e4bd4284ad614382f6b5f2b29a959a 100644 (file)
@@ -26,7 +26,7 @@ install-progs:
        cd pppdump; $(MAKE) $(MFLAGS) install
 
 install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
        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
 
 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 $@
        $(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 $@
 
 $(BINDIR):
        $(INSTALL) -d -m 755 $@
index a22dcfab9d74f9658a1522bada021a41249aa90d..44d47ad7f46f35bce09a86998cf4ebaab2ebd15f 100644 (file)
@@ -81,6 +81,9 @@ PLUGIN=y
 # Use libutil
 USE_LIBUTIL=y
 
 # Use libutil
 USE_LIBUTIL=y
 
+# Enable EAP-TLS authentication (requires MPPE support, libssl and libcrypto)
+USE_EAPTLS=y
+
 MAXOCTETS=y
 
 INCLUDE_DIRS= -I../include
 MAXOCTETS=y
 
 INCLUDE_DIRS= -I../include
@@ -106,7 +109,8 @@ endif
 # EAP SRP-SHA1
 ifdef USE_SRP
 CFLAGS += -DUSE_SRP -DOPENSSL -I/usr/local/ssl/include
 # EAP SRP-SHA1
 ifdef USE_SRP
 CFLAGS += -DUSE_SRP -DOPENSSL -I/usr/local/ssl/include
-LIBS   += -lsrp -L/usr/local/ssl/lib -lcrypto
+LIBS   += -lsrp -L/usr/local/ssl/lib
+NEEDCRYPTOLIB = y
 TARGETS        += srp-entry
 EXTRAINSTALL = $(INSTALL) -s -c -m 555 srp-entry $(BINDIR)/srp-entry
 MANPAGES += srp-entry.8
 TARGETS        += srp-entry
 EXTRAINSTALL = $(INSTALL) -s -c -m 555 srp-entry $(BINDIR)/srp-entry
 MANPAGES += srp-entry.8
@@ -121,6 +125,16 @@ HEADERS += sha1.h
 PPPDOBJS += sha1.o
 endif
 
 PPPDOBJS += sha1.o
 endif
 
+# EAP-TLS
+ifdef USE_EAPTLS
+CFLAGS += -DUSE_EAPTLS=1
+LIBS += -lssl
+NEEDCRYPTOLIB = y
+PPPDSRC += eap-tls.c
+HEADERS += eap-tls.h
+PPPDOBJS += eap-tls.o
+endif
+
 ifdef HAS_SHADOW
 CFLAGS   += -DHAS_SHADOW
 #LIBS     += -lshadow $(LIBS)
 ifdef HAS_SHADOW
 CFLAGS   += -DHAS_SHADOW
 #LIBS     += -lshadow $(LIBS)
@@ -139,7 +153,7 @@ endif
 ifdef NEEDDES
 ifndef USE_CRYPT
 CFLAGS   += -I$(shell $(CC) --print-sysroot)/usr/include/openssl
 ifdef NEEDDES
 ifndef USE_CRYPT
 CFLAGS   += -I$(shell $(CC) --print-sysroot)/usr/include/openssl
-LIBS     += -lcrypto
+NEEDCRYPTOLIB = y
 else
 CFLAGS   += -DUSE_CRYPT=1
 endif
 else
 CFLAGS   += -DUSE_CRYPT=1
 endif
@@ -147,6 +161,10 @@ PPPDOBJS += pppcrypt.o
 HEADERS += pppcrypt.h
 endif
 
 HEADERS += pppcrypt.h
 endif
 
+ifdef NEEDCRYPTOLIB
+LIBS     += -lcrypto
+endif
+
 # For "Pluggable Authentication Modules", see ftp.redhat.com:/pub/pam/.
 ifdef USE_PAM
 CFLAGS   += -DUSE_PAM
 # For "Pluggable Authentication Modules", see ftp.redhat.com:/pub/pam/.
 ifdef USE_PAM
 CFLAGS   += -DUSE_PAM
index 45b6b6269bd2a096a433bf284b7eac67b2d88cc7..809cb4b3519fcd4af10e67601300dd707af84921 100644 (file)
@@ -39,6 +39,14 @@ OBJS += ipv6cp.o eui64.o
 CFLAGS += -DUSE_CRYPT -DCHAPMS -DMSLANMAN -DHAVE_CRYPT_H
 OBJS += chap_ms.o pppcrypt.o md4.o sha1.o
 
 CFLAGS += -DUSE_CRYPT -DCHAPMS -DMSLANMAN -DHAVE_CRYPT_H
 OBJS += chap_ms.o pppcrypt.o md4.o sha1.o
 
+# Uncomment to enable MPPE (in both CHAP and EAP-TLS)
+CFLAGS += -DMPPE
+
+# Uncomment to enable EAP-TLS
+CFLAGS += -DUSE_EAPTLS
+LIBS += -lcrypto -lssl
+OBJS += eap-tls.o
+
 # Uncomment for CBCP
 #CFLAGS += -DCBCP_SUPPORT
 #OBJS += cbcp.o
 # Uncomment for CBCP
 #CFLAGS += -DCBCP_SUPPORT
 #OBJS += cbcp.o
index 3641b6ea701f11af845331926d308c366103a4d5..601241f18164a576f01496755b7725a9c6e6fb24 100644 (file)
@@ -78,6 +78,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <string.h>
 #include <pwd.h>
 #include <grp.h>
 #include <string.h>
+#include <strings.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include "upap.h"
 #include "chap-new.h"
 #include "eap.h"
 #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
 #ifdef CBCP_SUPPORT
 #include "cbcp.h"
 #endif
@@ -186,6 +190,11 @@ int (*chap_check_hook) __P((void)) = NULL;
 /* Hook for a plugin to get the CHAP password for authenticating us */
 int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
 
 /* Hook for a plugin to get the CHAP password for authenticating us */
 int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
 
+#ifdef USE_EAPTLS
+/* Hook for a plugin to get the EAP-TLS password for authenticating us */
+int (*eaptls_passwd_hook) __P((char *user, char *passwd)) = NULL;
+#endif
+
 /* Hook for a plugin to say whether it is OK if the peer
    refuses to authenticate. */
 int (*null_auth_hook) __P((struct wordlist **paddrs,
 /* Hook for a plugin to say whether it is OK if the peer
    refuses to authenticate. */
 int (*null_auth_hook) __P((struct wordlist **paddrs,
@@ -241,6 +250,16 @@ 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 */
 bool explicit_user = 0;                /* Set if "user" option supplied */
 bool explicit_passwd = 0;      /* Set if "password" option supplied */
 char remote_name[MAXNAMELEN];  /* Peer's name for authentication */
+#ifdef USE_EAPTLS
+char *cacert_file  = NULL;     /* CA certificate file (pem format) */
+char *ca_path      = NULL;     /* directory with CA certificates */
+char *cert_file    = NULL;     /* client certificate file (pem format) */
+char *privkey_file = NULL;     /* client private key file (pem format) */
+char *crl_dir      = NULL;     /* directory containing CRL files */
+char *crl_file     = NULL;     /* Certificate Revocation List (CRL) file (pem format) */
+char *max_tls_version = NULL;  /* Maximum TLS protocol version (default=1.2) */
+bool need_peer_eap = 0;                        /* Require peer to authenticate us */
+#endif
 
 static char *uafname;          /* name of most recent +ua file */
 
 
 static char *uafname;          /* name of most recent +ua file */
 
@@ -257,6 +276,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));
 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 **,
 static int  ip_addr_check __P((u_int32_t, struct permitted_ip *));
 static int  scan_authfile __P((FILE *, char *, char *, char *,
                               struct wordlist **, struct wordlist **,
@@ -404,6 +436,18 @@ option_t auth_options[] = {
       "Set telephone number(s) which are allowed to connect",
       OPT_PRIV | OPT_A2LIST },
 
       "Set telephone number(s) which are allowed to connect",
       OPT_PRIV | OPT_A2LIST },
 
+#ifdef USE_EAPTLS
+    { "ca", o_string, &cacert_file,   "EAP-TLS CA certificate in PEM format" },
+    { "capath", o_string, &ca_path,   "EAP-TLS CA certificate directory" },
+    { "cert", o_string, &cert_file,   "EAP-TLS client certificate in PEM format" },
+    { "key", o_string, &privkey_file, "EAP-TLS client private key in PEM format" },
+    { "crl-dir", o_string, &crl_dir,  "Use CRLs in directory" },
+    { "crl", o_string, &crl_file,     "Use specific CRL file" },
+    { "max-tls-version", o_string, &max_tls_version,
+      "Maximum TLS version (1.0/1.1/1.2 (default)/1.3)" },
+    { "need-peer-eap", o_bool, &need_peer_eap,
+      "Require the peer to authenticate us", 1 },
+#endif /* USE_EAPTLS */
     { NULL }
 };
 
     { NULL }
 };
 
@@ -737,6 +781,9 @@ link_established(unit)
     lcp_options *wo = &lcp_wantoptions[unit];
     lcp_options *go = &lcp_gotoptions[unit];
     lcp_options *ho = &lcp_hisoptions[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;
 
     int i;
     struct protent *protp;
 
@@ -771,6 +818,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) {
     new_phase(PHASE_AUTHENTICATE);
     auth = 0;
     if (go->neg_eap) {
@@ -1291,6 +1354,15 @@ auth_check_options()
                                    our_name, 1, &lacks_ip);
     }
 
                                    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(
     if (auth_required && !can_auth && noauth_addrs == NULL) {
        if (default_auth) {
            option_error(
@@ -1345,7 +1417,11 @@ auth_reset(unit)
        passwd[0] != 0 ||
        (hadchap == 1 || (hadchap == -1 && have_chap_secret(user,
            (explicit_remote? remote_name: NULL), 0, NULL))) ||
        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))
 
     hadchap = -1;
     if (go->neg_upap && !uselogin && !have_pap_secret(NULL))
@@ -1360,7 +1436,12 @@ 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,
            !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;
 }
 
        go->neg_eap = 0;
 }
 
@@ -2373,3 +2454,344 @@ auth_script(script)
 
     auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0);
 }
 
     auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0);
 }
+
+
+#ifdef USE_EAPTLS
+static int
+have_eaptls_secret_server(client, server, need_ip, lacks_ipp)
+    char *client;
+    char *server;
+    int need_ip;
+    int *lacks_ipp;
+{
+    FILE *f;
+    int ret;
+    char *filename;
+    struct wordlist *addrs;
+    char servcertfile[MAXWORDLEN];
+    char clicertfile[MAXWORDLEN];
+    char cacertfile[MAXWORDLEN];
+    char pkfile[MAXWORDLEN];
+
+    filename = _PATH_EAPTLSSERVFILE;
+    f = fopen(filename, "r");
+    if (f == NULL)
+               return 0;
+
+    if (client != NULL && client[0] == 0)
+               client = NULL;
+    else if (server != NULL && server[0] == 0)
+               server = NULL;
+
+    ret =
+       scan_authfile_eaptls(f, client, server, clicertfile, servcertfile,
+                            cacertfile, pkfile, &addrs, NULL, filename,
+                            0);
+
+    fclose(f);
+
+/*
+    if (ret >= 0 && !eaptls_init_ssl(1, cacertfile, servcertfile,
+                               clicertfile, pkfile))
+               ret = -1;
+*/
+
+       if (ret >= 0 && need_ip && !some_ip_ok(addrs)) {
+               if (lacks_ipp != 0)
+                       *lacks_ipp = 1;
+               ret = -1;
+    }
+    if (addrs != 0)
+               free_wordlist(addrs);
+
+    return ret >= 0;
+}
+
+
+static int
+have_eaptls_secret_client(client, server)
+    char *client;
+    char *server;
+{
+    FILE *f;
+    int ret;
+    char *filename;
+    struct wordlist *addrs = NULL;
+    char servcertfile[MAXWORDLEN];
+    char clicertfile[MAXWORDLEN];
+    char cacertfile[MAXWORDLEN];
+    char pkfile[MAXWORDLEN];
+
+    if (client != NULL && client[0] == 0)
+               client = NULL;
+    else if (server != NULL && server[0] == 0)
+               server = NULL;
+
+       if ((cacert_file || ca_path) && cert_file && privkey_file)
+               return 1;
+
+    filename = _PATH_EAPTLSCLIFILE;
+    f = fopen(filename, "r");
+    if (f == NULL)
+               return 0;
+
+    ret =
+       scan_authfile_eaptls(f, client, server, clicertfile, servcertfile,
+                            cacertfile, pkfile, &addrs, NULL, filename,
+                            0);
+    fclose(f);
+
+/*
+    if (ret >= 0 && !eaptls_init_ssl(0, cacertfile, clicertfile,
+                               servcertfile, pkfile))
+               ret = -1;
+*/
+
+    if (addrs != 0)
+               free_wordlist(addrs);
+
+    return ret >= 0;
+}
+
+
+static int
+scan_authfile_eaptls(f, client, server, cli_cert, serv_cert, ca_cert, pk,
+                    addrs, opts, filename, flags)
+    FILE *f;
+    char *client;
+    char *server;
+    char *cli_cert;
+    char *serv_cert;
+    char *ca_cert;
+    char *pk;
+    struct wordlist **addrs;
+    struct wordlist **opts;
+    char *filename;
+    int flags;
+{
+    int newline;
+    int got_flag, best_flag;
+    struct wordlist *ap, *addr_list, *alist, **app;
+    char word[MAXWORDLEN];
+
+    if (addrs != NULL)
+       *addrs = NULL;
+    if (opts != NULL)
+       *opts = NULL;
+    addr_list = NULL;
+    if (!getword(f, word, &newline, filename))
+       return -1;              /* file is empty??? */
+    newline = 1;
+    best_flag = -1;
+    for (;;) {
+       /*
+        * Skip until we find a word at the start of a line.
+        */
+       while (!newline && getword(f, word, &newline, filename));
+       if (!newline)
+           break;              /* got to end of file */
+
+       /*
+        * Got a client - check if it's a match or a wildcard.
+        */
+       got_flag = 0;
+       if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) {
+           newline = 0;
+           continue;
+       }
+       if (!ISWILD(word))
+           got_flag = NONWILD_CLIENT;
+
+       /*
+        * Now get a server and check if it matches.
+        */
+       if (!getword(f, word, &newline, filename))
+           break;
+       if (newline)
+           continue;
+       if (!ISWILD(word)) {
+           if (server != NULL && strcmp(word, server) != 0)
+               continue;
+           got_flag |= NONWILD_SERVER;
+       }
+
+       /*
+        * Got some sort of a match - see if it's better than what
+        * we have already.
+        */
+       if (got_flag <= best_flag)
+           continue;
+
+       /*
+        * Get the cli_cert
+        */
+       if (!getword(f, word, &newline, filename))
+           break;
+       if (newline)
+           continue;
+       if (strcmp(word, "-") != 0) {
+           strlcpy(cli_cert, word, MAXWORDLEN);
+       } else
+           cli_cert[0] = 0;
+
+       /*
+        * Get serv_cert
+        */
+       if (!getword(f, word, &newline, filename))
+           break;
+       if (newline)
+           continue;
+       if (strcmp(word, "-") != 0) {
+           strlcpy(serv_cert, word, MAXWORDLEN);
+       } else
+           serv_cert[0] = 0;
+
+       /*
+        * Get ca_cert
+        */
+       if (!getword(f, word, &newline, filename))
+           break;
+       if (newline)
+           continue;
+       strlcpy(ca_cert, word, MAXWORDLEN);
+
+       /*
+        * Get pk
+        */
+       if (!getword(f, word, &newline, filename))
+           break;
+       if (newline)
+           continue;
+       strlcpy(pk, word, MAXWORDLEN);
+
+
+       /*
+        * Now read address authorization info and make a wordlist.
+        */
+       app = &alist;
+       for (;;) {
+           if (!getword(f, word, &newline, filename) || newline)
+               break;
+           ap = (struct wordlist *)
+               malloc(sizeof(struct wordlist) + strlen(word) + 1);
+           if (ap == NULL)
+               novm("authorized addresses");
+           ap->word = (char *) (ap + 1);
+           strcpy(ap->word, word);
+           *app = ap;
+           app = &ap->next;
+       }
+       *app = NULL;
+       /*
+        * This is the best so far; remember it.
+        */
+       best_flag = got_flag;
+       if (addr_list)
+           free_wordlist(addr_list);
+       addr_list = alist;
+
+       if (!newline)
+           break;
+    }
+
+    /* scan for a -- word indicating the start of options */
+    for (app = &addr_list; (ap = *app) != NULL; app = &ap->next)
+       if (strcmp(ap->word, "--") == 0)
+           break;
+    /* ap = start of options */
+    if (ap != NULL) {
+       ap = ap->next;          /* first option */
+       free(*app);             /* free the "--" word */
+       *app = NULL;            /* terminate addr list */
+    }
+    if (opts != NULL)
+       *opts = ap;
+    else if (ap != NULL)
+       free_wordlist(ap);
+    if (addrs != NULL)
+       *addrs = addr_list;
+    else if (addr_list != NULL)
+       free_wordlist(addr_list);
+
+    return best_flag;
+}
+
+
+int
+get_eaptls_secret(unit, client, server, clicertfile, servcertfile,
+                 cacertfile, capath, pkfile, am_server)
+    int unit;
+    char *client;
+    char *server;
+    char *clicertfile;
+    char *servcertfile;
+    char *cacertfile;
+    char *capath;
+    char *pkfile;
+    int am_server;
+{
+    FILE *fp;
+    int ret;
+    char *filename         = NULL;
+    struct wordlist *addrs = NULL;
+    struct wordlist *opts  = NULL;
+
+       /* maybe overkill, but it eases debugging */
+       bzero(clicertfile, MAXWORDLEN);
+       bzero(servcertfile, MAXWORDLEN);
+       bzero(cacertfile, MAXWORDLEN);
+       bzero(capath, MAXWORDLEN);
+       bzero(pkfile, MAXWORDLEN);
+
+       /* the ca+cert+privkey can also be specified as options */
+       if (!am_server && (cacert_file || ca_path) && cert_file && privkey_file )
+       {
+               strlcpy( clicertfile, cert_file, MAXWORDLEN );
+               if (cacert_file)
+                       strlcpy( cacertfile, cacert_file, MAXWORDLEN );
+               if (ca_path)
+                       strlcpy( capath, ca_path, MAXWORDLEN );
+               strlcpy( pkfile, privkey_file, MAXWORDLEN );
+       }
+       else
+       {
+               filename = (am_server ? _PATH_EAPTLSSERVFILE : _PATH_EAPTLSCLIFILE);
+               addrs = NULL;
+
+               fp = fopen(filename, "r");
+               if (fp == NULL)
+               {
+                       error("Can't open eap-tls secret file %s: %m", filename);
+                       return 0;
+               }
+
+               check_access(fp, filename);
+
+               ret = scan_authfile_eaptls(fp, client, server, clicertfile, servcertfile,
+                               cacertfile, pkfile, &addrs, &opts, filename, 0);
+
+               fclose(fp);
+
+               if (ret < 0) return 0;
+       }
+
+    if (eaptls_passwd_hook)
+    {
+               dbglog( "Calling eaptls password hook" );
+               if ( (*eaptls_passwd_hook)(pkfile, passwd) < 0)
+               {
+                        error("Unable to obtain EAP-TLS password for %s (%s) from plugin",
+                               client, pkfile);
+                   return 0;
+               }
+       }
+    if (am_server)
+               set_allowed_addrs(unit, addrs, opts);
+    else if (opts != NULL)
+               free_wordlist(opts);
+    if (addrs != NULL)
+               free_wordlist(addrs);
+
+    return 1;
+}
+#endif
index 61947d96992c55872874253a5a8219372b66c59b..dbc567e3c037b608b62a44039f1a66b547dd0dd5 100644 (file)
@@ -539,6 +539,9 @@ ccp_resetci(f)
     if (go->mppe) {
        ccp_options *ao = &ccp_allowoptions[f->unit];
        int auth_mschap_bits = auth_done[f->unit];
     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;
 
        /*
        int numbits;
 
        /*
@@ -566,8 +569,23 @@ ccp_resetci(f)
            lcp_close(f->unit, "MPPE required but not available");
            return;
        }
            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.");
        if (!numbits) {
            error("MPPE required, but MS-CHAP[v2] auth not performed.");
+#endif
            lcp_close(f->unit, "MPPE required but not available");
            return;
        }
            lcp_close(f->unit, "MPPE required but not available");
            return;
        }
diff --git a/pppd/eap-tls.c b/pppd/eap-tls.c
new file mode 100644 (file)
index 0000000..3d8fdc7
--- /dev/null
@@ -0,0 +1,1427 @@
+/* * eap-tls.c - EAP-TLS implementation for PPP
+ *
+ * Copyright (c) Beniamino Galvani 2005 All rights reserved.
+ *               Jan Just Keijser  2006-2019 All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/hmac.h>
+#include <openssl/err.h>
+#include <openssl/ui.h>
+#include <openssl/x509v3.h>
+
+#include "pppd.h"
+#include "eap.h"
+#include "eap-tls.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "pathnames.h"
+
+typedef struct pw_cb_data
+{
+    const void *password;
+    const char *prompt_info;
+} PW_CB_DATA;
+
+/* The openssl configuration file and engines can be loaded only once */
+static CONF   *ssl_config  = NULL;
+static ENGINE *cert_engine = NULL;
+static ENGINE *pkey_engine = NULL;
+
+/* TLSv1.3 do we have a session ticket ? */
+static int have_session_ticket = 0;
+
+int ssl_verify_callback(int, X509_STORE_CTX *); 
+void ssl_msg_callback(int write_p, int version, int ct, const void *buf,
+              size_t len, SSL * ssl, void *arg);
+int ssl_new_session_cb(SSL *s, SSL_SESSION *sess);
+
+X509 *get_X509_from_file(char *filename);
+int ssl_cmp_certs(char *filename, X509 * a); 
+
+#ifdef MPPE
+
+#define EAPTLS_MPPE_KEY_LEN     32
+
+/*
+ *  OpenSSL 1.1+ introduced a generic TLS_method()
+ *  For older releases we substitute the appropriate method
+ */
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+#define TLS_method SSLv23_method
+
+#define SSL3_RT_HEADER  0x100
+
+#ifndef SSL_CTX_set_max_proto_version
+/** Mimics SSL_CTX_set_max_proto_version for OpenSSL < 1.1 */
+static inline int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, long tls_ver_max)
+{
+    long sslopt = 0;
+
+    if (tls_ver_max < TLS1_VERSION)
+    {
+        sslopt |= SSL_OP_NO_TLSv1;
+    }
+#ifdef SSL_OP_NO_TLSv1_1
+    if (tls_ver_max < TLS1_1_VERSION)
+    {
+        sslopt |= SSL_OP_NO_TLSv1_1;
+    }
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+    if (tls_ver_max < TLS1_2_VERSION)
+    {
+        sslopt |= SSL_OP_NO_TLSv1_2;
+    }
+#endif
+    SSL_CTX_set_options(ctx, sslopt);
+
+    return 1;
+}
+#endif /* SSL_CTX_set_max_proto_version */
+
+#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
+
+
+/*
+ *  Generate keys according to RFC 2716 and add to reply
+ */
+void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client)
+{
+    unsigned char  out[4*EAPTLS_MPPE_KEY_LEN];
+    const char    *prf_label;
+    size_t         prf_size;
+    unsigned char  eap_tls13_context[] = { EAPT_TLS };
+    unsigned char *context = NULL;
+    size_t         context_len = 0;
+    unsigned char *p;
+
+    dbglog("EAP-TLS generating MPPE keys");
+    if (ets->tls_v13)
+    {
+        prf_label = "EXPORTER_EAP_TLS_Key_Material";
+        context   = eap_tls13_context;
+        context_len = 1;
+    }
+    else
+    {
+        prf_label = "client EAP encryption";
+    }
+
+    dbglog("EAP-TLS PRF label = %s", prf_label);
+    prf_size = strlen(prf_label);
+    if (SSL_export_keying_material(ets->ssl, out, sizeof(out), prf_label, prf_size, 
+                                   context, context_len, 0) != 1)
+    {
+        warn( "EAP-TLS: Failed generating keying material" );
+        return;
+    }   
+
+    /* 
+     * We now have the master send and receive keys.
+     * From these, generate the session send and receive keys.
+     * (see RFC3079 / draft-ietf-pppext-mppe-keys-03.txt for details)
+     */
+    if (client)
+    {
+        p = out;
+        BCOPY( p, mppe_send_key, sizeof(mppe_send_key) );
+        p += EAPTLS_MPPE_KEY_LEN;
+        BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) );
+    }
+    else
+    {
+        p = out;
+        BCOPY( p, mppe_recv_key, sizeof(mppe_recv_key) );
+        p += EAPTLS_MPPE_KEY_LEN;
+        BCOPY( p, mppe_send_key, sizeof(mppe_send_key) );
+    }
+
+    mppe_keys_set = 1;
+}
+
+#endif /* MPPE */
+
+void log_ssl_errors( void )
+{
+    unsigned long ssl_err = ERR_get_error();
+
+    if (ssl_err != 0)
+        dbglog("EAP-TLS SSL error stack:");
+    while (ssl_err != 0) {
+        dbglog( ERR_error_string( ssl_err, NULL ) );
+        ssl_err = ERR_get_error();
+    }
+}
+
+
+int password_callback (char *buf, int size, int rwflag, void *u)
+{
+    if (buf)
+    {
+        strlcpy (buf, passwd, size);
+        return strlen (buf);
+    }
+    return 0;
+}
+
+
+CONF *eaptls_ssl_load_config( void )
+{
+    CONF        *config;
+    int          ret_code;
+    long         error_line = 33;
+
+    config = NCONF_new( NULL );
+    dbglog( "Loading OpenSSL config file" );
+    ret_code = NCONF_load( config, _PATH_OPENSSLCONFFILE, &error_line );
+    if (ret_code == 0)
+    {
+        warn( "EAP-TLS: Error in OpenSSL config file %s at line %d", _PATH_OPENSSLCONFFILE, error_line );
+        NCONF_free( config );
+        config = NULL;
+        ERR_clear_error();
+    }
+
+    dbglog( "Loading OpenSSL built-ins" );
+    ENGINE_load_builtin_engines();
+    OPENSSL_load_builtin_modules();
+   
+    dbglog( "Loading OpenSSL configured modules" );
+    if (CONF_modules_load( config, NULL, 0 ) <= 0 )
+    {
+        warn( "EAP-TLS: Error loading OpenSSL modules" );
+        log_ssl_errors();
+        config = NULL;
+    }
+
+    return config;
+}
+
+ENGINE *eaptls_ssl_load_engine( char *engine_name )
+{
+    ENGINE      *e = NULL;
+
+    dbglog( "Enabling OpenSSL auto engines" );
+    ENGINE_register_all_complete();
+
+    dbglog( "Loading OpenSSL '%s' engine support", engine_name );
+    e = ENGINE_by_id( engine_name );
+    if (!e) 
+    {
+        dbglog( "EAP-TLS: Cannot load '%s' engine support, trying 'dynamic'", engine_name );
+        e = ENGINE_by_id( "dynamic" );
+        if (e)
+        {
+            if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine_name, 0)
+             || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
+            {
+                warn( "EAP-TLS: Error loading dynamic engine '%s'", engine_name );
+                log_ssl_errors();
+                ENGINE_free(e);
+                e = NULL;
+            }
+        }
+        else
+        {
+            warn( "EAP-TLS: Cannot load dynamic engine support" );
+        }
+    }
+
+    if (e)
+    {
+        dbglog( "Initialising engine" );
+        if(!ENGINE_set_default(e, ENGINE_METHOD_ALL))
+        {
+            warn( "EAP-TLS: Cannot use that engine" );
+            log_ssl_errors();
+            ENGINE_free(e);
+            e = NULL;
+        }
+    }
+
+    return e;
+}
+
+
+
+/*
+ * Initialize the SSL stacks and tests if certificates, key and crl
+ * for client or server use can be loaded.
+ */
+SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
+            char *certfile, char *peer_certfile, char *privkeyfile)
+{
+    char        *cert_engine_name = NULL;
+    char        *cert_identifier = NULL;
+    char        *pkey_engine_name = NULL;
+    char        *pkey_identifier = NULL;
+    SSL_CTX     *ctx;
+    SSL         *ssl;
+    X509_STORE  *certstore;
+    X509_LOOKUP *lookup;
+    X509        *tmp;
+    int          ret;
+#if defined(TLS1_2_VERSION)
+    long         tls_version = TLS1_2_VERSION; 
+#elif defined(TLS1_1_VERSION)
+    long         tls_version = TLS1_1_VERSION; 
+#else
+    long         tls_version = TLS1_VERSION; 
+#endif
+
+    /*
+     * Without these can't continue 
+     */
+    if (!(cacertfile[0] || capath[0]))
+    {
+        error("EAP-TLS: CA certificate file or path missing");
+        return NULL;
+    }
+
+    if (!certfile[0])
+    {
+        error("EAP-TLS: Certificate missing");
+        return NULL;
+    }
+
+    if (!privkeyfile[0])
+    {
+        error("EAP-TLS: Private key missing");
+        return NULL;
+    }
+
+    SSL_library_init();
+    SSL_load_error_strings();
+
+    /* load the openssl config file only once and load it before triggering
+       the loading of a global openssl config file via SSL_CTX_new()
+     */
+    if (!ssl_config)
+        ssl_config = eaptls_ssl_load_config();
+
+    ctx = SSL_CTX_new(TLS_method());
+
+    if (!ctx) {
+        error("EAP-TLS: Cannot initialize SSL CTX context");
+        goto fail;
+    }
+
+    /* if the certificate filename is of the form engine:id. e.g.
+        pkcs11:12345
+       then we try to load and use this engine.
+       If the certificate filename starts with a / or . then we
+       ALWAYS assume it is a file and not an engine/pkcs11 identifier
+     */
+    if ( index( certfile, '/' ) == NULL && index( certfile, '.') == NULL )
+    {
+        cert_identifier = index( certfile, ':' );
+
+        if (cert_identifier)
+        {
+            cert_engine_name = certfile;
+            *cert_identifier = '\0';
+            cert_identifier++;
+
+            dbglog( "Found certificate engine '%s'", cert_engine_name );
+            dbglog( "Found certificate identifier '%s'", cert_identifier );
+        }
+    }
+
+    /* if the privatekey filename is of the form engine:id. e.g.
+        pkcs11:12345
+       then we try to load and use this engine.
+       If the privatekey filename starts with a / or . then we
+       ALWAYS assume it is a file and not an engine/pkcs11 identifier
+     */
+    if ( index( privkeyfile, '/' ) == NULL && index( privkeyfile, '.') == NULL )
+    {
+        pkey_identifier = index( privkeyfile, ':' );
+
+        if (pkey_identifier)
+        {
+            pkey_engine_name = privkeyfile;
+            *pkey_identifier = '\0';
+            pkey_identifier++;
+
+            dbglog( "Found privatekey engine '%s'", pkey_engine_name );
+            dbglog( "Found privatekey identifier '%s'", pkey_identifier );
+        }
+    }
+
+    if (cert_identifier && pkey_identifier)
+    {
+        if (strlen( cert_identifier ) == 0)
+        {
+            if (strlen( pkey_identifier ) == 0)
+                error( "EAP-TLS: both the certificate and privatekey identifiers are missing!" );
+            else
+            {
+                dbglog( "Substituting privatekey identifier for certificate identifier" );
+                cert_identifier = pkey_identifier;
+            }
+        }
+        else
+        {
+            if (strlen( pkey_identifier ) == 0)
+            {
+                dbglog( "Substituting certificate identifier for privatekey identifier" );
+                pkey_identifier = cert_identifier;
+            }
+        }
+    }
+
+    if (ssl_config && cert_engine_name)
+        cert_engine = eaptls_ssl_load_engine( cert_engine_name );
+
+    if (ssl_config && pkey_engine_name)
+    {
+        /* don't load the same engine twice */
+        if ( cert_engine && strcmp( cert_engine_name, pkey_engine_name) == 0 )
+            pkey_engine = cert_engine;
+        else
+            pkey_engine = eaptls_ssl_load_engine( pkey_engine_name );
+    }
+
+    SSL_CTX_set_default_passwd_cb (ctx, password_callback);
+
+    if (strlen(cacertfile) == 0) cacertfile = NULL;
+    if (strlen(capath) == 0)     capath = NULL;
+
+    if (!SSL_CTX_load_verify_locations(ctx, cacertfile, capath))
+    {
+        error("EAP-TLS: Cannot load verify locations");
+        if (cacertfile) dbglog("CA certificate file = [%s]", cacertfile);
+        if (capath) dbglog("CA certificate path = [%s]", capath);
+        goto fail;
+    }
+
+    if (init_server)
+        SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(cacertfile));
+
+    if (cert_engine)
+    {
+        struct
+        {
+            const char *s_slot_cert_id;
+            X509 *cert;
+        } cert_info;
+
+        cert_info.s_slot_cert_id = cert_identifier;
+        cert_info.cert = NULL;
+        
+        if (!ENGINE_ctrl_cmd( cert_engine, "LOAD_CERT_CTRL", 0, &cert_info, NULL, 0 ) )
+        {
+            error( "EAP-TLS: Error loading certificate with id '%s' from engine", cert_identifier );
+            goto fail;
+        }
+
+        if (cert_info.cert)
+        {
+            dbglog( "Got the certificate, adding it to SSL context" );
+            dbglog( "subject = %s", X509_NAME_oneline( X509_get_subject_name( cert_info.cert ), NULL, 0 ) );
+            if (SSL_CTX_use_certificate(ctx, cert_info.cert) <= 0)
+            {
+                error("EAP-TLS: Cannot use PKCS11 certificate %s", cert_identifier);
+                goto fail;
+            }
+        }
+        else
+        {
+            warn("EAP-TLS: Cannot load PKCS11 key %s", cert_identifier);
+            log_ssl_errors();
+        }
+    }
+    else
+    {
+        if (!SSL_CTX_use_certificate_chain_file(ctx, certfile))
+        {
+            error( "EAP-TLS: Cannot use public certificate %s", certfile );
+            goto fail;
+        }
+    }
+
+
+    /*
+     *  Check the Before and After dates of the certificate
+     */
+    ssl = SSL_new(ctx);
+    tmp = SSL_get_certificate(ssl);
+
+    ret = X509_cmp_time(X509_get_notBefore(tmp), NULL);
+    if (ret == 0)
+    {    
+        warn( "EAP-TLS: Failed to read certificate notBefore field.");
+    }    
+    if (ret > 0) 
+    {    
+        warn( "EAP-TLS: Your certificate is not yet valid!");
+    }    
+
+    ret = X509_cmp_time(X509_get_notAfter(tmp), NULL);
+    if (ret == 0)
+    {    
+        warn( "EAP-TLS: Failed to read certificate notAfter field.");
+    }    
+    if (ret < 0)
+    {
+        warn( "EAP-TLS: Your certificate has expired!");
+    }
+    SSL_free(ssl);
+
+    if (pkey_engine)
+    {
+        EVP_PKEY   *pkey = NULL;
+        PW_CB_DATA  cb_data;
+        UI_METHOD* transfer_pin = NULL;
+
+        cb_data.password = passwd;
+        cb_data.prompt_info = pkey_identifier;
+
+        if (passwd[0] != 0)
+        {
+            UI_METHOD* transfer_pin = UI_create_method("transfer_pin");
+
+            int writer (UI *ui, UI_STRING *uis)
+            {
+                PW_CB_DATA* cb_data = (PW_CB_DATA*)UI_get0_user_data(ui);
+                UI_set_result(ui, uis, cb_data->password);
+                return 1;
+            };
+            int stub (UI* ui) {return 1;};
+            int stub_reader (UI *ui, UI_STRING *uis) {return 1;};
+
+            UI_method_set_writer(transfer_pin,  writer);
+            UI_method_set_opener(transfer_pin,  stub);
+            UI_method_set_closer(transfer_pin,  stub);
+            UI_method_set_flusher(transfer_pin, stub);
+            UI_method_set_reader(transfer_pin,  stub_reader);
+
+            dbglog( "Using our private key '%s' in engine", pkey_identifier );
+            pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, transfer_pin, &cb_data);
+        }
+        else {
+            dbglog( "Loading private key '%s' from engine", pkey_identifier );
+            pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, NULL, NULL);
+        }
+        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();
+        }
+
+        if (transfer_pin) UI_destroy_method(transfer_pin);
+    }
+    else
+    {
+        if (!SSL_CTX_use_PrivateKey_file(ctx, privkeyfile, SSL_FILETYPE_PEM))
+        { 
+            error("EAP-TLS: Cannot use private key %s", privkeyfile);
+            goto fail;
+        }
+    }
+
+    if (SSL_CTX_check_private_key(ctx) != 1) {
+        error("EAP-TLS: Private key %s fails security check", privkeyfile);
+        goto fail;
+    }
+
+    /* Explicitly set the NO_TICKETS flag to support Win7/Win8 clients */
+    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3
+#ifdef SSL_OP_NO_TICKET
+    | SSL_OP_NO_TICKET
+#endif
+    );
+
+    /* OpenSSL 1.1.1+ does not include RC4 ciphers by default.
+     * This causes totally obsolete WinXP clients to fail. If you really
+     * need ppp+EAP-TLS+openssl 1.1.1+WinXP then enable RC4 cipers and
+     * make sure that you use an OpenSSL that supports them
+
+    SSL_CTX_set_cipher_list(ctx, "RC4");
+     */
+
+
+    /* Set up a SSL Session cache with a callback. This is needed for TLSv1.3+.
+     * During the initial handshake the server signals to the client early on
+     * that the handshake is finished, even before the client has sent its
+     * credentials to the server. The actual connection (and moment that the
+     * client sends its credentials) only starts after the arrival of the first
+     * session ticket. The 'ssl_new_session_cb' catches this ticket.
+     */
+    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE);
+    SSL_CTX_sess_set_new_cb(ctx, ssl_new_session_cb);
+
+    /* As EAP-TLS+TLSv1.3 is highly experimental we offer the user a chance to override */
+    if (max_tls_version)
+    {
+        if (strncmp(max_tls_version, "1.0", 3) == 0)
+            tls_version = TLS1_VERSION;
+        else if (strncmp(max_tls_version, "1.1", 3) == 0)
+            tls_version = TLS1_1_VERSION;
+        else if (strncmp(max_tls_version, "1.2", 3) == 0)
+#ifdef TLS1_2_VERSION
+            tls_version = TLS1_2_VERSION;
+#else
+        {
+            warn("TLSv1.2 not available. Defaulting to TLSv1.1");
+            tls_version = TLS_1_1_VERSION;
+        }
+#endif
+        else if (strncmp(max_tls_version, "1.3", 3) == 0)
+#ifdef TLS1_3_VERSION
+            tls_version = TLS1_3_VERSION;
+#else
+            warn("TLSv1.3 not available.");
+#endif
+    }
+
+    dbglog("EAP-TLS: Setting max protocol version to 0x%X", tls_version);
+    SSL_CTX_set_max_proto_version(ctx, tls_version);
+
+    SSL_CTX_set_verify_depth(ctx, 5);
+    SSL_CTX_set_verify(ctx,
+               SSL_VERIFY_PEER |
+               SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+               &ssl_verify_callback);
+
+    if (crl_dir) {
+        if (!(certstore = SSL_CTX_get_cert_store(ctx))) {
+            error("EAP-TLS: Failed to get certificate store");
+            goto fail;
+        }
+
+        if (!(lookup =
+             X509_STORE_add_lookup(certstore, X509_LOOKUP_hash_dir()))) {
+            error("EAP-TLS: Store lookup for CRL failed");
+
+            goto fail;
+        }
+
+        X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM);
+        X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
+    }
+
+    if (crl_file) {
+        FILE     *fp  = NULL;
+        X509_CRL *crl = NULL;
+
+        fp = fopen(crl_file, "r");
+        if (!fp) {
+            error("EAP-TLS: Cannot open CRL file '%s'", crl_file);
+            goto fail;
+        }
+
+        crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL);
+        if (!crl) {
+            error("EAP-TLS: Cannot read CRL file '%s'", crl_file);
+            goto fail;
+        }
+
+        if (!(certstore = SSL_CTX_get_cert_store(ctx))) {
+            error("EAP-TLS: Failed to get certificate store");
+            goto fail;
+        }
+        if (!X509_STORE_add_crl(certstore, crl)) {
+            error("EAP-TLS: Cannot add CRL to certificate store");
+            goto fail;
+        }
+        X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
+
+    }
+
+    /*
+     * If a peer certificate file was specified, it must be valid, else fail 
+     */
+    if (peer_certfile[0]) {
+        if (!(tmp = get_X509_from_file(peer_certfile))) {
+            error("EAP-TLS: Error loading client certificate from file %s",
+                 peer_certfile);
+            goto fail;
+        }
+        X509_free(tmp);
+    }
+
+    return ctx;
+
+fail:
+    log_ssl_errors();
+    SSL_CTX_free(ctx);
+    return NULL;
+}
+
+/*
+ * Determine the maximum packet size by looking at the LCP handshake
+ */
+
+int eaptls_get_mtu(int unit)
+{
+    int mtu, mru;
+
+    lcp_options *wo = &lcp_wantoptions[unit];
+    lcp_options *go = &lcp_gotoptions[unit];
+    lcp_options *ho = &lcp_hisoptions[unit];
+    lcp_options *ao = &lcp_allowoptions[unit];
+
+    mtu = ho->neg_mru? ho->mru: PPP_MRU;
+    mru = go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU;
+    mtu = MIN(MIN(mtu, mru), ao->mru)- PPP_HDRLEN - 10;
+
+    dbglog("MTU = %d", mtu);
+    return mtu;
+}
+
+
+/*
+ * Init the ssl handshake (server mode)
+ */
+int eaptls_init_ssl_server(eap_state * esp)
+{
+    struct eaptls_session *ets;
+    char servcertfile[MAXWORDLEN];
+    char clicertfile[MAXWORDLEN];
+    char cacertfile[MAXWORDLEN];
+    char capath[MAXWORDLEN];
+    char pkfile[MAXWORDLEN];
+    /*
+     * Allocate new eaptls session 
+     */
+    esp->es_server.ea_session = malloc(sizeof(struct eaptls_session));
+    if (!esp->es_server.ea_session)
+        fatal("Allocation error");
+    ets = esp->es_server.ea_session;
+
+    if (!esp->es_server.ea_peer) {
+        error("EAP-TLS: Error: client name not set (BUG)");
+        return 0;
+    }
+
+    strlcpy(ets->peer, esp->es_server.ea_peer, MAXWORDLEN-1);
+
+    dbglog( "getting eaptls secret" );
+    if (!get_eaptls_secret(esp->es_unit, esp->es_server.ea_peer,
+                   esp->es_server.ea_name, clicertfile,
+                   servcertfile, cacertfile, capath, pkfile, 1)) {
+        error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
+                esp->es_server.ea_peer, esp->es_server.ea_name );
+        return 0;
+    }
+
+    ets->mtu = eaptls_get_mtu(esp->es_unit);
+
+    ets->ctx = eaptls_init_ssl(1, cacertfile, capath, servcertfile, clicertfile, pkfile);
+    if (!ets->ctx)
+        goto fail;
+
+    if (!(ets->ssl = SSL_new(ets->ctx)))
+        goto fail;
+
+    /*
+     * Set auto-retry to avoid timeouts on BIO_read
+     */
+    SSL_set_mode(ets->ssl, SSL_MODE_AUTO_RETRY);
+
+    /*
+     * Initialize the BIOs we use to read/write to ssl engine 
+     */
+    ets->into_ssl = BIO_new(BIO_s_mem());
+    ets->from_ssl = BIO_new(BIO_s_mem());
+    SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl);
+
+    SSL_set_msg_callback(ets->ssl, ssl_msg_callback);
+    SSL_set_msg_callback_arg(ets->ssl, ets);
+
+    /*
+     * Attach the session struct to the connection, so we can later
+     * retrieve it when doing certificate verification
+     */
+    SSL_set_ex_data(ets->ssl, 0, ets);
+
+    SSL_set_accept_state(ets->ssl);
+
+    ets->tls_v13 = 0;
+
+    ets->data = NULL;
+    ets->datalen = 0;
+    ets->alert_sent = 0;
+    ets->alert_recv = 0;
+
+    /*
+     * If we specified the client certificate file, store it in ets->peercertfile,
+     * so we can check it later in ssl_verify_callback()
+     */
+    if (clicertfile[0])
+        strlcpy(&ets->peercertfile[0], clicertfile, MAXWORDLEN);
+    else
+        ets->peercertfile[0] = 0;
+
+    return 1;
+
+fail:
+    SSL_CTX_free(ets->ctx);
+    return 0;
+}
+
+/*
+ * Init the ssl handshake (client mode)
+ */
+int eaptls_init_ssl_client(eap_state * esp)
+{
+    struct eaptls_session *ets;
+    char servcertfile[MAXWORDLEN];
+    char clicertfile[MAXWORDLEN];
+    char cacertfile[MAXWORDLEN];
+    char capath[MAXWORDLEN];
+    char pkfile[MAXWORDLEN];
+
+    /*
+     * Allocate new eaptls session 
+     */
+    esp->es_client.ea_session = malloc(sizeof(struct eaptls_session));
+    if (!esp->es_client.ea_session)
+        fatal("Allocation error");
+    ets = esp->es_client.ea_session;
+
+    /*
+     * If available, copy server name in ets; it will be used in cert
+     * verify 
+     */
+    if (esp->es_client.ea_peer)
+        strlcpy(ets->peer, esp->es_client.ea_peer, MAXWORDLEN-1);
+    else
+        ets->peer[0] = 0;
+    
+    ets->mtu = eaptls_get_mtu(esp->es_unit);
+
+    dbglog( "calling get_eaptls_secret" );
+    if (!get_eaptls_secret(esp->es_unit, esp->es_client.ea_name,
+                   ets->peer, clicertfile,
+                   servcertfile, cacertfile, capath, pkfile, 0)) {
+        error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
+                esp->es_client.ea_name, ets->peer );
+        return 0;
+    }
+
+    dbglog( "calling eaptls_init_ssl" );
+    ets->ctx = eaptls_init_ssl(0, cacertfile, capath, clicertfile, servcertfile, pkfile);
+    if (!ets->ctx)
+        goto fail;
+
+    ets->ssl = SSL_new(ets->ctx);
+
+    if (!ets->ssl)
+        goto fail;
+
+    /*
+     * Initialize the BIOs we use to read/write to ssl engine 
+     */
+    dbglog( "Initializing SSL BIOs" );
+    ets->into_ssl = BIO_new(BIO_s_mem());
+    ets->from_ssl = BIO_new(BIO_s_mem());
+    SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl);
+
+    SSL_set_msg_callback(ets->ssl, ssl_msg_callback);
+    SSL_set_msg_callback_arg(ets->ssl, ets);
+
+    /*
+     * Attach the session struct to the connection, so we can later
+     * retrieve it when doing certificate verification
+     */
+    SSL_set_ex_data(ets->ssl, 0, ets);
+
+    SSL_set_connect_state(ets->ssl);
+
+    ets->tls_v13 = 0;
+
+    ets->data = NULL;
+    ets->datalen = 0;
+    ets->alert_sent = 0;
+    ets->alert_recv = 0;
+
+    /*
+     * If we specified the server certificate file, store it in
+     * ets->peercertfile, so we can check it later in
+     * ssl_verify_callback() 
+     */
+    if (servcertfile[0])
+        strlcpy(ets->peercertfile, servcertfile, MAXWORDLEN);
+    else
+        ets->peercertfile[0] = 0;
+
+    return 1;
+
+fail:
+    dbglog( "eaptls_init_ssl_client: fail" );
+    SSL_CTX_free(ets->ctx);
+    return 0;
+
+}
+
+void eaptls_free_session(struct eaptls_session *ets)
+{
+    if (ets->ssl)
+        SSL_free(ets->ssl);
+
+    if (ets->ctx)
+        SSL_CTX_free(ets->ctx);
+
+    free(ets);
+}
+
+
+int eaptls_is_init_finished(struct eaptls_session *ets)
+{
+    if (ets->ssl && SSL_is_init_finished(ets->ssl))
+    {
+        if (ets->tls_v13) 
+            return have_session_ticket;
+        else
+            return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * Handle a received packet, reassembling fragmented messages and
+ * passing them to the ssl engine
+ */
+int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len)
+{
+    u_char flags;
+    u_int tlslen = 0;
+    u_char dummy[65536];
+
+    if (len < 1) {
+        warn("EAP-TLS: received no or invalid data");
+        return 1;
+    }
+        
+    GETCHAR(flags, inp);
+    len--;
+
+    if (flags & EAP_TLS_FLAGS_LI && len > 4) {
+        /*
+         * LenghtIncluded flag set -> this is the first packet of a message
+        */
+
+        /*
+         * the first 4 octets are the length of the EAP-TLS message
+         */
+        GETLONG(tlslen, inp);
+        len -= 4;
+
+        if (!ets->data) {
+
+            if (tlslen > EAP_TLS_MAX_LEN) {
+                error("EAP-TLS: TLS message length > %d, truncated", EAP_TLS_MAX_LEN);
+                tlslen = EAP_TLS_MAX_LEN;
+            }
+
+            /*
+             * Allocate memory for the whole message
+            */
+            ets->data = malloc(tlslen);
+            if (!ets->data)
+                fatal("EAP-TLS: allocation error\n");
+
+            ets->datalen = 0;
+            ets->tlslen = tlslen;
+        }
+        else
+            warn("EAP-TLS: non-first LI packet? that's odd...");
+    }
+    else if (!ets->data) {
+        /*
+         * A non fragmented message without LI flag
+        */
+        ets->data = malloc(len);
+        if (!ets->data)
+            fatal("EAP-TLS: allocation error\n");
+        ets->datalen = 0;
+        ets->tlslen = len;
+    }
+
+    if (flags & EAP_TLS_FLAGS_MF)
+        ets->frag = 1;
+    else
+        ets->frag = 0;
+
+    if (len < 0) {
+        warn("EAP-TLS: received malformed data");
+        return 1;
+    }
+
+    if (len + ets->datalen > ets->tlslen) {
+        warn("EAP-TLS: received data > TLS message length");
+        return 1;
+    }
+
+    BCOPY(inp, ets->data + ets->datalen, len);
+    ets->datalen += len;
+
+    if (!ets->frag) {
+
+        /*
+         * If we have the whole message, pass it to ssl 
+         */
+
+        if (ets->datalen != ets->tlslen) {
+            warn("EAP-TLS: received data != TLS message length");
+            return 1;
+        }
+
+        if (BIO_write(ets->into_ssl, ets->data, ets->datalen) == -1)
+            log_ssl_errors();
+
+        SSL_read(ets->ssl, dummy, 65536);
+
+        free(ets->data);
+        ets->data = NULL;
+        ets->datalen = 0;
+    }
+
+    return 0;
+}
+
+/*
+ * Return an eap-tls packet in outp.
+ * A TLS message read from the ssl engine is buffered in ets->data.
+ * At each call we control if there is buffered data and send a 
+ * packet of mtu bytes.
+ */
+int eaptls_send(struct eaptls_session *ets, u_char ** outp)
+{
+    bool first = 0;
+    int size;
+    u_char fromtls[65536];
+    int res;
+    u_char *start;
+
+    start = *outp;
+
+    if (!ets->data)
+    {
+        if(!ets->alert_sent)
+        {
+            res = SSL_read(ets->ssl, fromtls, 65536);
+        }
+
+        /*
+         * Read from ssl 
+         */
+        if ((res = BIO_read(ets->from_ssl, fromtls, 65536)) == -1)
+        {
+            warn("EAP-TLS send: No data from BIO_read");
+            return 1;
+        }
+
+        ets->datalen = res;
+
+        ets->data = malloc(ets->datalen);
+        BCOPY(fromtls, ets->data, ets->datalen);
+
+        ets->offset = 0;
+        first = 1;
+
+    }
+
+    size = ets->datalen - ets->offset;
+    
+    if (size > ets->mtu) {
+        size = ets->mtu;
+        ets->frag = 1;
+    } else
+        ets->frag = 0;
+
+    PUTCHAR(EAPT_TLS, *outp);
+
+    /*
+     * Set right flags and length if necessary 
+     */
+    if (ets->frag && first) {
+        PUTCHAR(EAP_TLS_FLAGS_LI | EAP_TLS_FLAGS_MF, *outp);
+        PUTLONG(ets->datalen, *outp);
+    } else if (ets->frag) {
+        PUTCHAR(EAP_TLS_FLAGS_MF, *outp);
+    } else
+        PUTCHAR(0, *outp);
+
+    /*
+     * Copy the data in outp 
+     */
+    BCOPY(ets->data + ets->offset, *outp, size);
+    INCPTR(size, *outp);
+
+    /*
+     * Copy the packet in retransmission buffer 
+     */
+    BCOPY(start, &ets->rtx[0], *outp - start);
+    ets->rtx_len = *outp - start;
+
+    ets->offset += size;
+
+    if (ets->offset >= ets->datalen) {
+
+        /*
+         * The whole message has been sent 
+         */
+
+        free(ets->data);
+        ets->data = NULL;
+        ets->datalen = 0;
+        ets->offset = 0;
+    }
+
+    return 0;
+}
+
+/*
+ * Get the sent packet from the retransmission buffer
+ */
+void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp)
+{
+    BCOPY(ets->rtx, *outp, ets->rtx_len);
+    INCPTR(ets->rtx_len, *outp);
+}
+
+/*
+ * Verify a certificate.
+ * Most of the work (signatures and issuer attributes checking)
+ * is done by ssl; we check the CN in the peer certificate 
+ * against the peer name.
+ */
+int ssl_verify_callback(int ok, X509_STORE_CTX * ctx)
+{
+    char subject[256];
+    char cn_str[256];
+    X509 *peer_cert;
+    int err, depth;
+    SSL *ssl;
+    struct eaptls_session *ets;
+
+    peer_cert = X509_STORE_CTX_get_current_cert(ctx);
+    err = X509_STORE_CTX_get_error(ctx);
+    depth = X509_STORE_CTX_get_error_depth(ctx);
+
+    dbglog("certificate verify depth: %d", depth);
+
+    if (auth_required && !ok) {
+        X509_NAME_oneline(X509_get_subject_name(peer_cert),
+                  subject, 256);
+
+        X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
+                      NID_commonName, cn_str, 256);
+
+        dbglog("Certificate verification error:\n depth: %d CN: %s"
+               "\n err: %d (%s)\n", depth, cn_str, err,
+               X509_verify_cert_error_string(err));
+
+        return 0;
+    }
+
+    ssl = X509_STORE_CTX_get_ex_data(ctx,
+                       SSL_get_ex_data_X509_STORE_CTX_idx());
+
+    ets = (struct eaptls_session *)SSL_get_ex_data(ssl, 0);
+
+    if (ets == NULL) {
+        error("Error: SSL_get_ex_data returned NULL");
+        return 0;
+    }
+
+    log_ssl_errors();
+
+    if (!depth) 
+    {
+        /* This is the peer certificate */
+
+        X509_NAME_oneline(X509_get_subject_name(peer_cert),
+                  subject, 256);
+
+        X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
+                      NID_commonName, cn_str, 256);
+
+        /*
+         * If acting as client and the name of the server wasn't specified
+         * explicitely, we can't verify the server authenticity 
+         */
+        if (!ets->peer[0]) {
+            warn("Peer name not specified: no check");
+            return ok;
+        }
+
+        /*
+         * Check the CN 
+         */
+        if (strcmp(cn_str, ets->peer)) {
+            error
+                ("Certificate verification error: CN (%s) != peer_name (%s)",
+                 cn_str, ets->peer);
+            return 0;
+        }
+
+        warn("Certificate CN: %s , peer name %s", cn_str, ets->peer);
+
+        /*
+         * If a peer certificate file was specified, here we check it 
+         */
+        if (ets->peercertfile[0]) {
+            if (ssl_cmp_certs(&ets->peercertfile[0], peer_cert)
+                != 0) {
+                error
+                    ("Peer certificate doesn't match stored certificate");
+                return 0;
+            }
+        }
+    }
+
+    return ok;
+}
+
+/*
+ * Compare a certificate with the one stored in a file
+ */
+int ssl_cmp_certs(char *filename, X509 * a)
+{
+    X509 *b;
+    int ret;
+
+    if (!(b = get_X509_from_file(filename)))
+        return 1;
+
+    ret = X509_cmp(a, b);
+    X509_free(b);
+
+    return ret;
+
+}
+
+X509 *get_X509_from_file(char *filename)
+{
+    FILE *fp;
+    X509 *ret;
+
+    if (!(fp = fopen(filename, "r")))
+        return NULL;
+
+    ret = PEM_read_X509(fp, NULL, NULL, NULL);
+
+    fclose(fp);
+
+    return ret;
+}
+
+/*
+ * Every sent & received message this callback function is invoked,
+ * so we know when alert messages have arrived or are sent and
+ * we can print debug information about TLS handshake.
+ */
+void
+ssl_msg_callback(int write_p, int version, int content_type,
+         const void *buf, size_t len, SSL * ssl, void *arg)
+{
+    char string[256];
+    struct eaptls_session *ets = (struct eaptls_session *)arg;
+    unsigned char code;
+    const unsigned char*msg = buf;
+    int hvers = msg[1] << 8 | msg[2];
+
+    if(write_p)
+        strcpy(string, " -> ");
+    else
+        strcpy(string, " <- ");
+
+    switch(content_type) {
+
+    case SSL3_RT_HEADER:
+        strcat(string, "SSL/TLS Header: ");
+        switch(hvers) {
+        case SSL3_VERSION:
+                strcat(string, "SSL 3.0");
+                break;
+        case TLS1_VERSION:
+                strcat(string, "TLS 1.0");
+                break;
+        case TLS1_1_VERSION:
+                strcat(string, "TLS 1.1");
+                break;
+        case TLS1_2_VERSION:
+                strcat(string, "TLS 1.2");
+                break;
+        default:
+            sprintf(string, "SSL/TLS Header: Unknown version (%d)", hvers);
+        }
+        break;
+
+    case SSL3_RT_ALERT:
+        strcat(string, "Alert: ");
+        code = msg[1];
+
+        if (write_p) {
+            ets->alert_sent = 1;
+            ets->alert_sent_desc = code;
+        } else {
+            ets->alert_recv = 1;
+            ets->alert_recv_desc = code;
+        }
+
+        strcat(string, SSL_alert_desc_string_long(code));
+        break;
+
+    case SSL3_RT_CHANGE_CIPHER_SPEC:
+        strcat(string, "ChangeCipherSpec");
+        break;
+
+#ifdef SSL3_RT_INNER_CONTENT_TYPE
+    case SSL3_RT_INNER_CONTENT_TYPE:
+        strcat(string, "InnerContentType (TLS1.3)");
+        break;
+#endif
+
+    case SSL3_RT_HANDSHAKE:
+
+        strcat(string, "Handshake: ");
+        code = msg[0];
+
+        switch(code) {
+            case SSL3_MT_HELLO_REQUEST:
+                strcat(string,"Hello Request");
+                break;
+            case SSL3_MT_CLIENT_HELLO:
+                strcat(string,"Client Hello");
+                break;
+            case SSL3_MT_SERVER_HELLO:
+                strcat(string,"Server Hello");
+                break;
+#ifdef SSL3_MT_NEWSESSION_TICKET
+            case SSL3_MT_NEWSESSION_TICKET:
+                strcat(string,"New Session Ticket");
+                break;
+#endif
+#ifdef SSL3_MT_END_OF_EARLY_DATA
+            case SSL3_MT_END_OF_EARLY_DATA:
+                strcat(string,"End of Early Data");
+                break;
+#endif
+#ifdef SSL3_MT_ENCRYPTED_EXTENSIONS
+            case SSL3_MT_ENCRYPTED_EXTENSIONS:
+                strcat(string,"Encryped Extensions");
+                break;
+#endif
+            case SSL3_MT_CERTIFICATE:
+                strcat(string,"Certificate");
+                break;
+            case SSL3_MT_SERVER_KEY_EXCHANGE:
+                strcat(string,"Server Key Exchange");
+                break;
+            case SSL3_MT_CERTIFICATE_REQUEST:
+                strcat(string,"Certificate Request");
+                break;
+            case SSL3_MT_SERVER_DONE:
+                strcat(string,"Server Hello Done");
+                break;
+            case SSL3_MT_CERTIFICATE_VERIFY:
+                strcat(string,"Certificate Verify");
+                break;
+            case SSL3_MT_CLIENT_KEY_EXCHANGE:
+                strcat(string,"Client Key Exchange");
+                break;
+            case SSL3_MT_FINISHED:
+                strcat(string,"Finished: ");
+                hvers = SSL_version(ssl);
+                switch(hvers){
+                    case SSL3_VERSION:
+                        strcat(string, "SSL 3.0");
+                        break;
+                    case TLS1_VERSION:
+                        strcat(string, "TLS 1.0");
+                        break;
+                    case TLS1_1_VERSION:
+                        strcat(string, "TLS 1.1");
+                        break;
+                    case TLS1_2_VERSION:
+                        strcat(string, "TLS 1.2");
+                        break;
+#ifdef TLS1_3_VERSION
+                    case TLS1_3_VERSION:
+                        strcat(string, "TLS 1.3 (experimental)");
+                        ets->tls_v13 = 1;
+                        break;
+#endif
+                    default:
+                        strcat(string, "Unknown version");
+                }
+                break;
+            default:
+                sprintf( string, "Handshake: Unknown SSL3 code received: %d", code );
+        }
+        break;
+
+    default:
+        sprintf( string, "SSL message contains unknown content type: %d", content_type );
+    }
+
+    /* Alert messages must always be displayed */
+    if(content_type == SSL3_RT_ALERT)
+        error("%s", string);
+    else
+        dbglog("%s", string);
+}
+
+int 
+ssl_new_session_cb(SSL *s, SSL_SESSION *sess)
+{
+    dbglog("EAP-TLS: Post-Handshake New Session Ticket arrived:");
+    have_session_ticket = 1;
+
+    /* always return success */
+    return 1;
+}
+
diff --git a/pppd/eap-tls.c.rej b/pppd/eap-tls.c.rej
new file mode 100644 (file)
index 0000000..fc09719
--- /dev/null
@@ -0,0 +1,35 @@
+--- pppd/eap-tls.c
++++ pppd/eap-tls.c
+@@ -328,11 +328,12 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
+       SSL_library_init();
+       SSL_load_error_strings();
+-      /* load the openssl config file only once */
+-        if (!ssl_config)
+-        {
+-                ssl_config = eaptls_ssl_load_config();
+-      }
++
++      /* load the openssl config file only once and load it before triggering
++         the loading of a global openssl config file via SSL_CTX_new()
++       */
++      if (!ssl_config)
++              ssl_config = eaptls_ssl_load_config();
+       ctx = SSL_CTX_new(TLS_method());
+@@ -403,13 +404,12 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
+                               pkey_identifier = cert_identifier;
+                       }
+               }
+-
+       }
+       if (ssl_config && cert_engine_name)
+               cert_engine = eaptls_ssl_load_engine( cert_engine_name );
+-      if (pkey_engine_name)
++      if (ssl_config && pkey_engine_name)
+       {
+               /* don't load the same engine twice */
+               if ( cert_engine && strcmp( cert_engine_name, pkey_engine_name) == 0 )
diff --git a/pppd/eap-tls.h b/pppd/eap-tls.h
new file mode 100644 (file)
index 0000000..cdbc9e4
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * eap-tls.h
+ *
+ * Copyright (c) Beniamino Galvani 2005 All rights reserved.
+ *               Jan Just Keijser  2006-2019 All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef __EAP_TLS_H__
+#define __EAP_TLS_H__
+
+#include "eap.h"
+
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+
+#define EAP_TLS_FLAGS_LI        128    /* length included flag */
+#define EAP_TLS_FLAGS_MF        64     /* more fragments flag */
+#define EAP_TLS_FLAGS_START     32     /* start flag */
+
+#define EAP_TLS_MAX_LEN         65536  /* max eap tls packet size */
+
+struct eaptls_session
+{
+    u_char *data;               /* buffered data */
+    int datalen;                /* buffered data len */
+    int offset;                 /* from where to send */
+    int tlslen;                 /* total length of tls data */
+    bool frag;                  /* packet is fragmented */
+    bool tls_v13;               /* whether we've negotiated TLSv1.3 */
+    SSL_CTX *ctx;
+    SSL *ssl;                   /* ssl connection */
+    BIO *from_ssl;
+    BIO *into_ssl;
+    char peer[MAXWORDLEN];      /* peer name */
+    char peercertfile[MAXWORDLEN];
+    bool alert_sent;
+    u_char alert_sent_desc;
+    bool alert_recv;
+    u_char alert_recv_desc;
+    char rtx[EAP_TLS_MAX_LEN];  /* retransmission buffer */
+    int rtx_len;
+    int mtu;                    /* unit mtu */
+};
+
+
+SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
+            char *certfile, char *peer_certfile, char *privkeyfile);
+int eaptls_init_ssl_server(eap_state * esp);
+int eaptls_init_ssl_client(eap_state * esp);
+void eaptls_free_session(struct eaptls_session *ets);
+
+int eaptls_is_init_finished(struct eaptls_session *ets);
+
+int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len);
+int eaptls_send(struct eaptls_session *ets, u_char ** outp);
+void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp);
+
+int get_eaptls_secret(int unit, char *client, char *server,
+              char *clicertfile, char *servcertfile, char *cacertfile,
+              char *capath, char *pkfile, int am_server);
+
+#ifdef MPPE
+#include "mppe.h"   /* MPPE_MAX_KEY_LEN */
+extern u_char mppe_send_key[MPPE_MAX_KEY_LEN];
+extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
+extern int mppe_keys_set;
+
+void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client);
+#endif
+
+#endif
index 082e95343120954abe1de82991387373344e1ba7..aa14208ec644534d27a9d4d8a89c21124c4fb71c 100644 (file)
  * Based on draft-ietf-pppext-eap-srp-03.txt.
  */
 
  * 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 $"
 
 /*
 #define RCSID  "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $"
 
 /*
@@ -76,6 +81,9 @@
 #define        SHA_DIGESTSIZE 20
 #endif
 
 #define        SHA_DIGESTSIZE 20
 #endif
 
+#ifdef USE_EAPTLS
+#include "eap-tls.h"
+#endif /* USE_EAPTLS */
 
 eap_state eap_states[NUM_PPP];         /* EAP state; one for each unit */
 #ifdef USE_SRP
 
 eap_state eap_states[NUM_PPP];         /* EAP state; one for each unit */
 #ifdef USE_SRP
@@ -208,6 +216,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;
        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 */
 }
 
 /*
 }
 
 /*
@@ -435,8 +446,16 @@ int status;
        u_char vals[2];
        struct b64state bs;
 #endif /* USE_SRP */
        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;
 
        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;
        switch (esp->es_server.ea_state) {
        case eapBadAuth:
                return;
@@ -561,9 +580,81 @@ int status;
                        break;
                }
 #endif /* USE_SRP */
                        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;
 
                esp->es_server.ea_state = eapMD5Chall;
                break;
 
+#ifdef USE_EAPTLS
+       case eapTlsStart:
+               /* Initialize ssl session */
+               if(!eaptls_init_ssl_server(esp)) {
+                       esp->es_server.ea_state = eapBadAuth;
+                       break;
+               }
+
+               esp->es_server.ea_state = eapTlsRecv;
+               break;
+
+       case eapTlsRecv:
+               ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+               if(ets->alert_sent) {
+                       esp->es_server.ea_state = eapTlsSendAlert;
+                       break;
+               }
+
+               if (status) {
+                       esp->es_server.ea_state = eapBadAuth;
+                       break;
+               }
+               ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+               if(ets->frag)
+                       esp->es_server.ea_state = eapTlsSendAck;
+               else
+                       esp->es_server.ea_state = eapTlsSend;
+               break;
+
+       case eapTlsSend:
+               ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+               if(ets->frag)
+                       esp->es_server.ea_state = eapTlsRecvAck;
+               else
+                       if(SSL_is_init_finished(ets->ssl))
+                               esp->es_server.ea_state = eapTlsRecvClient;
+                       else
+                               /* JJK Add "TLS empty record" message here ??? */
+                               esp->es_server.ea_state = eapTlsRecv;
+               break;
+
+       case eapTlsSendAck:
+               esp->es_server.ea_state = eapTlsRecv;
+               break;
+
+       case eapTlsRecvAck:
+               if (status)
+               {
+                       esp->es_server.ea_state = eapBadAuth;
+                       break;
+               }
+
+               esp->es_server.ea_state = eapTlsSend;
+               break;
+
+       case eapTlsSendAlert:
+               esp->es_server.ea_state = eapTlsRecvAlertAck;
+               break;
+#endif /* USE_EAPTLS */
+
        case eapSRP1:
 #ifdef USE_SRP
                ts = (struct t_server *)esp->es_server.ea_session;
        case eapSRP1:
 #ifdef USE_SRP
                ts = (struct t_server *)esp->es_server.ea_session;
@@ -629,6 +720,10 @@ int status;
        }
        if (esp->es_server.ea_state == eapBadAuth)
                eap_send_failure(esp);
        }
        if (esp->es_server.ea_state == eapBadAuth)
                eap_send_failure(esp);
+
+#ifdef USE_EAPTLS
+       dbglog("EAP id=0x%2x '%s' -> '%s'", esp->es_server.ea_id, eap_state_name(esp->es_server.ea_prev_state), eap_state_name(esp->es_server.ea_state));
+#endif /* USE_EAPTLS */
 }
 
 /*
 }
 
 /*
@@ -717,6 +812,30 @@ eap_state *esp;
                INCPTR(esp->es_server.ea_namelen, outp);
                break;
 
                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);
 #ifdef USE_SRP
        case eapSRP1:
                PUTCHAR(EAPT_SRP, outp);
@@ -903,11 +1022,57 @@ static void
 eap_server_timeout(arg)
 void *arg;
 {
 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;
 
        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);
 }
        /* EAP ID number must not change on timeout. */
        eap_send_request(esp);
 }
@@ -1165,6 +1330,79 @@ u_char *str;
 }
 #endif /* USE_SRP */
 
 }
 #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;
 static void
 eap_send_nak(esp, id, type)
 eap_state *esp;
@@ -1319,6 +1557,11 @@ int len;
        char rhostname[256];
        MD5_CTX mdContext;
        u_char hash[MD5_SIGNATURE_SIZE];
        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;
 #ifdef USE_SRP
        struct t_client *tc;
        struct t_num sval, gval, Nval, *Ap, Bval;
@@ -1461,6 +1704,96 @@ int len;
                    esp->es_client.ea_namelen);
                break;
 
                    esp->es_client.ea_namelen);
                break;
 
+#ifdef USE_EAPTLS
+       case EAPT_TLS:
+
+               switch(esp->es_client.ea_state) {
+
+               case eapListen:
+
+                       if (len < 1) {
+                               error("EAP: received EAP-TLS Listen packet with no data");
+                               /* Bogus request; wait for something real. */
+                               return;
+                       }
+                       GETCHAR(flags, inp);
+                       if(flags & EAP_TLS_FLAGS_START){
+
+                               esp->es_client.ea_using_eaptls = 1;
+
+                               if (explicit_remote){
+                                       esp->es_client.ea_peer = strdup(remote_name);
+                                       esp->es_client.ea_peerlen = strlen(remote_name);
+                               } else
+                                       esp->es_client.ea_peer = NULL;
+
+                               /* Init ssl session */
+                               if(!eaptls_init_ssl_client(esp)) {
+                                       dbglog("cannot init ssl");
+                                       eap_send_nak(esp, id, EAPT_TLS);
+                                       esp->es_client.ea_using_eaptls = 0;
+                                       break;
+                               }
+
+                               ets = esp->es_client.ea_session;
+                               eap_tls_response(esp, id);
+                               esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv);
+                               break;
+                       }
+
+                       /* The server has sent a bad start packet. */
+                       eap_send_nak(esp, id, EAPT_TLS);
+                       break;
+
+               case eapTlsRecvAck:
+                       eap_tls_response(esp, id);
+                       esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv);
+                       break;
+
+               case eapTlsRecv:
+                       if (len < 1) {
+                               error("EAP: discarding EAP-TLS Receive packet with no data");
+                               /* Bogus request; wait for something real. */
+                               return;
+                       }
+                       eaptls_receive(ets, inp, len);
+
+                       if(ets->frag) {
+                               eap_tls_sendack(esp, id);
+                               esp->es_client.ea_state = eapTlsRecv;
+                               break;
+                       }
+
+                       if(ets->alert_recv) {
+                               eap_tls_sendack(esp, id);
+                               esp->es_client.ea_state = eapTlsRecvFailure;
+                               break;
+                       }
+
+                       /* Check if TLS handshake is finished */
+                       if(eaptls_is_init_finished(ets)) {
+#ifdef MPPE
+                               eaptls_gen_mppe_keys(ets, 1);
+#endif
+                               eaptls_free_session(ets);
+                               eap_tls_sendack(esp, id);
+                               esp->es_client.ea_state = eapTlsRecvSuccess;
+                               break;
+                       }
+
+                       eap_tls_response(esp,id);
+                       esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv);
+                       break;
+
+               default:
+                       eap_send_nak(esp, id, EAPT_TLS);
+                       esp->es_client.ea_using_eaptls = 0;
+                       break;
+               }
+
+               break;
+#endif /* USE_EAPTLS */
+
 #ifdef USE_SRP
        case EAPT_SRP:
                if (len < 1) {
 #ifdef USE_SRP
        case EAPT_SRP:
                if (len < 1) {
@@ -1740,8 +2073,15 @@ int len;
        struct t_num A;
        SHA1_CTX ctxt;
        u_char dig[SHA_DIGESTSIZE];
        struct t_num A;
        SHA1_CTX ctxt;
        u_char dig[SHA_DIGESTSIZE];
+       SHA1_CTX ctxt;
+       u_char dig[SHA_DIGESTSIZE];
 #endif /* USE_SRP */
 
 #endif /* USE_SRP */
 
+#ifdef USE_EAPTLS
+       struct eaptls_session *ets;
+       u_char flags;
+#endif /* USE_EAPTLS */
+
        /*
         * Ignore responses if we're not open
         */
        /*
         * Ignore responses if we're not open
         */
@@ -1787,6 +2127,64 @@ int len;
                eap_figure_next_state(esp, 0);
                break;
 
                eap_figure_next_state(esp, 0);
                break;
 
+#ifdef USE_EAPTLS
+       case EAPT_TLS:
+               switch(esp->es_server.ea_state) {
+
+               case eapTlsRecv:
+
+                       ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+                       eap_figure_next_state(esp,
+                               eaptls_receive(esp->es_server.ea_session, inp, len));
+
+                       if(ets->alert_recv) {
+                               eap_send_failure(esp);
+                               break;
+                       }
+                       break;
+
+               case eapTlsRecvAck:
+                       if(len > 1) {
+                               dbglog("EAP-TLS ACK with extra data");
+                       }
+                       eap_figure_next_state(esp, 0);
+                       break;
+
+               case eapTlsRecvClient:
+                       /* Receive authentication response from client */
+                       if (len > 0) {
+                               GETCHAR(flags, inp);
+
+                               if(len == 1 && !flags) {        /* Ack = ok */
+#ifdef MPPE
+                                       eaptls_gen_mppe_keys( esp->es_server.ea_session, 0 );
+#endif
+                                       eap_send_success(esp);
+                               }
+                               else {                  /* failure */
+                                       warn("Server authentication failed");
+                                       eap_send_failure(esp);
+                               }
+                       }
+                       else
+                               warn("Bogus EAP-TLS packet received from client");
+
+                       eaptls_free_session(esp->es_server.ea_session);
+
+                       break;
+
+               case eapTlsRecvAlertAck:
+                       eap_send_failure(esp);
+                       break;
+
+               default:
+                       eap_figure_next_state(esp, 1);
+                       break;
+               }
+               break;
+#endif /* USE_EAPTLS */
+
        case EAPT_NOTIFICATION:
                dbglog("EAP unexpected Notification; response discarded");
                break;
        case EAPT_NOTIFICATION:
                dbglog("EAP unexpected Notification; response discarded");
                break;
@@ -1818,6 +2216,13 @@ int len;
                        esp->es_server.ea_state = eapMD5Chall;
                        break;
 
                        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) {
                default:
                        dbglog("EAP: peer requesting unknown Type %d", vallen);
                        switch (esp->es_server.ea_state) {
@@ -2029,13 +2434,27 @@ u_char *inp;
 int id;
 int len;
 {
 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;
        }
 
                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);
        }
        if (esp->es_client.ea_timeout > 0) {
                UNTIMEOUT(eap_client_timeout, (void *)esp);
        }
@@ -2167,6 +2586,9 @@ void *arg;
        int code, id, len, rtype, vallen;
        u_char *pstart;
        u_int32_t uval;
        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);
 
        if (inlen < EAP_HEADERLEN)
                return (0);
@@ -2231,6 +2653,24 @@ void *arg;
                        }
                        break;
 
                        }
                        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;
                case EAPT_SRP:
                        if (len < 3)
                                goto truncated;
@@ -2342,6 +2782,25 @@ void *arg;
                        }
                        break;
 
                        }
                        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>");
                case EAPT_NAK:
                        if (len <= 0) {
                                printer(arg, " <missing hint>");
index 199d1849b8261093ebd0f54a1b100081f27d2f3f..087baad83eed8ca2dd4a2405626165d7e3ca66f7 100644 (file)
@@ -84,6 +84,16 @@ enum eap_state_code {
        eapClosed,      /* Authentication not in use */
        eapListen,      /* Client ready (and timer running) */
        eapIdentify,    /* EAP Identify sent */
        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 */
        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", \
 
 #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"
 
        "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)
 #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;
        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 */
        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 */
  * 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 */
 #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 */
 
 #define        EAP_DEFREQTIME          20      /* Time to wait for peer request */
 #define        EAP_DEFALLOWREQ         20      /* max # times to accept requests */
 
index a33f0466c9d6d7e86e17316e0672477fd31228aa..5c8cfe8aae92d62a9f6c1a5a9108645cc8c67440 100644 (file)
 #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"
 #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"
 #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"
index af5384381cb07c27fa4043824f80b6ab69807fa9..5a7bd7966215e97f89b774d95645fb37477a7240 100644 (file)
@@ -4,6 +4,9 @@ CFLAGS  = $(COPTS) -I.. -I../../include -fPIC
 LDFLAGS_SHARED = -shared
 INSTALL        = install
 
 LDFLAGS_SHARED = -shared
 INSTALL        = install
 
+# EAP-TLS
+CFLAGS += -DUSE_EAPTLS=1
+
 DESTDIR = $(INSTROOT)@DESTDIR@
 BINDIR = $(DESTDIR)/sbin
 MANDIR = $(DESTDIR)/share/man/man8
 DESTDIR = $(INSTROOT)@DESTDIR@
 BINDIR = $(DESTDIR)/sbin
 MANDIR = $(DESTDIR)/share/man/man8
index 2091f1361f0c863b5a26c09c77e3f18bdda9b803..ab9f390c2d1c968c8054b60e1e5da7cc81eb5e00 100644 (file)
@@ -113,4 +113,7 @@ void plugin_init(void)
 {
     add_options(options);
     pap_passwd_hook = promptpass;
 {
     add_options(options);
     pap_passwd_hook = promptpass;
+#ifdef USE_EAPTLS
+    eaptls_passwd_hook = promptpass;
+#endif
 }
 }
index d718f3bdf81d74fd82d2d221e4b260d69d484040..c3f9793e41a01b141da91d7a5370e04dec51af83 100644 (file)
@@ -79,4 +79,8 @@ void plugin_init (void)
 
     chap_check_hook = pwfd_check;
     chap_passwd_hook = pwfd_passwd;
 
     chap_check_hook = pwfd_check;
     chap_passwd_hook = pwfd_passwd;
+
+#ifdef USE_EAPTLS
+    eaptls_passwd_hook = pwfd_passwd;
+#endif
 }
 }
index 1cf0f67db62b181f584903a52eafd8b3aafa45fe..8ad98cb37ce7e7f172c4c9e8de3b1dd515e93323 100644 (file)
@@ -260,6 +260,12 @@ Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
 compression in the corresponding direction.  Use \fInobsdcomp\fR or
 \fIbsdcomp 0\fR to disable BSD-Compress compression entirely.
 .TP
 compression in the corresponding direction.  Use \fInobsdcomp\fR or
 \fIbsdcomp 0\fR to disable BSD-Compress compression entirely.
 .TP
+.B ca \fIca-file
+(EAP-TLS) Use the file \fIca-file\fR as the X.509 Certificate Authority
+(CA) file (in PEM format), needed for setting up an EAP-TLS connection.
+This option is used on the client-side in conjunction with the \fBcert\fR
+and \fBkey\fR options.
+.TP
 .B cdtrcts
 Use a non-standard hardware flow control (i.e. DTR/CTS) to control
 the flow of data on the serial port.  If neither the \fIcrtscts\fR,
 .B cdtrcts
 Use a non-standard hardware flow control (i.e. DTR/CTS) to control
 the flow of data on the serial port.  If neither the \fIcrtscts\fR,
@@ -271,6 +277,12 @@ RTS output. Such serial ports use this mode to implement true
 bi-directional flow control. The sacrifice is that this flow
 control mode does not permit using DTR as a modem control line.
 .TP
 bi-directional flow control. The sacrifice is that this flow
 control mode does not permit using DTR as a modem control line.
 .TP
+.B cert \fIcertfile
+(EAP-TLS) Use the file \fIcertfile\fR as the X.509 certificate (in PEM
+format), needed for setting up an EAP-TLS connection. This option is
+used on the client-side in conjunction with the \fBca\fR and 
+\fBkey\fR options.
+.TP
 .B chap\-interval \fIn
 If this option is given, pppd will rechallenge the peer every \fIn\fR
 seconds.
 .B chap\-interval \fIn
 If this option is given, pppd will rechallenge the peer every \fIn\fR
 seconds.
@@ -299,6 +311,18 @@ negotiation by sending its first LCP packet.  The default value is
 1000 (1 second).  This wait period only applies if the \fBconnect\fR
 or \fBpty\fR option is used.
 .TP
 1000 (1 second).  This wait period only applies if the \fBconnect\fR
 or \fBpty\fR option is used.
 .TP
+.B crl \fIfilename
+(EAP-TLS) Use the file \fIfilename\fR as the Certificate Revocation List
+to check for the validity of the peer's certificate. This option is not
+mandatory for setting up an EAP-TLS connection. Also see the \fBcrl-dir\fR
+option.
+.TP
+.B crl-dir \fIdirectory
+(EAP-TLS) Use the directory \fIdirectory\fR to scan for CRL files in
+has format ($hash.r0) to check for the validity of the peer's certificate.
+This option is not mandatory for setting up an EAP-TLS connection.
+Also see the \fBcrl\fR option.
+.TP
 .B debug
 Enables connection debugging facilities.
 If this option is given, pppd will log the contents of all
 .B debug
 Enables connection debugging facilities.
 If this option is given, pppd will log the contents of all
@@ -568,6 +592,12 @@ transmitted packets be printed.  On most systems, messages printed by
 the kernel are logged by syslog(1) to a file as directed in the
 /etc/syslog.conf configuration file.
 .TP
 the kernel are logged by syslog(1) to a file as directed in the
 /etc/syslog.conf configuration file.
 .TP
+.B key \fIkeyfile
+(EAP-TLS) Use the file \fIkeyfile\fR as the private key file (in PEM
+format), needed for setting up an EAP-TLS connection. This option is
+used on the client-side in conjunction with the \fBca\fR and 
+\fBcert\fR options.
+.TP
 .B ktune
 Enables pppd to alter kernel settings as appropriate.  Under Linux,
 pppd will enable IP forwarding (i.e. set /proc/sys/net/ipv4/ip_forward
 .B ktune
 Enables pppd to alter kernel settings as appropriate.  Under Linux,
 pppd will enable IP forwarding (i.e. set /proc/sys/net/ipv4/ip_forward
@@ -731,6 +761,9 @@ name to \fIname\fR.)
 Disable Address/Control compression in both directions (send and
 receive).
 .TP
 Disable Address/Control compression in both directions (send and
 receive).
 .TP
+.B need-peer-eap
+(EAP-TLS) Require the peer to verify our authentication credentials.
+.TP
 .B noauth
 Do not require the peer to authenticate itself.  This option is
 privileged.
 .B noauth
 Do not require the peer to authenticate itself.  This option is
 privileged.
index f44fe016c82847b6f402a635329aa082eba5d897..a35deaa8e00ac19316ea09c1fd6c1534a142c1a6 100644 (file)
@@ -342,6 +342,12 @@ 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 */
 
 extern bool    dryrun;         /* check everything, print options, exit */
 extern int     child_wait;     /* # seconds to wait for children at end */
 
+#ifdef USE_EAPTLS
+extern char    *crl_dir;
+extern char    *crl_file;
+extern char *max_tls_version;
+#endif /* USE_EAPTLS */
+
 #ifdef MAXOCTETS
 extern unsigned int maxoctets;      /* Maximum octetes per session (in bytes) */
 extern int       maxoctets_dir;      /* Direction :
 #ifdef MAXOCTETS
 extern unsigned int maxoctets;      /* Maximum octetes per session (in bytes) */
 extern int       maxoctets_dir;      /* Direction :
@@ -766,6 +772,10 @@ extern int (*chap_check_hook) __P((void));
 extern int (*chap_passwd_hook) __P((char *user, char *passwd));
 extern void (*multilink_join_hook) __P((void));
 
 extern int (*chap_passwd_hook) __P((char *user, char *passwd));
 extern void (*multilink_join_hook) __P((void));
 
+#ifdef USE_EAPTLS
+extern int (*eaptls_passwd_hook) __P((char *user, char *passwd));
+#endif
+
 /* Let a plugin snoop sent and received packets.  Useful for L2TP */
 extern void (*snoop_recv_hook) __P((unsigned char *p, int len));
 extern void (*snoop_send_hook) __P((unsigned char *p, int len));
 /* 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));
index a85c73301ed2b474ee644f170ff733714811306d..113eb7bdf74c7617e577a41c1dfac9a0e74d8b67 100644 (file)
@@ -1551,6 +1551,26 @@ netif_set_mtu(unit, mtu)
 #endif /* defined(INET6) && defined(SOL2) */
 }
 
 #endif /* defined(INET6) && defined(SOL2) */
 }
 
+
+
+/*
+ * netif_get_mtu - get the MTU on the PPP network interface.
+ */
+int
+netif_get_mtu(int unit)
+{
+    struct ifreq ifr;
+
+    memset (&ifr, '\0', sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+
+    if (ioctl(ipfd, SIOCGIFMTU, (caddr_t) &ifr) < 0) {
+    error("ioctl(SIOCGIFMTU): %m (line %d)", __LINE__);
+    return 0;
+    }
+    return ifr.ifr_mtu;
+}
+
 /*
  * tty_send_config - configure the transmit characteristics of
  * the ppp interface.
 /*
  * tty_send_config - configure the transmit characteristics of
  * the ppp interface.