diff -Naur ppp-2.4.3/etc.ppp/eaptls-client ppp-2.4.3-eaptls/etc.ppp/eaptls-client --- ppp-2.4.3/etc.ppp/eaptls-client 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.3-eaptls/etc.ppp/eaptls-client 2005-11-22 16:01:06.000000000 +0100 @@ -0,0 +1,10 @@ +# Parameters for authentication using EAP-TLS (client) + +# client name (can be *) +# server name (can be *) +# client certificate file (required) +# server certificate file (optional, if unused put '-') +# CA certificate file (required) +# client private key file (required) + +#client server /root/cert/client.crt - /root/cert/ca.crt /root/cert/client.key diff -Naur ppp-2.4.3/etc.ppp/eaptls-server ppp-2.4.3-eaptls/etc.ppp/eaptls-server --- ppp-2.4.3/etc.ppp/eaptls-server 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.3-eaptls/etc.ppp/eaptls-server 2005-11-22 16:01:06.000000000 +0100 @@ -0,0 +1,11 @@ +# Parameters for authentication using EAP-TLS (server) + +# client name (can be *) +# server name (can be *) +# client certificate file (optional, if unused put '-') +# server certificate file (required) +# CA certificate file (required) +# server private key file (required) +# allowed addresses (required, can be *) + +#client server - /root/cert/server.crt /root/cert/ca.crt /root/cert/server.key 192.168.1.0/24 diff -Naur ppp-2.4.3/linux/Makefile.top ppp-2.4.3-eaptls/linux/Makefile.top --- ppp-2.4.3/linux/Makefile.top 2004-10-31 23:25:16.000000000 +0100 +++ ppp-2.4.3-eaptls/linux/Makefile.top 2005-11-22 16:11:06.000000000 +0100 @@ -26,7 +26,7 @@ cd pppdump; $(MAKE) $(MFLAGS) install install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \ - $(ETCDIR)/chap-secrets + $(ETCDIR)/chap-secrets $(ETCDIR)/eaptls-server $(ETCDIR)/eaptls-client install-devel: cd pppd; $(MAKE) $(MFLAGS) install-devel @@ -37,6 +37,10 @@ $(INSTALL) -c -m 600 etc.ppp/pap-secrets $@ $(ETCDIR)/chap-secrets: $(INSTALL) -c -m 600 etc.ppp/chap-secrets $@ +$(ETCDIR)/eaptls-server: + $(INSTALL) -c -m 600 etc.ppp/eaptls-server $@ +$(ETCDIR)/eaptls-client: + $(INSTALL) -c -m 600 etc.ppp/eaptls-client $@ $(BINDIR): $(INSTALL) -d -m 755 $@ diff -Naur ppp-2.4.3/pppd/auth.c ppp-2.4.3-eaptls/pppd/auth.c --- ppp-2.4.3/pppd/auth.c 2004-11-12 11:30:51.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/auth.c 2005-09-01 11:40:21.000000000 +0200 @@ -112,6 +112,7 @@ #include "upap.h" #include "chap-new.h" #include "eap.h" +#include "eap-tls.h" #ifdef CBCP_SUPPORT #include "cbcp.h" #endif @@ -237,6 +238,7 @@ bool allow_any_ip = 0; /* Allow peer to use any IP address */ bool explicit_remote = 0; /* User specified explicit remote name */ char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ +bool need_peer_eap = 0; /* Require peer to authenticate us */ static char *uafname; /* name of most recent +ua file */ @@ -255,10 +257,23 @@ 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_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 ip_addr_check __P((u_int32_t, struct permitted_ip *)); static int scan_authfile __P((FILE *, char *, char *, char *, struct wordlist **, struct wordlist **, char *, int)); +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)); + static void free_wordlist __P((struct wordlist *)); static void auth_script __P((char *)); static void auth_script_done __P((void *)); @@ -397,6 +412,9 @@ "Set telephone number(s) which are allowed to connect", OPT_PRIV | OPT_A2LIST }, + { "need-peer-eap", o_bool, &need_peer_eap, + "Require the peer to authenticate us", 1 }, + { NULL } }; @@ -706,6 +724,7 @@ lcp_options *wo = &lcp_wantoptions[unit]; lcp_options *go = &lcp_gotoptions[unit]; lcp_options *ho = &lcp_hisoptions[unit]; + lcp_options *ao = &lcp_allowoptions[unit]; int i; struct protent *protp; @@ -740,6 +759,20 @@ } } + 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; + } + new_phase(PHASE_AUTHENTICATE); used_login = 0; auth = 0; @@ -1244,6 +1277,13 @@ our_name, 1, &lacks_ip); } + if (!can_auth && wo->neg_eap) { + can_auth = + have_eaptls_secret_server((explicit_remote ? remote_name : + NULL), our_name, 1, &lacks_ip); + + } + if (auth_required && !can_auth && noauth_addrs == NULL) { if (default_auth) { option_error( @@ -1298,7 +1338,8 @@ 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) || + have_eaptls_secret_client(user, (explicit_remote? remote_name: NULL))); hadchap = -1; if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) @@ -1313,8 +1354,11 @@ !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) && + !have_eaptls_secret_server((explicit_remote? remote_name: NULL), + our_name, 1, NULL)) go->neg_eap = 0; + } @@ -1893,6 +1937,100 @@ } +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_test_certs_server(servcertfile, cacertfile, + pkfile, clicertfile) == 0) + ret = -1; + + if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} + + +static int +have_eaptls_secret_client(client, server) + char *client; + char *server; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + char servcertfile[MAXWORDLEN]; + char clicertfile[MAXWORDLEN]; + char cacertfile[MAXWORDLEN]; + char pkfile[MAXWORDLEN]; + + filename = _PATH_EAPTLSCLIFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + if (client != NULL && client[0] == 0) + client = NULL; + else if (server != NULL && server[0] == 0) + server = NULL; + + ret = + scan_authfile_eaptls(f, client, server, clicertfile, servcertfile, + cacertfile, pkfile, &addrs, NULL, filename, + 0); + fclose(f); + + if (addrs != 0) + free_wordlist(addrs); + + if (ret < 0) + return 0; + + if (eaptls_test_certs_client + (clicertfile, cacertfile, pkfile, servcertfile) == 0) + return 0; + + + return 1; +} + /* * get_secret - open the CHAP secret file and return the secret * for authenticating the given client on the given server. @@ -2545,3 +2683,215 @@ auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL); } + + + +static int +scan_authfile_eaptls(f, client, server, cli_cert, serv_cert, ca_cert, pk, + addrs, opts, filename, flags) + FILE *f; + char *client; + char *server; + char *cli_cert; + char *serv_cert; + char *ca_cert; + char *pk; + struct wordlist **addrs; + struct wordlist **opts; + char *filename; + int flags; +{ + int newline; + int got_flag, best_flag; + struct wordlist *ap, *addr_list, *alist, **app; + char word[MAXWORDLEN]; + + if (addrs != NULL) + *addrs = NULL; + if (opts != NULL) + *opts = NULL; + addr_list = NULL; + if (!getword(f, word, &newline, filename)) + return -1; /* file is empty??? */ + newline = 1; + best_flag = -1; + for (;;) { + /* + * Skip until we find a word at the start of a line. + */ + while (!newline && getword(f, word, &newline, filename)); + if (!newline) + break; /* got to end of file */ + + /* + * Got a client - check if it's a match or a wildcard. + */ + got_flag = 0; + if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) { + newline = 0; + continue; + } + if (!ISWILD(word)) + got_flag = NONWILD_CLIENT; + + /* + * Now get a server and check if it matches. + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + if (!ISWILD(word)) { + if (server != NULL && strcmp(word, server) != 0) + continue; + got_flag |= NONWILD_SERVER; + } + + /* + * Got some sort of a match - see if it's better than what + * we have already. + */ + if (got_flag <= best_flag) + continue; + + /* + * Get the cli_cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + if (strcmp(word, "-") != 0) { + strlcpy(cli_cert, word, MAXWORDLEN); + } else + cli_cert[0] = 0; + + /* + * Get serv_cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + if (strcmp(word, "-") != 0) { + strlcpy(serv_cert, word, MAXWORDLEN); + } else + serv_cert[0] = 0; + + /* + * Get ca_cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + strlcpy(ca_cert, word, MAXWORDLEN); + + /* + * Get pk + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + strlcpy(pk, word, MAXWORDLEN); + + + /* + * Now read address authorization info and make a wordlist. + */ + app = &alist; + for (;;) { + if (!getword(f, word, &newline, filename) || newline) + break; + ap = (struct wordlist *) + malloc(sizeof(struct wordlist) + strlen(word) + 1); + if (ap == NULL) + novm("authorized addresses"); + ap->word = (char *) (ap + 1); + strcpy(ap->word, word); + *app = ap; + app = &ap->next; + } + *app = NULL; + /* + * This is the best so far; remember it. + */ + best_flag = got_flag; + if (addr_list) + free_wordlist(addr_list); + addr_list = alist; + + if (!newline) + break; + } + + /* scan for a -- word indicating the start of options */ + for (app = &addr_list; (ap = *app) != NULL; app = &ap->next) + if (strcmp(ap->word, "--") == 0) + break; + /* ap = start of options */ + if (ap != NULL) { + ap = ap->next; /* first option */ + free(*app); /* free the "--" word */ + *app = NULL; /* terminate addr list */ + } + if (opts != NULL) + *opts = ap; + else if (ap != NULL) + free_wordlist(ap); + if (addrs != NULL) + *addrs = addr_list; + else if (addr_list != NULL) + free_wordlist(addr_list); + + return best_flag; +} + + +int +get_eaptls_secret(unit, client, server, clicertfile, servcertfile, + cacertfile, pkfile, am_server) + int unit; + char *client; + char *server; + char *clicertfile; + char *servcertfile; + char *cacertfile; + char *pkfile; + int am_server; +{ + FILE *fp; + int ret; + char *filename; + struct wordlist *addrs, *opts; + + filename = (am_server ? _PATH_EAPTLSSERVFILE : _PATH_EAPTLSCLIFILE); + addrs = NULL; + + fp = fopen(filename, "r"); + if (fp == NULL) { + error("Can't open eap-tls secret file %s: %m", filename); + return 0; + } + + check_access(fp, filename); + + ret = scan_authfile_eaptls(fp, client, server, clicertfile, servcertfile, + cacertfile, pkfile, &addrs, &opts, filename, + 0); + + fclose(fp); + + if (ret < 0) + return 0; + + if (am_server) + set_allowed_addrs(unit, addrs, opts); + else if (opts != NULL) + free_wordlist(opts); + if (addrs != NULL) + free_wordlist(addrs); + + return 1; +} diff -Naur ppp-2.4.3/pppd/eap.c ppp-2.4.3-eaptls/pppd/eap.c --- ppp-2.4.3/pppd/eap.c 2004-11-09 23:39:25.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/eap.c 2005-11-22 16:06:06.000000000 +0100 @@ -43,6 +43,12 @@ * Based on draft-ietf-pppext-eap-srp-03.txt. */ +/* + * Modification by Beniamino Galvani, Mar 2005 + * Implemented EAP-TLS authentication + */ + + #define RCSID "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $" /* @@ -62,8 +68,9 @@ #include "pppd.h" #include "pathnames.h" -#include "md5.h" +//#include "md5.h" #include "eap.h" +#include "eap-tls.h" #ifdef USE_SRP #include @@ -83,6 +90,10 @@ static char *pn_secret = NULL; /* Pseudonym generating secret */ #endif +char *crl_dir = NULL; +bool auto_update_crl = 0; +int crl_update_time = CRL_UPDATE_TIME; + /* * Command-line options. */ @@ -105,6 +116,13 @@ { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo, "Use pseudonym if offered one by server", 1 }, #endif + { "crl-dir", o_string, &crl_dir, + "Use CRLs in directory" }, + { "auto-update-crl", o_bool, &auto_update_crl, + "Automatically download CA CRL if old or non existent", 1 }, + { "crl-update-time", o_int, &crl_update_time, + "Time (in hours) after which reload CA CRL" }, + { NULL } }; @@ -436,6 +454,9 @@ u_char vals[2]; struct b64state bs; #endif /* USE_SRP */ + struct eaptls_session *ets; + int secret_len; + char secret[MAXWORDLEN]; esp->es_server.ea_timeout = esp->es_savedtime; switch (esp->es_server.ea_state) { @@ -562,6 +583,19 @@ break; } #endif /* USE_SRP */ + + if (!get_secret(esp->es_unit, esp->es_server.ea_peer, + esp->es_server.ea_name, secret, &secret_len, 1)) { + + if(eaptls_init_server(esp)) { + esp->es_server.ea_state = eapTlsStart; + break; + } + + error("EAP: cannot find suitable secrets"); + esp->es_server.ea_state = eapBadAuth; + } + esp->es_server.ea_state = eapMD5Chall; break; @@ -624,6 +658,126 @@ } break; + case eapTlsStart: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if (status != 0) { + esp->es_server.ea_state = eapBadAuth; + } else { + if(ets->rx_flags & EAP_TLS_FLAGS_MF) + esp->es_server.ea_state = eapTlsSendAck; + else + esp->es_server.ea_state = eapTlsSendMsg; + } + + break; + + case eapTlsSendMsg: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + + if(SSL_is_init_finished(ets->ssl)){ + ets->status |= EAP_TLS_STATUS_FINISHED; + } + + + if (status != 0) { + esp->es_server.ea_state = eapBadAuth; + break; + } + + if(!(ets->rx_flags & EAP_TLS_FLAGS_MF) && + (ets->status & EAP_TLS_STATUS_ALERT_IN)) { + eap_send_failure(esp); + break; + } + + if(!(ets->rx_flags & EAP_TLS_FLAGS_MF)&& + !(ets->tx_flags & EAP_TLS_FLAGS_MF)&& + (ets->status & EAP_TLS_STATUS_ALERT_OUT)) { + esp->es_server.ea_state = eapTlsSendAlert; + break; + } + + + if(ets->rx_flags & EAP_TLS_FLAGS_ACK && + ets->tx_flags & EAP_TLS_FLAGS_MF) + break; // don't change state + + if(!(ets->rx_flags & EAP_TLS_FLAGS_MF) && + !(ets->tx_flags & EAP_TLS_FLAGS_MF) && + !(ets->rx_flags & EAP_TLS_FLAGS_ACK)) + break; // don't change state + + if(ets->rx_flags & EAP_TLS_FLAGS_MF && + !(ets->tx_flags & EAP_TLS_FLAGS_MF)) { + esp->es_server.ea_state = eapTlsSendAck; + break; + } + + if((ets->rx_flags & EAP_TLS_FLAGS_ACK) && + !(ets->tx_flags & EAP_TLS_FLAGS_MF) && + (ets->status & EAP_TLS_STATUS_FINISHED)) { + eap_send_success(esp); + esp->es_server.ea_state = eapOpen; + break; + } + + if(!(ets->rx_flags & EAP_TLS_FLAGS_ACK) && + !(ets->tx_flags & EAP_TLS_FLAGS_MF) && + ets->status & EAP_TLS_STATUS_FINISHED) { + eap_send_failure(esp); + break; + } + + warn("EAP-TLS state not changed, default to badAuth"); + esp->es_server.ea_state = eapBadAuth; + break; + + case eapTlsSendAck: + ets = (struct eaptls_session *) esp->es_server.ea_session; + if (status != 0) { + esp->es_server.ea_state = eapBadAuth; + break; + } + + if(ets->rx_flags & EAP_TLS_FLAGS_MF) + break; + + if(!(ets->rx_flags & EAP_TLS_FLAGS_MF) && + !(ets->status & EAP_TLS_STATUS_ALERT_OUT)) { + esp->es_server.ea_state = eapTlsSendMsg; + break; + } + + if(!(ets->rx_flags & EAP_TLS_FLAGS_MF) && + (ets->status & EAP_TLS_STATUS_ALERT_OUT)) { + esp->es_server.ea_state = eapTlsSendAlert; + break; + } + + warn("EAP-TLS state not changed, default to badAuth"); + esp->es_server.ea_state = eapBadAuth; + + break; + + case eapTlsSendAlert: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if (status != 0) { + esp->es_server.ea_state = eapBadAuth; + break; + } + + if(ets->rx_flags & EAP_TLS_FLAGS_ACK){ + eap_send_failure(esp); + break; + } + + warn("EAP-TLS state not changed, default to badAuth"); + esp->es_server.ea_state = eapBadAuth; + + break; default: esp->es_server.ea_state = eapBadAuth; break; @@ -653,6 +807,7 @@ struct b64state b64; SHA1_CTX ctxt; #endif /* USE_SRP */ + struct eaptls_session *ets; /* Handle both initial auth and restart */ if (esp->es_server.ea_state < eapIdentify && @@ -718,6 +873,31 @@ INCPTR(esp->es_server.ea_namelen, outp); break; + + case eapTlsStart: + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(EAP_TLS_FLAGS_START, outp); + break; + + case eapTlsSendMsg: + case eapTlsSendAlert: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + /* handle retransmission */ + if(esp->es_server.ea_id == ets->prev_id) + eaptls_read(ets, &outp, 1); + else + eaptls_read(ets, &outp, 0); + + ets->prev_id = esp->es_server.ea_id; + + break; + + case eapTlsSendAck: + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(0, outp); + break; + #ifdef USE_SRP case eapSRP1: PUTCHAR(EAPT_SRP, outp); @@ -1303,6 +1483,95 @@ } #endif /* USE_SRP */ + + +/* + * Send an EAP-TLS ack + */ +static void +eap_tls_send_ack(esp, id) +eap_state *esp; +u_char id; +{ + u_char *outp; + int outlen; + u_char *lenloc; + struct eaptls_session *ets = esp->es_client.ea_session; + + 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); + + BCOPY(outpacket_buf, &ets->rtx[0], outlen); + ets->rtx_len = outlen; + +} + +/* + * 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; + struct eaptls_session *ets = esp->es_client.ea_session; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + + lenloc = outp; + INCPTR(2, outp); + + eaptls_read(esp->es_client.ea_session, &outp, 0); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); + + esp->es_client.ea_id = id; + + BCOPY(outpacket_buf, &ets->rtx[0], PPP_HDRLEN + outlen); + ets->rtx_len = outlen; + +} + + +static void +eap_tls_rtx(esp) +eap_state *esp; +{ + struct eaptls_session *ets = esp->es_client.ea_session; + + BCOPY(ets->rtx, outpacket_buf, ets->rtx_len); + output(esp->es_unit, outpacket_buf, ets->rtx_len); + +} + + /* * eap_request - Receive EAP Request message (client mode). */ @@ -1328,6 +1597,8 @@ u_char dig[SHA_DIGESTSIZE]; int fd; #endif /* USE_SRP */ + u_char flags; + struct eaptls_session *ets = esp->es_client.ea_session; /* * Note: we update es_client.ea_id *only if* a Response @@ -1456,6 +1727,128 @@ esp->es_client.ea_namelen); break; + case EAPT_TLS: + + /* + If the id in the request is unchanged, we must retransmit + the old data + */ + if(id == esp->es_client.ea_id) { + eap_tls_rtx(esp); + break; + } + + switch(esp->es_client.ea_state) { + + case eapListen: + GETCHAR(flags, inp); + + if(flags & EAP_TLS_FLAGS_START){ + + esp->es_client.ea_using_eaptls = 1; + + if (explicit_remote){ + esp->es_client.ea_peer = strdup(remote_name); + esp->es_client.ea_peerlen = strlen(remote_name); + } else + esp->es_client.ea_peer = NULL; + + /* Init ssl session */ + if(!eaptls_init_client(esp)) { + error("cannot init ssl"); + eap_send_nak(esp, id, EAPT_SRP); + esp->es_client.ea_using_eaptls = 0; + break; + } + + ets = esp->es_client.ea_session; + eap_tls_response(esp, id); + esp->es_client.ea_state = eapTlsSendMsg; + break; + } + + /* The server sent a bad start packet. */ + eap_send_nak(esp, id, EAPT_SRP); + break; + + case eapTlsSendMsg: + eaptls_write(ets, inp, len); + + if(SSL_is_init_finished(ets->ssl)) + ets->status |= EAP_TLS_STATUS_FINISHED; + + if((ets->rx_flags & EAP_TLS_FLAGS_ACK)&& + (ets->tx_flags & EAP_TLS_FLAGS_MF)) { + eap_tls_response(esp, id); + break; //don't change state + } + + if((ets->rx_flags & EAP_TLS_FLAGS_MF)&& + !(ets->tx_flags & EAP_TLS_FLAGS_MF)) { + esp->es_client.ea_state = eapTlsSendAck; + eap_tls_send_ack(esp, id); + break; + } + + if(!(ets->rx_flags & EAP_TLS_FLAGS_MF)&& + !(ets->rx_flags & EAP_TLS_FLAGS_ACK)&& + !(ets->tx_flags & EAP_TLS_FLAGS_MF)){ + + if(ets->status == 0){ + eap_tls_response(esp, id); + break; //don't change state + } + + esp->es_client.ea_state = eapTlsSendLastAck; + eap_tls_send_ack(esp, id); + break; + } + + eap_send_nak(esp, id, EAPT_SRP); + break; + + case eapTlsSendAck: + eaptls_write(ets, inp, len); + + if(SSL_is_init_finished(ets->ssl)) + ets->status |= EAP_TLS_STATUS_FINISHED; + + if((ets->rx_flags & EAP_TLS_FLAGS_MF)) { + eap_tls_send_ack(esp, id); + break; + } + + // ! rx mf + + if(ets->status == 0){ + eap_tls_response(esp, id); + esp->es_client.ea_state = eapTlsSendMsg; + break; + } + + if(ets->status & EAP_TLS_STATUS_ALERT_OUT){ + eap_tls_response(esp, id); + esp->es_client.ea_state = eapTlsSendLastAck; + break; + } + + eap_tls_send_ack(esp, id); + esp->es_client.ea_state = eapTlsSendLastAck; + + break; + case eapTlsSendLastAck: + // in this state we can only receive success or failure + eap_send_nak(esp, id, EAPT_SRP); + break; + + default: + eap_send_nak(esp, id, EAPT_SRP); + esp->es_client.ea_using_eaptls = 0; + break; + } + + break; + #ifdef USE_SRP case EAPT_SRP: if (len < 1) { @@ -1713,6 +2106,7 @@ #endif /* USE_SRP */ } + /* * eap_response - Receive EAP Response message (server mode). */ @@ -1736,6 +2130,7 @@ SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; #endif /* USE_SRP */ + struct eaptls_session *ets; if (esp->es_server.ea_id != id) { dbglog("EAP: discarding Response %d; expected ID %d", id, @@ -1888,6 +2283,25 @@ TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge); break; + case EAPT_TLS: + if(esp->es_server.ea_state < eapTlsStart || + esp->es_server.ea_state > eapTlsSendAlert) { + eap_send_failure(); + break; + } + + if (len < 1) { + error("EAP: empty TLS Response"); + eap_figure_next_state(esp, 1); + break; + } + + ets = (struct eaptls_session *) esp->es_server.ea_session; + + eap_figure_next_state(esp, eaptls_write(ets, inp, len)); + + break; + #ifdef USE_SRP case EAPT_SRP: if (len < 1) { @@ -2018,13 +2432,28 @@ 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) && + esp->es_client.ea_state != eapTlsSendLastAck) { dbglog("EAP unexpected success message in state %s (%d)", eap_state_name(esp->es_client.ea_state), esp->es_client.ea_state); return; } + if(esp->es_client.ea_using_eaptls) { + struct eaptls_session *ets = + (struct eaptls_session *)esp->es_client.ea_session; + + if(ets->status != EAP_TLS_STATUS_FINISHED) { + error("EAP-TLS: unexpected success message"); + return; + } + + eaptls_destroy(ets); + + } + + if (esp->es_client.ea_timeout > 0) { UNTIMEOUT(eap_client_timeout, (void *)esp); } @@ -2150,6 +2579,7 @@ int code, id, len, rtype, vallen; u_char *pstart; u_int32_t uval; + u_char flags; if (inlen < EAP_HEADERLEN) return (0); @@ -2214,6 +2644,23 @@ } break; + 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; + case EAPT_SRP: if (len < 3) goto truncated; @@ -2362,6 +2809,24 @@ } break; + + 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; + case EAPT_SRP: if (len < 1) goto truncated; diff -Naur ppp-2.4.3/pppd/eap.h ppp-2.4.3-eaptls/pppd/eap.h --- ppp-2.4.3/pppd/eap.h 2003-06-12 01:56:26.000000000 +0200 +++ ppp-2.4.3-eaptls/pppd/eap.h 2005-10-03 14:04:46.000000000 +0200 @@ -90,14 +90,28 @@ eapMD5Chall, /* Sent MD5-Challenge */ eapOpen, /* Completed authentication */ eapSRP4, /* Sent EAP SRP-SHA1 Subtype 4 */ + + /* EAP TLS */ + eapTlsStart, /* Send EAP TLS start packet */ + eapTlsSendMsg, /* Send EAP TLS Msg */ + eapTlsSendAck, /* Send EAP TLS Ack */ + eapTlsSendAlert,/* Send EAP TLS Alert */ + eapTlsSendLastAck, + eapBadAuth /* Failed authentication */ }; #define EAP_STATES \ "Initial", "Pending", "Closed", "Listen", "Identify", \ - "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth" + "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", \ + "TLS Start","TLS send msg","TLS send ack","TLS send alert", \ + "TLS Send Last Ack", "BadAuth" + +#define eap_client_active(esp) ((esp)->es_client.ea_state != eapInitial ||\ + (esp)->es_client.ea_state != eapPending ||\ + (esp)->es_client.ea_state != eapClosed) + -#define eap_client_active(esp) ((esp)->es_client.ea_state == eapListen) #define eap_server_active(esp) \ ((esp)->es_server.ea_state >= eapIdentify && \ (esp)->es_server.ea_state <= eapMD5Chall) @@ -117,6 +131,7 @@ u_char ea_responses; /* Number of Responses */ u_char ea_type; /* One of EAPT_* */ u_int32_t ea_keyflags; /* SRP shared key usage flags */ + bool ea_using_eaptls; }; /* @@ -138,7 +153,7 @@ /* * Timeouts. */ -#define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */ +#define EAP_DEFTIMEOUT 20 /* Timeout (seconds) for rexmit */ #define EAP_DEFTRANSMITS 10 /* max # times to transmit */ #define EAP_DEFREQTIME 20 /* Time to wait for peer request */ #define EAP_DEFALLOWREQ 20 /* max # times to accept requests */ diff -Naur ppp-2.4.3/pppd/eap-tls.c ppp-2.4.3-eaptls/pppd/eap-tls.c --- ppp-2.4.3/pppd/eap-tls.c 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/eap-tls.c 2005-11-22 16:07:47.000000000 +0100 @@ -0,0 +1,1266 @@ +/* + * eap-tls.c - EAP-TLS implementation for PPP + * + * Copyright (c) Beniamino Galvani 2005 All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pppd.h" +#include "eap.h" +#include "eap-tls.h" +#include "pathnames.h" + +extern char *crl_dir; +extern bool auto_update_crl; +extern int crl_update_time; + +static int search_wordlist(struct wordlist *wl, char *word); +static void add_wordlist(struct wordlist *wl, char *word); +static void destroy_wordlist(struct wordlist *wl); + +/* + * Tests if certificates, key and crl for server use can be loaded. + */ +int eaptls_test_certs_server(char *servcertfile, char *cacertfile, + char *pkfile, char *clicertfile) +{ + SSL_CTX *ctx; + X509_STORE *certstore; + X509_LOOKUP *lookup; + X509 *tmp; + + /* + * Without these can't continue + */ + if (!cacertfile[0] || !servcertfile[0] || !pkfile[0]) + return 0; + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(TLSv1_method()); + + if (!ctx) { + ERR_print_errors_fp(stderr); + error("Can't initialize CTX"); + return 0; + } + + if (!SSL_CTX_load_verify_locations(ctx, cacertfile, NULL)) + goto fail; + + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(cacertfile)); + + if (!SSL_CTX_use_certificate_file(ctx, servcertfile, SSL_FILETYPE_PEM)) + goto fail; + + if (!SSL_CTX_use_PrivateKey_file(ctx, pkfile, SSL_FILETYPE_PEM)) + goto fail; + + if (SSL_CTX_check_private_key(ctx) != 1) + goto fail; + + if (crl_dir) { + if (!(certstore = SSL_CTX_get_cert_store(ctx))) + goto fail; + + if (!(lookup = + X509_STORE_add_lookup(certstore, X509_LOOKUP_hash_dir()))) + goto fail; + + X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM); + X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK); + } + + /* + * If a client certificate file was specified, it must be valid, else + * fail + */ + if (clicertfile[0]) { + if (!(tmp = get_X509_from_file(clicertfile))) { + warn("Error loading client certificate from file %s", + clicertfile); + goto fail; + } + X509_free(tmp); + } + + SSL_CTX_free(ctx); + + return 1; + + fail: + ERR_print_errors_fp(stderr); + SSL_CTX_free(ctx); + return 0; +} + +/* + * Tests if certificates, key and crl for client use can be loaded. + */ +int eaptls_test_certs_client(char *clicertfile, char *cacertfile, char *pkfile, + char *servcertfile) +{ + + SSL_CTX *ctx; + X509_STORE *certstore; + X509_LOOKUP *lookup; + X509 *tmp; + + /* + * Without these we can't continue + */ + if (!cacertfile[0] || !clicertfile[0] || !pkfile[0]) + return 0; + + SSL_library_init(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new(TLSv1_method()); + + if (!ctx) { + ERR_print_errors_fp(stderr); + error("Can't initialize CTX"); + return 0; + } + + if (!SSL_CTX_load_verify_locations(ctx, cacertfile, NULL)) + goto fail; + + if (!SSL_CTX_use_certificate_file(ctx, clicertfile, SSL_FILETYPE_PEM)) + goto fail; + + if (!SSL_CTX_use_PrivateKey_file(ctx, pkfile, SSL_FILETYPE_PEM)) + goto fail; + + if (SSL_CTX_check_private_key(ctx) != 1) + goto fail; + + if (crl_dir) { + + if (!(certstore = SSL_CTX_get_cert_store(ctx))) + goto fail; + + if (!(lookup = + X509_STORE_add_lookup(certstore, X509_LOOKUP_hash_dir()))) + goto fail; + + X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM); + X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK); + } + + /* + * If a server certificate file was specified, it must be valid, else + * fail + */ + if (servcertfile[0]) { + if (!(tmp = get_X509_from_file(servcertfile))) { + warn("Error loading client certificate from file %s", + clicertfile); + goto fail; + } + X509_free(tmp); + } + + SSL_CTX_free(ctx); + + return 1; + + fail: + ERR_print_errors_fp(stderr); + SSL_CTX_free(ctx); + return 0; +} + +/* + * Init the ssl handshake (server mode) + */ +int eaptls_init_server(eap_state * esp) +{ + struct eaptls_session *ets; + X509_STORE *certstore; + X509_LOOKUP *lookup; + char servcertfile[MAXWORDLEN]; + char clicertfile[MAXWORDLEN]; + char cacertfile[MAXWORDLEN]; + char pkfile[MAXWORDLEN]; + struct wordlist updatedfiles; + + updatedfiles.next = NULL; + updatedfiles.word = NULL; + + //printf("eaptls_init_server\n"); + + /* + * Allocate new eaptls session + */ + esp->es_server.ea_session = malloc(sizeof(struct eaptls_session)); + if (!esp->es_server.ea_session) + fatal("Allocation error"); + ets = esp->es_server.ea_session; + + if (!esp->es_server.ea_peer) { + error("Error: client name not set (BUG)"); + return 0; + } + + strncpy(ets->peer, esp->es_server.ea_peer, MAXWORDLEN); + + if (!get_eaptls_secret(esp->es_unit, esp->es_server.ea_peer, + esp->es_server.ea_name, clicertfile, + servcertfile, cacertfile, pkfile, 1)) { + dbglog("get_eaptls_secret error"); + return 0; + } + + ets->mtu = netif_get_mtu(esp->es_unit) - PPP_HDRLEN - 10; + + SSL_library_init(); + SSL_load_error_strings(); + + ets->ctx = SSL_CTX_new(TLSv1_method()); + + if (!ets->ctx) { + ERR_print_errors_fp(stderr); + error("Can't initialize CTX"); + return 0; + } + + if (!SSL_CTX_load_verify_locations(ets->ctx, cacertfile, NULL)) + goto fail; + + SSL_CTX_set_client_CA_list(ets->ctx, + SSL_load_client_CA_file(cacertfile)); + + if (!SSL_CTX_use_certificate_file + (ets->ctx, servcertfile, SSL_FILETYPE_PEM)) + goto fail; + + if (!SSL_CTX_use_PrivateKey_file(ets->ctx, pkfile, SSL_FILETYPE_PEM)) + goto fail; + + if (SSL_CTX_check_private_key(ets->ctx) != 1) + goto fail; + + SSL_CTX_set_options(ets->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + SSL_CTX_set_verify_depth(ets->ctx, 5); + SSL_CTX_set_verify(ets->ctx, + SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + &ssl_verify_callback); + + if (crl_dir) { + if (!(certstore = SSL_CTX_get_cert_store(ets->ctx))) + goto fail; + + if (!(lookup = X509_STORE_add_lookup(certstore, + X509_LOOKUP_hash_dir()))) + goto fail; + + if (auto_update_crl) + eaptls_update_crls(crl_dir, cacertfile, &updatedfiles); + + destroy_wordlist(&updatedfiles); + + X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM); + X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK); + } + + if (!(ets->ssl = SSL_new(ets->ctx))) + goto fail; + + /* + * Initialize the BIOs we use to read/write to ssl engine + */ + ets->into_ssl = BIO_new(BIO_s_mem()); + ets->from_ssl = BIO_new(BIO_s_mem()); + SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl); + + SSL_set_msg_callback(ets->ssl, ssl_msg_callback); + SSL_set_msg_callback_arg(ets->ssl, ets); + + /* + * Attach the session struct to the connection, so we can later + * retrieve it when doing certificate verification + */ + SSL_set_ex_data(ets->ssl, 0, ets); + + SSL_set_accept_state(ets->ssl); + + ets->data = NULL; + ets->datalen = 0; + ets->status = 0; + ets->prev_id = 0xffff; + + /* + * If we specified the client certificate file, store it in ets->peercertfile, + * so we can check it later in ssl_verify_callback() + */ + if (clicertfile[0]) + strncpy(&ets->peercertfile[0], clicertfile, MAXWORDLEN); + else + ets->peercertfile[0] = 0; + + return 1; + + fail: + ERR_print_errors_fp(stderr); + SSL_CTX_free(ets->ctx); + return 0; +} + +/* + * Init the ssl handshake (client mode) + */ +int eaptls_init_client(eap_state * esp) +{ + struct eaptls_session *ets; + X509_STORE *certstore; + X509_LOOKUP *lookup; + char servcertfile[MAXWORDLEN]; + char clicertfile[MAXWORDLEN]; + char cacertfile[MAXWORDLEN]; + char pkfile[MAXWORDLEN]; + struct wordlist updatedfiles; + + updatedfiles.next = NULL; + updatedfiles.word = NULL; + + /* + * Allocate new eaptls session + */ + esp->es_client.ea_session = malloc(sizeof(struct eaptls_session)); + if (!esp->es_client.ea_session) + fatal("Allocation error"); + ets = esp->es_client.ea_session; + + /* + * If available, copy server name in ets; it will be used in cert + * verify + */ + if (esp->es_client.ea_peer) + strncpy(ets->peer, esp->es_client.ea_peer, MAXWORDLEN); + else + ets->peer[0] = 0; + + ets->mtu = netif_get_mtu(esp->es_unit) - PPP_HDRLEN - 10; + + if (!get_eaptls_secret(esp->es_unit, esp->es_client.ea_name, + esp->es_client.ea_peer, clicertfile, + servcertfile, cacertfile, pkfile, 0)) { + dbglog("get_eaptls_secret error"); + return 0; + } + + SSL_library_init(); + SSL_load_error_strings(); + + ets->ctx = SSL_CTX_new(TLSv1_method()); + + if (!ets->ctx) { + ERR_print_errors_fp(stderr); + error("Can't initialize CTX"); + return 0; + } + + if (!SSL_CTX_load_verify_locations(ets->ctx, cacertfile, NULL)) + goto fail; + + if (!SSL_CTX_use_certificate_file + (ets->ctx, clicertfile, SSL_FILETYPE_PEM)) + goto fail; + + if (!SSL_CTX_use_PrivateKey_file(ets->ctx, pkfile, SSL_FILETYPE_PEM)) + goto fail; + + if (SSL_CTX_check_private_key(ets->ctx) != 1) + goto fail; + + SSL_CTX_set_options(ets->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + SSL_CTX_set_verify_depth(ets->ctx, 5); + SSL_CTX_set_verify(ets->ctx, SSL_VERIFY_PEER, &ssl_verify_callback); + + if (crl_dir) { + if (!(certstore = SSL_CTX_get_cert_store(ets->ctx))) + goto fail; + + if (!(lookup = X509_STORE_add_lookup(certstore, + X509_LOOKUP_hash_dir()))) + goto fail; + + if (auto_update_crl) + eaptls_update_crls(crl_dir, cacertfile, &updatedfiles); + + destroy_wordlist(&updatedfiles); + + X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM); + X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK); + } + + ets->ssl = SSL_new(ets->ctx); + + if (!ets->ssl) + goto fail; + + /* + * Initialize the BIOs we use to read/write to ssl engine + */ + ets->into_ssl = BIO_new(BIO_s_mem()); + ets->from_ssl = BIO_new(BIO_s_mem()); + SSL_set_bio(ets->ssl, ets->into_ssl, ets->from_ssl); + + SSL_set_msg_callback(ets->ssl, ssl_msg_callback); + SSL_set_msg_callback_arg(ets->ssl, ets); + + /* + * Attach the session struct to the connection, so we can later + * retrieve it when doing certificate verification + */ + SSL_set_ex_data(ets->ssl, 0, ets); + + SSL_set_connect_state(ets->ssl); + + ets->data = NULL; + ets->datalen = 0; + ets->status = 0; + ets->prev_id = 0xffff; + + /* + * If we specified the server certificate file, store it in + * ets->peercertfile, so we can check it later in + * ssl_verify_callback() + */ + if (servcertfile[0]) + strncpy(ets->peercertfile, servcertfile, MAXWORDLEN); + else + ets->peercertfile[0] = 0; + + return 1; + fail: + ERR_print_errors_fp(stderr); + SSL_CTX_free(ets->ctx); + return 0; + +} + + +int eaptls_read(struct eaptls_session *ets, u_char **outp, int rtx) +{ + u_char fromtls[65536], *start; + int mf, first = 0, size; + + if(rtx){ + BCOPY(ets->rtx, *outp, ets->rtx_len); + INCPTR(ets->rtx_len, *outp); + return 0; + } + + start = *outp; + + if (!ets->data) { + + if(!(ets->status & EAP_TLS_STATUS_ALERT_OUT)) + SSL_read(ets->ssl, fromtls, 65536); + + /* + * Read from ssl + */ + if ((ets->datalen = BIO_read(ets->from_ssl, fromtls, 65536)) == -1){ + warn("No data from BIO_read"); + return 1; + } + + 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; + mf = 1; + ets->tx_flags = EAP_TLS_FLAGS_MF; + } else { + mf = 0; + ets->tx_flags = 0; + } + + PUTCHAR(EAPT_TLS, *outp); + + /* + * Set right flags and TLS length if necessary + */ + if (mf && first) { + PUTCHAR(EAP_TLS_FLAGS_LI | EAP_TLS_FLAGS_MF, *outp); + PUTLONG(ets->datalen, *outp); + + } + + if (mf && !first) + PUTCHAR(EAP_TLS_FLAGS_MF, *outp); + + if(!mf) + 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; +} + +int eaptls_write(struct eaptls_session *ets, u_char *inp, int len) +{ + u_char flags; + u_int tlslen = 0; + u_char dummy[65536]; + + GETCHAR(flags, inp); + len--; + + ets->rx_flags = flags; + if(len == 0) { + ets->rx_flags = EAP_TLS_FLAGS_ACK; // ack excludes others flags + return 0; + } + + if(!ets->data) { // this is the first/only fragment + + if(flags & EAP_TLS_FLAGS_MF && ! (flags & EAP_TLS_FLAGS_LI)) { + warn("EAP-TLS: peer sending first fragment w/o TLS Length"); + return 1; + } + + if(flags & EAP_TLS_FLAGS_LI){ + + GETLONG(tlslen, inp); + len -= 4; + + if (tlslen > EAP_TLS_MAX_LEN) { + error("Error: tls message length > %d, truncated", + EAP_TLS_MAX_LEN); + tlslen = EAP_TLS_MAX_LEN; + } + } + + if(flags & EAP_TLS_FLAGS_MF){ + + ets->data = malloc(tlslen); + if (!ets->data) + fatal("EAP TLS: allocation error\n"); + + ets->datalen = 0; + ets->tlslen = tlslen; + + } else { + ets->data = malloc(len); + if (!ets->data) + fatal("EAP TLS: allocation error\n"); + ets->datalen = 0; + ets->tlslen = len; + } + + } else { + if(flags & EAP_TLS_FLAGS_LI) { + GETLONG(tlslen, inp); + len -=4; + } + } + + 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 (!(flags & EAP_TLS_FLAGS_MF)) { + + /* + * 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) + ERR_print_errors_fp(stderr); + + SSL_read(ets->ssl, dummy, 65536); + + free(ets->data); + ets->data = NULL; + ets->datalen = 0; + + } + + return 0; +} + +/* + * Updates the CA CRL + */ +void eaptls_update_crls(char *crldir, char *cacertfile, struct wordlist *uf) +{ + FILE *file; + X509 *cert; + char *filename; + + if (!(file = fopen(cacertfile, "r"))) + return; + + filename = malloc(strlen(crldir) + 15); + + /* + * for each CA certificate, control if the CRL must be updated + */ + while ((cert = PEM_read_X509(file, NULL, NULL, NULL))) { + + if (eaptls_must_update(cert, crldir, filename, uf) == 1) { + + eaptls_get_crl(cert, filename); + add_wordlist(uf, filename); + } + + } + + free(filename); + fclose(file); +} + +/* + * Control if the CA CRL must be updated + * Return in filename the file to be updated + */ +int eaptls_must_update(X509 * cert, char *crldir, char *filename, + struct wordlist *uf) +{ + X509_NAME *xn; + unsigned long hash; + int found = 0, i, hours; + FILE *file; + X509_CRL *crl; + time_t curr_time, mod_time; + struct stat file_stat; + char tmpname[15]; + char subject[256]; + char cn_str[256]; + + /* + * Get CA subject name and calculate its hash + */ + xn = X509_get_subject_name(cert); + hash = X509_NAME_hash(xn); + + X509_NAME_oneline(xn, subject, 256); + X509_NAME_get_text_by_NID(xn, NID_commonName, cn_str, 256); + dbglog(" -> processing CA: %s", cn_str); + + /* + * Search a CRL for this CA in crldir + */ + for (i = 0; i < 10; i++) { + sprintf(tmpname, "%08lx.r%1d", hash, i); + strcpy(filename, crldir); + strcat(filename, "/"); + strcat(filename, tmpname); + + if (!(file = fopen(filename, "r"))) + break; /* CRL not found */ + + if (!(crl = PEM_read_X509_CRL(file, NULL, NULL, NULL))) { + fclose(file); + continue; + } + fclose(file); + + /* + * test if it's the right CRL + */ + if (X509_NAME_cmp(xn, X509_CRL_get_issuer(crl)) == 0) { + found = 1; + X509_CRL_free(crl); + break; + } + X509_CRL_free(crl); + } + + /* + * If file already in list, we've already updated it + */ + if (search_wordlist(uf, filename) == 1) + return 0; + + /* + * If CRL file for this CA not found, need update + */ + if (!found) + return 1; + + curr_time = time(NULL); + stat(filename, &file_stat); + mod_time = file_stat.st_mtime; + hours = (curr_time - mod_time) / 3600; + + /* + * If file too old, need update + */ + if (hours >= crl_update_time) { + dbglog(" file %s is %d hours old, need update", + filename, hours); + return 1; + } + + return 0; +} + +/* + * Extract CDPs from certificate + */ +void eaptls_get_crl(X509 * cert, char *filename) +{ + STACK_OF(DIST_POINT) * distpoints = NULL; + DIST_POINT *dp; + DIST_POINT_NAME *dpn; + STACK_OF(GENERAL_NAME) * names; + GENERAL_NAME *name; + ASN1_IA5STRING *uri_asn; + char *uri; + int num_dp, i; + int num_name, j; + + distpoints = X509_get_ext_d2i(cert, + NID_crl_distribution_points, NULL, NULL); + num_dp = sk_DIST_POINT_num(distpoints); + + dbglog(" CA certificate contains %d CDP", num_dp); + + for (i = 0; i < num_dp; i++) { + + dp = sk_DIST_POINT_value(distpoints, i); + dpn = dp->distpoint; + names = dpn->name.fullname; + num_name = sk_GENERAL_NAME_num(names); + + for (j = 0; j < num_name; j++) { + + name = sk_GENERAL_NAME_value(names, j); + + if (name->type == GEN_URI) { + uri_asn = name->d.uniformResourceIdentifier; + uri = ASN1_STRING_data(uri_asn); + + if (eaptls_download_crl(uri, filename)) { + dbglog + (" * %s successfully loaded", + uri); + return; + } + + } + + } + } +} + +/* + * Download a CRL from uri into file + */ +int eaptls_download_crl(char *uri, char *filename) +{ + FILE *tmpfile; + FILE *destfile; + int tmpfd; + char tmpname[30]; + CURL *curl; + int res; + X509_CRL *crl; + + strcpy(tmpname, "/tmp/ppp-tmp-XXXXXX"); + + if ((tmpfd = mkstemp(tmpname)) == -1) { + error("error creating temp file /tmp/ppp-tmp-*"); + return 0; + } + + tmpfile = fdopen(tmpfd, "w"); + if (!tmpfile) { + error("error fdopen"); + close(tmpfd); + return 0; + } + + /* + * download in temp file using libcurl + */ + curl_global_init(CURL_GLOBAL_NOTHING); + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, uri); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, tmpfile); + + res = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + curl_global_cleanup(); + + if (res != CURLE_OK) { + dbglog(" * %s download failed", uri); + fclose(tmpfile); + unlink(tmpname); + return 0; + } + + fclose(tmpfile); + tmpfile = fopen(tmpname, "r"); + if(!tmpfile) + return 0; + + /* + * load CRL from temp file + */ + crl = d2i_X509_CRL_fp(tmpfile, NULL); + + fclose(tmpfile); + unlink(tmpname); + + if (!crl) { + warn("cannot load DER CRL"); + return 0; + } + + destfile = fopen(filename, "w"); + if (!destfile) { + X509_CRL_free(crl); + return 0; + } + + /* + * write CRL in PEM format to destination file + */ + PEM_write_X509_CRL(destfile, crl); + + X509_CRL_free(crl); + fclose(destfile); + + return 1; +} + +void eaptls_destroy(struct eaptls_session *ets) +{ + if (ets->ssl) + SSL_free(ets->ssl); + + if (ets->ctx) + SSL_CTX_free(ets->ctx); + + free(ets); +} + +/* + * Verify a certificate. + * Most of the work (signatures and issuer attributes checking) + * is done by ssl; we check the CN in the peer certificate + * against the peer name. + */ +int ssl_verify_callback(int preverify_ok, X509_STORE_CTX * ctx) +{ + char subject[256]; + char cn_str[256]; + X509 *peer_cert; + int err, depth; + int ok = preverify_ok; + SSL *ssl; + struct eaptls_session *ets; + + peer_cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + dbglog("certificate verify depth: %d", depth); + + if (!ok) { + X509_NAME_oneline(X509_get_subject_name(peer_cert), + subject, 256); + + X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert), + NID_commonName, cn_str, 256); + + dbglog("Certificate verification error:\n depth: %d CN: %s" + "\n err: %d (%s)\n", depth, cn_str, err, + X509_verify_cert_error_string(err)); + + return 0; + } + + ssl = X509_STORE_CTX_get_ex_data(ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + + ets = (struct eaptls_session *)SSL_get_ex_data(ssl, 0); + + if (ets == NULL) { + error("Error: SSL_get_ex_data returned NULL"); + return 0; + } + + ERR_print_errors_fp(stderr); + + if (!depth) { /* This is the peer certificate */ + + X509_NAME_oneline(X509_get_subject_name(peer_cert), + subject, 256); + + X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert), + NID_commonName, cn_str, 256); + + /* + * If acting as client and the name of the server wasn't specified + * explicitely, we can't verify the server authenticity + */ + if (!ets->peer[0]) { + warn("Peer name not specified: no check"); + return 1; + } + + /* + * Check the CN + */ + if (strcmp(cn_str, ets->peer)) { + error + ("Certificate verification error: CN (%s) != peer_name (%s)", + cn_str, ets->peer); + return 0; + } + + warn("Certificate CN: %s , peer name %s", cn_str, ets->peer); + + /* + * If a peer certificate file was specified, here we check it + */ + if (ets->peercertfile[0]) { + if (ssl_cmp_certs(&ets->peercertfile[0], peer_cert) + != 0) { + error + ("Peer certificate doesn't match stored certificate"); + return 0; + } + } + } + + return 1; +} + +/* + * Compare a certificate with the one stored in a file + */ +int ssl_cmp_certs(char *filename, X509 * a) +{ + X509 *b; + int ret; + + if (!(b = get_X509_from_file(filename))) + return 1; + + ret = X509_cmp(a, b); + X509_free(b); + + return ret; + +} + +X509 *get_X509_from_file(char *filename) +{ + FILE *fp; + X509 *ret; + + if (!(fp = fopen(filename, "r"))) + return NULL; + + ret = PEM_read_X509(fp, NULL, NULL, NULL); + + fclose(fp); + + return ret; +} + +/* + * Every sent & received message this callback function is invoked, + * so we know when alert messages have arrived or are sent and + * we can print debug information about TLS handshake. + */ +void +ssl_msg_callback(int write_p, int version, int content_type, + const void *buf, size_t len, SSL * ssl, void *arg) +{ + char string[256]; + struct eaptls_session *ets = (struct eaptls_session *)arg; + unsigned char code; + + if(write_p) + strcpy(string, " -> "); + else + strcpy(string, " <- "); + + + switch(content_type) { + + case SSL3_RT_ALERT: + strcat(string, "Alert: "); + code = ((const unsigned char *)buf)[1]; + + if (write_p) { + ets->status |= EAP_TLS_STATUS_ALERT_OUT; + ets->alert_out_desc = code; + } else { + ets->status |= EAP_TLS_STATUS_ALERT_IN; + ets->alert_in_desc = code; + } + + strcat(string, SSL_alert_desc_string_long(code)); + break; + + case SSL3_RT_CHANGE_CIPHER_SPEC: + strcat(string, "ChangeCipherSpec"); + break; + + case SSL3_RT_HANDSHAKE: + + strcat(string, "Handshake: "); + code = ((const unsigned char *)buf)[0]; + + switch(code) { + case SSL3_MT_HELLO_REQUEST: + strcat(string,"Hello Request"); + break; + case SSL3_MT_CLIENT_HELLO: + strcat(string,"Client Hello"); + break; + case SSL3_MT_SERVER_HELLO: + strcat(string,"Server Hello"); + break; + case SSL3_MT_CERTIFICATE: + strcat(string,"Certificate"); + break; + case SSL3_MT_SERVER_KEY_EXCHANGE: + strcat(string,"Server Key Exchange"); + break; + case SSL3_MT_CERTIFICATE_REQUEST: + strcat(string,"Certificate Request"); + break; + case SSL3_MT_SERVER_DONE: + strcat(string,"Server Hello Done"); + break; + case SSL3_MT_CERTIFICATE_VERIFY: + strcat(string,"Certificate Verify"); + break; + case SSL3_MT_CLIENT_KEY_EXCHANGE: + strcat(string,"Client Key Exchange"); + break; + case SSL3_MT_FINISHED: + strcat(string,"Finished"); + break; + } + break; + } + + + /* Alert messages must always be displayed */ + if(content_type == SSL3_RT_ALERT) + error("%s", string); + else + dbglog("%s", string); + +} + +/* + * Extract all CA files from conf file 'filename' and update crl + */ +void eaptls_do_update(char *filename, struct wordlist *updatedfiles) +{ + int newline; + FILE *f; + char word[MAXWORDLEN]; + + if (!(f = fopen(filename, "r"))) { + fprintf(stderr, "can't open %s", filename); + die(1); + } + + if (!getword(f, word, &newline, filename)) + return; /* file is empty??? */ + + newline = 1; + + for (;;) { + + /* + * Skip until we find a word at the start of a line. + */ + while (!newline && getword(f, word, &newline, filename)) ; + if (!newline) + break; /* got to end of file */ + + /* + * server + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + + /* + * client cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + + /* + * server cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + + /* + * ca cert + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + + printf("Updating CRLs for CA file %s\n", word); + + eaptls_update_crls(crl_dir, word, updatedfiles); + } + + fclose(f); +} + +void eaptls_only_update_crl(int server, int client) +{ + /* + * mantain a list of updated crl files, so if a CA appears more + * times, it is updated once + */ + struct wordlist updatedfiles; + + updatedfiles.next = NULL; + updatedfiles.word = NULL; + + if (server) + eaptls_do_update(_PATH_EAPTLSSERVFILE, &updatedfiles); + + if (client) + eaptls_do_update(_PATH_EAPTLSCLIFILE, &updatedfiles); + + destroy_wordlist(&updatedfiles); +} + +static int search_wordlist(struct wordlist *wl, char *word) +{ + struct wordlist *tmp = wl->next; + + while (tmp) { + if (strcmp(tmp->word, word) == 0) + return 1; + tmp = tmp->next; + } + return 0; +} + +static void add_wordlist(struct wordlist *wl, char *word) +{ + struct wordlist *tmp = wl; + + while (tmp->next) + tmp = tmp->next; + + tmp->next = malloc(sizeof(struct wordlist)); + tmp->next->word = strdup(word); + tmp->next->next = NULL; + +} + +static void destroy_wordlist(struct wordlist *wl) +{ + struct wordlist *tmp = wl->next; + struct wordlist *next; + + while (tmp) { + next = tmp->next; + + if (tmp->word) + free(tmp->word); + + free(tmp); + tmp = next; + } + +} + diff -Naur ppp-2.4.3/pppd/eap-tls.h ppp-2.4.3-eaptls/pppd/eap-tls.h --- ppp-2.4.3/pppd/eap-tls.h 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/eap-tls.h 2005-09-01 11:40:22.000000000 +0200 @@ -0,0 +1,116 @@ +/* + * eap-tls.h + * + * Copyright (c) Beniamino Galvani 2005 All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef __EAP_TLS_H__ +#define __EAP_TLS_H__ + +#include "eap.h" + +#include +#include + +#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 */ + +/* this flag is virtual, only used internally + to indicate an ack was received */ +#define EAP_TLS_FLAGS_ACK 16 + + +#define EAP_TLS_STATUS_FINISHED 1 +#define EAP_TLS_STATUS_ALERT_OUT 2 +#define EAP_TLS_STATUS_ALERT_IN 4 + +#define EAP_TLS_MAX_LEN 65536 /* max eap tls packet size */ + +#define CRL_UPDATE_TIME 72 /* update time for crl: 72 hours */ + +struct eaptls_session { + + u_char rx_flags; + u_char tx_flags; + u_char status; + + u_char *data; /* buffered data */ + int datalen; /* buffered data len */ + int offset; /* from where to send */ + int tlslen; /* total length of tls data */ + SSL_CTX *ctx; + SSL *ssl; /* ssl connection */ + BIO *from_ssl; + BIO *into_ssl; + char peer[MAXWORDLEN]; /* peer name */ + char peercertfile[MAXWORDLEN]; + u_char alert_out_desc; + u_char alert_in_desc; + char rtx[65536]; /* retransmission buffer */ + int rtx_len; + int mtu; + int prev_id; /* identifier of the previuos request/response */ + +}; + + + +int eaptls_write(struct eaptls_session *ets, u_char *data, int len); +int eaptls_read(struct eaptls_session *ets, u_char **data, int rtx); + +void eaptls_destroy(struct eaptls_session *ets); + +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 eaptls_test_certs_server(char *servcertfile, char *cacertfile, char *pkfile, + char *clicertfile); +int eaptls_test_certs_client(char *clicertfile, char *cacertfile, char *pkfile, + char *servcertfile); + +X509 *get_X509_from_file(char *filename); +int ssl_cmp_certs(char *filename, X509 * a); + +int eaptls_init_server(eap_state * esp); +int eaptls_init_client(eap_state * esp); + +int get_eaptls_secret(int unit, char *client, char *server, + char *clicertfile, char *servcertfile, char *cacertfile, + char *pkfile, int am_server); + +void eaptls_update_crls(char *crldir, char *cacertfile, struct wordlist *wl); +int eaptls_must_update(X509 * cert, char *crldir, char *filename, + struct wordlist *wl); +void eaptls_get_crl(X509 * cert, char *filename); +int eaptls_download_crl(char *uri, char *filename); + +#endif + + diff -Naur ppp-2.4.3/pppd/main.c ppp-2.4.3-eaptls/pppd/main.c --- ppp-2.4.3/pppd/main.c 2004-11-13 13:05:48.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/main.c 2005-09-01 11:40:22.000000000 +0200 @@ -258,6 +258,7 @@ extern char *ttyname __P((int)); extern char *getlogin __P((void)); int main __P((int, char *[])); +void eaptls_only_update_crl(int serv, int cli); #ifdef ultrix #undef O_NONBLOCK @@ -417,6 +418,17 @@ if (dryrun) die(0); + if(only_update_crl_server || only_update_crl_client) { + if(!crl_dir){ + fprintf(stderr, "You must specify a crl dir\n"); + die(1); + } + + eaptls_only_update_crl(only_update_crl_server, only_update_crl_client); + + die(0); + } + /* Make sure fds 0, 1, 2 are open to somewhere. */ fd_devnull = open(_PATH_DEVNULL, O_RDWR); if (fd_devnull < 0) diff -Naur ppp-2.4.3/pppd/Makefile.linux ppp-2.4.3-eaptls/pppd/Makefile.linux --- ppp-2.4.3/pppd/Makefile.linux 2004-11-13 13:02:22.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/Makefile.linux 2005-11-22 16:02:05.000000000 +0100 @@ -13,16 +13,16 @@ PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c md5.c ccp.c \ ecp.c ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c \ - demand.c utils.c tty.c eap.c chap-md5.c + demand.c utils.c tty.c eap.c chap-md5.c eap-tls.c HEADERS = ccp.h chap-new.h ecp.h fsm.h ipcp.h \ ipxcp.h lcp.h magic.h md5.h patchlevel.h pathnames.h pppd.h \ - upap.h eap.h + upap.h eap.h eap-tls.h MANPAGES = pppd.8 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o md5.o ccp.o \ ecp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o tty.o \ - eap.o chap-md5.o + eap.o chap-md5.o eap-tls.o # # include dependencies if present @@ -32,8 +32,8 @@ # CC = gcc # -COPTS = -O2 -pipe -Wall -g -LIBS = +COPTS = -O2 -pipe -Wall -g -I/usr/kerberos/include +LIBS = -lssl -lcurl # Uncomment the next 2 lines to include support for Microsoft's # MS-CHAP authentication protocol. Also, edit plugins/radius/Makefile.linux. diff -Naur ppp-2.4.3/pppd/options.c ppp-2.4.3-eaptls/pppd/options.c --- ppp-2.4.3/pppd/options.c 2004-11-09 23:33:35.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/options.c 2005-09-01 11:40:22.000000000 +0200 @@ -114,6 +114,8 @@ bool dryrun; /* print out option values and exit */ char *domain; /* domain name set by domain option */ int child_wait = 5; /* # seconds to wait for children at exit */ +bool only_update_crl_server = 0; /* update server crl and exit */ +bool only_update_crl_client = 0; /* update client crl and exit */ #ifdef MAXOCTETS unsigned int maxoctets = 0; /* default - no limit */ @@ -315,6 +317,10 @@ { "mo-timeout", o_int, &maxoctets_timeout, "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 }, #endif + { "only-update-crl-server", o_bool, &only_update_crl_server, + "Update server CA CRLs and exit", 1 }, + { "only-update-crl-client", o_bool, &only_update_crl_client, + "Update client CA CRLs and exit", 1 }, { NULL } }; diff -Naur ppp-2.4.3/pppd/pathnames.h ppp-2.4.3-eaptls/pppd/pathnames.h --- ppp-2.4.3/pppd/pathnames.h 2004-11-13 13:02:22.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/pathnames.h 2005-09-01 11:40:22.000000000 +0200 @@ -21,6 +21,8 @@ #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_EAPTLSCLIFILE _ROOT_PATH "/etc/ppp/eaptls-client" +#define _PATH_EAPTLSSERVFILE _ROOT_PATH "/etc/ppp/eaptls-server" #define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options" #define _PATH_IPUP _ROOT_PATH "/etc/ppp/ip-up" #define _PATH_IPDOWN _ROOT_PATH "/etc/ppp/ip-down" diff -Naur ppp-2.4.3/pppd/pppd.h ppp-2.4.3-eaptls/pppd/pppd.h --- ppp-2.4.3/pppd/pppd.h 2004-11-13 13:02:22.000000000 +0100 +++ ppp-2.4.3-eaptls/pppd/pppd.h 2005-09-01 11:40:22.000000000 +0200 @@ -318,6 +318,9 @@ 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 only_update_crl_server; /* update server crls and exit */ +extern bool only_update_crl_client; /* update client crls and exit */ +extern char *crl_dir; #ifdef MAXOCTETS extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */ diff -Naur ppp-2.4.3/README.eap-tls ppp-2.4.3-eaptls/README.eap-tls --- ppp-2.4.3/README.eap-tls 1970-01-01 01:00:00.000000000 +0100 +++ ppp-2.4.3-eaptls/README.eap-tls 2005-11-22 16:47:33.000000000 +0100 @@ -0,0 +1,162 @@ +EAP-TLS authentication support for PPP +====================================== + +1. Intro + + The Extensible Authentication Protocol (EAP; RFC 3748) is a + security protocol that can be used with PPP. It provides a means + to plug in multiple optional authentication methods. + + Transport Level Security (TLS; RFC 2246) provides for mutual + authentication, integrity-protected ciphersuite negotiation and + key exchange between two endpoints. + + EAP-TLS (RFC 2716) incapsulates the TLS messages in EAP packets, + allowing TLS mutual authentication to be used as a generic EAP + mechanism. + + This patch provide EAP-TLS support to pppd. + This authentication method can be used in both client or server + mode. + +2. Building + + To build pppd with EAP-TLS support, OpenSSL (http://www.openssl.org) + is required. Any version from 0.9.7 should work. + + You must also have libcurl installed (used to fetch CRLs). + The version required is 7.9.8 or newer (because that's the one I used, + but an earlier version may work). + + Configure, compile, and install as usual. + +3. Configuration + + On the client side edit the /etc/ppp/eaptls-client file. + Insert a line for each system with which you use EAP-TLS. + The line is composed of this fields separated by tab: + + - Client name + The name used by the client for authentication, can be * + - Server name + The name of the server, can be * + - Client certificate file + The file containing the certificate chain for the + client in PEM format + - Server certificate file + If you want to specify the certificate that the + server is allowed to use, put the certificate file name. + Else put a dash '-'. + - CA certificate file + The file containing the trusted CA certificates in PEM + format. + - Client private key file + The file containing the client private key in PEM format. + + + On the server side edit the /etc/ppp/eaptls-server file. + Insert a line for each system with which you use EAP-TLS. + The line is composed of this fields separated by tab: + + - Client name + The name used by the client for authentication, can be * + - Server name + The name of the server, can be * + - Client certificate file + If you want to specify the certificate that the + client is allowed to use, put the certificate file name. + Else put a dash '-'. + - Server certificate file + The file containing the certificate chain for the + server in PEM format + - CA certificate file + The file containing the trusted CA certificates in PEM + format. + - Client private key file + The file containing the server private key in PEM format. + - addresses + A list of IP addresses the client is allowed to use. + + +4. Options + + These pppd options are available: + + crl-dir + Use CRL files from dir. It contains CRL files in PEM + format and each file contains a CRL. The files are looked up + by the issuer name hash value. Use the c_rehash utility + to create necessary links. + + auto-update-crl + On a new TLS handshake, try to fetch updated CRLs for the + trusted CAs. This is done only if the crl-dir option was used. + For each trusted CA, the appropriate CRL is checked and if + it doesn't exist or is too old, the update take place. + + crl-update-time + Time (in hours) after which a CRL must be updated if the option + auto-update-crl or only-update-crl-* were specified. Use 0 as + value if you want to force update. The default value is 72 + + need-peer-eap + If the peer doesn't ask us to authenticate or doesn't use eap + to authenticate us, disconnect. + + only-update-crl-server + Parse EAP-TLS server configuration file (/etc/ppp/eaptls-server) + and find all files containing trusted CAs; then update their CRL + and exit. + The 'crl-dir' option must be used to specify crl directory. + + only-update-crl-client + Similar to only-update-crl-server, but uses client configuration + file. + + +5. Connecting + + If you're setting up a pppd server, edit the EAP-TLS configuration file + as written above and then run pppd with the 'auth' option to authenticate + the client. The EAP-TLS method will be used if the other eap methods can't + be used (no secrets). + + If you're setting up a client, edit the configuration file and then run + pppd with 'remotename' option to specify the server name. Add the + 'need-peer-eap' option if you want to be sure the peer ask you to + authenticate (and to use eap) and to disconnect if it doesn't. + +6. Updating CRLs with cron + + With the 'auto-update-crl' option you can do crl updating at connect time. + In some situations this approach can't be used, because the download can + take long time and the peer will have to wait too much, possibly going in + timeout. + In such cases, you can update crls periodically (with cron) using pppd with + the 'only-update-crl-client' or 'only-update-crl-server' options, as + explained above. + Example: + + pppd crl-dir /root/crldir only-update-crl-server crl-update-time 0 + + To show debug information add '/dev/null debug' to the command line. + + +7. Changelog + + + 0.7a (09/2005) + --------------- + * State Machines rewrite (eap.c) + * eap-tls.c: changes in eaptls_read/write() + + 0.7 (04/2005) + -------------- + * Initial release + + +8. Notes + + This is experimental code. + Send suggestions and comments to Beniamino Galvani + diff -Naur ppp-2.4.3/solaris/Makefile.top ppp-2.4.3-eaptls/solaris/Makefile.top --- ppp-2.4.3/solaris/Makefile.top 2004-11-01 10:31:07.000000000 +0100 +++ ppp-2.4.3-eaptls/solaris/Makefile.top 2005-11-22 16:11:19.000000000 +0100 @@ -22,7 +22,7 @@ cd pppdump; $(MAKE) install install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \ - $(ETCDIR)/chap-secrets + $(ETCDIR)/chap-secrets $(ETCDIR)/eaptls-server $(ETCDIR)/eaptls-client install-modules: cd solaris; $(MAKE) install @@ -34,6 +34,11 @@ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/pap-secrets $(ETCDIR)/chap-secrets: $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/chap-secrets +$(ETCDIR)/eaptls-server: + $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/eaptls-server +$(ETCDIR)/eaptls-client: + $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/eaptls-client + $(BINDIR): mkdir -m 755 -p $@