diff -Naur /usr/portage/net-dialup/ppp/files/ppp-2.4.3-eaptls-0.7.patch /usr/local/portage/net-dialup/ppp/files/ppp-2.4.3-eaptls-0.7.patch --- /usr/portage/net-dialup/ppp/files/ppp-2.4.3-eaptls-0.7.patch 1970-01-01 01:00:00.000000000 +0100 +++ /usr/local/portage/net-dialup/ppp/files/ppp-2.4.3-eaptls-0.7.patch 2005-03-30 13:18:02.000000000 +0200 @@ -0,0 +1,2808 @@ +diff -Naur ppp-2.4.3/etc.ppp/eaptls-client ppp-2.4.3-eaptls-0.7/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-0.7/etc.ppp/eaptls-client 2005-03-18 10:45:22.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-0.7/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-0.7/etc.ppp/eaptls-server 2005-03-18 10:44:49.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-0.7/linux/Makefile.top +--- ppp-2.4.3/linux/Makefile.top 2004-10-31 23:25:16.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/linux/Makefile.top 2005-03-07 11:40:46.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-0.7/pppd/auth.c +--- ppp-2.4.3/pppd/auth.c 2004-11-12 11:30:51.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/pppd/auth.c 2005-03-21 14:15:18.000000000 +0100 +@@ -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-0.7/pppd/eap.c +--- ppp-2.4.3/pppd/eap.c 2004-11-09 23:39:25.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/pppd/eap.c 2005-03-21 11:19:55.000000000 +0100 +@@ -43,6 +43,11 @@ + * Based on draft-ietf-pppext-eap-srp-03.txt. + */ + ++/* ++ * Modification by Beniamino Galvani, Mar 2005 ++ * Implemented EAP-TLS authentication ++ */ ++ + #define RCSID "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $" + + /* +@@ -62,8 +67,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 +89,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 +115,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 } + }; + +@@ -209,6 +226,7 @@ + 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_client.ea_using_eaptls = 0; + } + + /* +@@ -426,6 +444,10 @@ + eap_state *esp; + int status; + { ++ ++ struct eaptls_session *ets; ++ int secret_len; ++ char secret[MAXWORDLEN]; + #ifdef USE_SRP + unsigned char secbuf[MAXWORDLEN], clear[8], *sp, *dp; + struct t_pw tpw; +@@ -438,6 +460,9 @@ + #endif /* USE_SRP */ + + esp->es_server.ea_timeout = esp->es_savedtime; ++ ++ esp->es_server.ea_prev_state = esp->es_server.ea_state; ++ + switch (esp->es_server.ea_state) { + case eapBadAuth: + return; +@@ -562,9 +587,78 @@ + break; + } + #endif /* USE_SRP */ ++ ++ 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; ++ } ++ + esp->es_server.ea_state = eapMD5Chall; + break; + ++ case eapTlsStart: ++ /* Initialize ssl session */ ++ if(!eaptls_init_ssl_server(esp)) { ++ esp->es_server.ea_state = eapBadAuth; ++ break; ++ } ++ ++ esp->es_server.ea_state = eapTlsRecv; ++ break; ++ ++ case eapTlsRecv: ++ ets = (struct eaptls_session *) esp->es_server.ea_session; ++ ++ if(ets->alert_sent) { ++ esp->es_server.ea_state = eapTlsSendAlert; ++ break; ++ } ++ ++ if (status) { ++ esp->es_server.ea_state = eapBadAuth; ++ break; ++ } ++ ets = (struct eaptls_session *) esp->es_server.ea_session; ++ ++ if(ets->frag) ++ esp->es_server.ea_state = eapTlsSendAck; ++ else ++ esp->es_server.ea_state = eapTlsSend; ++ break; ++ ++ case eapTlsSend: ++ ets = (struct eaptls_session *) esp->es_server.ea_session; ++ ++ if(SSL_is_init_finished(ets->ssl)) { ++ esp->es_server.ea_state = eapTlsRecvClient; ++ break; ++ } ++ ++ if(ets->frag) ++ esp->es_server.ea_state = eapTlsRecvAck; ++ else ++ esp->es_server.ea_state = eapTlsRecv; ++ break; ++ ++ case eapTlsSendAck: ++ esp->es_server.ea_state = eapTlsRecv; ++ break; ++ ++ case eapTlsRecvAck: ++ if (status) { ++ esp->es_server.ea_state = eapBadAuth; ++ break; ++ } ++ ++ esp->es_server.ea_state = eapTlsSend; ++ break; ++ ++ case eapTlsSendAlert: ++ esp->es_server.ea_state = eapTlsRecvAlertAck; ++ break; ++ + case eapSRP1: + #ifdef USE_SRP + ts = (struct t_server *)esp->es_server.ea_session; +@@ -718,6 +812,28 @@ + INCPTR(esp->es_server.ea_namelen, outp); + break; + ++ 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; ++ + #ifdef USE_SRP + case eapSRP1: + PUTCHAR(EAPT_SRP, outp); +@@ -904,11 +1020,53 @@ + eap_server_timeout(arg) + void *arg; + { ++ u_char *outp; ++ u_char *lenloc; ++ int outlen; ++ + eap_state *esp = (eap_state *) arg; + + if (!eap_server_active(esp)) + return; + ++ 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; ++ } ++ + /* EAP ID number must not change on timeout. */ + eap_send_request(esp); + } +@@ -1166,6 +1324,79 @@ + } + #endif /* USE_SRP */ + ++/* ++ * 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); ++ ++} ++ + static void + eap_send_nak(esp, id, type) + eap_state *esp; +@@ -1320,6 +1551,8 @@ + char rhostname[256]; + MD5_CTX mdContext; + u_char hash[MD5_SIGNATURE_SIZE]; ++ u_char flags; ++ struct eaptls_session *ets = esp->es_client.ea_session; + #ifdef USE_SRP + struct t_client *tc; + struct t_num sval, gval, Nval, *Ap, Bval; +@@ -1442,7 +1675,7 @@ + if (!get_secret(esp->es_unit, esp->es_client.ea_name, + rhostname, secret, &secret_len, 0)) { + dbglog("EAP: no MD5 secret for auth to %q", rhostname); +- eap_send_nak(esp, id, EAPT_SRP); ++ eap_send_nak(esp, id, EAPT_TLS); + break; + } + MD5_Init(&mdContext); +@@ -1456,6 +1689,85 @@ + esp->es_client.ea_namelen); + break; + ++ case EAPT_TLS: ++ ++ switch(esp->es_client.ea_state) { ++ ++ case eapListen: ++ ++ GETCHAR(flags, inp); ++ if(flags & EAP_TLS_FLAGS_START){ ++ ++ esp->es_client.ea_using_eaptls = 1; ++ ++ if (explicit_remote){ ++ esp->es_client.ea_peer = strdup(remote_name); ++ esp->es_client.ea_peerlen = strlen(remote_name); ++ } else ++ esp->es_client.ea_peer = NULL; ++ ++ /* Init ssl session */ ++ if(!eaptls_init_ssl_client(esp)) { ++ dbglog("cannot init ssl"); ++ eap_send_nak(esp, id, EAPT_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 = (ets->frag ? eapTlsRecvAck : ++ eapTlsRecv); ++ break; ++ } ++ ++ /* The server has sent a bad start packet. */ ++ eap_send_nak(esp, id, EAPT_SRP); ++ break; ++ ++ case eapTlsRecvAck: ++ eap_tls_response(esp, id); ++ esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : ++ eapTlsRecv); ++ break; ++ ++ case eapTlsRecv: ++ eaptls_receive(ets, inp, len); ++ ++ if(ets->frag) { ++ eap_tls_sendack(esp, id); ++ esp->es_client.ea_state = eapTlsRecv; ++ break; ++ } ++ ++ if(ets->alert_recv) { ++ eap_tls_sendack(esp, id); ++ esp->es_client.ea_state = eapTlsRecvFailure; ++ break; ++ } ++ ++ /* Check if TLS handshake is finished */ ++ if(SSL_is_init_finished(ets->ssl)){ ++ 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_SRP); ++ esp->es_client.ea_using_eaptls = 0; ++ break; ++ } ++ ++ break; ++ + #ifdef USE_SRP + case EAPT_SRP: + if (len < 1) { +@@ -1690,7 +2002,7 @@ + + default: + info("EAP: unknown authentication type %d; Naking", typenum); +- eap_send_nak(esp, id, EAPT_SRP); ++ eap_send_nak(esp, id, EAPT_TLS); + break; + } + +@@ -1730,6 +2042,8 @@ + char rhostname[256]; + MD5_CTX mdContext; + u_char hash[MD5_SIGNATURE_SIZE]; ++ struct eaptls_session *ets; ++ u_char flags; + #ifdef USE_SRP + struct t_server *ts; + struct t_num A; +@@ -1776,6 +2090,54 @@ + eap_figure_next_state(esp, 0); + break; + ++ case EAPT_TLS: ++ switch(esp->es_server.ea_state) { ++ ++ case eapTlsRecv: ++ ets = (struct eaptls_session *) esp->es_server.ea_session; ++ eap_figure_next_state(esp, ++ eaptls_receive(esp->es_server.ea_session, inp, len)); ++ ++ if(ets->alert_recv) { ++ eap_send_failure(esp); ++ break; ++ } ++ break; ++ ++ case eapTlsRecvAck: ++ if(len > 1) { ++ dbglog("EAP-TLS ACK with extra data"); ++ } ++ eap_figure_next_state(esp, 0); ++ break; ++ ++ case eapTlsRecvClient: ++ /* Receive authentication response from client */ ++ ++ GETCHAR(flags, inp); ++ ++ if(len == 1 && !flags) /* Ack = ok */ ++ eap_send_success(esp); ++ else { /* failure */ ++ eaptls_receive(esp->es_server.ea_session, inp, len); ++ warn("Server authentication failed"); ++ eap_send_failure(esp); ++ } ++ ++ eaptls_free_session(esp->es_server.ea_session); ++ ++ break; ++ ++ case eapTlsRecvAlertAck: ++ eap_send_failure(esp); ++ break; ++ ++ default: ++ eap_figure_next_state(esp, 1); ++ break; ++ } ++ break; ++ + case EAPT_NOTIFICATION: + dbglog("EAP unexpected Notification; response discarded"); + break; +@@ -1807,6 +2169,11 @@ + esp->es_server.ea_state = eapMD5Chall; + break; + ++ /* Send EAP-TLS start packet */ ++ case EAPT_TLS: ++ esp->es_server.ea_state = eapTlsStart; ++ break; ++ + default: + dbglog("EAP: peer requesting unknown Type %d", vallen); + switch (esp->es_server.ea_state) { +@@ -2018,13 +2385,22 @@ + 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 != eapTlsRecvSuccess) { + 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 && 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; ++ } ++ + if (esp->es_client.ea_timeout > 0) { + UNTIMEOUT(eap_client_timeout, (void *)esp); + } +@@ -2150,6 +2526,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 +2591,22 @@ + } + 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; +@@ -2325,6 +2718,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_NAK: + if (len <= 0) { + printer(arg, " "); +@@ -2426,3 +2836,5 @@ + + return (inp - pstart); + } ++ ++ +diff -Naur ppp-2.4.3/pppd/eap.h ppp-2.4.3-eaptls-0.7/pppd/eap.h +--- ppp-2.4.3/pppd/eap.h 2003-06-12 01:56:26.000000000 +0200 ++++ ppp-2.4.3-eaptls-0.7/pppd/eap.h 2005-03-07 09:25:12.000000000 +0100 +@@ -84,6 +84,18 @@ + eapClosed, /* Authentication not in use */ + eapListen, /* Client ready (and timer running) */ + eapIdentify, /* EAP Identify sent */ ++ ++ eapTlsStart, /* Send EAP-TLS start packet */ ++ eapTlsRecv, /* Receive EAP-TLS tls data */ ++ eapTlsSendAck, /* Send EAP-TLS ack */ ++ eapTlsSend, /* Send EAP-TLS tls data */ ++ eapTlsRecvAck, /* Receive EAP-TLS ack */ ++ eapTlsRecvClient, /* Receive EAP-TLS auth response from client*/ ++ eapTlsSendAlert, /* Send EAP-TLS tls alert (server)*/ ++ eapTlsRecvAlertAck, /* Receive EAP-TLS ack after sending alert */ ++ eapTlsRecvSuccess, /* Receive EAP success */ ++ eapTlsRecvFailure, /* Receive EAP failure */ ++ + eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */ + eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */ + eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */ +@@ -95,9 +107,13 @@ + + #define EAP_STATES \ + "Initial", "Pending", "Closed", "Listen", "Identify", \ ++ "TlsStart", "TlsRecv", "TlsSendAck", "TlsSend", "TlsRecvAck", "TlsRecvClient",\ ++ "TlsSendAlert", "TlsRecvAlertAck" , "TlsRecvSuccess", "TlsRecvFailure", \ + "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth" + +-#define eap_client_active(esp) ((esp)->es_client.ea_state == eapListen) ++#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_server_active(esp) \ + ((esp)->es_server.ea_state >= eapIdentify && \ + (esp)->es_server.ea_state <= eapMD5Chall) +@@ -112,11 +128,13 @@ + u_short ea_namelen; /* Length of our name */ + u_short ea_peerlen; /* Length of peer's name */ + enum eap_state_code ea_state; ++ enum eap_state_code ea_prev_state; + 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 */ ++ bool ea_using_eaptls; + }; + + /* +@@ -139,7 +157,8 @@ + * Timeouts. + */ + #define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */ +-#define EAP_DEFTRANSMITS 10 /* max # times to transmit */ ++#define EAP_DEFTRANSMITS 30 /* max # times to transmit */ ++ /* certificates can be long ... */ + #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-0.7/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-0.7/pppd/eap-tls.c 2005-03-21 14:39:48.000000000 +0100 +@@ -0,0 +1,1270 @@ ++/* ++ * 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_ssl_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; ++ ++ /* ++ * 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->alert_sent = 0; ++ ets->alert_recv = 0; ++ ++ /* ++ * If we specified the client certificate file, store it in ets->peercertfile, ++ * so we can check it later in ssl_verify_callback() ++ */ ++ if (clicertfile[0]) ++ strncpy(&ets->peercertfile[0], clicertfile, MAXWORDLEN); ++ else ++ ets->peercertfile[0] = 0; ++ ++ return 1; ++ ++ fail: ++ ERR_print_errors_fp(stderr); ++ 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; ++ 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->alert_sent = 0; ++ ets->alert_recv = 0; ++ ++ /* ++ * If we specified the server certificate file, store it in ++ * ets->peercertfile, so we can check it later in ++ * ssl_verify_callback() ++ */ ++ if (servcertfile[0]) ++ strncpy(ets->peercertfile, servcertfile, MAXWORDLEN); ++ else ++ ets->peercertfile[0] = 0; ++ ++ return 1; ++ fail: ++ ERR_print_errors_fp(stderr); ++ SSL_CTX_free(ets->ctx); ++ return 0; ++ ++} ++ ++/* ++ * Updates the CA CRL ++ */ ++void eaptls_update_crls(char *crldir, char *cacertfile, struct wordlist *uf) ++{ ++ FILE *file; ++ X509 *cert; ++ char *filename; ++ ++ if (!(file = fopen(cacertfile, "r"))) ++ return; ++ ++ filename = malloc(strlen(crldir) + 15); ++ ++ /* ++ * for each CA certificate, control if the CRL must be updated ++ */ ++ while ((cert = PEM_read_X509(file, NULL, NULL, NULL))) { ++ ++ if (eaptls_must_update(cert, crldir, filename, uf) == 1) { ++ ++ eaptls_get_crl(cert, filename); ++ add_wordlist(uf, filename); ++ } ++ ++ } ++ ++ free(filename); ++ fclose(file); ++ ++} ++ ++/* ++ * Control if the CA CRL must be updated ++ * Return in filename the file to be updated ++ */ ++int eaptls_must_update(X509 * cert, char *crldir, char *filename, ++ struct wordlist *uf) ++{ ++ X509_NAME *xn; ++ unsigned long hash; ++ int found = 0, i, hours; ++ FILE *file; ++ X509_CRL *crl; ++ time_t curr_time, mod_time; ++ struct stat file_stat; ++ char tmpname[15]; ++ char subject[256]; ++ char cn_str[256]; ++ ++ /* ++ * Get CA subject name and calculate its hash ++ */ ++ xn = X509_get_subject_name(cert); ++ hash = X509_NAME_hash(xn); ++ ++ X509_NAME_oneline(xn, subject, 256); ++ X509_NAME_get_text_by_NID(xn, NID_commonName, cn_str, 256); ++ dbglog(" -> processing CA: %s", cn_str); ++ ++ /* ++ * Search a CRL for this CA in crldir ++ */ ++ for (i = 0; i < 10; i++) { ++ sprintf(tmpname, "%08lx.r%1d", hash, i); ++ strcpy(filename, crldir); ++ strcat(filename, "/"); ++ strcat(filename, tmpname); ++ ++ if (!(file = fopen(filename, "r"))) ++ break; /* CRL not found */ ++ ++ if (!(crl = PEM_read_X509_CRL(file, NULL, NULL, NULL))) { ++ fclose(file); ++ continue; ++ } ++ fclose(file); ++ ++ /* ++ * test if it's the right CRL ++ */ ++ if (X509_NAME_cmp(xn, X509_CRL_get_issuer(crl)) == 0) { ++ found = 1; ++ X509_CRL_free(crl); ++ break; ++ } ++ X509_CRL_free(crl); ++ } ++ ++ /* ++ * If file already in list, we've already updated it ++ */ ++ if (search_wordlist(uf, filename) == 1) ++ return 0; ++ ++ /* ++ * If CRL file for this CA not found, need update ++ */ ++ if (!found) ++ return 1; ++ ++ curr_time = time(NULL); ++ stat(filename, &file_stat); ++ mod_time = file_stat.st_mtime; ++ hours = (curr_time - mod_time) / 3600; ++ ++ /* ++ * If file too old, need update ++ */ ++ if (hours >= crl_update_time) { ++ dbglog(" file %s is %d hours old, need update", ++ filename, hours); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Extract CDPs from certificate ++ */ ++void eaptls_get_crl(X509 * cert, char *filename) ++{ ++ STACK_OF(DIST_POINT) * distpoints = NULL; ++ DIST_POINT *dp; ++ DIST_POINT_NAME *dpn; ++ STACK_OF(GENERAL_NAME) * names; ++ GENERAL_NAME *name; ++ ASN1_IA5STRING *uri_asn; ++ char *uri; ++ int num_dp, i; ++ int num_name, j; ++ ++ distpoints = X509_get_ext_d2i(cert, ++ NID_crl_distribution_points, NULL, NULL); ++ num_dp = sk_DIST_POINT_num(distpoints); ++ ++ dbglog(" CA certificate contains %d CDP", num_dp); ++ ++ for (i = 0; i < num_dp; i++) { ++ ++ dp = sk_DIST_POINT_value(distpoints, i); ++ dpn = dp->distpoint; ++ names = dpn->name.fullname; ++ num_name = sk_GENERAL_NAME_num(names); ++ ++ for (j = 0; j < num_name; j++) { ++ ++ name = sk_GENERAL_NAME_value(names, j); ++ ++ if (name->type == GEN_URI) { ++ uri_asn = name->d.uniformResourceIdentifier; ++ uri = ASN1_STRING_data(uri_asn); ++ ++ if (eaptls_download_crl(uri, filename)) { ++ dbglog ++ (" * %s successfully loaded", ++ uri); ++ return; ++ } ++ ++ } ++ ++ } ++ } ++} ++ ++/* ++ * Download a CRL from uri into file ++ */ ++int eaptls_download_crl(char *uri, char *filename) ++{ ++ FILE *tmpfile; ++ FILE *destfile; ++ int tmpfd; ++ char tmpname[30]; ++ CURL *curl; ++ int res; ++ X509_CRL *crl; ++ ++ strcpy(tmpname, "/tmp/ppp-tmp-XXXXXX"); ++ ++ if ((tmpfd = mkstemp(tmpname)) == -1) { ++ error("error creating temp file /tmp/ppp-tmp-*"); ++ return 0; ++ } ++ ++ tmpfile = fdopen(tmpfd, "w"); ++ if (!tmpfile) { ++ error("error fdopen"); ++ close(tmpfd); ++ return 0; ++ } ++ ++ /* ++ * download in temp file using libcurl ++ */ ++ curl_global_init(CURL_GLOBAL_NOTHING); ++ curl = curl_easy_init(); ++ curl_easy_setopt(curl, CURLOPT_URL, uri); ++ curl_easy_setopt(curl, CURLOPT_WRITEDATA, tmpfile); ++ ++ res = curl_easy_perform(curl); ++ ++ curl_easy_cleanup(curl); ++ curl_global_cleanup(); ++ ++ if (res != CURLE_OK) { ++ dbglog(" * %s download failed", uri); ++ fclose(tmpfile); ++ unlink(tmpname); ++ return 0; ++ } ++ ++ fclose(tmpfile); ++ tmpfile = fopen(tmpname, "r"); ++ if(!tmpfile) ++ return 0; ++ ++ /* ++ * load CRL from temp file ++ */ ++ crl = d2i_X509_CRL_fp(tmpfile, NULL); ++ ++ fclose(tmpfile); ++ unlink(tmpname); ++ ++ if (!crl) { ++ warn("cannot load DER CRL"); ++ return 0; ++ } ++ ++ destfile = fopen(filename, "w"); ++ if (!destfile) { ++ X509_CRL_free(crl); ++ return 0; ++ } ++ ++ /* ++ * write CRL in PEM format to destination file ++ */ ++ PEM_write_X509_CRL(destfile, crl); ++ ++ X509_CRL_free(crl); ++ fclose(destfile); ++ ++ return 1; ++} ++ ++void eaptls_free_session(struct eaptls_session *ets) ++{ ++ if (ets->ssl) ++ SSL_free(ets->ssl); ++ ++ if (ets->ctx) ++ SSL_CTX_free(ets->ctx); ++ ++ free(ets); ++} ++ ++/* ++ * Handle a received packet, reassembling fragmented messages and ++ * passing them to the ssl engine ++ */ ++int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len) ++{ ++ u_char flags; ++ u_int tlslen; ++ u_char dummy[65536]; ++ ++ GETCHAR(flags, inp); ++ len--; ++ ++ if (flags & EAP_TLS_FLAGS_LI) { ++ ++ /* ++ * This is the first packet of a message ++ */ ++ ++ if (ets->data) { ++ warn("EAP TLS: unexpected first fragment"); ++ return 1; ++ } ++ ++ GETLONG(tlslen, inp); ++ len -= 4; ++ ++ if (tlslen > EAP_TLS_MAX_LEN) { ++ error("Error: tls message length > %d, truncated", ++ EAP_TLS_MAX_LEN); ++ tlslen = EAP_TLS_MAX_LEN; ++ } ++ ++ /* ++ * Allocate memory for the whole message ++ */ ++ ets->data = malloc(tlslen); ++ if (!ets->data) ++ fatal("EAP TLS: allocation error\n"); ++ ++ ets->datalen = 0; ++ ets->tlslen = tlslen; ++ ++ } else if (!ets->data) { ++ ++ /* ++ * A non fragmented message without LI flag ++ */ ++ ++ ets->data = malloc(len); ++ if (!ets->data) ++ fatal("EAP TLS: allocation error\n"); ++ ++ ets->datalen = 0; ++ ets->tlslen = len; ++ } ++ ++ if (flags & EAP_TLS_FLAGS_MF) ++ ets->frag = 1; ++ else ++ ets->frag = 0; ++ ++ if (len + ets->datalen > ets->tlslen) { ++ warn("EAP TLS: received data > TLS message length"); ++ return 1; ++ } ++ ++ BCOPY(inp, ets->data + ets->datalen, len); ++ ets->datalen += len; ++ ++ if (!ets->frag) { ++ ++ /* ++ * If we have the whole message, pass it to ssl ++ */ ++ ++ if (ets->datalen != ets->tlslen) { ++ warn("EAP TLS: received data != TLS message length"); ++ return 1; ++ } ++ ++ if (BIO_write(ets->into_ssl, ets->data, ets->datalen) == -1) ++ ERR_print_errors_fp(stderr); ++ ++ SSL_read(ets->ssl, dummy, 65536); ++ ++ free(ets->data); ++ ets->data = NULL; ++ ets->datalen = 0; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Return an eap-tls packet in outp. ++ * A TLS message read from the ssl engine is buffered in ets->data. ++ * At each call we control if there is buffered data and send a ++ * packet of mtu bytes. ++ */ ++int eaptls_send(struct eaptls_session *ets, u_char ** outp) ++{ ++ bool first = 0; ++ int size; ++ u_char fromtls[65536]; ++ int res; ++ u_char *start; ++ ++ start = *outp; ++ ++ if (!ets->data) { ++ ++ if(!ets->alert_sent) ++ SSL_read(ets->ssl, fromtls, 65536); ++ ++ /* ++ * Read from ssl ++ */ ++ if ((res = BIO_read(ets->from_ssl, fromtls, 65536)) == -1) ++ fatal("No data from BIO_read"); ++ ++ ets->datalen = res; ++ ++ ets->data = malloc(ets->datalen); ++ BCOPY(fromtls, ets->data, ets->datalen); ++ ++ ets->offset = 0; ++ first = 1; ++ ++ } ++ ++ size = ets->datalen - ets->offset; ++ ++ if (size > ets->mtu) { ++ size = ets->mtu; ++ ets->frag = 1; ++ } else ++ ets->frag = 0; ++ ++ PUTCHAR(EAPT_TLS, *outp); ++ ++ /* ++ * Set right flags and length if necessary ++ */ ++ if (ets->frag && first) { ++ PUTCHAR(EAP_TLS_FLAGS_LI | EAP_TLS_FLAGS_MF, *outp); ++ PUTLONG(ets->datalen, *outp); ++ } else if (ets->frag) { ++ PUTCHAR(EAP_TLS_FLAGS_MF, *outp); ++ } else ++ PUTCHAR(0, *outp); ++ ++ /* ++ * Copy the data in outp ++ */ ++ BCOPY(ets->data + ets->offset, *outp, size); ++ INCPTR(size, *outp); ++ ++ /* ++ * Copy the packet in retransmission buffer ++ */ ++ BCOPY(start, &ets->rtx[0], *outp - start); ++ ets->rtx_len = *outp - start; ++ ++ ets->offset += size; ++ ++ if (ets->offset >= ets->datalen) { ++ ++ /* ++ * The whole message has been sent ++ */ ++ ++ free(ets->data); ++ ets->data = NULL; ++ ets->datalen = 0; ++ ets->offset = 0; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Get the sent packet from the retransmission buffer ++ */ ++void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp) ++{ ++ BCOPY(ets->rtx, *outp, ets->rtx_len); ++ INCPTR(ets->rtx_len, *outp); ++} ++ ++/* ++ * Verify a certificate. ++ * Most of the work (signatures and issuer attributes checking) ++ * is done by ssl; we check the CN in the peer certificate ++ * against the peer name. ++ */ ++int ssl_verify_callback(int preverify_ok, X509_STORE_CTX * ctx) ++{ ++ char subject[256]; ++ char cn_str[256]; ++ X509 *peer_cert; ++ int err, depth; ++ int ok = preverify_ok; ++ SSL *ssl; ++ struct eaptls_session *ets; ++ ++ peer_cert = X509_STORE_CTX_get_current_cert(ctx); ++ err = X509_STORE_CTX_get_error(ctx); ++ depth = X509_STORE_CTX_get_error_depth(ctx); ++ ++ dbglog("certificate verify depth: %d", depth); ++ ++ if (!ok) { ++ X509_NAME_oneline(X509_get_subject_name(peer_cert), ++ subject, 256); ++ ++ X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert), ++ NID_commonName, cn_str, 256); ++ ++ dbglog("Certificate verification error:\n depth: %d CN: %s" ++ "\n err: %d (%s)\n", depth, cn_str, err, ++ X509_verify_cert_error_string(err)); ++ ++ return 0; ++ } ++ ++ ssl = X509_STORE_CTX_get_ex_data(ctx, ++ SSL_get_ex_data_X509_STORE_CTX_idx()); ++ ++ ets = (struct eaptls_session *)SSL_get_ex_data(ssl, 0); ++ ++ if (ets == NULL) { ++ error("Error: SSL_get_ex_data returned NULL"); ++ return 0; ++ } ++ ++ 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->alert_sent = 1; ++ ets->alert_sent_desc = code; ++ } else { ++ ets->alert_recv = 1; ++ ets->alert_recv_desc = code; ++ } ++ ++ strcat(string, SSL_alert_desc_string_long(code)); ++ break; ++ ++ case SSL3_RT_CHANGE_CIPHER_SPEC: ++ strcat(string, "ChangeCipherSpec"); ++ break; ++ ++ case SSL3_RT_HANDSHAKE: ++ ++ strcat(string, "Handshake: "); ++ code = ((const unsigned char *)buf)[0]; ++ ++ switch(code) { ++ case SSL3_MT_HELLO_REQUEST: ++ strcat(string,"Hello Request"); ++ break; ++ case SSL3_MT_CLIENT_HELLO: ++ strcat(string,"Client Hello"); ++ break; ++ case SSL3_MT_SERVER_HELLO: ++ strcat(string,"Server Hello"); ++ break; ++ case SSL3_MT_CERTIFICATE: ++ strcat(string,"Certificate"); ++ break; ++ case SSL3_MT_SERVER_KEY_EXCHANGE: ++ strcat(string,"Server Key Exchange"); ++ break; ++ case SSL3_MT_CERTIFICATE_REQUEST: ++ strcat(string,"Certificate Request"); ++ break; ++ case SSL3_MT_SERVER_DONE: ++ strcat(string,"Server Hello Done"); ++ break; ++ case SSL3_MT_CERTIFICATE_VERIFY: ++ strcat(string,"Certificate Verify"); ++ break; ++ case SSL3_MT_CLIENT_KEY_EXCHANGE: ++ strcat(string,"Client Key Exchange"); ++ break; ++ case SSL3_MT_FINISHED: ++ strcat(string,"Finished"); ++ break; ++ } ++ break; ++ } ++ ++ /* Alert messages must always be displayed */ ++ if(content_type == SSL3_RT_ALERT) ++ error("%s", string); ++ else ++ dbglog("%s", string); ++} ++ ++/* ++ * Extract all CA files from conf file 'filename' and update crl ++ */ ++void eaptls_do_update(char *filename, struct wordlist *updatedfiles) ++{ ++ int newline; ++ FILE *f; ++ char word[MAXWORDLEN]; ++ ++ if (!(f = fopen(filename, "r"))) { ++ fprintf(stderr, "can't open %s", filename); ++ die(1); ++ } ++ ++ if (!getword(f, word, &newline, filename)) ++ return; /* file is empty??? */ ++ ++ newline = 1; ++ ++ for (;;) { ++ ++ /* ++ * Skip until we find a word at the start of a line. ++ */ ++ while (!newline && getword(f, word, &newline, filename)) ; ++ if (!newline) ++ break; /* got to end of file */ ++ ++ /* ++ * server ++ */ ++ if (!getword(f, word, &newline, filename)) ++ break; ++ if (newline) ++ continue; ++ ++ /* ++ * client cert ++ */ ++ if (!getword(f, word, &newline, filename)) ++ break; ++ if (newline) ++ continue; ++ ++ /* ++ * server cert ++ */ ++ if (!getword(f, word, &newline, filename)) ++ break; ++ if (newline) ++ continue; ++ ++ /* ++ * ca cert ++ */ ++ if (!getword(f, word, &newline, filename)) ++ break; ++ if (newline) ++ continue; ++ ++ printf("Updating CRLs for CA file %s\n", word); ++ ++ eaptls_update_crls(crl_dir, word, updatedfiles); ++ } ++ ++ fclose(f); ++} ++ ++void eaptls_only_update_crl(int server, int client) ++{ ++ /* ++ * mantain a list of updated crl files, so if a CA appears more ++ * times, it is updated once ++ */ ++ struct wordlist updatedfiles; ++ ++ updatedfiles.next = NULL; ++ updatedfiles.word = NULL; ++ ++ if (server) ++ eaptls_do_update(_PATH_EAPTLSSERVFILE, &updatedfiles); ++ ++ if (client) ++ eaptls_do_update(_PATH_EAPTLSCLIFILE, &updatedfiles); ++ ++ destroy_wordlist(&updatedfiles); ++} ++ ++static int search_wordlist(struct wordlist *wl, char *word) ++{ ++ struct wordlist *tmp = wl->next; ++ ++ while (tmp) { ++ if (strcmp(tmp->word, word) == 0) ++ return 1; ++ tmp = tmp->next; ++ } ++ return 0; ++} ++ ++static void add_wordlist(struct wordlist *wl, char *word) ++{ ++ struct wordlist *tmp = wl; ++ ++ while (tmp->next) ++ tmp = tmp->next; ++ ++ tmp->next = malloc(sizeof(struct wordlist)); ++ tmp->next->word = strdup(word); ++ tmp->next->next = NULL; ++ ++} ++ ++static void destroy_wordlist(struct wordlist *wl) ++{ ++ struct wordlist *tmp = wl->next; ++ struct wordlist *next; ++ ++ while (tmp) { ++ next = tmp->next; ++ ++ if (tmp->word) ++ free(tmp->word); ++ ++ free(tmp); ++ tmp = next; ++ } ++ ++} +diff -Naur ppp-2.4.3/pppd/eap-tls.h ppp-2.4.3-eaptls-0.7/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-0.7/pppd/eap-tls.h 2005-03-21 14:58:51.268855248 +0100 +@@ -0,0 +1,99 @@ ++/* ++ * 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 */ ++ ++#define EAP_TLS_MAX_LEN 65536 /* max eap tls packet size */ ++ ++#define CRL_UPDATE_TIME 72 /* update time for crl: 72 hours */ ++ ++struct eaptls_session { ++ u_char *data; /* buffered data */ ++ int datalen; /* buffered data len */ ++ int offset; /* from where to send */ ++ int tlslen; /* total length of tls data */ ++ bool frag; /* packet is fragmented */ ++ SSL_CTX *ctx; ++ SSL *ssl; /* ssl connection */ ++ BIO *from_ssl; ++ BIO *into_ssl; ++ char peer[MAXWORDLEN]; /* peer name */ ++ char peercertfile[MAXWORDLEN]; ++ bool alert_sent; ++ u_char alert_sent_desc; ++ bool alert_recv; ++ u_char alert_recv_desc; ++ char rtx[65536]; /* retransmission buffer */ ++ int rtx_len; ++ int mtu; /* unit mtu */ ++}; ++ ++int ssl_verify_callback(int, X509_STORE_CTX *); ++void ssl_msg_callback(int write_p, int version, int ct, const void *buf, ++ size_t len, SSL * ssl, void *arg); ++ ++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_ssl_server(eap_state * esp); ++int eaptls_init_ssl_client(eap_state * esp); ++void eaptls_free_session(struct eaptls_session *ets); ++ ++int eaptls_receive(struct eaptls_session *ets, u_char * inp, int len); ++int eaptls_send(struct eaptls_session *ets, u_char ** outp); ++void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp); ++ ++int get_eaptls_secret(int unit, char *client, char *server, ++ char *clicertfile, char *servcertfile, char *cacertfile, ++ char *pkfile, int am_server); ++ ++void eaptls_update_crls(char *crldir, char *cacertfile, struct wordlist *wl); ++int eaptls_must_update(X509 * cert, char *crldir, char *filename, ++ struct wordlist *wl); ++void eaptls_get_crl(X509 * cert, char *filename); ++int eaptls_download_crl(char *uri, char *filename); ++ ++#endif +diff -Naur ppp-2.4.3/pppd/main.c ppp-2.4.3-eaptls-0.7/pppd/main.c +--- ppp-2.4.3/pppd/main.c 2004-11-13 13:05:48.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/pppd/main.c 2005-03-09 11:48:26.000000000 +0100 +@@ -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-0.7/pppd/Makefile.linux +--- ppp-2.4.3/pppd/Makefile.linux 2004-11-13 13:02:22.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/pppd/Makefile.linux 2005-03-18 10:47:31.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-0.7/pppd/options.c +--- ppp-2.4.3/pppd/options.c 2004-11-09 23:33:35.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/pppd/options.c 2005-03-09 10:25:12.000000000 +0100 +@@ -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-0.7/pppd/pathnames.h +--- ppp-2.4.3/pppd/pathnames.h 2004-11-13 13:02:22.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/pppd/pathnames.h 2005-02-28 17:38:17.000000000 +0100 +@@ -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-0.7/pppd/pppd.h +--- ppp-2.4.3/pppd/pppd.h 2004-11-13 13:02:22.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/pppd/pppd.h 2005-03-09 10:26:18.000000000 +0100 +@@ -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-0.7/README.eap-tls +--- ppp-2.4.3/README.eap-tls 1970-01-01 01:00:00.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/README.eap-tls 2005-03-21 15:14:01.872422464 +0100 +@@ -0,0 +1,147 @@ ++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. 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-0.7/solaris/Makefile.top +--- ppp-2.4.3/solaris/Makefile.top 2004-11-01 10:31:07.000000000 +0100 ++++ ppp-2.4.3-eaptls-0.7/solaris/Makefile.top 2005-03-07 11:42:57.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 $@ diff -Naur /usr/portage/net-dialup/ppp/files/ppp-2.4.3-eaptls-mppe-0.7.patch /usr/local/portage/net-dialup/ppp/files/ppp-2.4.3-eaptls-mppe-0.7.patch --- /usr/portage/net-dialup/ppp/files/ppp-2.4.3-eaptls-mppe-0.7.patch 1970-01-01 01:00:00.000000000 +0100 +++ /usr/local/portage/net-dialup/ppp/files/ppp-2.4.3-eaptls-mppe-0.7.patch 2005-10-18 15:59:46.000000000 +0200 @@ -0,0 +1,217 @@ +--- ppp-2.4.3/pppd/ccp.c 2004-11-13 03:28:15.000000000 +0100 ++++ ppp-2.4.3-eap-tls-mppe/pppd/ccp.c 2005-10-17 14:45:28.000000000 +0200 +@@ -540,6 +540,7 @@ + if (go->mppe) { + ccp_options *ao = &ccp_allowoptions[f->unit]; + int auth_mschap_bits = auth_done[f->unit]; ++ int auth_eap_bits = auth_done[f->unit]; + int numbits; + + /* +@@ -567,8 +568,18 @@ + lcp_close(f->unit, "MPPE required but not available"); + return; + } +- if (!numbits) { +- error("MPPE required, but MS-CHAP[v2] auth not performed."); ++ ++ /* ++ * 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."); + lcp_close(f->unit, "MPPE required but not available"); + return; + } +--- ppp-2.4.3/pppd/eap-tls.c 2005-10-17 14:57:22.000000000 +0200 ++++ ppp-2.4.3-eap-tls-mppe/pppd/eap-tls.c 2005-10-17 14:41:40.000000000 +0200 +@@ -35,7 +35,7 @@ + #include + #include + +-#include ++#include + #include + #include + #include +@@ -53,6 +53,120 @@ + static void add_wordlist(struct wordlist *wl, char *word); + static void destroy_wordlist(struct wordlist *wl); + ++#ifdef MPPE ++ ++/* ++ * TLS PRF from RFC 2246 ++ */ ++static void P_hash(const EVP_MD *evp_md, ++ const unsigned char *secret, unsigned int secret_len, ++ const unsigned char *seed, unsigned int seed_len, ++ unsigned char *out, unsigned int out_len) ++{ ++ HMAC_CTX ctx_a, ctx_out; ++ unsigned char a[HMAC_MAX_MD_CBLOCK]; ++ unsigned int size; ++ ++ HMAC_CTX_init(&ctx_a); ++ HMAC_CTX_init(&ctx_out); ++ HMAC_Init_ex(&ctx_a, secret, secret_len, evp_md, NULL); ++ HMAC_Init_ex(&ctx_out, secret, secret_len, evp_md, NULL); ++ ++ size = HMAC_size(&ctx_out); ++ ++ /* Calculate A(1) */ ++ HMAC_Update(&ctx_a, seed, seed_len); ++ HMAC_Final(&ctx_a, a, NULL); ++ ++ while (1) { ++ /* Calculate next part of output */ ++ HMAC_Update(&ctx_out, a, size); ++ HMAC_Update(&ctx_out, seed, seed_len); ++ ++ /* Check if last part */ ++ if (out_len < size) { ++ HMAC_Final(&ctx_out, a, NULL); ++ memcpy(out, a, out_len); ++ break; ++ } ++ ++ /* Place digest in output buffer */ ++ HMAC_Final(&ctx_out, out, NULL); ++ HMAC_Init_ex(&ctx_out, NULL, 0, NULL, NULL); ++ out += size; ++ out_len -= size; ++ ++ /* Calculate next A(i) */ ++ HMAC_Init_ex(&ctx_a, NULL, 0, NULL, NULL); ++ HMAC_Update(&ctx_a, a, size); ++ HMAC_Final(&ctx_a, a, NULL); ++ } ++ ++ HMAC_CTX_cleanup(&ctx_a); ++ HMAC_CTX_cleanup(&ctx_out); ++ memset(a, 0, sizeof(a)); ++} ++ ++static void PRF(const unsigned char *secret, unsigned int secret_len, ++ const unsigned char *seed, unsigned int seed_len, ++ unsigned char *out, unsigned char *buf, unsigned int out_len) ++{ ++ unsigned int i; ++ unsigned int len = (secret_len + 1) / 2; ++ const unsigned char *s1 = secret; ++ const unsigned char *s2 = secret + (secret_len - len); ++ ++ P_hash(EVP_md5(), s1, len, seed, seed_len, out, out_len); ++ P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len); ++ ++ for (i=0; i < out_len; i++) { ++ out[i] ^= buf[i]; ++ } ++} ++ ++#define EAPTLS_MPPE_KEY_LEN 32 ++ ++/* ++ * Generate keys according to RFC 2716 and add to reply ++ */ ++void eaptls_gen_mppe_keys(struct eaptls_session *ets, const char *prf_label) ++{ ++ unsigned char out[4*EAPTLS_MPPE_KEY_LEN], buf[4*EAPTLS_MPPE_KEY_LEN]; ++ unsigned char seed[64 + 2*SSL3_RANDOM_SIZE]; ++ unsigned char *p = seed; ++ SSL *s = ets->ssl; ++ size_t prf_size; ++ ++ prf_size = strlen(prf_label); ++ ++ memcpy(p, prf_label, prf_size); ++ p += prf_size; ++ ++ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); ++ p += SSL3_RANDOM_SIZE; ++ prf_size += SSL3_RANDOM_SIZE; ++ ++ memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE); ++ prf_size += SSL3_RANDOM_SIZE; ++ ++ PRF(s->session->master_key, s->session->master_key_length, ++ seed, prf_size, out, buf, sizeof(out)); ++ ++ /* ++ * We now have the master send and receive keys. ++ * From these, generate the session send and receive keys. ++ * (see RFC3079 / draft-ietf-pppext-mppe-keys-03.txt for details) ++ */ ++ 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 ++ + /* + * Tests if certificates, key and crl for server use can be loaded. + */ +@@ -190,8 +304,8 @@ + */ + if (servcertfile[0]) { + if (!(tmp = get_X509_from_file(servcertfile))) { +- warn("Error loading client certificate from file %s", +- clicertfile); ++ warn("Error loading server certificate from file %s", ++ servcertfile); + goto fail; + } + X509_free(tmp); +--- ppp-2.4.3/pppd/eap-tls.h 2005-10-17 14:57:22.000000000 +0200 ++++ ppp-2.4.3-eap-tls-mppe/pppd/eap-tls.h 2005-10-18 09:24:28.342960526 +0200 +@@ -96,4 +96,14 @@ + void eaptls_get_crl(X509 * cert, char *filename); + int eaptls_download_crl(char *uri, char *filename); + ++#ifdef MPPE ++#include /* MPPE_MAX_KEY_LEN */ ++extern u_char mppe_send_key[MPPE_MAX_KEY_LEN]; ++extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; ++extern int mppe_keys_set; ++ ++void eaptls_gen_mppe_keys(struct eaptls_session *ets, const char *prf_label); ++ ++#endif ++ + #endif +--- ppp-2.4.3/pppd/eap.c 2005-10-17 14:57:22.000000000 +0200 ++++ ppp-2.4.3-eap-tls-mppe/pppd/eap.c 2005-10-18 09:25:17.175205819 +0200 +@@ -2116,15 +2116,22 @@ + + GETCHAR(flags, inp); + +- if(len == 1 && !flags) /* Ack = ok */ ++ if(len == 1 && !flags) { /* Ack = ok */ ++#ifdef MPPE ++ eaptls_gen_mppe_keys( esp->es_server.ea_session, "client EAP encryption" ); ++#endif + eap_send_success(esp); ++ } + else { /* failure */ + eaptls_receive(esp->es_server.ea_session, inp, len); + warn("Server authentication failed"); + eap_send_failure(esp); + } + ++#ifndef MPPE ++ /* how can we determine if MPPE is required? */ + eaptls_free_session(esp->es_server.ea_session); ++#endif + + break; + diff -Naur /usr/portage/net-dialup/ppp/Manifest /usr/local/portage/net-dialup/ppp/Manifest --- /usr/portage/net-dialup/ppp/Manifest 2005-09-24 11:05:49.000000000 +0200 +++ /usr/local/portage/net-dialup/ppp/Manifest 2005-10-20 21:17:13.000000000 +0200 @@ -1,24 +1,26 @@ +MD5 06756b9843bf54824792153605bcac28 ppp-2.4.2-r12.ebuild 6935 +MD5 6205d840f3f2fda06c502408de02a298 ppp-2.4.3-r8.ebuild 9523 MD5 1679bdc947d662d842ffba712c44bc94 ChangeLog 22834 +MD5 ff2e9f24c17c1fa83d260539af3149cb ppp-2.4.2-r15.ebuild 7411 MD5 e6fdfdc4317d7fe324c50bd0477ca3f8 metadata.xml 295 MD5 fc56767c28bef6332decb0a5c48cad83 ppp-2.4.2-r10.ebuild 6209 -MD5 06756b9843bf54824792153605bcac28 ppp-2.4.2-r12.ebuild 6935 -MD5 ff2e9f24c17c1fa83d260539af3149cb ppp-2.4.2-r15.ebuild 7411 -MD5 2b7d702806660278ad8fc0f38b3cb842 ppp-2.4.3-r8.ebuild 8082 -MD5 1fd88dda7f4996799c69a9501d42cc23 files/README.mpls 530 +MD5 4e62cdeb360ca0a22becbd2deb6f2dac files/pon 957 +MD5 86cdaf133f7a79fb464f02d83afc7734 files/plog 146 +MD5 05b7394b35a2342033b52134568bf6b8 files/poff 2723 +MD5 2890b47660f967a07ac5b211850e46c5 files/options-pptp 238 MD5 140bc2a08334d3546f43259934da603e files/chat-default 347 +MD5 341c2661a11f00fdd1043a4d4e82977e files/ip-up 1083 +MD5 44cc662ba9aa61dd9add3ddd4c5ded57 files/pon.1 3607 MD5 c9117abf5fed623d5290779446e9855e files/confd.ppp0 2775 MD5 d90deeaef8dbdfcd18d1567681d03559 files/digest-ppp-2.4.2-r10 271 MD5 d90deeaef8dbdfcd18d1567681d03559 files/digest-ppp-2.4.2-r12 271 -MD5 5a554e2a04b9e11bb5bea839213bf97c files/ip-down 931 -MD5 341c2661a11f00fdd1043a4d4e82977e files/ip-up 1083 -MD5 5d83af7b897082a0b1ecd70a2cc2a0c7 files/modules.ppp 268 -MD5 2f3f8eb46b9d97a435a8694683f84651 files/net.ppp0 4408 -MD5 fa2a5b8df496922fa2fb592115953b6b files/options-pppoe 53 -MD5 2890b47660f967a07ac5b211850e46c5 files/options-pptp 238 -MD5 86cdaf133f7a79fb464f02d83afc7734 files/plog 146 -MD5 05b7394b35a2342033b52134568bf6b8 files/poff 2723 -MD5 4e62cdeb360ca0a22becbd2deb6f2dac files/pon 957 -MD5 44cc662ba9aa61dd9add3ddd4c5ded57 files/pon.1 3607 -MD5 f0ad3e0c62aec1771536caf00e28b9c6 files/pppoe.html 7605 MD5 23a7e77ad13ddd12f281fe134508e52f files/digest-ppp-2.4.2-r15 271 +MD5 fa2a5b8df496922fa2fb592115953b6b files/options-pppoe 53 +MD5 2f3f8eb46b9d97a435a8694683f84651 files/net.ppp0 4408 +MD5 af39f6df6bcd564f9ff725f3ab457ae4 files/ppp-2.4.3-eaptls-mppe-0.7.patch 6308 MD5 b7ba474b501edf4a1179142b306bdcd0 files/digest-ppp-2.4.3-r8 195 +MD5 1fd88dda7f4996799c69a9501d42cc23 files/README.mpls 530 +MD5 5d83af7b897082a0b1ecd70a2cc2a0c7 files/modules.ppp 268 +MD5 0dcb7dd0a688a256ca520727b5fc36d4 files/ppp-2.4.3-eaptls-0.7.patch 72420 +MD5 5a554e2a04b9e11bb5bea839213bf97c files/ip-down 931 +MD5 f0ad3e0c62aec1771536caf00e28b9c6 files/pppoe.html 7605 diff -Naur /usr/portage/net-dialup/ppp/ppp-2.4.3-r8.ebuild /usr/local/portage/net-dialup/ppp/ppp-2.4.3-r8.ebuild --- /usr/portage/net-dialup/ppp/ppp-2.4.3-r8.ebuild 2005-09-23 01:05:52.000000000 +0200 +++ /usr/local/portage/net-dialup/ppp/ppp-2.4.3-r8.ebuild 2005-10-20 21:05:11.000000000 +0200 @@ -13,13 +13,15 @@ LICENSE="BSD GPL-2" SLOT="0" KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~mips ~ppc ~ppc64 ~sparc ~x86" -IUSE="activefilter atm dhcp gtk ipv6 mppe-mppc pam radius" +IUSE="activefilter atm dhcp eap-tls gtk ipv6 mppe-mppc pam radius" RDEPEND="virtual/libc activefilter? ( >=virtual/libpcap-0.9.3 ) atm? ( net-dialup/linux-atm ) pam? ( sys-libs/pam ) - gtk? ( =x11-libs/gtk+-1* )" + gtk? ( =x11-libs/gtk+-1* ) + eap-tls? ( net-misc/curl ) + eap-tls? ( dev-libs/openssl )" DEPEND="${RDEPEND} >=sys-apps/sed-4" @@ -68,6 +70,28 @@ sed -i "s/#HAVE_INET6/HAVE_INET6/" pppd/Makefile.linux } + use eap-tls && { + einfo "Adding support of authenticating with certificates..." + cp ${FILESDIR}/ppp-2.4.3-eaptls-0.7.patch ${WORKDIR}/patch/ + sed -i "s/ eap\.c chap-md5\.c$/ eap.c chap-md5.c mplscp.c/" ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + sed -i "s/ eap\.c chap-md5\.c eap-tls\.c$/ eap.c chap-md5.c mplscp.c eap-tls.c/" ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + sed -i "s/ eap\.o chap-md5\.o$/ eap.o chap-md5.o mplscp.o/" ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + sed -i "s/ eap\.o chap-md5\.o eap-tls\.o$/ eap.o chap-md5.o mplscp.o eap-tls.o/" ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + sed -i "s/^-.*upap\.h eap\.h/- upap.h eap.h mplscp.h/" ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + sed -i "s/^\+.*upap\.h eap\.h eap-tls\.h$/+ upap.h eap.h mplscp.h eap-tls.h/" ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + sed -i "s/^-COPTS = -O2 -pipe -Wall -g$/-COPTS+= -Wall/" ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + sed -i "s|^\+COPTS = -O2 -pipe -Wall -g -I/usr/kerberos/include|+COPTS+= -Wall -I/usr/kerberos/include|" ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + epatch ${WORKDIR}/patch/ppp-2.4.3-eaptls-0.7.patch + } + + use eap-tls && use mppe-mppc && { + einfo "Allowing MPPE to work with autentification with certificates..." + opt="$EPATCH_OPTS" + EPATCH_OPTS="-l" + epatch ${FILESDIR}/ppp-2.4.3-eaptls-mppe-0.7.patch + EPATCH_OPTS="$opt" + } + einfo "Enabling CBCP" sed -i "s/^#CBCP=y/CBCP=y/" ${S}/pppd/Makefile.linux