Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_eap.c Source File

lwip_eap.c

00001 /*
00002  * eap.c - Extensible Authentication Protocol for PPP (RFC 2284)
00003  *
00004  * Copyright (c) 2001 by Sun Microsystems, Inc.
00005  * All rights reserved.
00006  *
00007  * Non-exclusive rights to redistribute, modify, translate, and use
00008  * this software in source and binary forms, in whole or in part, is
00009  * hereby granted, provided that the above copyright notice is
00010  * duplicated in any source form, and that neither the name of the
00011  * copyright holder nor the author is used to endorse or promote
00012  * products derived from this software.
00013  *
00014  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00015  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00016  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00017  *
00018  * Original version by James Carlson
00019  *
00020  * This implementation of EAP supports MD5-Challenge and SRP-SHA1
00021  * authentication styles.  Note that support of MD5-Challenge is a
00022  * requirement of RFC 2284, and that it's essentially just a
00023  * reimplementation of regular RFC 1994 CHAP using EAP messages.
00024  *
00025  * As an authenticator ("server"), there are multiple phases for each
00026  * style.  In the first phase of each style, the unauthenticated peer
00027  * name is queried using the EAP Identity request type.  If the
00028  * "remotename" option is used, then this phase is skipped, because
00029  * the peer's name is presumed to be known.
00030  *
00031  * For MD5-Challenge, there are two phases, and the second phase
00032  * consists of sending the challenge itself and handling the
00033  * associated response.
00034  *
00035  * For SRP-SHA1, there are four phases.  The second sends 's', 'N',
00036  * and 'g'.  The reply contains 'A'.  The third sends 'B', and the
00037  * reply contains 'M1'.  The forth sends the 'M2' value.
00038  *
00039  * As an authenticatee ("client"), there's just a single phase --
00040  * responding to the queries generated by the peer.  EAP is an
00041  * authenticator-driven protocol.
00042  *
00043  * Based on draft-ietf-pppext-eap-srp-03.txt.
00044  */
00045 
00046 #include "netif/ppp/ppp_opts.h"
00047 #if PPP_SUPPORT && EAP_SUPPORT  /* don't build if not configured for use in lwipopts.h */
00048 
00049 #include "netif/ppp/ppp_impl.h"
00050 #include "netif/ppp/eap.h"
00051 #include "netif/ppp/magic.h"
00052 #include "netif/ppp/pppcrypt.h"
00053 
00054 #ifdef USE_SRP
00055 #include <t_pwd.h>
00056 #include <t_server.h>
00057 #include <t_client.h>
00058 #endif /* USE_SRP */
00059 
00060 #ifndef SHA_DIGESTSIZE
00061 #define SHA_DIGESTSIZE 20
00062 #endif
00063 
00064 #ifdef USE_SRP
00065 static char *pn_secret = NULL;      /* Pseudonym generating secret */
00066 #endif
00067 
00068 #if PPP_OPTIONS
00069 /*
00070  * Command-line options.
00071  */
00072 static option_t eap_option_list[] = {
00073     { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout,
00074       "Set retransmit timeout for EAP Requests (server)" },
00075     { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests,
00076       "Set max number of EAP Requests sent (server)" },
00077     { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout,
00078       "Set time limit for peer EAP authentication" },
00079     { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests,
00080       "Set max number of EAP Requests allows (client)" },
00081     { "eap-interval", o_int, &eap_states[0].es_rechallenge,
00082       "Set interval for EAP rechallenge" },
00083 #ifdef USE_SRP
00084     { "srp-interval", o_int, &eap_states[0].es_lwrechallenge,
00085       "Set interval for SRP lightweight rechallenge" },
00086     { "srp-pn-secret", o_string, &pn_secret,
00087       "Long term pseudonym generation secret" },
00088     { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo,
00089       "Use pseudonym if offered one by server", 1 },
00090 #endif
00091     { NULL }
00092 };
00093 #endif /* PPP_OPTIONS */
00094 
00095 /*
00096  * Protocol entry points.
00097  */
00098 static void eap_init(ppp_pcb *pcb);
00099 static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen);
00100 static void eap_protrej(ppp_pcb *pcb);
00101 static void eap_lowerup(ppp_pcb *pcb);
00102 static void eap_lowerdown(ppp_pcb *pcb);
00103 #if PRINTPKT_SUPPORT
00104 static int  eap_printpkt(const u_char *inp, int inlen,
00105     void (*)(void *arg, const char *fmt, ...), void *arg);
00106 #endif /* PRINTPKT_SUPPORT */
00107 
00108 const struct protent eap_protent = {
00109     PPP_EAP,        /* protocol number */
00110     eap_init,       /* initialization procedure */
00111     eap_input,      /* process a received packet */
00112     eap_protrej,        /* process a received protocol-reject */
00113     eap_lowerup,        /* lower layer has gone up */
00114     eap_lowerdown,      /* lower layer has gone down */
00115     NULL,           /* open the protocol */
00116     NULL,           /* close the protocol */
00117 #if PRINTPKT_SUPPORT
00118     eap_printpkt,       /* print a packet in readable form */
00119 #endif /* PRINTPKT_SUPPORT */
00120 #if PPP_DATAINPUT
00121     NULL,           /* process a received data packet */
00122 #endif /* PPP_DATAINPUT */
00123 #if PRINTPKT_SUPPORT
00124     "EAP",          /* text name of protocol */
00125     NULL,           /* text name of corresponding data protocol */
00126 #endif /* PRINTPKT_SUPPORT */
00127 #if PPP_OPTIONS
00128     eap_option_list,    /* list of command-line options */
00129     NULL,           /* check requested options; assign defaults */
00130 #endif /* PPP_OPTIONS */
00131 #if DEMAND_SUPPORT
00132     NULL,           /* configure interface for demand-dial */
00133     NULL            /* say whether to bring up link for this pkt */
00134 #endif /* DEMAND_SUPPORT */
00135 };
00136 
00137 #ifdef USE_SRP
00138 /*
00139  * A well-known 2048 bit modulus.
00140  */
00141 static const u_char wkmodulus[] = {
00142     0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B,
00143     0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F,
00144     0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07,
00145     0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50,
00146     0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED,
00147     0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D,
00148     0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D,
00149     0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50,
00150     0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0,
00151     0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3,
00152     0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8,
00153     0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8,
00154     0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA,
00155     0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74,
00156     0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7,
00157     0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B,
00158     0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16,
00159     0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81,
00160     0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A,
00161     0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48,
00162     0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D,
00163     0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA,
00164     0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78,
00165     0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6,
00166     0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29,
00167     0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8,
00168     0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82,
00169     0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6,
00170     0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4,
00171     0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75,
00172     0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2,
00173     0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73
00174 };
00175 #endif
00176 
00177 #if PPP_SERVER
00178 /* Local forward declarations. */
00179 static void eap_server_timeout(void *arg);
00180 #endif /* PPP_SERVER */
00181 
00182 /*
00183  * Convert EAP state code to printable string for debug.
00184  */
00185 static const char * eap_state_name(enum eap_state_code esc)
00186 {
00187     static const char *state_names[] = { EAP_STATES };
00188 
00189     return (state_names[(int)esc]);
00190 }
00191 
00192 /*
00193  * eap_init - Initialize state for an EAP user.  This is currently
00194  * called once by main() during start-up.
00195  */
00196 static void eap_init(ppp_pcb *pcb) {
00197 
00198     BZERO(&pcb->eap, sizeof(eap_state));
00199 #if PPP_SERVER
00200     pcb->eap.es_server.ea_id = magic();
00201 #endif /* PPP_SERVER */
00202 }
00203 
00204 /*
00205  * eap_client_timeout - Give up waiting for the peer to send any
00206  * Request messages.
00207  */
00208 static void eap_client_timeout(void *arg) {
00209     ppp_pcb *pcb = (ppp_pcb*)arg;
00210 
00211     if (!eap_client_active(pcb))
00212         return;
00213 
00214     ppp_error("EAP: timeout waiting for Request from peer");
00215     auth_withpeer_fail(pcb, PPP_EAP);
00216     pcb->eap.es_client.ea_state = eapBadAuth;
00217 }
00218 
00219 /*
00220  * eap_authwithpeer - Authenticate to our peer (behave as client).
00221  *
00222  * Start client state and wait for requests.  This is called only
00223  * after eap_lowerup.
00224  */
00225 void eap_authwithpeer(ppp_pcb *pcb, const char *localname) {
00226 
00227     if(NULL == localname)
00228         return;
00229 
00230     /* Save the peer name we're given */
00231     pcb->eap.es_client.ea_name = localname;
00232     pcb->eap.es_client.ea_namelen = strlen(localname);
00233 
00234     pcb->eap.es_client.ea_state = eapListen;
00235 
00236     /*
00237      * Start a timer so that if the other end just goes
00238      * silent, we don't sit here waiting forever.
00239      */
00240     if (pcb->settings.eap_req_time > 0)
00241         TIMEOUT(eap_client_timeout, pcb,
00242             pcb->settings.eap_req_time);
00243 }
00244 
00245 #if PPP_SERVER
00246 /*
00247  * Format a standard EAP Failure message and send it to the peer.
00248  * (Server operation)
00249  */
00250 static void eap_send_failure(ppp_pcb *pcb) {
00251     struct pbuf *p;
00252     u_char *outp;
00253 
00254     p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE);
00255     if(NULL == p)
00256         return;
00257     if(p->tot_len != p->len) {
00258         pbuf_free(p);
00259         return;
00260     }
00261 
00262     outp = (u_char*)p->payload;
00263 
00264     MAKEHEADER(outp, PPP_EAP);
00265 
00266     PUTCHAR(EAP_FAILURE, outp);
00267     pcb->eap.es_server.ea_id++;
00268     PUTCHAR(pcb->eap.es_server.ea_id, outp);
00269     PUTSHORT(EAP_HEADERLEN, outp);
00270 
00271     ppp_write(pcb, p);
00272 
00273     pcb->eap.es_server.ea_state = eapBadAuth;
00274     auth_peer_fail(pcb, PPP_EAP);
00275 }
00276 
00277 /*
00278  * Format a standard EAP Success message and send it to the peer.
00279  * (Server operation)
00280  */
00281 static void eap_send_success(ppp_pcb *pcb) {
00282     struct pbuf *p;
00283     u_char *outp;
00284 
00285     p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE);
00286     if(NULL == p)
00287         return;
00288     if(p->tot_len != p->len) {
00289         pbuf_free(p);
00290         return;
00291     }
00292 
00293     outp = (u_char*)p->payload;
00294     
00295     MAKEHEADER(outp, PPP_EAP);
00296 
00297     PUTCHAR(EAP_SUCCESS, outp);
00298     pcb->eap.es_server.ea_id++;
00299     PUTCHAR(pcb->eap.es_server.ea_id, outp);
00300     PUTSHORT(EAP_HEADERLEN, outp);
00301 
00302     ppp_write(pcb, p);
00303 
00304     auth_peer_success(pcb, PPP_EAP, 0,
00305         pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen);
00306 }
00307 #endif /* PPP_SERVER */
00308 
00309 #ifdef USE_SRP
00310 /*
00311  * Set DES key according to pseudonym-generating secret and current
00312  * date.
00313  */
00314 static bool
00315 pncrypt_setkey(int timeoffs)
00316 {
00317     struct tm *tp;
00318     char tbuf[9];
00319     SHA1_CTX ctxt;
00320     u_char dig[SHA_DIGESTSIZE];
00321     time_t reftime;
00322 
00323     if (pn_secret == NULL)
00324         return (0);
00325     reftime = time(NULL) + timeoffs;
00326     tp = localtime(&reftime);
00327     SHA1Init(&ctxt);
00328     SHA1Update(&ctxt, pn_secret, strlen(pn_secret));
00329     strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp);
00330     SHA1Update(&ctxt, tbuf, strlen(tbuf));
00331     SHA1Final(dig, &ctxt);
00332     /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
00333     return (DesSetkey(dig));
00334 }
00335 
00336 static char base64[] =
00337 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00338 
00339 struct b64state {
00340     u32_t bs_bits;
00341     int bs_offs;
00342 };
00343 
00344 static int
00345 b64enc(bs, inp, inlen, outp)
00346 struct b64state *bs;
00347 u_char *inp;
00348 int inlen;
00349 u_char *outp;
00350 {
00351     int outlen = 0;
00352 
00353     while (inlen > 0) {
00354         bs->bs_bits = (bs->bs_bits << 8) | *inp++;
00355         inlen--;
00356         bs->bs_offs += 8;
00357         if (bs->bs_offs >= 24) {
00358             *outp++ = base64[(bs->bs_bits >> 18) & 0x3F];
00359             *outp++ = base64[(bs->bs_bits >> 12) & 0x3F];
00360             *outp++ = base64[(bs->bs_bits >> 6) & 0x3F];
00361             *outp++ = base64[bs->bs_bits & 0x3F];
00362             outlen += 4;
00363             bs->bs_offs = 0;
00364             bs->bs_bits = 0;
00365         }
00366     }
00367     return (outlen);
00368 }
00369 
00370 static int
00371 b64flush(bs, outp)
00372 struct b64state *bs;
00373 u_char *outp;
00374 {
00375     int outlen = 0;
00376 
00377     if (bs->bs_offs == 8) {
00378         *outp++ = base64[(bs->bs_bits >> 2) & 0x3F];
00379         *outp++ = base64[(bs->bs_bits << 4) & 0x3F];
00380         outlen = 2;
00381     } else if (bs->bs_offs == 16) {
00382         *outp++ = base64[(bs->bs_bits >> 10) & 0x3F];
00383         *outp++ = base64[(bs->bs_bits >> 4) & 0x3F];
00384         *outp++ = base64[(bs->bs_bits << 2) & 0x3F];
00385         outlen = 3;
00386     }
00387     bs->bs_offs = 0;
00388     bs->bs_bits = 0;
00389     return (outlen);
00390 }
00391 
00392 static int
00393 b64dec(bs, inp, inlen, outp)
00394 struct b64state *bs;
00395 u_char *inp;
00396 int inlen;
00397 u_char *outp;
00398 {
00399     int outlen = 0;
00400     char *cp;
00401 
00402     while (inlen > 0) {
00403         if ((cp = strchr(base64, *inp++)) == NULL)
00404             break;
00405         bs->bs_bits = (bs->bs_bits << 6) | (cp - base64);
00406         inlen--;
00407         bs->bs_offs += 6;
00408         if (bs->bs_offs >= 8) {
00409             *outp++ = bs->bs_bits >> (bs->bs_offs - 8);
00410             outlen++;
00411             bs->bs_offs -= 8;
00412         }
00413     }
00414     return (outlen);
00415 }
00416 #endif /* USE_SRP */
00417 
00418 #if PPP_SERVER
00419 /*
00420  * Assume that current waiting server state is complete and figure
00421  * next state to use based on available authentication data.  'status'
00422  * indicates if there was an error in handling the last query.  It is
00423  * 0 for success and non-zero for failure.
00424  */
00425 static void eap_figure_next_state(ppp_pcb *pcb, int status) {
00426 #ifdef USE_SRP
00427     unsigned char secbuf[MAXSECRETLEN], clear[8], *sp, *dp;
00428     struct t_pw tpw;
00429     struct t_confent *tce, mytce;
00430     char *cp, *cp2;
00431     struct t_server *ts;
00432     int id, i, plen, toffs;
00433     u_char vals[2];
00434     struct b64state bs;
00435 #endif /* USE_SRP */
00436 
00437     pcb->settings.eap_timeout_time = pcb->eap.es_savedtime;
00438     switch (pcb->eap.es_server.ea_state) {
00439     case eapBadAuth:
00440         return;
00441 
00442     case eapIdentify:
00443 #ifdef USE_SRP
00444         /* Discard any previous session. */
00445         ts = (struct t_server *)pcb->eap.es_server.ea_session;
00446         if (ts != NULL) {
00447             t_serverclose(ts);
00448             pcb->eap.es_server.ea_session = NULL;
00449             pcb->eap.es_server.ea_skey = NULL;
00450         }
00451 #endif /* USE_SRP */
00452         if (status != 0) {
00453             pcb->eap.es_server.ea_state = eapBadAuth;
00454             break;
00455         }
00456 #ifdef USE_SRP
00457         /* If we've got a pseudonym, try to decode to real name. */
00458         if (pcb->eap.es_server.ea_peerlen > SRP_PSEUDO_LEN &&
00459             strncmp(pcb->eap.es_server.ea_peer, SRP_PSEUDO_ID,
00460             SRP_PSEUDO_LEN) == 0 &&
00461             (pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 <
00462             sizeof (secbuf)) {
00463             BZERO(&bs, sizeof (bs));
00464             plen = b64dec(&bs,
00465                 pcb->eap.es_server.ea_peer + SRP_PSEUDO_LEN,
00466                 pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN,
00467                 secbuf);
00468             toffs = 0;
00469             for (i = 0; i < 5; i++) {
00470                 pncrypt_setkey(toffs);
00471                 toffs -= 86400;
00472                 /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
00473                 if (!DesDecrypt(secbuf, clear)) {
00474                     ppp_dbglog("no DES here; cannot decode "
00475                         "pseudonym");
00476                     return;
00477                 }
00478                 id = *(unsigned char *)clear;
00479                 if (id + 1 <= plen && id + 9 > plen)
00480                     break;
00481             }
00482             if (plen % 8 == 0 && i < 5) {
00483                 /*
00484                  * Note that this is always shorter than the
00485                  * original stored string, so there's no need
00486                  * to realloc.
00487                  */
00488                 if ((i = plen = *(unsigned char *)clear) > 7)
00489                     i = 7;
00490                 pcb->eap.es_server.ea_peerlen = plen;
00491                 dp = (unsigned char *)pcb->eap.es_server.ea_peer;
00492                 MEMCPY(dp, clear + 1, i);
00493                 plen -= i;
00494                 dp += i;
00495                 sp = secbuf + 8;
00496                 while (plen > 0) {
00497                     /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
00498                     (void) DesDecrypt(sp, dp);
00499                     sp += 8;
00500                     dp += 8;
00501                     plen -= 8;
00502                 }
00503                 pcb->eap.es_server.ea_peer[
00504                     pcb->eap.es_server.ea_peerlen] = '\0';
00505                 ppp_dbglog("decoded pseudonym to \"%.*q\"",
00506                     pcb->eap.es_server.ea_peerlen,
00507                     pcb->eap.es_server.ea_peer);
00508             } else {
00509                 ppp_dbglog("failed to decode real name");
00510                 /* Stay in eapIdentfy state; requery */
00511                 break;
00512             }
00513         }
00514         /* Look up user in secrets database. */
00515         if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_server.ea_peer,
00516             pcb->eap.es_server.ea_name, (char *)secbuf, 1) != 0) {
00517             /* Set up default in case SRP entry is bad */
00518             pcb->eap.es_server.ea_state = eapMD5Chall;
00519             /* Get t_confent based on index in srp-secrets */
00520             id = strtol((char *)secbuf, &cp, 10);
00521             if (*cp++ != ':' || id < 0)
00522                 break;
00523             if (id == 0) {
00524                 mytce.index = 0;
00525                 mytce.modulus.data = (u_char *)wkmodulus;
00526                 mytce.modulus.len = sizeof (wkmodulus);
00527                 mytce.generator.data = (u_char *)"\002";
00528                 mytce.generator.len = 1;
00529                 tce = &mytce;
00530             } else if ((tce = gettcid(id)) != NULL) {
00531                 /*
00532                  * Client will have to verify this modulus/
00533                  * generator combination, and that will take
00534                  * a while.  Lengthen the timeout here.
00535                  */
00536                 if (pcb->settings.eap_timeout_time > 0 &&
00537                     pcb->settings.eap_timeout_time < 30)
00538                     pcb->settings.eap_timeout_time = 30;
00539             } else {
00540                 break;
00541             }
00542             if ((cp2 = strchr(cp, ':')) == NULL)
00543                 break;
00544             *cp2++ = '\0';
00545             tpw.pebuf.name = pcb->eap.es_server.ea_peer;
00546             tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf,
00547                 cp);
00548             tpw.pebuf.password.data = tpw.pwbuf;
00549             tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf,
00550                 cp2);
00551             tpw.pebuf.salt.data = tpw.saltbuf;
00552             if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL)
00553                 break;
00554             pcb->eap.es_server.ea_session = (void *)ts;
00555             pcb->eap.es_server.ea_state = eapSRP1;
00556             vals[0] = pcb->eap.es_server.ea_id + 1;
00557             vals[1] = EAPT_SRP;
00558             t_serveraddexdata(ts, vals, 2);
00559             /* Generate B; must call before t_servergetkey() */
00560             t_servergenexp(ts);
00561             break;
00562         }
00563 #endif /* USE_SRP */
00564         pcb->eap.es_server.ea_state = eapMD5Chall;
00565         break;
00566 
00567     case eapSRP1:
00568 #ifdef USE_SRP
00569         ts = (struct t_server *)pcb->eap.es_server.ea_session;
00570         if (ts != NULL && status != 0) {
00571             t_serverclose(ts);
00572             pcb->eap.es_server.ea_session = NULL;
00573             pcb->eap.es_server.ea_skey = NULL;
00574         }
00575 #endif /* USE_SRP */
00576         if (status == 1) {
00577             pcb->eap.es_server.ea_state = eapMD5Chall;
00578         } else if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
00579             pcb->eap.es_server.ea_state = eapBadAuth;
00580         } else {
00581             pcb->eap.es_server.ea_state = eapSRP2;
00582         }
00583         break;
00584 
00585     case eapSRP2:
00586 #ifdef USE_SRP
00587         ts = (struct t_server *)pcb->eap.es_server.ea_session;
00588         if (ts != NULL && status != 0) {
00589             t_serverclose(ts);
00590             pcb->eap.es_server.ea_session = NULL;
00591             pcb->eap.es_server.ea_skey = NULL;
00592         }
00593 #endif /* USE_SRP */
00594         if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
00595             pcb->eap.es_server.ea_state = eapBadAuth;
00596         } else {
00597             pcb->eap.es_server.ea_state = eapSRP3;
00598         }
00599         break;
00600 
00601     case eapSRP3:
00602     case eapSRP4:
00603 #ifdef USE_SRP
00604         ts = (struct t_server *)pcb->eap.es_server.ea_session;
00605         if (ts != NULL && status != 0) {
00606             t_serverclose(ts);
00607             pcb->eap.es_server.ea_session = NULL;
00608             pcb->eap.es_server.ea_skey = NULL;
00609         }
00610 #endif /* USE_SRP */
00611         if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
00612             pcb->eap.es_server.ea_state = eapBadAuth;
00613         } else {
00614             pcb->eap.es_server.ea_state = eapOpen;
00615         }
00616         break;
00617 
00618     case eapMD5Chall:
00619         if (status != 0) {
00620             pcb->eap.es_server.ea_state = eapBadAuth;
00621         } else {
00622             pcb->eap.es_server.ea_state = eapOpen;
00623         }
00624         break;
00625 
00626     default:
00627         pcb->eap.es_server.ea_state = eapBadAuth;
00628         break;
00629     }
00630     if (pcb->eap.es_server.ea_state == eapBadAuth)
00631         eap_send_failure(pcb);
00632 }
00633 
00634 /*
00635  * Format an EAP Request message and send it to the peer.  Message
00636  * type depends on current state.  (Server operation)
00637  */
00638 static void eap_send_request(ppp_pcb *pcb) {
00639     struct pbuf *p;
00640     u_char *outp;
00641     u_char *lenloc;
00642     int outlen;
00643     int len;
00644     const char *str;
00645 #ifdef USE_SRP
00646     struct t_server *ts;
00647     u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp;
00648     int i, j;
00649     struct b64state b64;
00650     SHA1_CTX ctxt;
00651 #endif /* USE_SRP */
00652 
00653     /* Handle both initial auth and restart */
00654     if (pcb->eap.es_server.ea_state < eapIdentify &&
00655         pcb->eap.es_server.ea_state != eapInitial) {
00656         pcb->eap.es_server.ea_state = eapIdentify;
00657 #if PPP_REMOTENAME
00658         if (pcb->settings.explicit_remote && pcb->remote_name) {
00659             /*
00660              * If we already know the peer's
00661              * unauthenticated name, then there's no
00662              * reason to ask.  Go to next state instead.
00663              */
00664             int len = (int)strlen(pcb->remote_name);
00665             if (len > MAXNAMELEN) {
00666                 len = MAXNAMELEN;
00667             }
00668             MEMCPY(pcb->eap.es_server.ea_peer, pcb->remote_name, len);
00669             pcb->eap.es_server.ea_peer[len] = '\0';
00670             pcb->eap.es_server.ea_peerlen = len;
00671             eap_figure_next_state(pcb, 0);
00672         }
00673 #endif /* PPP_REMOTENAME */
00674     }
00675 
00676     if (pcb->settings.eap_max_transmits > 0 &&
00677         pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) {
00678         if (pcb->eap.es_server.ea_responses > 0)
00679             ppp_error("EAP: too many Requests sent");
00680         else
00681             ppp_error("EAP: no response to Requests");
00682         eap_send_failure(pcb);
00683         return;
00684     }
00685 
00686     p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE);
00687     if(NULL == p)
00688         return;
00689     if(p->tot_len != p->len) {
00690         pbuf_free(p);
00691         return;
00692     }
00693 
00694     outp = (u_char*)p->payload;
00695     
00696     MAKEHEADER(outp, PPP_EAP);
00697 
00698     PUTCHAR(EAP_REQUEST, outp);
00699     PUTCHAR(pcb->eap.es_server.ea_id, outp);
00700     lenloc = outp;
00701     INCPTR(2, outp);
00702 
00703     switch (pcb->eap.es_server.ea_state) {
00704     case eapIdentify:
00705         PUTCHAR(EAPT_IDENTITY, outp);
00706         str = "Name";
00707         len = strlen(str);
00708         MEMCPY(outp, str, len);
00709         INCPTR(len, outp);
00710         break;
00711 
00712     case eapMD5Chall:
00713         PUTCHAR(EAPT_MD5CHAP, outp);
00714         /*
00715          * pick a random challenge length between
00716          * EAP_MIN_CHALLENGE_LENGTH and EAP_MAX_CHALLENGE_LENGTH
00717          */
00718         pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH +
00719             magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH);
00720         PUTCHAR(pcb->eap.es_challen, outp);
00721         magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen);
00722         MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen);
00723         INCPTR(pcb->eap.es_challen, outp);
00724         MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen);
00725         INCPTR(pcb->eap.es_server.ea_namelen, outp);
00726         break;
00727 
00728 #ifdef USE_SRP
00729     case eapSRP1:
00730         PUTCHAR(EAPT_SRP, outp);
00731         PUTCHAR(EAPSRP_CHALLENGE, outp);
00732 
00733         PUTCHAR(pcb->eap.es_server.ea_namelen, outp);
00734         MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen);
00735         INCPTR(pcb->eap.es_server.ea_namelen, outp);
00736 
00737         ts = (struct t_server *)pcb->eap.es_server.ea_session;
00738         assert(ts != NULL);
00739         PUTCHAR(ts->s.len, outp);
00740         MEMCPY(outp, ts->s.data, ts->s.len);
00741         INCPTR(ts->s.len, outp);
00742 
00743         if (ts->g.len == 1 && ts->g.data[0] == 2) {
00744             PUTCHAR(0, outp);
00745         } else {
00746             PUTCHAR(ts->g.len, outp);
00747             MEMCPY(outp, ts->g.data, ts->g.len);
00748             INCPTR(ts->g.len, outp);
00749         }
00750 
00751         if (ts->n.len != sizeof (wkmodulus) ||
00752             BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) {
00753             MEMCPY(outp, ts->n.data, ts->n.len);
00754             INCPTR(ts->n.len, outp);
00755         }
00756         break;
00757 
00758     case eapSRP2:
00759         PUTCHAR(EAPT_SRP, outp);
00760         PUTCHAR(EAPSRP_SKEY, outp);
00761 
00762         ts = (struct t_server *)pcb->eap.es_server.ea_session;
00763         assert(ts != NULL);
00764         MEMCPY(outp, ts->B.data, ts->B.len);
00765         INCPTR(ts->B.len, outp);
00766         break;
00767 
00768     case eapSRP3:
00769         PUTCHAR(EAPT_SRP, outp);
00770         PUTCHAR(EAPSRP_SVALIDATOR, outp);
00771         PUTLONG(SRPVAL_EBIT, outp);
00772         ts = (struct t_server *)pcb->eap.es_server.ea_session;
00773         assert(ts != NULL);
00774         MEMCPY(outp, t_serverresponse(ts), SHA_DIGESTSIZE);
00775         INCPTR(SHA_DIGESTSIZE, outp);
00776 
00777         if (pncrypt_setkey(0)) {
00778             /* Generate pseudonym */
00779             optr = outp;
00780             cp = (unsigned char *)pcb->eap.es_server.ea_peer;
00781             if ((j = i = pcb->eap.es_server.ea_peerlen) > 7)
00782                 j = 7;
00783             clear[0] = i;
00784             MEMCPY(clear + 1, cp, j);
00785             i -= j;
00786             cp += j;
00787             /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
00788             if (!DesEncrypt(clear, cipher)) {
00789                 ppp_dbglog("no DES here; not generating pseudonym");
00790                 break;
00791             }
00792             BZERO(&b64, sizeof (b64));
00793             outp++;     /* space for pseudonym length */
00794             outp += b64enc(&b64, cipher, 8, outp);
00795             while (i >= 8) {
00796                 /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
00797                 (void) DesEncrypt(cp, cipher);
00798                 outp += b64enc(&b64, cipher, 8, outp);
00799                 cp += 8;
00800                 i -= 8;
00801             }
00802             if (i > 0) {
00803                 MEMCPY(clear, cp, i);
00804                 cp += i;
00805                 magic_random_bytes(cp, 8-i);
00806                 /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
00807                 (void) DesEncrypt(clear, cipher);
00808                 outp += b64enc(&b64, cipher, 8, outp);
00809             }
00810             outp += b64flush(&b64, outp);
00811 
00812             /* Set length and pad out to next 20 octet boundary */
00813             i = outp - optr - 1;
00814             *optr = i;
00815             i %= SHA_DIGESTSIZE;
00816             if (i != 0) {
00817                 magic_random_bytes(outp, SHA_DIGESTSIZE-i);
00818                 INCPTR(SHA_DIGESTSIZE-i, outp);
00819             }
00820 
00821             /* Obscure the pseudonym with SHA1 hash */
00822             SHA1Init(&ctxt);
00823             SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1);
00824             SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
00825                 SESSION_KEY_LEN);
00826             SHA1Update(&ctxt, pcb->eap.es_server.ea_peer,
00827                 pcb->eap.es_server.ea_peerlen);
00828             while (optr < outp) {
00829                 SHA1Final(dig, &ctxt);
00830                 cp = dig;
00831                 while (cp < dig + SHA_DIGESTSIZE)
00832                     *optr++ ^= *cp++;
00833                 SHA1Init(&ctxt);
00834                 SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1);
00835                 SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
00836                     SESSION_KEY_LEN);
00837                 SHA1Update(&ctxt, optr - SHA_DIGESTSIZE,
00838                     SHA_DIGESTSIZE);
00839             }
00840         }
00841         break;
00842 
00843     case eapSRP4:
00844         PUTCHAR(EAPT_SRP, outp);
00845         PUTCHAR(EAPSRP_LWRECHALLENGE, outp);
00846         pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH +
00847             magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH);
00848         magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen);
00849         MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen);
00850         INCPTR(pcb->eap.es_challen, outp);
00851         break;
00852 #endif /* USE_SRP */
00853 
00854     default:
00855         return;
00856     }
00857 
00858     outlen = (outp - (unsigned char*)p->payload) - PPP_HDRLEN;
00859     PUTSHORT(outlen, lenloc);
00860 
00861     pbuf_realloc(p, outlen + PPP_HDRLEN);
00862     ppp_write(pcb, p);
00863 
00864     pcb->eap.es_server.ea_requests++;
00865 
00866     if (pcb->settings.eap_timeout_time > 0)
00867         TIMEOUT(eap_server_timeout, pcb, pcb->settings.eap_timeout_time);
00868 }
00869 
00870 /*
00871  * eap_authpeer - Authenticate our peer (behave as server).
00872  *
00873  * Start server state and send first request.  This is called only
00874  * after eap_lowerup.
00875  */
00876 void eap_authpeer(ppp_pcb *pcb, const char *localname) {
00877 
00878     /* Save the name we're given. */
00879     pcb->eap.es_server.ea_name = localname;
00880     pcb->eap.es_server.ea_namelen = strlen(localname);
00881 
00882     pcb->eap.es_savedtime = pcb->settings.eap_timeout_time;
00883 
00884     /* Lower layer up yet? */
00885     if (pcb->eap.es_server.ea_state == eapInitial ||
00886         pcb->eap.es_server.ea_state == eapPending) {
00887         pcb->eap.es_server.ea_state = eapPending;
00888         return;
00889     }
00890 
00891     pcb->eap.es_server.ea_state = eapPending;
00892 
00893     /* ID number not updated here intentionally; hashed into M1 */
00894     eap_send_request(pcb);
00895 }
00896 
00897 /*
00898  * eap_server_timeout - Retransmission timer for sending Requests
00899  * expired.
00900  */
00901 static void eap_server_timeout(void *arg) {
00902     ppp_pcb *pcb = (ppp_pcb*)arg;
00903 
00904     if (!eap_server_active(pcb))
00905         return;
00906 
00907     /* EAP ID number must not change on timeout. */
00908     eap_send_request(pcb);
00909 }
00910 
00911 /*
00912  * When it's time to send rechallenge the peer, this timeout is
00913  * called.  Once the rechallenge is successful, the response handler
00914  * will restart the timer.  If it fails, then the link is dropped.
00915  */
00916 static void eap_rechallenge(void *arg) {
00917     ppp_pcb *pcb = (ppp_pcb*)arg;
00918 
00919     if (pcb->eap.es_server.ea_state != eapOpen &&
00920         pcb->eap.es_server.ea_state != eapSRP4)
00921         return;
00922 
00923     pcb->eap.es_server.ea_requests = 0;
00924     pcb->eap.es_server.ea_state = eapIdentify;
00925     eap_figure_next_state(pcb, 0);
00926     pcb->eap.es_server.ea_id++;
00927     eap_send_request(pcb);
00928 }
00929 
00930 static void srp_lwrechallenge(void *arg) {
00931     ppp_pcb *pcb = (ppp_pcb*)arg;
00932 
00933     if (pcb->eap.es_server.ea_state != eapOpen ||
00934         pcb->eap.es_server.ea_type != EAPT_SRP)
00935         return;
00936 
00937     pcb->eap.es_server.ea_requests = 0;
00938     pcb->eap.es_server.ea_state = eapSRP4;
00939     pcb->eap.es_server.ea_id++;
00940     eap_send_request(pcb);
00941 }
00942 #endif /* PPP_SERVER */
00943 
00944 /*
00945  * eap_lowerup - The lower layer is now up.
00946  *
00947  * This is called before either eap_authpeer or eap_authwithpeer.  See
00948  * link_established() in auth.c.  All that's necessary here is to
00949  * return to closed state so that those two routines will do the right
00950  * thing.
00951  */
00952 static void eap_lowerup(ppp_pcb *pcb) {
00953     pcb->eap.es_client.ea_state = eapClosed;
00954 #if PPP_SERVER
00955     pcb->eap.es_server.ea_state = eapClosed;
00956 #endif /* PPP_SERVER */
00957 }
00958 
00959 /*
00960  * eap_lowerdown - The lower layer is now down.
00961  *
00962  * Cancel all timeouts and return to initial state.
00963  */
00964 static void eap_lowerdown(ppp_pcb *pcb) {
00965 
00966     if (eap_client_active(pcb) && pcb->settings.eap_req_time > 0) {
00967         UNTIMEOUT(eap_client_timeout, pcb);
00968     }
00969 #if PPP_SERVER
00970     if (eap_server_active(pcb)) {
00971         if (pcb->settings.eap_timeout_time > 0) {
00972             UNTIMEOUT(eap_server_timeout, pcb);
00973         }
00974     } else {
00975         if ((pcb->eap.es_server.ea_state == eapOpen ||
00976             pcb->eap.es_server.ea_state == eapSRP4) &&
00977             pcb->eap.es_rechallenge > 0) {
00978             UNTIMEOUT(eap_rechallenge, (void *)pcb);
00979         }
00980         if (pcb->eap.es_server.ea_state == eapOpen &&
00981             pcb->eap.es_lwrechallenge > 0) {
00982             UNTIMEOUT(srp_lwrechallenge, (void *)pcb);
00983         }
00984     }
00985 
00986     pcb->eap.es_client.ea_state = pcb->eap.es_server.ea_state = eapInitial;
00987     pcb->eap.es_client.ea_requests = pcb->eap.es_server.ea_requests = 0;
00988 #endif /* PPP_SERVER */
00989 }
00990 
00991 /*
00992  * eap_protrej - Peer doesn't speak this protocol.
00993  *
00994  * This shouldn't happen.  If it does, it represents authentication
00995  * failure.
00996  */
00997 static void eap_protrej(ppp_pcb *pcb) {
00998 
00999     if (eap_client_active(pcb)) {
01000         ppp_error("EAP authentication failed due to Protocol-Reject");
01001         auth_withpeer_fail(pcb, PPP_EAP);
01002     }
01003 #if PPP_SERVER
01004     if (eap_server_active(pcb)) {
01005         ppp_error("EAP authentication of peer failed on Protocol-Reject");
01006         auth_peer_fail(pcb, PPP_EAP);
01007     }
01008 #endif /* PPP_SERVER */
01009     eap_lowerdown(pcb);
01010 }
01011 
01012 /*
01013  * Format and send a regular EAP Response message.
01014  */
01015 static void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, const u_char *str, int lenstr) {
01016     struct pbuf *p;
01017     u_char *outp;
01018     int msglen;
01019 
01020     msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr;
01021     p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
01022     if(NULL == p)
01023         return;
01024     if(p->tot_len != p->len) {
01025         pbuf_free(p);
01026         return;
01027     }
01028 
01029     outp = (u_char*)p->payload;
01030 
01031     MAKEHEADER(outp, PPP_EAP);
01032 
01033     PUTCHAR(EAP_RESPONSE, outp);
01034     PUTCHAR(id, outp);
01035     pcb->eap.es_client.ea_id = id;
01036     PUTSHORT(msglen, outp);
01037     PUTCHAR(typenum, outp);
01038     if (lenstr > 0) {
01039         MEMCPY(outp, str, lenstr);
01040     }
01041 
01042     ppp_write(pcb, p);
01043 }
01044 
01045 /*
01046  * Format and send an MD5-Challenge EAP Response message.
01047  */
01048 static void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, const char *name, int namelen) {
01049     struct pbuf *p;
01050     u_char *outp;
01051     int msglen;
01052 
01053     msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE +
01054         namelen;
01055     p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
01056     if(NULL == p)
01057         return;
01058     if(p->tot_len != p->len) {
01059         pbuf_free(p);
01060         return;
01061     }
01062 
01063     outp = (u_char*)p->payload;
01064     
01065     MAKEHEADER(outp, PPP_EAP);
01066 
01067     PUTCHAR(EAP_RESPONSE, outp);
01068     PUTCHAR(id, outp);
01069     pcb->eap.es_client.ea_id = id;
01070     PUTSHORT(msglen, outp);
01071     PUTCHAR(EAPT_MD5CHAP, outp);
01072     PUTCHAR(MD5_SIGNATURE_SIZE, outp);
01073     MEMCPY(outp, hash, MD5_SIGNATURE_SIZE);
01074     INCPTR(MD5_SIGNATURE_SIZE, outp);
01075     if (namelen > 0) {
01076         MEMCPY(outp, name, namelen);
01077     }
01078 
01079     ppp_write(pcb, p);
01080 }
01081 
01082 #ifdef USE_SRP
01083 /*
01084  * Format and send a SRP EAP Response message.
01085  */
01086 static void
01087 eap_srp_response(esp, id, subtypenum, str, lenstr)
01088 eap_state *esp;
01089 u_char id;
01090 u_char subtypenum;
01091 u_char *str;
01092 int lenstr;
01093 {
01094     ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit];
01095     struct pbuf *p;
01096     u_char *outp;
01097     int msglen;
01098 
01099     msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr;
01100     p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
01101     if(NULL == p)
01102         return;
01103     if(p->tot_len != p->len) {
01104         pbuf_free(p);
01105         return;
01106     }
01107 
01108     outp = p->payload;
01109 
01110     MAKEHEADER(outp, PPP_EAP);
01111 
01112     PUTCHAR(EAP_RESPONSE, outp);
01113     PUTCHAR(id, outp);
01114     pcb->eap.es_client.ea_id = id;
01115     PUTSHORT(msglen, outp);
01116     PUTCHAR(EAPT_SRP, outp);
01117     PUTCHAR(subtypenum, outp);
01118     if (lenstr > 0) {
01119         MEMCPY(outp, str, lenstr);
01120     }
01121 
01122     ppp_write(pcb, p);
01123 }
01124 
01125 /*
01126  * Format and send a SRP EAP Client Validator Response message.
01127  */
01128 static void
01129 eap_srpval_response(esp, id, flags, str)
01130 eap_state *esp;
01131 u_char id;
01132 u32_t flags;
01133 u_char *str;
01134 {
01135     ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit];
01136     struct pbuf *p;
01137     u_char *outp;
01138     int msglen;
01139 
01140     msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) +
01141         SHA_DIGESTSIZE;
01142     p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
01143     if(NULL == p)
01144         return;
01145     if(p->tot_len != p->len) {
01146         pbuf_free(p);
01147         return;
01148     }
01149 
01150     outp = p->payload;
01151 
01152     MAKEHEADER(outp, PPP_EAP);
01153 
01154     PUTCHAR(EAP_RESPONSE, outp);
01155     PUTCHAR(id, outp);
01156     pcb->eap.es_client.ea_id = id;
01157     PUTSHORT(msglen, outp);
01158     PUTCHAR(EAPT_SRP, outp);
01159     PUTCHAR(EAPSRP_CVALIDATOR, outp);
01160     PUTLONG(flags, outp);
01161     MEMCPY(outp, str, SHA_DIGESTSIZE);
01162 
01163     ppp_write(pcb, p);
01164 }
01165 #endif /* USE_SRP */
01166 
01167 static void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) {
01168     struct pbuf *p;
01169     u_char *outp;
01170     int msglen;
01171 
01172     msglen = EAP_HEADERLEN + 2 * sizeof (u_char);
01173     p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
01174     if(NULL == p)
01175         return;
01176     if(p->tot_len != p->len) {
01177         pbuf_free(p);
01178         return;
01179     }
01180 
01181     outp = (u_char*)p->payload;
01182 
01183     MAKEHEADER(outp, PPP_EAP);
01184 
01185     PUTCHAR(EAP_RESPONSE, outp);
01186     PUTCHAR(id, outp);
01187     pcb->eap.es_client.ea_id = id;
01188     PUTSHORT(msglen, outp);
01189     PUTCHAR(EAPT_NAK, outp);
01190     PUTCHAR(type, outp);
01191 
01192     ppp_write(pcb, p);
01193 }
01194 
01195 #ifdef USE_SRP
01196 static char *
01197 name_of_pn_file()
01198 {
01199     char *user, *path, *file;
01200     struct passwd *pw;
01201     size_t pl;
01202     static bool pnlogged = 0;
01203 
01204     pw = getpwuid(getuid());
01205     if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) {
01206         errno = EINVAL;
01207         return (NULL);
01208     }
01209     file = _PATH_PSEUDONYM;
01210     pl = strlen(user) + strlen(file) + 2;
01211     path = malloc(pl);
01212     if (path == NULL)
01213         return (NULL);
01214     (void) slprintf(path, pl, "%s/%s", user, file);
01215     if (!pnlogged) {
01216         ppp_dbglog("pseudonym file: %s", path);
01217         pnlogged = 1;
01218     }
01219     return (path);
01220 }
01221 
01222 static int
01223 open_pn_file(modebits)
01224 mode_t modebits;
01225 {
01226     char *path;
01227     int fd, err;
01228 
01229     if ((path = name_of_pn_file()) == NULL)
01230         return (-1);
01231     fd = open(path, modebits, S_IRUSR | S_IWUSR);
01232     err = errno;
01233     free(path);
01234     errno = err;
01235     return (fd);
01236 }
01237 
01238 static void
01239 remove_pn_file()
01240 {
01241     char *path;
01242 
01243     if ((path = name_of_pn_file()) != NULL) {
01244         (void) unlink(path);
01245         (void) free(path);
01246     }
01247 }
01248 
01249 static void
01250 write_pseudonym(esp, inp, len, id)
01251 eap_state *esp;
01252 u_char *inp;
01253 int len, id;
01254 {
01255     u_char val;
01256     u_char *datp, *digp;
01257     SHA1_CTX ctxt;
01258     u_char dig[SHA_DIGESTSIZE];
01259     int dsize, fd, olen = len;
01260 
01261     /*
01262      * Do the decoding by working backwards.  This eliminates the need
01263      * to save the decoded output in a separate buffer.
01264      */
01265     val = id;
01266     while (len > 0) {
01267         if ((dsize = len % SHA_DIGESTSIZE) == 0)
01268             dsize = SHA_DIGESTSIZE;
01269         len -= dsize;
01270         datp = inp + len;
01271         SHA1Init(&ctxt);
01272         SHA1Update(&ctxt, &val, 1);
01273         SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, SESSION_KEY_LEN);
01274         if (len > 0) {
01275             SHA1Update(&ctxt, datp, SHA_DIGESTSIZE);
01276         } else {
01277             SHA1Update(&ctxt, pcb->eap.es_client.ea_name,
01278                 pcb->eap.es_client.ea_namelen);
01279         }
01280         SHA1Final(dig, &ctxt);
01281         for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++)
01282             *datp++ ^= *digp;
01283     }
01284 
01285     /* Now check that the result is sane */
01286     if (olen <= 0 || *inp + 1 > olen) {
01287         ppp_dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp);
01288         return;
01289     }
01290 
01291     /* Save it away */
01292     fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC);
01293     if (fd < 0) {
01294         ppp_dbglog("EAP: error saving pseudonym: %m");
01295         return;
01296     }
01297     len = write(fd, inp + 1, *inp);
01298     if (close(fd) != -1 && len == *inp) {
01299         ppp_dbglog("EAP: saved pseudonym");
01300         pcb->eap.es_usedpseudo = 0;
01301     } else {
01302         ppp_dbglog("EAP: failed to save pseudonym");
01303         remove_pn_file();
01304     }
01305 }
01306 #endif /* USE_SRP */
01307 
01308 /*
01309  * eap_request - Receive EAP Request message (client mode).
01310  */
01311 static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) {
01312     u_char typenum;
01313     u_char vallen;
01314     int secret_len;
01315     char secret[MAXSECRETLEN];
01316     char rhostname[MAXNAMELEN];
01317     lwip_md5_context mdContext;
01318     u_char hash[MD5_SIGNATURE_SIZE];
01319 #ifdef USE_SRP
01320     struct t_client *tc;
01321     struct t_num sval, gval, Nval, *Ap, Bval;
01322     u_char vals[2];
01323     SHA1_CTX ctxt;
01324     u_char dig[SHA_DIGESTSIZE];
01325     int fd;
01326 #endif /* USE_SRP */
01327 
01328     /*
01329      * Note: we update es_client.ea_id *only if* a Response
01330      * message is being generated.  Otherwise, we leave it the
01331      * same for duplicate detection purposes.
01332      */
01333 
01334     pcb->eap.es_client.ea_requests++;
01335     if (pcb->settings.eap_allow_req != 0 &&
01336         pcb->eap.es_client.ea_requests > pcb->settings.eap_allow_req) {
01337         ppp_info("EAP: received too many Request messages");
01338         if (pcb->settings.eap_req_time > 0) {
01339             UNTIMEOUT(eap_client_timeout, pcb);
01340         }
01341         auth_withpeer_fail(pcb, PPP_EAP);
01342         return;
01343     }
01344 
01345     if (len <= 0) {
01346         ppp_error("EAP: empty Request message discarded");
01347         return;
01348     }
01349 
01350     GETCHAR(typenum, inp);
01351     len--;
01352 
01353     switch (typenum) {
01354     case EAPT_IDENTITY:
01355         if (len > 0)
01356             ppp_info("EAP: Identity prompt \"%.*q\"", len, inp);
01357 #ifdef USE_SRP
01358         if (pcb->eap.es_usepseudo &&
01359             (pcb->eap.es_usedpseudo == 0 ||
01360             (pcb->eap.es_usedpseudo == 1 &&
01361                 id == pcb->eap.es_client.ea_id))) {
01362             pcb->eap.es_usedpseudo = 1;
01363             /* Try to get a pseudonym */
01364             if ((fd = open_pn_file(O_RDONLY)) >= 0) {
01365                 strcpy(rhostname, SRP_PSEUDO_ID);
01366                 len = read(fd, rhostname + SRP_PSEUDO_LEN,
01367                     sizeof (rhostname) - SRP_PSEUDO_LEN);
01368                 /* XXX NAI unsupported */
01369                 if (len > 0) {
01370                     eap_send_response(pcb, id, typenum,
01371                         rhostname, len + SRP_PSEUDO_LEN);
01372                 }
01373                 (void) close(fd);
01374                 if (len > 0)
01375                     break;
01376             }
01377         }
01378         /* Stop using pseudonym now. */
01379         if (pcb->eap.es_usepseudo && pcb->eap.es_usedpseudo != 2) {
01380             remove_pn_file();
01381             pcb->eap.es_usedpseudo = 2;
01382         }
01383 #endif /* USE_SRP */
01384         eap_send_response(pcb, id, typenum, (const u_char*)pcb->eap.es_client.ea_name,
01385             pcb->eap.es_client.ea_namelen);
01386         break;
01387 
01388     case EAPT_NOTIFICATION:
01389         if (len > 0)
01390             ppp_info("EAP: Notification \"%.*q\"", len, inp);
01391         eap_send_response(pcb, id, typenum, NULL, 0);
01392         break;
01393 
01394     case EAPT_NAK:
01395         /*
01396          * Avoid the temptation to send Response Nak in reply
01397          * to Request Nak here.  It can only lead to trouble.
01398          */
01399         ppp_warn("EAP: unexpected Nak in Request; ignored");
01400         /* Return because we're waiting for something real. */
01401         return;
01402 
01403     case EAPT_MD5CHAP:
01404         if (len < 1) {
01405             ppp_error("EAP: received MD5-Challenge with no data");
01406             /* Bogus request; wait for something real. */
01407             return;
01408         }
01409         GETCHAR(vallen, inp);
01410         len--;
01411         if (vallen < 8 || vallen > len) {
01412             ppp_error("EAP: MD5-Challenge with bad length %d (8..%d)",
01413                 vallen, len);
01414             /* Try something better. */
01415             eap_send_nak(pcb, id, EAPT_SRP);
01416             break;
01417         }
01418 
01419         /* Not so likely to happen. */
01420         if (vallen >= len + sizeof (rhostname)) {
01421             ppp_dbglog("EAP: trimming really long peer name down");
01422             MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1);
01423             rhostname[sizeof (rhostname) - 1] = '\0';
01424         } else {
01425             MEMCPY(rhostname, inp + vallen, len - vallen);
01426             rhostname[len - vallen] = '\0';
01427         }
01428 
01429 #if PPP_REMOTENAME
01430         /* In case the remote doesn't give us his name. */
01431         if (pcb->settings.explicit_remote ||
01432             (pcb->settings.remote_name[0] != '\0' && vallen == len))
01433             strlcpy(rhostname, pcb->settings.remote_name, sizeof (rhostname));
01434 #endif /* PPP_REMOTENAME */
01435 
01436         /*
01437          * Get the secret for authenticating ourselves with
01438          * the specified host.
01439          */
01440         if (!get_secret(pcb, pcb->eap.es_client.ea_name,
01441             rhostname, secret, &secret_len, 0)) {
01442             ppp_dbglog("EAP: no MD5 secret for auth to %q", rhostname);
01443             eap_send_nak(pcb, id, EAPT_SRP);
01444             break;
01445         }
01446         lwip_md5_init(&mdContext);
01447         lwip_md5_starts(&mdContext);
01448         typenum = id;
01449         lwip_md5_update(&mdContext, &typenum, 1);
01450         lwip_md5_update(&mdContext, (u_char *)secret, secret_len);
01451         BZERO(secret, sizeof (secret));
01452         lwip_md5_update(&mdContext, inp, vallen);
01453         lwip_md5_finish(&mdContext, hash);
01454         lwip_md5_free(&mdContext);
01455         eap_chap_response(pcb, id, hash, pcb->eap.es_client.ea_name,
01456             pcb->eap.es_client.ea_namelen);
01457         break;
01458 
01459 #ifdef USE_SRP
01460     case EAPT_SRP:
01461         if (len < 1) {
01462             ppp_error("EAP: received empty SRP Request");
01463             /* Bogus request; wait for something real. */
01464             return;
01465         }
01466 
01467         /* Get subtype */
01468         GETCHAR(vallen, inp);
01469         len--;
01470         switch (vallen) {
01471         case EAPSRP_CHALLENGE:
01472             tc = NULL;
01473             if (pcb->eap.es_client.ea_session != NULL) {
01474                 tc = (struct t_client *)pcb->eap.es_client.
01475                     ea_session;
01476                 /*
01477                  * If this is a new challenge, then start
01478                  * over with a new client session context.
01479                  * Otherwise, just resend last response.
01480                  */
01481                 if (id != pcb->eap.es_client.ea_id) {
01482                     t_clientclose(tc);
01483                     pcb->eap.es_client.ea_session = NULL;
01484                     tc = NULL;
01485                 }
01486             }
01487             /* No session key just yet */
01488             pcb->eap.es_client.ea_skey = NULL;
01489             if (tc == NULL) {
01490                 int rhostnamelen;
01491 
01492                 GETCHAR(vallen, inp);
01493                 len--;
01494                 if (vallen >= len) {
01495                     ppp_error("EAP: badly-formed SRP Challenge"
01496                         " (name)");
01497                     /* Ignore badly-formed messages */
01498                     return;
01499                 }
01500                 MEMCPY(rhostname, inp, vallen);
01501                 rhostname[vallen] = '\0';
01502                 INCPTR(vallen, inp);
01503                 len -= vallen;
01504 
01505                 /*
01506                  * In case the remote doesn't give us his name,
01507                  * use configured name.
01508                  */
01509                 if (explicit_remote ||
01510                     (remote_name[0] != '\0' && vallen == 0)) {
01511                     strlcpy(rhostname, remote_name,
01512                         sizeof (rhostname));
01513                 }
01514 
01515                 rhostnamelen = (int)strlen(rhostname);
01516                 if (rhostnamelen > MAXNAMELEN) {
01517                     rhostnamelen = MAXNAMELEN;
01518                 }
01519                 MEMCPY(pcb->eap.es_client.ea_peer, rhostname, rhostnamelen);
01520                 pcb->eap.es_client.ea_peer[rhostnamelen] = '\0';
01521                 pcb->eap.es_client.ea_peerlen = rhostnamelen;
01522 
01523                 GETCHAR(vallen, inp);
01524                 len--;
01525                 if (vallen >= len) {
01526                     ppp_error("EAP: badly-formed SRP Challenge"
01527                         " (s)");
01528                     /* Ignore badly-formed messages */
01529                     return;
01530                 }
01531                 sval.data = inp;
01532                 sval.len = vallen;
01533                 INCPTR(vallen, inp);
01534                 len -= vallen;
01535 
01536                 GETCHAR(vallen, inp);
01537                 len--;
01538                 if (vallen > len) {
01539                     ppp_error("EAP: badly-formed SRP Challenge"
01540                         " (g)");
01541                     /* Ignore badly-formed messages */
01542                     return;
01543                 }
01544                 /* If no generator present, then use value 2 */
01545                 if (vallen == 0) {
01546                     gval.data = (u_char *)"\002";
01547                     gval.len = 1;
01548                 } else {
01549                     gval.data = inp;
01550                     gval.len = vallen;
01551                 }
01552                 INCPTR(vallen, inp);
01553                 len -= vallen;
01554 
01555                 /*
01556                  * If no modulus present, then use well-known
01557                  * value.
01558                  */
01559                 if (len == 0) {
01560                     Nval.data = (u_char *)wkmodulus;
01561                     Nval.len = sizeof (wkmodulus);
01562                 } else {
01563                     Nval.data = inp;
01564                     Nval.len = len;
01565                 }
01566                 tc = t_clientopen(pcb->eap.es_client.ea_name,
01567                     &Nval, &gval, &sval);
01568                 if (tc == NULL) {
01569                     eap_send_nak(pcb, id, EAPT_MD5CHAP);
01570                     break;
01571                 }
01572                 pcb->eap.es_client.ea_session = (void *)tc;
01573 
01574                 /* Add Challenge ID & type to verifier */
01575                 vals[0] = id;
01576                 vals[1] = EAPT_SRP;
01577                 t_clientaddexdata(tc, vals, 2);
01578             }
01579             Ap = t_clientgenexp(tc);
01580             eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data,
01581                 Ap->len);
01582             break;
01583 
01584         case EAPSRP_SKEY:
01585             tc = (struct t_client *)pcb->eap.es_client.ea_session;
01586             if (tc == NULL) {
01587                 ppp_warn("EAP: peer sent Subtype 2 without 1");
01588                 eap_send_nak(pcb, id, EAPT_MD5CHAP);
01589                 break;
01590             }
01591             if (pcb->eap.es_client.ea_skey != NULL) {
01592                 /*
01593                  * ID number should not change here.  Warn
01594                  * if it does (but otherwise ignore).
01595                  */
01596                 if (id != pcb->eap.es_client.ea_id) {
01597                     ppp_warn("EAP: ID changed from %d to %d "
01598                         "in SRP Subtype 2 rexmit",
01599                         pcb->eap.es_client.ea_id, id);
01600                 }
01601             } else {
01602                 if (get_srp_secret(pcb->eap.es_unit,
01603                     pcb->eap.es_client.ea_name,
01604                     pcb->eap.es_client.ea_peer, secret, 0) == 0) {
01605                     /*
01606                      * Can't work with this peer because
01607                      * the secret is missing.  Just give
01608                      * up.
01609                      */
01610                     eap_send_nak(pcb, id, EAPT_MD5CHAP);
01611                     break;
01612                 }
01613                 Bval.data = inp;
01614                 Bval.len = len;
01615                 t_clientpasswd(tc, secret);
01616                 BZERO(secret, sizeof (secret));
01617                 pcb->eap.es_client.ea_skey =
01618                     t_clientgetkey(tc, &Bval);
01619                 if (pcb->eap.es_client.ea_skey == NULL) {
01620                     /* Server is rogue; stop now */
01621                     ppp_error("EAP: SRP server is rogue");
01622                     goto client_failure;
01623                 }
01624             }
01625             eap_srpval_response(esp, id, SRPVAL_EBIT,
01626                 t_clientresponse(tc));
01627             break;
01628 
01629         case EAPSRP_SVALIDATOR:
01630             tc = (struct t_client *)pcb->eap.es_client.ea_session;
01631             if (tc == NULL || pcb->eap.es_client.ea_skey == NULL) {
01632                 ppp_warn("EAP: peer sent Subtype 3 without 1/2");
01633                 eap_send_nak(pcb, id, EAPT_MD5CHAP);
01634                 break;
01635             }
01636             /*
01637              * If we're already open, then this ought to be a
01638              * duplicate.  Otherwise, check that the server is
01639              * who we think it is.
01640              */
01641             if (pcb->eap.es_client.ea_state == eapOpen) {
01642                 if (id != pcb->eap.es_client.ea_id) {
01643                     ppp_warn("EAP: ID changed from %d to %d "
01644                         "in SRP Subtype 3 rexmit",
01645                         pcb->eap.es_client.ea_id, id);
01646                 }
01647             } else {
01648                 len -= sizeof (u32_t) + SHA_DIGESTSIZE;
01649                 if (len < 0 || t_clientverify(tc, inp +
01650                     sizeof (u32_t)) != 0) {
01651                     ppp_error("EAP: SRP server verification "
01652                         "failed");
01653                     goto client_failure;
01654                 }
01655                 GETLONG(pcb->eap.es_client.ea_keyflags, inp);
01656                 /* Save pseudonym if user wants it. */
01657                 if (len > 0 && pcb->eap.es_usepseudo) {
01658                     INCPTR(SHA_DIGESTSIZE, inp);
01659                     write_pseudonym(esp, inp, len, id);
01660                 }
01661             }
01662             /*
01663              * We've verified our peer.  We're now mostly done,
01664              * except for waiting on the regular EAP Success
01665              * message.
01666              */
01667             eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0);
01668             break;
01669 
01670         case EAPSRP_LWRECHALLENGE:
01671             if (len < 4) {
01672                 ppp_warn("EAP: malformed Lightweight rechallenge");
01673                 return;
01674             }
01675             SHA1Init(&ctxt);
01676             vals[0] = id;
01677             SHA1Update(&ctxt, vals, 1);
01678             SHA1Update(&ctxt, pcb->eap.es_client.ea_skey,
01679                 SESSION_KEY_LEN);
01680             SHA1Update(&ctxt, inp, len);
01681             SHA1Update(&ctxt, pcb->eap.es_client.ea_name,
01682                 pcb->eap.es_client.ea_namelen);
01683             SHA1Final(dig, &ctxt);
01684             eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig,
01685                 SHA_DIGESTSIZE);
01686             break;
01687 
01688         default:
01689             ppp_error("EAP: unknown SRP Subtype %d", vallen);
01690             eap_send_nak(pcb, id, EAPT_MD5CHAP);
01691             break;
01692         }
01693         break;
01694 #endif /* USE_SRP */
01695 
01696     default:
01697         ppp_info("EAP: unknown authentication type %d; Naking", typenum);
01698         eap_send_nak(pcb, id, EAPT_SRP);
01699         break;
01700     }
01701 
01702     if (pcb->settings.eap_req_time > 0) {
01703         UNTIMEOUT(eap_client_timeout, pcb);
01704         TIMEOUT(eap_client_timeout, pcb,
01705             pcb->settings.eap_req_time);
01706     }
01707     return;
01708 
01709 #ifdef USE_SRP
01710 client_failure:
01711     pcb->eap.es_client.ea_state = eapBadAuth;
01712     if (pcb->settings.eap_req_time > 0) {
01713         UNTIMEOUT(eap_client_timeout, (void *)esp);
01714     }
01715     pcb->eap.es_client.ea_session = NULL;
01716     t_clientclose(tc);
01717     auth_withpeer_fail(pcb, PPP_EAP);
01718 #endif /* USE_SRP */
01719 }
01720 
01721 #if PPP_SERVER
01722 /*
01723  * eap_response - Receive EAP Response message (server mode).
01724  */
01725 static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) {
01726     u_char typenum;
01727     u_char vallen;
01728     int secret_len;
01729     char secret[MAXSECRETLEN];
01730     char rhostname[MAXNAMELEN];
01731     lwip_md5_context mdContext;
01732     u_char hash[MD5_SIGNATURE_SIZE];
01733 #ifdef USE_SRP
01734     struct t_server *ts;
01735     struct t_num A;
01736     SHA1_CTX ctxt;
01737     u_char dig[SHA_DIGESTSIZE];
01738 #endif /* USE_SRP */
01739 
01740     if (pcb->eap.es_server.ea_id != id) {
01741         ppp_dbglog("EAP: discarding Response %d; expected ID %d", id,
01742             pcb->eap.es_server.ea_id);
01743         return;
01744     }
01745 
01746     pcb->eap.es_server.ea_responses++;
01747 
01748     if (len <= 0) {
01749         ppp_error("EAP: empty Response message discarded");
01750         return;
01751     }
01752 
01753     GETCHAR(typenum, inp);
01754     len--;
01755 
01756     switch (typenum) {
01757     case EAPT_IDENTITY:
01758         if (pcb->eap.es_server.ea_state != eapIdentify) {
01759             ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len,
01760                 inp);
01761             break;
01762         }
01763         ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp);
01764         if (len > MAXNAMELEN) {
01765           len = MAXNAMELEN;
01766         }
01767         MEMCPY(pcb->eap.es_server.ea_peer, inp, len);
01768         pcb->eap.es_server.ea_peer[len] = '\0';
01769         pcb->eap.es_server.ea_peerlen = len;
01770         eap_figure_next_state(pcb, 0);
01771         break;
01772 
01773     case EAPT_NOTIFICATION:
01774         ppp_dbglog("EAP unexpected Notification; response discarded");
01775         break;
01776 
01777     case EAPT_NAK:
01778         if (len < 1) {
01779             ppp_info("EAP: Nak Response with no suggested protocol");
01780             eap_figure_next_state(pcb, 1);
01781             break;
01782         }
01783 
01784         GETCHAR(vallen, inp);
01785         len--;
01786 
01787         if (
01788 #if PPP_REMOTENAME
01789         !pcb->explicit_remote &&
01790 #endif /* PPP_REMOTENAME */
01791         pcb->eap.es_server.ea_state == eapIdentify){
01792             /* Peer cannot Nak Identify Request */
01793             eap_figure_next_state(pcb, 1);
01794             break;
01795         }
01796 
01797         switch (vallen) {
01798         case EAPT_SRP:
01799             /* Run through SRP validator selection again. */
01800             pcb->eap.es_server.ea_state = eapIdentify;
01801             eap_figure_next_state(pcb, 0);
01802             break;
01803 
01804         case EAPT_MD5CHAP:
01805             pcb->eap.es_server.ea_state = eapMD5Chall;
01806             break;
01807 
01808         default:
01809             ppp_dbglog("EAP: peer requesting unknown Type %d", vallen);
01810             switch (pcb->eap.es_server.ea_state) {
01811             case eapSRP1:
01812             case eapSRP2:
01813             case eapSRP3:
01814                 pcb->eap.es_server.ea_state = eapMD5Chall;
01815                 break;
01816             case eapMD5Chall:
01817             case eapSRP4:
01818                 pcb->eap.es_server.ea_state = eapIdentify;
01819                 eap_figure_next_state(pcb, 0);
01820                 break;
01821             default:
01822                 break;
01823             }
01824             break;
01825         }
01826         break;
01827 
01828     case EAPT_MD5CHAP:
01829         if (pcb->eap.es_server.ea_state != eapMD5Chall) {
01830             ppp_error("EAP: unexpected MD5-Response");
01831             eap_figure_next_state(pcb, 1);
01832             break;
01833         }
01834         if (len < 1) {
01835             ppp_error("EAP: received MD5-Response with no data");
01836             eap_figure_next_state(pcb, 1);
01837             break;
01838         }
01839         GETCHAR(vallen, inp);
01840         len--;
01841         if (vallen != 16 || vallen > len) {
01842             ppp_error("EAP: MD5-Response with bad length %d", vallen);
01843             eap_figure_next_state(pcb, 1);
01844             break;
01845         }
01846 
01847         /* Not so likely to happen. */
01848         if (vallen >= len + sizeof (rhostname)) {
01849             ppp_dbglog("EAP: trimming really long peer name down");
01850             MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1);
01851             rhostname[sizeof (rhostname) - 1] = '\0';
01852         } else {
01853             MEMCPY(rhostname, inp + vallen, len - vallen);
01854             rhostname[len - vallen] = '\0';
01855         }
01856 
01857 #if PPP_REMOTENAME
01858         /* In case the remote doesn't give us his name. */
01859         if (explicit_remote ||
01860             (remote_name[0] != '\0' && vallen == len))
01861             strlcpy(rhostname, remote_name, sizeof (rhostname));
01862 #endif /* PPP_REMOTENAME */
01863 
01864         /*
01865          * Get the secret for authenticating the specified
01866          * host.
01867          */
01868         if (!get_secret(pcb, rhostname,
01869             pcb->eap.es_server.ea_name, secret, &secret_len, 1)) {
01870             ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname);
01871             eap_send_failure(pcb);
01872             break;
01873         }
01874         lwip_md5_init(&mdContext);
01875         lwip_md5_starts(&mdContext);
01876         lwip_md5_update(&mdContext, &pcb->eap.es_server.ea_id, 1);
01877         lwip_md5_update(&mdContext, (u_char *)secret, secret_len);
01878         BZERO(secret, sizeof (secret));
01879         lwip_md5_update(&mdContext, pcb->eap.es_challenge, pcb->eap.es_challen);
01880         lwip_md5_finish(&mdContext, hash);
01881         lwip_md5_free(&mdContext);
01882         if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) {
01883             eap_send_failure(pcb);
01884             break;
01885         }
01886         pcb->eap.es_server.ea_type = EAPT_MD5CHAP;
01887         eap_send_success(pcb);
01888         eap_figure_next_state(pcb, 0);
01889         if (pcb->eap.es_rechallenge != 0)
01890             TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge);
01891         break;
01892 
01893 #ifdef USE_SRP
01894     case EAPT_SRP:
01895         if (len < 1) {
01896             ppp_error("EAP: empty SRP Response");
01897             eap_figure_next_state(pcb, 1);
01898             break;
01899         }
01900         GETCHAR(typenum, inp);
01901         len--;
01902         switch (typenum) {
01903         case EAPSRP_CKEY:
01904             if (pcb->eap.es_server.ea_state != eapSRP1) {
01905                 ppp_error("EAP: unexpected SRP Subtype 1 Response");
01906                 eap_figure_next_state(pcb, 1);
01907                 break;
01908             }
01909             A.data = inp;
01910             A.len = len;
01911             ts = (struct t_server *)pcb->eap.es_server.ea_session;
01912             assert(ts != NULL);
01913             pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A);
01914             if (pcb->eap.es_server.ea_skey == NULL) {
01915                 /* Client's A value is bogus; terminate now */
01916                 ppp_error("EAP: bogus A value from client");
01917                 eap_send_failure(pcb);
01918             } else {
01919                 eap_figure_next_state(pcb, 0);
01920             }
01921             break;
01922 
01923         case EAPSRP_CVALIDATOR:
01924             if (pcb->eap.es_server.ea_state != eapSRP2) {
01925                 ppp_error("EAP: unexpected SRP Subtype 2 Response");
01926                 eap_figure_next_state(pcb, 1);
01927                 break;
01928             }
01929             if (len < sizeof (u32_t) + SHA_DIGESTSIZE) {
01930                 ppp_error("EAP: M1 length %d < %d", len,
01931                     sizeof (u32_t) + SHA_DIGESTSIZE);
01932                 eap_figure_next_state(pcb, 1);
01933                 break;
01934             }
01935             GETLONG(pcb->eap.es_server.ea_keyflags, inp);
01936             ts = (struct t_server *)pcb->eap.es_server.ea_session;
01937             assert(ts != NULL);
01938             if (t_serververify(ts, inp)) {
01939                 ppp_info("EAP: unable to validate client identity");
01940                 eap_send_failure(pcb);
01941                 break;
01942             }
01943             eap_figure_next_state(pcb, 0);
01944             break;
01945 
01946         case EAPSRP_ACK:
01947             if (pcb->eap.es_server.ea_state != eapSRP3) {
01948                 ppp_error("EAP: unexpected SRP Subtype 3 Response");
01949                 eap_send_failure(esp);
01950                 break;
01951             }
01952             pcb->eap.es_server.ea_type = EAPT_SRP;
01953             eap_send_success(pcb, esp);
01954             eap_figure_next_state(pcb, 0);
01955             if (pcb->eap.es_rechallenge != 0)
01956                 TIMEOUT(eap_rechallenge, pcb,
01957                     pcb->eap.es_rechallenge);
01958             if (pcb->eap.es_lwrechallenge != 0)
01959                 TIMEOUT(srp_lwrechallenge, pcb,
01960                     pcb->eap.es_lwrechallenge);
01961             break;
01962 
01963         case EAPSRP_LWRECHALLENGE:
01964             if (pcb->eap.es_server.ea_state != eapSRP4) {
01965                 ppp_info("EAP: unexpected SRP Subtype 4 Response");
01966                 return;
01967             }
01968             if (len != SHA_DIGESTSIZE) {
01969                 ppp_error("EAP: bad Lightweight rechallenge "
01970                     "response");
01971                 return;
01972             }
01973             SHA1Init(&ctxt);
01974             vallen = id;
01975             SHA1Update(&ctxt, &vallen, 1);
01976             SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
01977                 SESSION_KEY_LEN);
01978             SHA1Update(&ctxt, pcb->eap.es_challenge, pcb->eap.es_challen);
01979             SHA1Update(&ctxt, pcb->eap.es_server.ea_peer,
01980                 pcb->eap.es_server.ea_peerlen);
01981             SHA1Final(dig, &ctxt);
01982             if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) {
01983                 ppp_error("EAP: failed Lightweight rechallenge");
01984                 eap_send_failure(pcb);
01985                 break;
01986             }
01987             pcb->eap.es_server.ea_state = eapOpen;
01988             if (pcb->eap.es_lwrechallenge != 0)
01989                 TIMEOUT(srp_lwrechallenge, esp,
01990                     pcb->eap.es_lwrechallenge);
01991             break;
01992         }
01993         break;
01994 #endif /* USE_SRP */
01995 
01996     default:
01997         /* This can't happen. */
01998         ppp_error("EAP: unknown Response type %d; ignored", typenum);
01999         return;
02000     }
02001 
02002     if (pcb->settings.eap_timeout_time > 0) {
02003         UNTIMEOUT(eap_server_timeout, pcb);
02004     }
02005 
02006     if (pcb->eap.es_server.ea_state != eapBadAuth &&
02007         pcb->eap.es_server.ea_state != eapOpen) {
02008         pcb->eap.es_server.ea_id++;
02009         eap_send_request(pcb);
02010     }
02011 }
02012 #endif /* PPP_SERVER */
02013 
02014 /*
02015  * eap_success - Receive EAP Success message (client mode).
02016  */
02017 static void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) {
02018     LWIP_UNUSED_ARG(id);
02019 
02020     if (pcb->eap.es_client.ea_state != eapOpen && !eap_client_active(pcb)) {
02021         ppp_dbglog("EAP unexpected success message in state %s (%d)",
02022             eap_state_name(pcb->eap.es_client.ea_state),
02023             pcb->eap.es_client.ea_state);
02024         return;
02025     }
02026 
02027     if (pcb->settings.eap_req_time > 0) {
02028         UNTIMEOUT(eap_client_timeout, pcb);
02029     }
02030 
02031     if (len > 0) {
02032         /* This is odd.  The spec doesn't allow for this. */
02033         PRINTMSG(inp, len);
02034     }
02035 
02036     pcb->eap.es_client.ea_state = eapOpen;
02037     auth_withpeer_success(pcb, PPP_EAP, 0);
02038 }
02039 
02040 /*
02041  * eap_failure - Receive EAP Failure message (client mode).
02042  */
02043 static void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) {
02044     LWIP_UNUSED_ARG(id);
02045 
02046     if (!eap_client_active(pcb)) {
02047         ppp_dbglog("EAP unexpected failure message in state %s (%d)",
02048             eap_state_name(pcb->eap.es_client.ea_state),
02049             pcb->eap.es_client.ea_state);
02050     }
02051 
02052     if (pcb->settings.eap_req_time > 0) {
02053         UNTIMEOUT(eap_client_timeout, pcb);
02054     }
02055 
02056     if (len > 0) {
02057         /* This is odd.  The spec doesn't allow for this. */
02058         PRINTMSG(inp, len);
02059     }
02060 
02061     pcb->eap.es_client.ea_state = eapBadAuth;
02062 
02063     ppp_error("EAP: peer reports authentication failure");
02064     auth_withpeer_fail(pcb, PPP_EAP);
02065 }
02066 
02067 /*
02068  * eap_input - Handle received EAP message.
02069  */
02070 static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) {
02071     u_char code, id;
02072     int len;
02073 
02074     /*
02075      * Parse header (code, id and length).  If packet too short,
02076      * drop it.
02077      */
02078     if (inlen < EAP_HEADERLEN) {
02079         ppp_error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN);
02080         return;
02081     }
02082     GETCHAR(code, inp);
02083     GETCHAR(id, inp);
02084     GETSHORT(len, inp);
02085     if (len < EAP_HEADERLEN || len > inlen) {
02086         ppp_error("EAP: packet has illegal length field %d (%d..%d)", len,
02087             EAP_HEADERLEN, inlen);
02088         return;
02089     }
02090     len -= EAP_HEADERLEN;
02091 
02092     /* Dispatch based on message code */
02093     switch (code) {
02094     case EAP_REQUEST:
02095         eap_request(pcb, inp, id, len);
02096         break;
02097 
02098 #if PPP_SERVER
02099     case EAP_RESPONSE:
02100         eap_response(pcb, inp, id, len);
02101         break;
02102 #endif /* PPP_SERVER */
02103 
02104     case EAP_SUCCESS:
02105         eap_success(pcb, inp, id, len);
02106         break;
02107 
02108     case EAP_FAILURE:
02109         eap_failure(pcb, inp, id, len);
02110         break;
02111 
02112     default:                /* XXX Need code reject */
02113         /* Note: it's not legal to send EAP Nak here. */
02114         ppp_warn("EAP: unknown code %d received", code);
02115         break;
02116     }
02117 }
02118 
02119 #if PRINTPKT_SUPPORT
02120 /*
02121  * eap_printpkt - print the contents of an EAP packet.
02122  */
02123 static const char* const eap_codenames[] = {
02124     "Request", "Response", "Success", "Failure"
02125 };
02126 
02127 static const char* const eap_typenames[] = {
02128     "Identity", "Notification", "Nak", "MD5-Challenge",
02129     "OTP", "Generic-Token", NULL, NULL,
02130     "RSA", "DSS", "KEA", "KEA-Validate",
02131     "TLS", "Defender", "Windows 2000", "Arcot",
02132     "Cisco", "Nokia", "SRP"
02133 };
02134 
02135 static int eap_printpkt(const u_char *inp, int inlen, void (*printer) (void *, const char *, ...), void *arg) {
02136     int code, id, len, rtype, vallen;
02137     const u_char *pstart;
02138     u32_t uval;
02139 
02140     if (inlen < EAP_HEADERLEN)
02141         return (0);
02142     pstart = inp;
02143     GETCHAR(code, inp);
02144     GETCHAR(id, inp);
02145     GETSHORT(len, inp);
02146     if (len < EAP_HEADERLEN || len > inlen)
02147         return (0);
02148 
02149     if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(eap_codenames))
02150         printer(arg, " %s", eap_codenames[code-1]);
02151     else
02152         printer(arg, " code=0x%x", code);
02153     printer(arg, " id=0x%x", id);
02154     len -= EAP_HEADERLEN;
02155     switch (code) {
02156     case EAP_REQUEST:
02157         if (len < 1) {
02158             printer(arg, " <missing type>");
02159             break;
02160         }
02161         GETCHAR(rtype, inp);
02162         len--;
02163         if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames))
02164             printer(arg, " %s", eap_typenames[rtype-1]);
02165         else
02166             printer(arg, " type=0x%x", rtype);
02167         switch (rtype) {
02168         case EAPT_IDENTITY:
02169         case EAPT_NOTIFICATION:
02170             if (len > 0) {
02171                 printer(arg, " <Message ");
02172                 ppp_print_string(inp, len, printer, arg);
02173                 printer(arg, ">");
02174                 INCPTR(len, inp);
02175                 len = 0;
02176             } else {
02177                 printer(arg, " <No message>");
02178             }
02179             break;
02180 
02181         case EAPT_MD5CHAP:
02182             if (len <= 0)
02183                 break;
02184             GETCHAR(vallen, inp);
02185             len--;
02186             if (vallen > len)
02187                 goto truncated;
02188             printer(arg, " <Value%.*B>", vallen, inp);
02189             INCPTR(vallen, inp);
02190             len -= vallen;
02191             if (len > 0) {
02192                 printer(arg, " <Name ");
02193                 ppp_print_string(inp, len, printer, arg);
02194                 printer(arg, ">");
02195                 INCPTR(len, inp);
02196                 len = 0;
02197             } else {
02198                 printer(arg, " <No name>");
02199             }
02200             break;
02201 
02202         case EAPT_SRP:
02203             if (len < 3)
02204                 goto truncated;
02205             GETCHAR(vallen, inp);
02206             len--;
02207             printer(arg, "-%d", vallen);
02208             switch (vallen) {
02209             case EAPSRP_CHALLENGE:
02210                 GETCHAR(vallen, inp);
02211                 len--;
02212                 if (vallen >= len)
02213                     goto truncated;
02214                 if (vallen > 0) {
02215                     printer(arg, " <Name ");
02216                     ppp_print_string(inp, vallen, printer,
02217                         arg);
02218                     printer(arg, ">");
02219                 } else {
02220                     printer(arg, " <No name>");
02221                 }
02222                 INCPTR(vallen, inp);
02223                 len -= vallen;
02224                 GETCHAR(vallen, inp);
02225                 len--;
02226                 if (vallen >= len)
02227                     goto truncated;
02228                 printer(arg, " <s%.*B>", vallen, inp);
02229                 INCPTR(vallen, inp);
02230                 len -= vallen;
02231                 GETCHAR(vallen, inp);
02232                 len--;
02233                 if (vallen > len)
02234                     goto truncated;
02235                 if (vallen == 0) {
02236                     printer(arg, " <Default g=2>");
02237                 } else {
02238                     printer(arg, " <g%.*B>", vallen, inp);
02239                 }
02240                 INCPTR(vallen, inp);
02241                 len -= vallen;
02242                 if (len == 0) {
02243                     printer(arg, " <Default N>");
02244                 } else {
02245                     printer(arg, " <N%.*B>", len, inp);
02246                     INCPTR(len, inp);
02247                     len = 0;
02248                 }
02249                 break;
02250 
02251             case EAPSRP_SKEY:
02252                 printer(arg, " <B%.*B>", len, inp);
02253                 INCPTR(len, inp);
02254                 len = 0;
02255                 break;
02256 
02257             case EAPSRP_SVALIDATOR:
02258                 if (len < (int)sizeof (u32_t))
02259                     break;
02260                 GETLONG(uval, inp);
02261                 len -= sizeof (u32_t);
02262                 if (uval & SRPVAL_EBIT) {
02263                     printer(arg, " E");
02264                     uval &= ~SRPVAL_EBIT;
02265                 }
02266                 if (uval != 0) {
02267                     printer(arg, " f<%X>", uval);
02268                 }
02269                 if ((vallen = len) > SHA_DIGESTSIZE)
02270                     vallen = SHA_DIGESTSIZE;
02271                 printer(arg, " <M2%.*B%s>", len, inp,
02272                     len < SHA_DIGESTSIZE ? "?" : "");
02273                 INCPTR(vallen, inp);
02274                 len -= vallen;
02275                 if (len > 0) {
02276                     printer(arg, " <PN%.*B>", len, inp);
02277                     INCPTR(len, inp);
02278                     len = 0;
02279                 }
02280                 break;
02281 
02282             case EAPSRP_LWRECHALLENGE:
02283                 printer(arg, " <Challenge%.*B>", len, inp);
02284                 INCPTR(len, inp);
02285                 len = 0;
02286                 break;
02287             default:
02288                 break;
02289             }
02290             break;
02291         default:
02292             break;
02293         }
02294         break;
02295 
02296     case EAP_RESPONSE:
02297         if (len < 1)
02298             break;
02299         GETCHAR(rtype, inp);
02300         len--;
02301         if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames))
02302             printer(arg, " %s", eap_typenames[rtype-1]);
02303         else
02304             printer(arg, " type=0x%x", rtype);
02305         switch (rtype) {
02306         case EAPT_IDENTITY:
02307             if (len > 0) {
02308                 printer(arg, " <Name ");
02309                 ppp_print_string(inp, len, printer, arg);
02310                 printer(arg, ">");
02311                 INCPTR(len, inp);
02312                 len = 0;
02313             }
02314             break;
02315 
02316         case EAPT_NAK:
02317             if (len <= 0) {
02318                 printer(arg, " <missing hint>");
02319                 break;
02320             }
02321             GETCHAR(rtype, inp);
02322             len--;
02323             printer(arg, " <Suggested-type %02X", rtype);
02324             if (rtype >= 1 && rtype < (int)LWIP_ARRAYSIZE(eap_typenames))
02325                 printer(arg, " (%s)", eap_typenames[rtype-1]);
02326             printer(arg, ">");
02327             break;
02328 
02329         case EAPT_MD5CHAP:
02330             if (len <= 0) {
02331                 printer(arg, " <missing length>");
02332                 break;
02333             }
02334             GETCHAR(vallen, inp);
02335             len--;
02336             if (vallen > len)
02337                 goto truncated;
02338             printer(arg, " <Value%.*B>", vallen, inp);
02339             INCPTR(vallen, inp);
02340             len -= vallen;
02341             if (len > 0) {
02342                 printer(arg, " <Name ");
02343                 ppp_print_string(inp, len, printer, arg);
02344                 printer(arg, ">");
02345                 INCPTR(len, inp);
02346                 len = 0;
02347             } else {
02348                 printer(arg, " <No name>");
02349             }
02350             break;
02351 
02352         case EAPT_SRP:
02353             if (len < 1)
02354                 goto truncated;
02355             GETCHAR(vallen, inp);
02356             len--;
02357             printer(arg, "-%d", vallen);
02358             switch (vallen) {
02359             case EAPSRP_CKEY:
02360                 printer(arg, " <A%.*B>", len, inp);
02361                 INCPTR(len, inp);
02362                 len = 0;
02363                 break;
02364 
02365             case EAPSRP_CVALIDATOR:
02366                 if (len < (int)sizeof (u32_t))
02367                     break;
02368                 GETLONG(uval, inp);
02369                 len -= sizeof (u32_t);
02370                 if (uval & SRPVAL_EBIT) {
02371                     printer(arg, " E");
02372                     uval &= ~SRPVAL_EBIT;
02373                 }
02374                 if (uval != 0) {
02375                     printer(arg, " f<%X>", uval);
02376                 }
02377                 printer(arg, " <M1%.*B%s>", len, inp,
02378                     len == SHA_DIGESTSIZE ? "" : "?");
02379                 INCPTR(len, inp);
02380                 len = 0;
02381                 break;
02382 
02383             case EAPSRP_ACK:
02384                 break;
02385 
02386             case EAPSRP_LWRECHALLENGE:
02387                 printer(arg, " <Response%.*B%s>", len, inp,
02388                     len == SHA_DIGESTSIZE ? "" : "?");
02389                 if ((vallen = len) > SHA_DIGESTSIZE)
02390                     vallen = SHA_DIGESTSIZE;
02391                 INCPTR(vallen, inp);
02392                 len -= vallen;
02393                 break;
02394             default:
02395                 break;
02396             }
02397             break;
02398         default:
02399             break;
02400         }
02401         break;
02402 
02403     case EAP_SUCCESS:   /* No payload expected for these! */
02404     case EAP_FAILURE:
02405     default:
02406         break;
02407 
02408     truncated:
02409         printer(arg, " <truncated>");
02410         break;
02411     }
02412 
02413     if (len > 8)
02414         printer(arg, "%8B...", inp);
02415     else if (len > 0)
02416         printer(arg, "%.*B", len, inp);
02417     INCPTR(len, inp);
02418 
02419     return (inp - pstart);
02420 }
02421 #endif /* PRINTPKT_SUPPORT */
02422 
02423 #endif /* PPP_SUPPORT && EAP_SUPPORT */