X-Git-Url: https://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Feap.c;h=aa14208ec644534d27a9d4d8a89c21124c4fb71c;hp=1b93db01aebd7a2b6ca2dd8ed9848222cacdd997;hb=e87fe1bbd37a1486c5223f110e9ce3ef75971f93;hpb=8d7970b8f3db727fe798b65f3377fe6787575426 diff --git a/pppd/eap.c b/pppd/eap.c index 1b93db0..aa14208 100644 --- a/pppd/eap.c +++ b/pppd/eap.c @@ -43,6 +43,11 @@ * Based on draft-ietf-pppext-eap-srp-03.txt. */ +/* + * Modification by Beniamino Galvani, Mar 2005 + * Implemented EAP-TLS authentication + */ + #define RCSID "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $" /* @@ -76,6 +81,9 @@ #define SHA_DIGESTSIZE 20 #endif +#ifdef USE_EAPTLS +#include "eap-tls.h" +#endif /* USE_EAPTLS */ eap_state eap_states[NUM_PPP]; /* EAP state; one for each unit */ #ifdef USE_SRP @@ -208,6 +216,9 @@ int unit; esp->es_server.ea_id = (u_char)(drand48() * 0x100); esp->es_client.ea_timeout = EAP_DEFREQTIME; esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ; +#ifdef USE_EAPTLS + esp->es_client.ea_using_eaptls = 0; +#endif /* USE_EAPTLS */ } /* @@ -435,8 +446,16 @@ int status; u_char vals[2]; struct b64state bs; #endif /* USE_SRP */ +#ifdef USE_EAPTLS + struct eaptls_session *ets; + int secret_len; + char secret[MAXWORDLEN]; +#endif /* USE_EAPTLS */ esp->es_server.ea_timeout = esp->es_savedtime; +#ifdef USE_EAPTLS + esp->es_server.ea_prev_state = esp->es_server.ea_state; +#endif /* USE_EAPTLS */ switch (esp->es_server.ea_state) { case eapBadAuth: return; @@ -561,9 +580,81 @@ int status; break; } #endif /* USE_SRP */ +#ifdef USE_EAPTLS + if (!get_secret(esp->es_unit, esp->es_server.ea_peer, + esp->es_server.ea_name, secret, &secret_len, 1)) { + + esp->es_server.ea_state = eapTlsStart; + break; + } +#endif /* USE_EAPTLS */ + esp->es_server.ea_state = eapMD5Chall; break; +#ifdef USE_EAPTLS + case eapTlsStart: + /* Initialize ssl session */ + if(!eaptls_init_ssl_server(esp)) { + esp->es_server.ea_state = eapBadAuth; + break; + } + + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsRecv: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->alert_sent) { + esp->es_server.ea_state = eapTlsSendAlert; + break; + } + + if (status) { + esp->es_server.ea_state = eapBadAuth; + break; + } + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->frag) + esp->es_server.ea_state = eapTlsSendAck; + else + esp->es_server.ea_state = eapTlsSend; + break; + + case eapTlsSend: + ets = (struct eaptls_session *) esp->es_server.ea_session; + + if(ets->frag) + esp->es_server.ea_state = eapTlsRecvAck; + else + if(SSL_is_init_finished(ets->ssl)) + esp->es_server.ea_state = eapTlsRecvClient; + else + /* JJK Add "TLS empty record" message here ??? */ + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsSendAck: + esp->es_server.ea_state = eapTlsRecv; + break; + + case eapTlsRecvAck: + if (status) + { + esp->es_server.ea_state = eapBadAuth; + break; + } + + esp->es_server.ea_state = eapTlsSend; + break; + + case eapTlsSendAlert: + esp->es_server.ea_state = eapTlsRecvAlertAck; + break; +#endif /* USE_EAPTLS */ + case eapSRP1: #ifdef USE_SRP ts = (struct t_server *)esp->es_server.ea_session; @@ -629,6 +720,10 @@ int status; } if (esp->es_server.ea_state == eapBadAuth) eap_send_failure(esp); + +#ifdef USE_EAPTLS + dbglog("EAP id=0x%2x '%s' -> '%s'", esp->es_server.ea_id, eap_state_name(esp->es_server.ea_prev_state), eap_state_name(esp->es_server.ea_state)); +#endif /* USE_EAPTLS */ } /* @@ -717,6 +812,30 @@ eap_state *esp; INCPTR(esp->es_server.ea_namelen, outp); break; +#ifdef USE_EAPTLS + case eapTlsStart: + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(EAP_TLS_FLAGS_START, outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSend: + eaptls_send(esp->es_server.ea_session, &outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSendAck: + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(0, outp); + eap_figure_next_state(esp, 0); + break; + + case eapTlsSendAlert: + eaptls_send(esp->es_server.ea_session, &outp); + eap_figure_next_state(esp, 0); + break; +#endif /* USE_EAPTLS */ + #ifdef USE_SRP case eapSRP1: PUTCHAR(EAPT_SRP, outp); @@ -903,11 +1022,57 @@ static void eap_server_timeout(arg) void *arg; { +#ifdef USE_EAPTLS + u_char *outp; + u_char *lenloc; + int outlen; +#endif /* USE_EAPTLS */ + eap_state *esp = (eap_state *) arg; if (!eap_server_active(esp)) return; +#ifdef USE_EAPTLS + switch(esp->es_server.ea_prev_state) { + + /* + * In eap-tls the state changes after a request, so we return to + * previous state ... + */ + case(eapTlsStart): + case(eapTlsSendAck): + esp->es_server.ea_state = esp->es_server.ea_prev_state; + break; + + /* + * ... or resend the stored data + */ + case(eapTlsSend): + case(eapTlsSendAlert): + outp = outpacket_buf; + MAKEHEADER(outp, PPP_EAP); + PUTCHAR(EAP_REQUEST, outp); + PUTCHAR(esp->es_server.ea_id, outp); + lenloc = outp; + INCPTR(2, outp); + + eaptls_retransmit(esp->es_server.ea_session, &outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN); + esp->es_server.ea_requests++; + + if (esp->es_server.ea_timeout > 0) + TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout); + + return; + default: + break; + } +#endif /* USE_EAPTLS */ + /* EAP ID number must not change on timeout. */ eap_send_request(esp); } @@ -1165,6 +1330,79 @@ u_char *str; } #endif /* USE_SRP */ +#ifdef USE_EAPTLS +/* + * Send an EAP-TLS response message with tls data + */ +static void +eap_tls_response(esp, id) +eap_state *esp; +u_char id; +{ + u_char *outp; + int outlen; + u_char *lenloc; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + + lenloc = outp; + INCPTR(2, outp); + + /* + If the id in the request is unchanged, we must retransmit + the old data + */ + if(id == esp->es_client.ea_id) + eaptls_retransmit(esp->es_client.ea_session, &outp); + else + eaptls_send(esp->es_client.ea_session, &outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); + + esp->es_client.ea_id = id; +} + +/* + * Send an EAP-TLS ack + */ +static void +eap_tls_sendack(esp, id) +eap_state *esp; +u_char id; +{ + u_char *outp; + int outlen; + u_char *lenloc; + + outp = outpacket_buf; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + esp->es_client.ea_id = id; + + lenloc = outp; + INCPTR(2, outp); + + PUTCHAR(EAPT_TLS, outp); + PUTCHAR(0, outp); + + outlen = (outp - outpacket_buf) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); +} +#endif /* USE_EAPTLS */ + static void eap_send_nak(esp, id, type) eap_state *esp; @@ -1319,6 +1557,11 @@ int len; char rhostname[256]; MD5_CTX mdContext; u_char hash[MD5_SIGNATURE_SIZE]; +#ifdef USE_EAPTLS + u_char flags; + struct eaptls_session *ets = esp->es_client.ea_session; +#endif /* USE_EAPTLS */ + #ifdef USE_SRP struct t_client *tc; struct t_num sval, gval, Nval, *Ap, Bval; @@ -1328,6 +1571,12 @@ int len; int fd; #endif /* USE_SRP */ + /* + * Ignore requests if we're not open + */ + if (esp->es_client.ea_state <= eapClosed) + return; + /* * Note: we update es_client.ea_id *only if* a Response * message is being generated. Otherwise, we leave it the @@ -1455,6 +1704,96 @@ int len; esp->es_client.ea_namelen); break; +#ifdef USE_EAPTLS + case EAPT_TLS: + + switch(esp->es_client.ea_state) { + + case eapListen: + + if (len < 1) { + error("EAP: received EAP-TLS Listen packet with no data"); + /* Bogus request; wait for something real. */ + return; + } + GETCHAR(flags, inp); + if(flags & EAP_TLS_FLAGS_START){ + + esp->es_client.ea_using_eaptls = 1; + + if (explicit_remote){ + esp->es_client.ea_peer = strdup(remote_name); + esp->es_client.ea_peerlen = strlen(remote_name); + } else + esp->es_client.ea_peer = NULL; + + /* Init ssl session */ + if(!eaptls_init_ssl_client(esp)) { + dbglog("cannot init ssl"); + eap_send_nak(esp, id, EAPT_TLS); + esp->es_client.ea_using_eaptls = 0; + break; + } + + ets = esp->es_client.ea_session; + eap_tls_response(esp, id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + } + + /* The server has sent a bad start packet. */ + eap_send_nak(esp, id, EAPT_TLS); + break; + + case eapTlsRecvAck: + eap_tls_response(esp, id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + + case eapTlsRecv: + if (len < 1) { + error("EAP: discarding EAP-TLS Receive packet with no data"); + /* Bogus request; wait for something real. */ + return; + } + eaptls_receive(ets, inp, len); + + if(ets->frag) { + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecv; + break; + } + + if(ets->alert_recv) { + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecvFailure; + break; + } + + /* Check if TLS handshake is finished */ + if(eaptls_is_init_finished(ets)) { +#ifdef MPPE + eaptls_gen_mppe_keys(ets, 1); +#endif + eaptls_free_session(ets); + eap_tls_sendack(esp, id); + esp->es_client.ea_state = eapTlsRecvSuccess; + break; + } + + eap_tls_response(esp,id); + esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); + break; + + default: + eap_send_nak(esp, id, EAPT_TLS); + esp->es_client.ea_using_eaptls = 0; + break; + } + + break; +#endif /* USE_EAPTLS */ + #ifdef USE_SRP case EAPT_SRP: if (len < 1) { @@ -1734,8 +2073,21 @@ int len; struct t_num A; SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; #endif /* USE_SRP */ +#ifdef USE_EAPTLS + struct eaptls_session *ets; + u_char flags; +#endif /* USE_EAPTLS */ + + /* + * Ignore responses if we're not open + */ + if (esp->es_server.ea_state <= eapClosed) + return; + if (esp->es_server.ea_id != id) { dbglog("EAP: discarding Response %d; expected ID %d", id, esp->es_server.ea_id); @@ -1775,6 +2127,64 @@ int len; eap_figure_next_state(esp, 0); break; +#ifdef USE_EAPTLS + case EAPT_TLS: + switch(esp->es_server.ea_state) { + + case eapTlsRecv: + + ets = (struct eaptls_session *) esp->es_server.ea_session; + + eap_figure_next_state(esp, + eaptls_receive(esp->es_server.ea_session, inp, len)); + + if(ets->alert_recv) { + eap_send_failure(esp); + break; + } + break; + + case eapTlsRecvAck: + if(len > 1) { + dbglog("EAP-TLS ACK with extra data"); + } + eap_figure_next_state(esp, 0); + break; + + case eapTlsRecvClient: + /* Receive authentication response from client */ + if (len > 0) { + GETCHAR(flags, inp); + + if(len == 1 && !flags) { /* Ack = ok */ +#ifdef MPPE + eaptls_gen_mppe_keys( esp->es_server.ea_session, 0 ); +#endif + eap_send_success(esp); + } + else { /* failure */ + warn("Server authentication failed"); + eap_send_failure(esp); + } + } + else + warn("Bogus EAP-TLS packet received from client"); + + eaptls_free_session(esp->es_server.ea_session); + + break; + + case eapTlsRecvAlertAck: + eap_send_failure(esp); + break; + + default: + eap_figure_next_state(esp, 1); + break; + } + break; +#endif /* USE_EAPTLS */ + case EAPT_NOTIFICATION: dbglog("EAP unexpected Notification; response discarded"); break; @@ -1806,6 +2216,13 @@ int len; esp->es_server.ea_state = eapMD5Chall; break; +#ifdef USE_EAPTLS + /* Send EAP-TLS start packet */ + case EAPT_TLS: + esp->es_server.ea_state = eapTlsStart; + break; +#endif /* USE_EAPTLS */ + default: dbglog("EAP: peer requesting unknown Type %d", vallen); switch (esp->es_server.ea_state) { @@ -2017,13 +2434,27 @@ u_char *inp; int id; int len; { - if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)) { + if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp) +#ifdef USE_EAPTLS + && esp->es_client.ea_state != eapTlsRecvSuccess +#endif /* USE_EAPTLS */ + ) { dbglog("EAP unexpected success message in state %s (%d)", eap_state_name(esp->es_client.ea_state), esp->es_client.ea_state); return; } +#ifdef USE_EAPTLS + if(esp->es_client.ea_using_eaptls && esp->es_client.ea_state != + eapTlsRecvSuccess) { + dbglog("EAP-TLS unexpected success message in state %s (%d)", + eap_state_name(esp->es_client.ea_state), + esp->es_client.ea_state); + return; + } +#endif /* USE_EAPTLS */ + if (esp->es_client.ea_timeout > 0) { UNTIMEOUT(eap_client_timeout, (void *)esp); } @@ -2047,6 +2478,12 @@ u_char *inp; int id; int len; { + /* + * Ignore failure messages if we're not open + */ + if (esp->es_client.ea_state <= eapClosed) + return; + if (!eap_client_active(esp)) { dbglog("EAP unexpected failure message in state %s (%d)", eap_state_name(esp->es_client.ea_state), @@ -2149,6 +2586,9 @@ void *arg; int code, id, len, rtype, vallen; u_char *pstart; u_int32_t uval; +#ifdef USE_EAPTLS + u_char flags; +#endif /* USE_EAPTLS */ if (inlen < EAP_HEADERLEN) return (0); @@ -2213,6 +2653,24 @@ void *arg; } break; +#ifdef USE_EAPTLS + case EAPT_TLS: + if (len < 1) + break; + GETCHAR(flags, inp); + len--; + + if(flags == 0 && len == 0){ + printer(arg, " Ack"); + break; + } + + printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -"); + printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); + printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); + break; +#endif /* USE_EAPTLS */ + case EAPT_SRP: if (len < 3) goto truncated; @@ -2324,6 +2782,25 @@ void *arg; } break; +#ifdef USE_EAPTLS + case EAPT_TLS: + if (len < 1) + break; + GETCHAR(flags, inp); + len--; + + if(flags == 0 && len == 0){ + printer(arg, " Ack"); + break; + } + + printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -"); + printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); + printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); + + break; +#endif /* USE_EAPTLS */ + case EAPT_NAK: if (len <= 0) { printer(arg, " ");