xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.0.2/src/netif/ppp/eap.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * eap.c - Extensible Authentication Protocol for PPP (RFC 2284)
3*10465441SEvalZero  *
4*10465441SEvalZero  * Copyright (c) 2001 by Sun Microsystems, Inc.
5*10465441SEvalZero  * All rights reserved.
6*10465441SEvalZero  *
7*10465441SEvalZero  * Non-exclusive rights to redistribute, modify, translate, and use
8*10465441SEvalZero  * this software in source and binary forms, in whole or in part, is
9*10465441SEvalZero  * hereby granted, provided that the above copyright notice is
10*10465441SEvalZero  * duplicated in any source form, and that neither the name of the
11*10465441SEvalZero  * copyright holder nor the author is used to endorse or promote
12*10465441SEvalZero  * products derived from this software.
13*10465441SEvalZero  *
14*10465441SEvalZero  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15*10465441SEvalZero  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16*10465441SEvalZero  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17*10465441SEvalZero  *
18*10465441SEvalZero  * Original version by James Carlson
19*10465441SEvalZero  *
20*10465441SEvalZero  * This implementation of EAP supports MD5-Challenge and SRP-SHA1
21*10465441SEvalZero  * authentication styles.  Note that support of MD5-Challenge is a
22*10465441SEvalZero  * requirement of RFC 2284, and that it's essentially just a
23*10465441SEvalZero  * reimplementation of regular RFC 1994 CHAP using EAP messages.
24*10465441SEvalZero  *
25*10465441SEvalZero  * As an authenticator ("server"), there are multiple phases for each
26*10465441SEvalZero  * style.  In the first phase of each style, the unauthenticated peer
27*10465441SEvalZero  * name is queried using the EAP Identity request type.  If the
28*10465441SEvalZero  * "remotename" option is used, then this phase is skipped, because
29*10465441SEvalZero  * the peer's name is presumed to be known.
30*10465441SEvalZero  *
31*10465441SEvalZero  * For MD5-Challenge, there are two phases, and the second phase
32*10465441SEvalZero  * consists of sending the challenge itself and handling the
33*10465441SEvalZero  * associated response.
34*10465441SEvalZero  *
35*10465441SEvalZero  * For SRP-SHA1, there are four phases.  The second sends 's', 'N',
36*10465441SEvalZero  * and 'g'.  The reply contains 'A'.  The third sends 'B', and the
37*10465441SEvalZero  * reply contains 'M1'.  The forth sends the 'M2' value.
38*10465441SEvalZero  *
39*10465441SEvalZero  * As an authenticatee ("client"), there's just a single phase --
40*10465441SEvalZero  * responding to the queries generated by the peer.  EAP is an
41*10465441SEvalZero  * authenticator-driven protocol.
42*10465441SEvalZero  *
43*10465441SEvalZero  * Based on draft-ietf-pppext-eap-srp-03.txt.
44*10465441SEvalZero  */
45*10465441SEvalZero 
46*10465441SEvalZero #include "netif/ppp/ppp_opts.h"
47*10465441SEvalZero #if PPP_SUPPORT && EAP_SUPPORT  /* don't build if not configured for use in lwipopts.h */
48*10465441SEvalZero 
49*10465441SEvalZero #include "netif/ppp/ppp_impl.h"
50*10465441SEvalZero #include "netif/ppp/eap.h"
51*10465441SEvalZero #include "netif/ppp/magic.h"
52*10465441SEvalZero #include "netif/ppp/pppcrypt.h"
53*10465441SEvalZero 
54*10465441SEvalZero #ifdef USE_SRP
55*10465441SEvalZero #include <t_pwd.h>
56*10465441SEvalZero #include <t_server.h>
57*10465441SEvalZero #include <t_client.h>
58*10465441SEvalZero #endif /* USE_SRP */
59*10465441SEvalZero 
60*10465441SEvalZero #ifndef SHA_DIGESTSIZE
61*10465441SEvalZero #define	SHA_DIGESTSIZE 20
62*10465441SEvalZero #endif
63*10465441SEvalZero 
64*10465441SEvalZero #ifdef USE_SRP
65*10465441SEvalZero static char *pn_secret = NULL;		/* Pseudonym generating secret */
66*10465441SEvalZero #endif
67*10465441SEvalZero 
68*10465441SEvalZero #if PPP_OPTIONS
69*10465441SEvalZero /*
70*10465441SEvalZero  * Command-line options.
71*10465441SEvalZero  */
72*10465441SEvalZero static option_t eap_option_list[] = {
73*10465441SEvalZero     { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout,
74*10465441SEvalZero       "Set retransmit timeout for EAP Requests (server)" },
75*10465441SEvalZero     { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests,
76*10465441SEvalZero       "Set max number of EAP Requests sent (server)" },
77*10465441SEvalZero     { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout,
78*10465441SEvalZero       "Set time limit for peer EAP authentication" },
79*10465441SEvalZero     { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests,
80*10465441SEvalZero       "Set max number of EAP Requests allows (client)" },
81*10465441SEvalZero     { "eap-interval", o_int, &eap_states[0].es_rechallenge,
82*10465441SEvalZero       "Set interval for EAP rechallenge" },
83*10465441SEvalZero #ifdef USE_SRP
84*10465441SEvalZero     { "srp-interval", o_int, &eap_states[0].es_lwrechallenge,
85*10465441SEvalZero       "Set interval for SRP lightweight rechallenge" },
86*10465441SEvalZero     { "srp-pn-secret", o_string, &pn_secret,
87*10465441SEvalZero       "Long term pseudonym generation secret" },
88*10465441SEvalZero     { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo,
89*10465441SEvalZero       "Use pseudonym if offered one by server", 1 },
90*10465441SEvalZero #endif
91*10465441SEvalZero     { NULL }
92*10465441SEvalZero };
93*10465441SEvalZero #endif /* PPP_OPTIONS */
94*10465441SEvalZero 
95*10465441SEvalZero /*
96*10465441SEvalZero  * Protocol entry points.
97*10465441SEvalZero  */
98*10465441SEvalZero static void eap_init(ppp_pcb *pcb);
99*10465441SEvalZero static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen);
100*10465441SEvalZero static void eap_protrej(ppp_pcb *pcb);
101*10465441SEvalZero static void eap_lowerup(ppp_pcb *pcb);
102*10465441SEvalZero static void eap_lowerdown(ppp_pcb *pcb);
103*10465441SEvalZero #if PRINTPKT_SUPPORT
104*10465441SEvalZero static int  eap_printpkt(const u_char *inp, int inlen,
105*10465441SEvalZero     void (*)(void *arg, const char *fmt, ...), void *arg);
106*10465441SEvalZero #endif /* PRINTPKT_SUPPORT */
107*10465441SEvalZero 
108*10465441SEvalZero const struct protent eap_protent = {
109*10465441SEvalZero 	PPP_EAP,		/* protocol number */
110*10465441SEvalZero 	eap_init,		/* initialization procedure */
111*10465441SEvalZero 	eap_input,		/* process a received packet */
112*10465441SEvalZero 	eap_protrej,		/* process a received protocol-reject */
113*10465441SEvalZero 	eap_lowerup,		/* lower layer has gone up */
114*10465441SEvalZero 	eap_lowerdown,		/* lower layer has gone down */
115*10465441SEvalZero 	NULL,			/* open the protocol */
116*10465441SEvalZero 	NULL,			/* close the protocol */
117*10465441SEvalZero #if PRINTPKT_SUPPORT
118*10465441SEvalZero 	eap_printpkt,		/* print a packet in readable form */
119*10465441SEvalZero #endif /* PRINTPKT_SUPPORT */
120*10465441SEvalZero #if PPP_DATAINPUT
121*10465441SEvalZero 	NULL,			/* process a received data packet */
122*10465441SEvalZero #endif /* PPP_DATAINPUT */
123*10465441SEvalZero #if PRINTPKT_SUPPORT
124*10465441SEvalZero 	"EAP",			/* text name of protocol */
125*10465441SEvalZero 	NULL,			/* text name of corresponding data protocol */
126*10465441SEvalZero #endif /* PRINTPKT_SUPPORT */
127*10465441SEvalZero #if PPP_OPTIONS
128*10465441SEvalZero 	eap_option_list,	/* list of command-line options */
129*10465441SEvalZero 	NULL,			/* check requested options; assign defaults */
130*10465441SEvalZero #endif /* PPP_OPTIONS */
131*10465441SEvalZero #if DEMAND_SUPPORT
132*10465441SEvalZero 	NULL,			/* configure interface for demand-dial */
133*10465441SEvalZero 	NULL			/* say whether to bring up link for this pkt */
134*10465441SEvalZero #endif /* DEMAND_SUPPORT */
135*10465441SEvalZero };
136*10465441SEvalZero 
137*10465441SEvalZero #ifdef USE_SRP
138*10465441SEvalZero /*
139*10465441SEvalZero  * A well-known 2048 bit modulus.
140*10465441SEvalZero  */
141*10465441SEvalZero static const u_char wkmodulus[] = {
142*10465441SEvalZero 	0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B,
143*10465441SEvalZero 	0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F,
144*10465441SEvalZero 	0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07,
145*10465441SEvalZero 	0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50,
146*10465441SEvalZero 	0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED,
147*10465441SEvalZero 	0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D,
148*10465441SEvalZero 	0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D,
149*10465441SEvalZero 	0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50,
150*10465441SEvalZero 	0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0,
151*10465441SEvalZero 	0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3,
152*10465441SEvalZero 	0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8,
153*10465441SEvalZero 	0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8,
154*10465441SEvalZero 	0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA,
155*10465441SEvalZero 	0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74,
156*10465441SEvalZero 	0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7,
157*10465441SEvalZero 	0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B,
158*10465441SEvalZero 	0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16,
159*10465441SEvalZero 	0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81,
160*10465441SEvalZero 	0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A,
161*10465441SEvalZero 	0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48,
162*10465441SEvalZero 	0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D,
163*10465441SEvalZero 	0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA,
164*10465441SEvalZero 	0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78,
165*10465441SEvalZero 	0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6,
166*10465441SEvalZero 	0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29,
167*10465441SEvalZero 	0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8,
168*10465441SEvalZero 	0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82,
169*10465441SEvalZero 	0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6,
170*10465441SEvalZero 	0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4,
171*10465441SEvalZero 	0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75,
172*10465441SEvalZero 	0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2,
173*10465441SEvalZero 	0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73
174*10465441SEvalZero };
175*10465441SEvalZero #endif
176*10465441SEvalZero 
177*10465441SEvalZero #if PPP_SERVER
178*10465441SEvalZero /* Local forward declarations. */
179*10465441SEvalZero static void eap_server_timeout(void *arg);
180*10465441SEvalZero #endif /* PPP_SERVER */
181*10465441SEvalZero 
182*10465441SEvalZero /*
183*10465441SEvalZero  * Convert EAP state code to printable string for debug.
184*10465441SEvalZero  */
eap_state_name(enum eap_state_code esc)185*10465441SEvalZero static const char * eap_state_name(enum eap_state_code esc)
186*10465441SEvalZero {
187*10465441SEvalZero 	static const char *state_names[] = { EAP_STATES };
188*10465441SEvalZero 
189*10465441SEvalZero 	return (state_names[(int)esc]);
190*10465441SEvalZero }
191*10465441SEvalZero 
192*10465441SEvalZero /*
193*10465441SEvalZero  * eap_init - Initialize state for an EAP user.  This is currently
194*10465441SEvalZero  * called once by main() during start-up.
195*10465441SEvalZero  */
eap_init(ppp_pcb * pcb)196*10465441SEvalZero static void eap_init(ppp_pcb *pcb) {
197*10465441SEvalZero 
198*10465441SEvalZero 	BZERO(&pcb->eap, sizeof(eap_state));
199*10465441SEvalZero #if PPP_SERVER
200*10465441SEvalZero 	pcb->eap.es_server.ea_id = magic();
201*10465441SEvalZero #endif /* PPP_SERVER */
202*10465441SEvalZero }
203*10465441SEvalZero 
204*10465441SEvalZero /*
205*10465441SEvalZero  * eap_client_timeout - Give up waiting for the peer to send any
206*10465441SEvalZero  * Request messages.
207*10465441SEvalZero  */
eap_client_timeout(void * arg)208*10465441SEvalZero static void eap_client_timeout(void *arg) {
209*10465441SEvalZero 	ppp_pcb *pcb = (ppp_pcb*)arg;
210*10465441SEvalZero 
211*10465441SEvalZero 	if (!eap_client_active(pcb))
212*10465441SEvalZero 		return;
213*10465441SEvalZero 
214*10465441SEvalZero 	ppp_error("EAP: timeout waiting for Request from peer");
215*10465441SEvalZero 	auth_withpeer_fail(pcb, PPP_EAP);
216*10465441SEvalZero 	pcb->eap.es_client.ea_state = eapBadAuth;
217*10465441SEvalZero }
218*10465441SEvalZero 
219*10465441SEvalZero /*
220*10465441SEvalZero  * eap_authwithpeer - Authenticate to our peer (behave as client).
221*10465441SEvalZero  *
222*10465441SEvalZero  * Start client state and wait for requests.  This is called only
223*10465441SEvalZero  * after eap_lowerup.
224*10465441SEvalZero  */
eap_authwithpeer(ppp_pcb * pcb,const char * localname)225*10465441SEvalZero void eap_authwithpeer(ppp_pcb *pcb, const char *localname) {
226*10465441SEvalZero 
227*10465441SEvalZero 	if(NULL == localname)
228*10465441SEvalZero 		return;
229*10465441SEvalZero 
230*10465441SEvalZero 	/* Save the peer name we're given */
231*10465441SEvalZero 	pcb->eap.es_client.ea_name = localname;
232*10465441SEvalZero 	pcb->eap.es_client.ea_namelen = strlen(localname);
233*10465441SEvalZero 
234*10465441SEvalZero 	pcb->eap.es_client.ea_state = eapListen;
235*10465441SEvalZero 
236*10465441SEvalZero 	/*
237*10465441SEvalZero 	 * Start a timer so that if the other end just goes
238*10465441SEvalZero 	 * silent, we don't sit here waiting forever.
239*10465441SEvalZero 	 */
240*10465441SEvalZero 	if (pcb->settings.eap_req_time > 0)
241*10465441SEvalZero 		TIMEOUT(eap_client_timeout, pcb,
242*10465441SEvalZero 		    pcb->settings.eap_req_time);
243*10465441SEvalZero }
244*10465441SEvalZero 
245*10465441SEvalZero #if PPP_SERVER
246*10465441SEvalZero /*
247*10465441SEvalZero  * Format a standard EAP Failure message and send it to the peer.
248*10465441SEvalZero  * (Server operation)
249*10465441SEvalZero  */
eap_send_failure(ppp_pcb * pcb)250*10465441SEvalZero static void eap_send_failure(ppp_pcb *pcb) {
251*10465441SEvalZero 	struct pbuf *p;
252*10465441SEvalZero 	u_char *outp;
253*10465441SEvalZero 
254*10465441SEvalZero 	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE);
255*10465441SEvalZero 	if(NULL == p)
256*10465441SEvalZero 		return;
257*10465441SEvalZero 	if(p->tot_len != p->len) {
258*10465441SEvalZero 		pbuf_free(p);
259*10465441SEvalZero 		return;
260*10465441SEvalZero 	}
261*10465441SEvalZero 
262*10465441SEvalZero 	outp = (u_char*)p->payload;
263*10465441SEvalZero 
264*10465441SEvalZero 	MAKEHEADER(outp, PPP_EAP);
265*10465441SEvalZero 
266*10465441SEvalZero 	PUTCHAR(EAP_FAILURE, outp);
267*10465441SEvalZero 	pcb->eap.es_server.ea_id++;
268*10465441SEvalZero 	PUTCHAR(pcb->eap.es_server.ea_id, outp);
269*10465441SEvalZero 	PUTSHORT(EAP_HEADERLEN, outp);
270*10465441SEvalZero 
271*10465441SEvalZero 	ppp_write(pcb, p);
272*10465441SEvalZero 
273*10465441SEvalZero 	pcb->eap.es_server.ea_state = eapBadAuth;
274*10465441SEvalZero 	auth_peer_fail(pcb, PPP_EAP);
275*10465441SEvalZero }
276*10465441SEvalZero 
277*10465441SEvalZero /*
278*10465441SEvalZero  * Format a standard EAP Success message and send it to the peer.
279*10465441SEvalZero  * (Server operation)
280*10465441SEvalZero  */
eap_send_success(ppp_pcb * pcb)281*10465441SEvalZero static void eap_send_success(ppp_pcb *pcb) {
282*10465441SEvalZero 	struct pbuf *p;
283*10465441SEvalZero 	u_char *outp;
284*10465441SEvalZero 
285*10465441SEvalZero 	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE);
286*10465441SEvalZero 	if(NULL == p)
287*10465441SEvalZero 		return;
288*10465441SEvalZero 	if(p->tot_len != p->len) {
289*10465441SEvalZero 		pbuf_free(p);
290*10465441SEvalZero 		return;
291*10465441SEvalZero 	}
292*10465441SEvalZero 
293*10465441SEvalZero 	outp = (u_char*)p->payload;
294*10465441SEvalZero 
295*10465441SEvalZero 	MAKEHEADER(outp, PPP_EAP);
296*10465441SEvalZero 
297*10465441SEvalZero 	PUTCHAR(EAP_SUCCESS, outp);
298*10465441SEvalZero 	pcb->eap.es_server.ea_id++;
299*10465441SEvalZero 	PUTCHAR(pcb->eap.es_server.ea_id, outp);
300*10465441SEvalZero 	PUTSHORT(EAP_HEADERLEN, outp);
301*10465441SEvalZero 
302*10465441SEvalZero 	ppp_write(pcb, p);
303*10465441SEvalZero 
304*10465441SEvalZero 	auth_peer_success(pcb, PPP_EAP, 0,
305*10465441SEvalZero 	    pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen);
306*10465441SEvalZero }
307*10465441SEvalZero #endif /* PPP_SERVER */
308*10465441SEvalZero 
309*10465441SEvalZero #ifdef USE_SRP
310*10465441SEvalZero /*
311*10465441SEvalZero  * Set DES key according to pseudonym-generating secret and current
312*10465441SEvalZero  * date.
313*10465441SEvalZero  */
314*10465441SEvalZero static bool
pncrypt_setkey(int timeoffs)315*10465441SEvalZero pncrypt_setkey(int timeoffs)
316*10465441SEvalZero {
317*10465441SEvalZero 	struct tm *tp;
318*10465441SEvalZero 	char tbuf[9];
319*10465441SEvalZero 	SHA1_CTX ctxt;
320*10465441SEvalZero 	u_char dig[SHA_DIGESTSIZE];
321*10465441SEvalZero 	time_t reftime;
322*10465441SEvalZero 
323*10465441SEvalZero 	if (pn_secret == NULL)
324*10465441SEvalZero 		return (0);
325*10465441SEvalZero 	reftime = time(NULL) + timeoffs;
326*10465441SEvalZero 	tp = localtime(&reftime);
327*10465441SEvalZero 	SHA1Init(&ctxt);
328*10465441SEvalZero 	SHA1Update(&ctxt, pn_secret, strlen(pn_secret));
329*10465441SEvalZero 	strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp);
330*10465441SEvalZero 	SHA1Update(&ctxt, tbuf, strlen(tbuf));
331*10465441SEvalZero 	SHA1Final(dig, &ctxt);
332*10465441SEvalZero 	/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
333*10465441SEvalZero 	return (DesSetkey(dig));
334*10465441SEvalZero }
335*10465441SEvalZero 
336*10465441SEvalZero static char base64[] =
337*10465441SEvalZero "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
338*10465441SEvalZero 
339*10465441SEvalZero struct b64state {
340*10465441SEvalZero 	u32_t bs_bits;
341*10465441SEvalZero 	int bs_offs;
342*10465441SEvalZero };
343*10465441SEvalZero 
344*10465441SEvalZero static int
b64enc(bs,inp,inlen,outp)345*10465441SEvalZero b64enc(bs, inp, inlen, outp)
346*10465441SEvalZero struct b64state *bs;
347*10465441SEvalZero u_char *inp;
348*10465441SEvalZero int inlen;
349*10465441SEvalZero u_char *outp;
350*10465441SEvalZero {
351*10465441SEvalZero 	int outlen = 0;
352*10465441SEvalZero 
353*10465441SEvalZero 	while (inlen > 0) {
354*10465441SEvalZero 		bs->bs_bits = (bs->bs_bits << 8) | *inp++;
355*10465441SEvalZero 		inlen--;
356*10465441SEvalZero 		bs->bs_offs += 8;
357*10465441SEvalZero 		if (bs->bs_offs >= 24) {
358*10465441SEvalZero 			*outp++ = base64[(bs->bs_bits >> 18) & 0x3F];
359*10465441SEvalZero 			*outp++ = base64[(bs->bs_bits >> 12) & 0x3F];
360*10465441SEvalZero 			*outp++ = base64[(bs->bs_bits >> 6) & 0x3F];
361*10465441SEvalZero 			*outp++ = base64[bs->bs_bits & 0x3F];
362*10465441SEvalZero 			outlen += 4;
363*10465441SEvalZero 			bs->bs_offs = 0;
364*10465441SEvalZero 			bs->bs_bits = 0;
365*10465441SEvalZero 		}
366*10465441SEvalZero 	}
367*10465441SEvalZero 	return (outlen);
368*10465441SEvalZero }
369*10465441SEvalZero 
370*10465441SEvalZero static int
b64flush(bs,outp)371*10465441SEvalZero b64flush(bs, outp)
372*10465441SEvalZero struct b64state *bs;
373*10465441SEvalZero u_char *outp;
374*10465441SEvalZero {
375*10465441SEvalZero 	int outlen = 0;
376*10465441SEvalZero 
377*10465441SEvalZero 	if (bs->bs_offs == 8) {
378*10465441SEvalZero 		*outp++ = base64[(bs->bs_bits >> 2) & 0x3F];
379*10465441SEvalZero 		*outp++ = base64[(bs->bs_bits << 4) & 0x3F];
380*10465441SEvalZero 		outlen = 2;
381*10465441SEvalZero 	} else if (bs->bs_offs == 16) {
382*10465441SEvalZero 		*outp++ = base64[(bs->bs_bits >> 10) & 0x3F];
383*10465441SEvalZero 		*outp++ = base64[(bs->bs_bits >> 4) & 0x3F];
384*10465441SEvalZero 		*outp++ = base64[(bs->bs_bits << 2) & 0x3F];
385*10465441SEvalZero 		outlen = 3;
386*10465441SEvalZero 	}
387*10465441SEvalZero 	bs->bs_offs = 0;
388*10465441SEvalZero 	bs->bs_bits = 0;
389*10465441SEvalZero 	return (outlen);
390*10465441SEvalZero }
391*10465441SEvalZero 
392*10465441SEvalZero static int
b64dec(bs,inp,inlen,outp)393*10465441SEvalZero b64dec(bs, inp, inlen, outp)
394*10465441SEvalZero struct b64state *bs;
395*10465441SEvalZero u_char *inp;
396*10465441SEvalZero int inlen;
397*10465441SEvalZero u_char *outp;
398*10465441SEvalZero {
399*10465441SEvalZero 	int outlen = 0;
400*10465441SEvalZero 	char *cp;
401*10465441SEvalZero 
402*10465441SEvalZero 	while (inlen > 0) {
403*10465441SEvalZero 		if ((cp = strchr(base64, *inp++)) == NULL)
404*10465441SEvalZero 			break;
405*10465441SEvalZero 		bs->bs_bits = (bs->bs_bits << 6) | (cp - base64);
406*10465441SEvalZero 		inlen--;
407*10465441SEvalZero 		bs->bs_offs += 6;
408*10465441SEvalZero 		if (bs->bs_offs >= 8) {
409*10465441SEvalZero 			*outp++ = bs->bs_bits >> (bs->bs_offs - 8);
410*10465441SEvalZero 			outlen++;
411*10465441SEvalZero 			bs->bs_offs -= 8;
412*10465441SEvalZero 		}
413*10465441SEvalZero 	}
414*10465441SEvalZero 	return (outlen);
415*10465441SEvalZero }
416*10465441SEvalZero #endif /* USE_SRP */
417*10465441SEvalZero 
418*10465441SEvalZero #if PPP_SERVER
419*10465441SEvalZero /*
420*10465441SEvalZero  * Assume that current waiting server state is complete and figure
421*10465441SEvalZero  * next state to use based on available authentication data.  'status'
422*10465441SEvalZero  * indicates if there was an error in handling the last query.  It is
423*10465441SEvalZero  * 0 for success and non-zero for failure.
424*10465441SEvalZero  */
eap_figure_next_state(ppp_pcb * pcb,int status)425*10465441SEvalZero static void eap_figure_next_state(ppp_pcb *pcb, int status) {
426*10465441SEvalZero #ifdef USE_SRP
427*10465441SEvalZero 	unsigned char secbuf[MAXSECRETLEN], clear[8], *sp, *dp;
428*10465441SEvalZero 	struct t_pw tpw;
429*10465441SEvalZero 	struct t_confent *tce, mytce;
430*10465441SEvalZero 	char *cp, *cp2;
431*10465441SEvalZero 	struct t_server *ts;
432*10465441SEvalZero 	int id, i, plen, toffs;
433*10465441SEvalZero 	u_char vals[2];
434*10465441SEvalZero 	struct b64state bs;
435*10465441SEvalZero #endif /* USE_SRP */
436*10465441SEvalZero 
437*10465441SEvalZero 	pcb->settings.eap_timeout_time = pcb->eap.es_savedtime;
438*10465441SEvalZero 	switch (pcb->eap.es_server.ea_state) {
439*10465441SEvalZero 	case eapBadAuth:
440*10465441SEvalZero 		return;
441*10465441SEvalZero 
442*10465441SEvalZero 	case eapIdentify:
443*10465441SEvalZero #ifdef USE_SRP
444*10465441SEvalZero 		/* Discard any previous session. */
445*10465441SEvalZero 		ts = (struct t_server *)pcb->eap.es_server.ea_session;
446*10465441SEvalZero 		if (ts != NULL) {
447*10465441SEvalZero 			t_serverclose(ts);
448*10465441SEvalZero 			pcb->eap.es_server.ea_session = NULL;
449*10465441SEvalZero 			pcb->eap.es_server.ea_skey = NULL;
450*10465441SEvalZero 		}
451*10465441SEvalZero #endif /* USE_SRP */
452*10465441SEvalZero 		if (status != 0) {
453*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapBadAuth;
454*10465441SEvalZero 			break;
455*10465441SEvalZero 		}
456*10465441SEvalZero #ifdef USE_SRP
457*10465441SEvalZero 		/* If we've got a pseudonym, try to decode to real name. */
458*10465441SEvalZero 		if (pcb->eap.es_server.ea_peerlen > SRP_PSEUDO_LEN &&
459*10465441SEvalZero 		    strncmp(pcb->eap.es_server.ea_peer, SRP_PSEUDO_ID,
460*10465441SEvalZero 			SRP_PSEUDO_LEN) == 0 &&
461*10465441SEvalZero 		    (pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 <
462*10465441SEvalZero 		    sizeof (secbuf)) {
463*10465441SEvalZero 			BZERO(&bs, sizeof (bs));
464*10465441SEvalZero 			plen = b64dec(&bs,
465*10465441SEvalZero 			    pcb->eap.es_server.ea_peer + SRP_PSEUDO_LEN,
466*10465441SEvalZero 			    pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN,
467*10465441SEvalZero 			    secbuf);
468*10465441SEvalZero 			toffs = 0;
469*10465441SEvalZero 			for (i = 0; i < 5; i++) {
470*10465441SEvalZero 				pncrypt_setkey(toffs);
471*10465441SEvalZero 				toffs -= 86400;
472*10465441SEvalZero 				/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
473*10465441SEvalZero 				if (!DesDecrypt(secbuf, clear)) {
474*10465441SEvalZero 					ppp_dbglog("no DES here; cannot decode "
475*10465441SEvalZero 					    "pseudonym");
476*10465441SEvalZero 					return;
477*10465441SEvalZero 				}
478*10465441SEvalZero 				id = *(unsigned char *)clear;
479*10465441SEvalZero 				if (id + 1 <= plen && id + 9 > plen)
480*10465441SEvalZero 					break;
481*10465441SEvalZero 			}
482*10465441SEvalZero 			if (plen % 8 == 0 && i < 5) {
483*10465441SEvalZero 				/*
484*10465441SEvalZero 				 * Note that this is always shorter than the
485*10465441SEvalZero 				 * original stored string, so there's no need
486*10465441SEvalZero 				 * to realloc.
487*10465441SEvalZero 				 */
488*10465441SEvalZero 				if ((i = plen = *(unsigned char *)clear) > 7)
489*10465441SEvalZero 					i = 7;
490*10465441SEvalZero 				pcb->eap.es_server.ea_peerlen = plen;
491*10465441SEvalZero 				dp = (unsigned char *)pcb->eap.es_server.ea_peer;
492*10465441SEvalZero 				MEMCPY(dp, clear + 1, i);
493*10465441SEvalZero 				plen -= i;
494*10465441SEvalZero 				dp += i;
495*10465441SEvalZero 				sp = secbuf + 8;
496*10465441SEvalZero 				while (plen > 0) {
497*10465441SEvalZero 					/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
498*10465441SEvalZero 					(void) DesDecrypt(sp, dp);
499*10465441SEvalZero 					sp += 8;
500*10465441SEvalZero 					dp += 8;
501*10465441SEvalZero 					plen -= 8;
502*10465441SEvalZero 				}
503*10465441SEvalZero 				pcb->eap.es_server.ea_peer[
504*10465441SEvalZero 					pcb->eap.es_server.ea_peerlen] = '\0';
505*10465441SEvalZero 				ppp_dbglog("decoded pseudonym to \"%.*q\"",
506*10465441SEvalZero 				    pcb->eap.es_server.ea_peerlen,
507*10465441SEvalZero 				    pcb->eap.es_server.ea_peer);
508*10465441SEvalZero 			} else {
509*10465441SEvalZero 				ppp_dbglog("failed to decode real name");
510*10465441SEvalZero 				/* Stay in eapIdentfy state; requery */
511*10465441SEvalZero 				break;
512*10465441SEvalZero 			}
513*10465441SEvalZero 		}
514*10465441SEvalZero 		/* Look up user in secrets database. */
515*10465441SEvalZero 		if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_server.ea_peer,
516*10465441SEvalZero 		    pcb->eap.es_server.ea_name, (char *)secbuf, 1) != 0) {
517*10465441SEvalZero 			/* Set up default in case SRP entry is bad */
518*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapMD5Chall;
519*10465441SEvalZero 			/* Get t_confent based on index in srp-secrets */
520*10465441SEvalZero 			id = strtol((char *)secbuf, &cp, 10);
521*10465441SEvalZero 			if (*cp++ != ':' || id < 0)
522*10465441SEvalZero 				break;
523*10465441SEvalZero 			if (id == 0) {
524*10465441SEvalZero 				mytce.index = 0;
525*10465441SEvalZero 				mytce.modulus.data = (u_char *)wkmodulus;
526*10465441SEvalZero 				mytce.modulus.len = sizeof (wkmodulus);
527*10465441SEvalZero 				mytce.generator.data = (u_char *)"\002";
528*10465441SEvalZero 				mytce.generator.len = 1;
529*10465441SEvalZero 				tce = &mytce;
530*10465441SEvalZero 			} else if ((tce = gettcid(id)) != NULL) {
531*10465441SEvalZero 				/*
532*10465441SEvalZero 				 * Client will have to verify this modulus/
533*10465441SEvalZero 				 * generator combination, and that will take
534*10465441SEvalZero 				 * a while.  Lengthen the timeout here.
535*10465441SEvalZero 				 */
536*10465441SEvalZero 				if (pcb->settings.eap_timeout_time > 0 &&
537*10465441SEvalZero 				    pcb->settings.eap_timeout_time < 30)
538*10465441SEvalZero 					pcb->settings.eap_timeout_time = 30;
539*10465441SEvalZero 			} else {
540*10465441SEvalZero 				break;
541*10465441SEvalZero 			}
542*10465441SEvalZero 			if ((cp2 = strchr(cp, ':')) == NULL)
543*10465441SEvalZero 				break;
544*10465441SEvalZero 			*cp2++ = '\0';
545*10465441SEvalZero 			tpw.pebuf.name = pcb->eap.es_server.ea_peer;
546*10465441SEvalZero 			tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf,
547*10465441SEvalZero 			    cp);
548*10465441SEvalZero 			tpw.pebuf.password.data = tpw.pwbuf;
549*10465441SEvalZero 			tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf,
550*10465441SEvalZero 			    cp2);
551*10465441SEvalZero 			tpw.pebuf.salt.data = tpw.saltbuf;
552*10465441SEvalZero 			if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL)
553*10465441SEvalZero 				break;
554*10465441SEvalZero 			pcb->eap.es_server.ea_session = (void *)ts;
555*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapSRP1;
556*10465441SEvalZero 			vals[0] = pcb->eap.es_server.ea_id + 1;
557*10465441SEvalZero 			vals[1] = EAPT_SRP;
558*10465441SEvalZero 			t_serveraddexdata(ts, vals, 2);
559*10465441SEvalZero 			/* Generate B; must call before t_servergetkey() */
560*10465441SEvalZero 			t_servergenexp(ts);
561*10465441SEvalZero 			break;
562*10465441SEvalZero 		}
563*10465441SEvalZero #endif /* USE_SRP */
564*10465441SEvalZero 		pcb->eap.es_server.ea_state = eapMD5Chall;
565*10465441SEvalZero 		break;
566*10465441SEvalZero 
567*10465441SEvalZero 	case eapSRP1:
568*10465441SEvalZero #ifdef USE_SRP
569*10465441SEvalZero 		ts = (struct t_server *)pcb->eap.es_server.ea_session;
570*10465441SEvalZero 		if (ts != NULL && status != 0) {
571*10465441SEvalZero 			t_serverclose(ts);
572*10465441SEvalZero 			pcb->eap.es_server.ea_session = NULL;
573*10465441SEvalZero 			pcb->eap.es_server.ea_skey = NULL;
574*10465441SEvalZero 		}
575*10465441SEvalZero #endif /* USE_SRP */
576*10465441SEvalZero 		if (status == 1) {
577*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapMD5Chall;
578*10465441SEvalZero 		} else if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
579*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapBadAuth;
580*10465441SEvalZero 		} else {
581*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapSRP2;
582*10465441SEvalZero 		}
583*10465441SEvalZero 		break;
584*10465441SEvalZero 
585*10465441SEvalZero 	case eapSRP2:
586*10465441SEvalZero #ifdef USE_SRP
587*10465441SEvalZero 		ts = (struct t_server *)pcb->eap.es_server.ea_session;
588*10465441SEvalZero 		if (ts != NULL && status != 0) {
589*10465441SEvalZero 			t_serverclose(ts);
590*10465441SEvalZero 			pcb->eap.es_server.ea_session = NULL;
591*10465441SEvalZero 			pcb->eap.es_server.ea_skey = NULL;
592*10465441SEvalZero 		}
593*10465441SEvalZero #endif /* USE_SRP */
594*10465441SEvalZero 		if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
595*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapBadAuth;
596*10465441SEvalZero 		} else {
597*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapSRP3;
598*10465441SEvalZero 		}
599*10465441SEvalZero 		break;
600*10465441SEvalZero 
601*10465441SEvalZero 	case eapSRP3:
602*10465441SEvalZero 	case eapSRP4:
603*10465441SEvalZero #ifdef USE_SRP
604*10465441SEvalZero 		ts = (struct t_server *)pcb->eap.es_server.ea_session;
605*10465441SEvalZero 		if (ts != NULL && status != 0) {
606*10465441SEvalZero 			t_serverclose(ts);
607*10465441SEvalZero 			pcb->eap.es_server.ea_session = NULL;
608*10465441SEvalZero 			pcb->eap.es_server.ea_skey = NULL;
609*10465441SEvalZero 		}
610*10465441SEvalZero #endif /* USE_SRP */
611*10465441SEvalZero 		if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
612*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapBadAuth;
613*10465441SEvalZero 		} else {
614*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapOpen;
615*10465441SEvalZero 		}
616*10465441SEvalZero 		break;
617*10465441SEvalZero 
618*10465441SEvalZero 	case eapMD5Chall:
619*10465441SEvalZero 		if (status != 0) {
620*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapBadAuth;
621*10465441SEvalZero 		} else {
622*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapOpen;
623*10465441SEvalZero 		}
624*10465441SEvalZero 		break;
625*10465441SEvalZero 
626*10465441SEvalZero 	default:
627*10465441SEvalZero 		pcb->eap.es_server.ea_state = eapBadAuth;
628*10465441SEvalZero 		break;
629*10465441SEvalZero 	}
630*10465441SEvalZero 	if (pcb->eap.es_server.ea_state == eapBadAuth)
631*10465441SEvalZero 		eap_send_failure(pcb);
632*10465441SEvalZero }
633*10465441SEvalZero 
634*10465441SEvalZero /*
635*10465441SEvalZero  * Format an EAP Request message and send it to the peer.  Message
636*10465441SEvalZero  * type depends on current state.  (Server operation)
637*10465441SEvalZero  */
eap_send_request(ppp_pcb * pcb)638*10465441SEvalZero static void eap_send_request(ppp_pcb *pcb) {
639*10465441SEvalZero 	struct pbuf *p;
640*10465441SEvalZero 	u_char *outp;
641*10465441SEvalZero 	u_char *lenloc;
642*10465441SEvalZero 	int outlen;
643*10465441SEvalZero 	int len;
644*10465441SEvalZero 	const char *str;
645*10465441SEvalZero #ifdef USE_SRP
646*10465441SEvalZero 	struct t_server *ts;
647*10465441SEvalZero 	u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp;
648*10465441SEvalZero 	int i, j;
649*10465441SEvalZero 	struct b64state b64;
650*10465441SEvalZero 	SHA1_CTX ctxt;
651*10465441SEvalZero #endif /* USE_SRP */
652*10465441SEvalZero 
653*10465441SEvalZero 	/* Handle both initial auth and restart */
654*10465441SEvalZero 	if (pcb->eap.es_server.ea_state < eapIdentify &&
655*10465441SEvalZero 	    pcb->eap.es_server.ea_state != eapInitial) {
656*10465441SEvalZero 		pcb->eap.es_server.ea_state = eapIdentify;
657*10465441SEvalZero #if PPP_REMOTENAME
658*10465441SEvalZero 		if (pcb->settings.explicit_remote && pcb->remote_name) {
659*10465441SEvalZero 			/*
660*10465441SEvalZero 			 * If we already know the peer's
661*10465441SEvalZero 			 * unauthenticated name, then there's no
662*10465441SEvalZero 			 * reason to ask.  Go to next state instead.
663*10465441SEvalZero 			 */
664*10465441SEvalZero 			int len = (int)strlen(pcb->remote_name);
665*10465441SEvalZero 			if (len > MAXNAMELEN) {
666*10465441SEvalZero 				len = MAXNAMELEN;
667*10465441SEvalZero 			}
668*10465441SEvalZero 			MEMCPY(pcb->eap.es_server.ea_peer, pcb->remote_name, len);
669*10465441SEvalZero 			pcb->eap.es_server.ea_peer[len] = '\0';
670*10465441SEvalZero 			pcb->eap.es_server.ea_peerlen = len;
671*10465441SEvalZero 			eap_figure_next_state(pcb, 0);
672*10465441SEvalZero 		}
673*10465441SEvalZero #endif /* PPP_REMOTENAME */
674*10465441SEvalZero 	}
675*10465441SEvalZero 
676*10465441SEvalZero 	if (pcb->settings.eap_max_transmits > 0 &&
677*10465441SEvalZero 	    pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) {
678*10465441SEvalZero 		if (pcb->eap.es_server.ea_responses > 0)
679*10465441SEvalZero 			ppp_error("EAP: too many Requests sent");
680*10465441SEvalZero 		else
681*10465441SEvalZero 			ppp_error("EAP: no response to Requests");
682*10465441SEvalZero 		eap_send_failure(pcb);
683*10465441SEvalZero 		return;
684*10465441SEvalZero 	}
685*10465441SEvalZero 
686*10465441SEvalZero 	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE);
687*10465441SEvalZero 	if(NULL == p)
688*10465441SEvalZero 		return;
689*10465441SEvalZero 	if(p->tot_len != p->len) {
690*10465441SEvalZero 		pbuf_free(p);
691*10465441SEvalZero 		return;
692*10465441SEvalZero 	}
693*10465441SEvalZero 
694*10465441SEvalZero 	outp = (u_char*)p->payload;
695*10465441SEvalZero 
696*10465441SEvalZero 	MAKEHEADER(outp, PPP_EAP);
697*10465441SEvalZero 
698*10465441SEvalZero 	PUTCHAR(EAP_REQUEST, outp);
699*10465441SEvalZero 	PUTCHAR(pcb->eap.es_server.ea_id, outp);
700*10465441SEvalZero 	lenloc = outp;
701*10465441SEvalZero 	INCPTR(2, outp);
702*10465441SEvalZero 
703*10465441SEvalZero 	switch (pcb->eap.es_server.ea_state) {
704*10465441SEvalZero 	case eapIdentify:
705*10465441SEvalZero 		PUTCHAR(EAPT_IDENTITY, outp);
706*10465441SEvalZero 		str = "Name";
707*10465441SEvalZero 		len = strlen(str);
708*10465441SEvalZero 		MEMCPY(outp, str, len);
709*10465441SEvalZero 		INCPTR(len, outp);
710*10465441SEvalZero 		break;
711*10465441SEvalZero 
712*10465441SEvalZero 	case eapMD5Chall:
713*10465441SEvalZero 		PUTCHAR(EAPT_MD5CHAP, outp);
714*10465441SEvalZero 		/*
715*10465441SEvalZero 		 * pick a random challenge length between
716*10465441SEvalZero 		 * EAP_MIN_CHALLENGE_LENGTH and EAP_MAX_CHALLENGE_LENGTH
717*10465441SEvalZero 		 */
718*10465441SEvalZero 		pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH +
719*10465441SEvalZero 		    magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH);
720*10465441SEvalZero 		PUTCHAR(pcb->eap.es_challen, outp);
721*10465441SEvalZero 		magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen);
722*10465441SEvalZero 		MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen);
723*10465441SEvalZero 		INCPTR(pcb->eap.es_challen, outp);
724*10465441SEvalZero 		MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen);
725*10465441SEvalZero 		INCPTR(pcb->eap.es_server.ea_namelen, outp);
726*10465441SEvalZero 		break;
727*10465441SEvalZero 
728*10465441SEvalZero #ifdef USE_SRP
729*10465441SEvalZero 	case eapSRP1:
730*10465441SEvalZero 		PUTCHAR(EAPT_SRP, outp);
731*10465441SEvalZero 		PUTCHAR(EAPSRP_CHALLENGE, outp);
732*10465441SEvalZero 
733*10465441SEvalZero 		PUTCHAR(pcb->eap.es_server.ea_namelen, outp);
734*10465441SEvalZero 		MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen);
735*10465441SEvalZero 		INCPTR(pcb->eap.es_server.ea_namelen, outp);
736*10465441SEvalZero 
737*10465441SEvalZero 		ts = (struct t_server *)pcb->eap.es_server.ea_session;
738*10465441SEvalZero 		assert(ts != NULL);
739*10465441SEvalZero 		PUTCHAR(ts->s.len, outp);
740*10465441SEvalZero 		MEMCPY(outp, ts->s.data, ts->s.len);
741*10465441SEvalZero 		INCPTR(ts->s.len, outp);
742*10465441SEvalZero 
743*10465441SEvalZero 		if (ts->g.len == 1 && ts->g.data[0] == 2) {
744*10465441SEvalZero 			PUTCHAR(0, outp);
745*10465441SEvalZero 		} else {
746*10465441SEvalZero 			PUTCHAR(ts->g.len, outp);
747*10465441SEvalZero 			MEMCPY(outp, ts->g.data, ts->g.len);
748*10465441SEvalZero 			INCPTR(ts->g.len, outp);
749*10465441SEvalZero 		}
750*10465441SEvalZero 
751*10465441SEvalZero 		if (ts->n.len != sizeof (wkmodulus) ||
752*10465441SEvalZero 		    BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) {
753*10465441SEvalZero 			MEMCPY(outp, ts->n.data, ts->n.len);
754*10465441SEvalZero 			INCPTR(ts->n.len, outp);
755*10465441SEvalZero 		}
756*10465441SEvalZero 		break;
757*10465441SEvalZero 
758*10465441SEvalZero 	case eapSRP2:
759*10465441SEvalZero 		PUTCHAR(EAPT_SRP, outp);
760*10465441SEvalZero 		PUTCHAR(EAPSRP_SKEY, outp);
761*10465441SEvalZero 
762*10465441SEvalZero 		ts = (struct t_server *)pcb->eap.es_server.ea_session;
763*10465441SEvalZero 		assert(ts != NULL);
764*10465441SEvalZero 		MEMCPY(outp, ts->B.data, ts->B.len);
765*10465441SEvalZero 		INCPTR(ts->B.len, outp);
766*10465441SEvalZero 		break;
767*10465441SEvalZero 
768*10465441SEvalZero 	case eapSRP3:
769*10465441SEvalZero 		PUTCHAR(EAPT_SRP, outp);
770*10465441SEvalZero 		PUTCHAR(EAPSRP_SVALIDATOR, outp);
771*10465441SEvalZero 		PUTLONG(SRPVAL_EBIT, outp);
772*10465441SEvalZero 		ts = (struct t_server *)pcb->eap.es_server.ea_session;
773*10465441SEvalZero 		assert(ts != NULL);
774*10465441SEvalZero 		MEMCPY(outp, t_serverresponse(ts), SHA_DIGESTSIZE);
775*10465441SEvalZero 		INCPTR(SHA_DIGESTSIZE, outp);
776*10465441SEvalZero 
777*10465441SEvalZero 		if (pncrypt_setkey(0)) {
778*10465441SEvalZero 			/* Generate pseudonym */
779*10465441SEvalZero 			optr = outp;
780*10465441SEvalZero 			cp = (unsigned char *)pcb->eap.es_server.ea_peer;
781*10465441SEvalZero 			if ((j = i = pcb->eap.es_server.ea_peerlen) > 7)
782*10465441SEvalZero 				j = 7;
783*10465441SEvalZero 			clear[0] = i;
784*10465441SEvalZero 			MEMCPY(clear + 1, cp, j);
785*10465441SEvalZero 			i -= j;
786*10465441SEvalZero 			cp += j;
787*10465441SEvalZero 			/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
788*10465441SEvalZero 			if (!DesEncrypt(clear, cipher)) {
789*10465441SEvalZero 				ppp_dbglog("no DES here; not generating pseudonym");
790*10465441SEvalZero 				break;
791*10465441SEvalZero 			}
792*10465441SEvalZero 			BZERO(&b64, sizeof (b64));
793*10465441SEvalZero 			outp++;		/* space for pseudonym length */
794*10465441SEvalZero 			outp += b64enc(&b64, cipher, 8, outp);
795*10465441SEvalZero 			while (i >= 8) {
796*10465441SEvalZero 				/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
797*10465441SEvalZero 				(void) DesEncrypt(cp, cipher);
798*10465441SEvalZero 				outp += b64enc(&b64, cipher, 8, outp);
799*10465441SEvalZero 				cp += 8;
800*10465441SEvalZero 				i -= 8;
801*10465441SEvalZero 			}
802*10465441SEvalZero 			if (i > 0) {
803*10465441SEvalZero 				MEMCPY(clear, cp, i);
804*10465441SEvalZero 				cp += i;
805*10465441SEvalZero 				magic_random_bytes(cp, 8-i);
806*10465441SEvalZero 				/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
807*10465441SEvalZero 				(void) DesEncrypt(clear, cipher);
808*10465441SEvalZero 				outp += b64enc(&b64, cipher, 8, outp);
809*10465441SEvalZero 			}
810*10465441SEvalZero 			outp += b64flush(&b64, outp);
811*10465441SEvalZero 
812*10465441SEvalZero 			/* Set length and pad out to next 20 octet boundary */
813*10465441SEvalZero 			i = outp - optr - 1;
814*10465441SEvalZero 			*optr = i;
815*10465441SEvalZero 			i %= SHA_DIGESTSIZE;
816*10465441SEvalZero 			if (i != 0) {
817*10465441SEvalZero 				magic_random_bytes(outp, SHA_DIGESTSIZE-i);
818*10465441SEvalZero 				INCPTR(SHA_DIGESTSIZE-i, outp);
819*10465441SEvalZero 			}
820*10465441SEvalZero 
821*10465441SEvalZero 			/* Obscure the pseudonym with SHA1 hash */
822*10465441SEvalZero 			SHA1Init(&ctxt);
823*10465441SEvalZero 			SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1);
824*10465441SEvalZero 			SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
825*10465441SEvalZero 			    SESSION_KEY_LEN);
826*10465441SEvalZero 			SHA1Update(&ctxt, pcb->eap.es_server.ea_peer,
827*10465441SEvalZero 			    pcb->eap.es_server.ea_peerlen);
828*10465441SEvalZero 			while (optr < outp) {
829*10465441SEvalZero 				SHA1Final(dig, &ctxt);
830*10465441SEvalZero 				cp = dig;
831*10465441SEvalZero 				while (cp < dig + SHA_DIGESTSIZE)
832*10465441SEvalZero 					*optr++ ^= *cp++;
833*10465441SEvalZero 				SHA1Init(&ctxt);
834*10465441SEvalZero 				SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1);
835*10465441SEvalZero 				SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
836*10465441SEvalZero 				    SESSION_KEY_LEN);
837*10465441SEvalZero 				SHA1Update(&ctxt, optr - SHA_DIGESTSIZE,
838*10465441SEvalZero 				    SHA_DIGESTSIZE);
839*10465441SEvalZero 			}
840*10465441SEvalZero 		}
841*10465441SEvalZero 		break;
842*10465441SEvalZero 
843*10465441SEvalZero 	case eapSRP4:
844*10465441SEvalZero 		PUTCHAR(EAPT_SRP, outp);
845*10465441SEvalZero 		PUTCHAR(EAPSRP_LWRECHALLENGE, outp);
846*10465441SEvalZero 		pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH +
847*10465441SEvalZero 		    magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH);
848*10465441SEvalZero 		magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen);
849*10465441SEvalZero 		MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen);
850*10465441SEvalZero 		INCPTR(pcb->eap.es_challen, outp);
851*10465441SEvalZero 		break;
852*10465441SEvalZero #endif /* USE_SRP */
853*10465441SEvalZero 
854*10465441SEvalZero 	default:
855*10465441SEvalZero 		return;
856*10465441SEvalZero 	}
857*10465441SEvalZero 
858*10465441SEvalZero 	outlen = (outp - (unsigned char*)p->payload) - PPP_HDRLEN;
859*10465441SEvalZero 	PUTSHORT(outlen, lenloc);
860*10465441SEvalZero 
861*10465441SEvalZero 	pbuf_realloc(p, outlen + PPP_HDRLEN);
862*10465441SEvalZero 	ppp_write(pcb, p);
863*10465441SEvalZero 
864*10465441SEvalZero 	pcb->eap.es_server.ea_requests++;
865*10465441SEvalZero 
866*10465441SEvalZero 	if (pcb->settings.eap_timeout_time > 0)
867*10465441SEvalZero 		TIMEOUT(eap_server_timeout, pcb, pcb->settings.eap_timeout_time);
868*10465441SEvalZero }
869*10465441SEvalZero 
870*10465441SEvalZero /*
871*10465441SEvalZero  * eap_authpeer - Authenticate our peer (behave as server).
872*10465441SEvalZero  *
873*10465441SEvalZero  * Start server state and send first request.  This is called only
874*10465441SEvalZero  * after eap_lowerup.
875*10465441SEvalZero  */
eap_authpeer(ppp_pcb * pcb,const char * localname)876*10465441SEvalZero void eap_authpeer(ppp_pcb *pcb, const char *localname) {
877*10465441SEvalZero 
878*10465441SEvalZero 	/* Save the name we're given. */
879*10465441SEvalZero 	pcb->eap.es_server.ea_name = localname;
880*10465441SEvalZero 	pcb->eap.es_server.ea_namelen = strlen(localname);
881*10465441SEvalZero 
882*10465441SEvalZero 	pcb->eap.es_savedtime = pcb->settings.eap_timeout_time;
883*10465441SEvalZero 
884*10465441SEvalZero 	/* Lower layer up yet? */
885*10465441SEvalZero 	if (pcb->eap.es_server.ea_state == eapInitial ||
886*10465441SEvalZero 	    pcb->eap.es_server.ea_state == eapPending) {
887*10465441SEvalZero 		pcb->eap.es_server.ea_state = eapPending;
888*10465441SEvalZero 		return;
889*10465441SEvalZero 	}
890*10465441SEvalZero 
891*10465441SEvalZero 	pcb->eap.es_server.ea_state = eapPending;
892*10465441SEvalZero 
893*10465441SEvalZero 	/* ID number not updated here intentionally; hashed into M1 */
894*10465441SEvalZero 	eap_send_request(pcb);
895*10465441SEvalZero }
896*10465441SEvalZero 
897*10465441SEvalZero /*
898*10465441SEvalZero  * eap_server_timeout - Retransmission timer for sending Requests
899*10465441SEvalZero  * expired.
900*10465441SEvalZero  */
eap_server_timeout(void * arg)901*10465441SEvalZero static void eap_server_timeout(void *arg) {
902*10465441SEvalZero 	ppp_pcb *pcb = (ppp_pcb*)arg;
903*10465441SEvalZero 
904*10465441SEvalZero 	if (!eap_server_active(pcb))
905*10465441SEvalZero 		return;
906*10465441SEvalZero 
907*10465441SEvalZero 	/* EAP ID number must not change on timeout. */
908*10465441SEvalZero 	eap_send_request(pcb);
909*10465441SEvalZero }
910*10465441SEvalZero 
911*10465441SEvalZero /*
912*10465441SEvalZero  * When it's time to send rechallenge the peer, this timeout is
913*10465441SEvalZero  * called.  Once the rechallenge is successful, the response handler
914*10465441SEvalZero  * will restart the timer.  If it fails, then the link is dropped.
915*10465441SEvalZero  */
eap_rechallenge(void * arg)916*10465441SEvalZero static void eap_rechallenge(void *arg) {
917*10465441SEvalZero 	ppp_pcb *pcb = (ppp_pcb*)arg;
918*10465441SEvalZero 
919*10465441SEvalZero 	if (pcb->eap.es_server.ea_state != eapOpen &&
920*10465441SEvalZero 	    pcb->eap.es_server.ea_state != eapSRP4)
921*10465441SEvalZero 		return;
922*10465441SEvalZero 
923*10465441SEvalZero 	pcb->eap.es_server.ea_requests = 0;
924*10465441SEvalZero 	pcb->eap.es_server.ea_state = eapIdentify;
925*10465441SEvalZero 	eap_figure_next_state(pcb, 0);
926*10465441SEvalZero 	pcb->eap.es_server.ea_id++;
927*10465441SEvalZero 	eap_send_request(pcb);
928*10465441SEvalZero }
929*10465441SEvalZero 
srp_lwrechallenge(void * arg)930*10465441SEvalZero static void srp_lwrechallenge(void *arg) {
931*10465441SEvalZero 	ppp_pcb *pcb = (ppp_pcb*)arg;
932*10465441SEvalZero 
933*10465441SEvalZero 	if (pcb->eap.es_server.ea_state != eapOpen ||
934*10465441SEvalZero 	    pcb->eap.es_server.ea_type != EAPT_SRP)
935*10465441SEvalZero 		return;
936*10465441SEvalZero 
937*10465441SEvalZero 	pcb->eap.es_server.ea_requests = 0;
938*10465441SEvalZero 	pcb->eap.es_server.ea_state = eapSRP4;
939*10465441SEvalZero 	pcb->eap.es_server.ea_id++;
940*10465441SEvalZero 	eap_send_request(pcb);
941*10465441SEvalZero }
942*10465441SEvalZero #endif /* PPP_SERVER */
943*10465441SEvalZero 
944*10465441SEvalZero /*
945*10465441SEvalZero  * eap_lowerup - The lower layer is now up.
946*10465441SEvalZero  *
947*10465441SEvalZero  * This is called before either eap_authpeer or eap_authwithpeer.  See
948*10465441SEvalZero  * link_established() in auth.c.  All that's necessary here is to
949*10465441SEvalZero  * return to closed state so that those two routines will do the right
950*10465441SEvalZero  * thing.
951*10465441SEvalZero  */
eap_lowerup(ppp_pcb * pcb)952*10465441SEvalZero static void eap_lowerup(ppp_pcb *pcb) {
953*10465441SEvalZero 	pcb->eap.es_client.ea_state = eapClosed;
954*10465441SEvalZero #if PPP_SERVER
955*10465441SEvalZero 	pcb->eap.es_server.ea_state = eapClosed;
956*10465441SEvalZero #endif /* PPP_SERVER */
957*10465441SEvalZero }
958*10465441SEvalZero 
959*10465441SEvalZero /*
960*10465441SEvalZero  * eap_lowerdown - The lower layer is now down.
961*10465441SEvalZero  *
962*10465441SEvalZero  * Cancel all timeouts and return to initial state.
963*10465441SEvalZero  */
eap_lowerdown(ppp_pcb * pcb)964*10465441SEvalZero static void eap_lowerdown(ppp_pcb *pcb) {
965*10465441SEvalZero 
966*10465441SEvalZero 	if (eap_client_active(pcb) && pcb->settings.eap_req_time > 0) {
967*10465441SEvalZero 		UNTIMEOUT(eap_client_timeout, pcb);
968*10465441SEvalZero 	}
969*10465441SEvalZero #if PPP_SERVER
970*10465441SEvalZero 	if (eap_server_active(pcb)) {
971*10465441SEvalZero 		if (pcb->settings.eap_timeout_time > 0) {
972*10465441SEvalZero 			UNTIMEOUT(eap_server_timeout, pcb);
973*10465441SEvalZero 		}
974*10465441SEvalZero 	} else {
975*10465441SEvalZero 		if ((pcb->eap.es_server.ea_state == eapOpen ||
976*10465441SEvalZero 		    pcb->eap.es_server.ea_state == eapSRP4) &&
977*10465441SEvalZero 		    pcb->eap.es_rechallenge > 0) {
978*10465441SEvalZero 			UNTIMEOUT(eap_rechallenge, (void *)pcb);
979*10465441SEvalZero 		}
980*10465441SEvalZero 		if (pcb->eap.es_server.ea_state == eapOpen &&
981*10465441SEvalZero 		    pcb->eap.es_lwrechallenge > 0) {
982*10465441SEvalZero 			UNTIMEOUT(srp_lwrechallenge, (void *)pcb);
983*10465441SEvalZero 		}
984*10465441SEvalZero 	}
985*10465441SEvalZero 
986*10465441SEvalZero 	pcb->eap.es_client.ea_state = pcb->eap.es_server.ea_state = eapInitial;
987*10465441SEvalZero 	pcb->eap.es_client.ea_requests = pcb->eap.es_server.ea_requests = 0;
988*10465441SEvalZero #endif /* PPP_SERVER */
989*10465441SEvalZero }
990*10465441SEvalZero 
991*10465441SEvalZero /*
992*10465441SEvalZero  * eap_protrej - Peer doesn't speak this protocol.
993*10465441SEvalZero  *
994*10465441SEvalZero  * This shouldn't happen.  If it does, it represents authentication
995*10465441SEvalZero  * failure.
996*10465441SEvalZero  */
eap_protrej(ppp_pcb * pcb)997*10465441SEvalZero static void eap_protrej(ppp_pcb *pcb) {
998*10465441SEvalZero 
999*10465441SEvalZero 	if (eap_client_active(pcb)) {
1000*10465441SEvalZero 		ppp_error("EAP authentication failed due to Protocol-Reject");
1001*10465441SEvalZero 		auth_withpeer_fail(pcb, PPP_EAP);
1002*10465441SEvalZero 	}
1003*10465441SEvalZero #if PPP_SERVER
1004*10465441SEvalZero 	if (eap_server_active(pcb)) {
1005*10465441SEvalZero 		ppp_error("EAP authentication of peer failed on Protocol-Reject");
1006*10465441SEvalZero 		auth_peer_fail(pcb, PPP_EAP);
1007*10465441SEvalZero 	}
1008*10465441SEvalZero #endif /* PPP_SERVER */
1009*10465441SEvalZero 	eap_lowerdown(pcb);
1010*10465441SEvalZero }
1011*10465441SEvalZero 
1012*10465441SEvalZero /*
1013*10465441SEvalZero  * Format and send a regular EAP Response message.
1014*10465441SEvalZero  */
eap_send_response(ppp_pcb * pcb,u_char id,u_char typenum,const u_char * str,int lenstr)1015*10465441SEvalZero static void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, const u_char *str, int lenstr) {
1016*10465441SEvalZero 	struct pbuf *p;
1017*10465441SEvalZero 	u_char *outp;
1018*10465441SEvalZero 	int msglen;
1019*10465441SEvalZero 
1020*10465441SEvalZero 	msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr;
1021*10465441SEvalZero 	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1022*10465441SEvalZero 	if(NULL == p)
1023*10465441SEvalZero 		return;
1024*10465441SEvalZero 	if(p->tot_len != p->len) {
1025*10465441SEvalZero 		pbuf_free(p);
1026*10465441SEvalZero 		return;
1027*10465441SEvalZero 	}
1028*10465441SEvalZero 
1029*10465441SEvalZero 	outp = (u_char*)p->payload;
1030*10465441SEvalZero 
1031*10465441SEvalZero 	MAKEHEADER(outp, PPP_EAP);
1032*10465441SEvalZero 
1033*10465441SEvalZero 	PUTCHAR(EAP_RESPONSE, outp);
1034*10465441SEvalZero 	PUTCHAR(id, outp);
1035*10465441SEvalZero 	pcb->eap.es_client.ea_id = id;
1036*10465441SEvalZero 	PUTSHORT(msglen, outp);
1037*10465441SEvalZero 	PUTCHAR(typenum, outp);
1038*10465441SEvalZero 	if (lenstr > 0) {
1039*10465441SEvalZero 		MEMCPY(outp, str, lenstr);
1040*10465441SEvalZero 	}
1041*10465441SEvalZero 
1042*10465441SEvalZero 	ppp_write(pcb, p);
1043*10465441SEvalZero }
1044*10465441SEvalZero 
1045*10465441SEvalZero /*
1046*10465441SEvalZero  * Format and send an MD5-Challenge EAP Response message.
1047*10465441SEvalZero  */
eap_chap_response(ppp_pcb * pcb,u_char id,u_char * hash,const char * name,int namelen)1048*10465441SEvalZero static void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, const char *name, int namelen) {
1049*10465441SEvalZero 	struct pbuf *p;
1050*10465441SEvalZero 	u_char *outp;
1051*10465441SEvalZero 	int msglen;
1052*10465441SEvalZero 
1053*10465441SEvalZero 	msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE +
1054*10465441SEvalZero 	    namelen;
1055*10465441SEvalZero 	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1056*10465441SEvalZero 	if(NULL == p)
1057*10465441SEvalZero 		return;
1058*10465441SEvalZero 	if(p->tot_len != p->len) {
1059*10465441SEvalZero 		pbuf_free(p);
1060*10465441SEvalZero 		return;
1061*10465441SEvalZero 	}
1062*10465441SEvalZero 
1063*10465441SEvalZero 	outp = (u_char*)p->payload;
1064*10465441SEvalZero 
1065*10465441SEvalZero 	MAKEHEADER(outp, PPP_EAP);
1066*10465441SEvalZero 
1067*10465441SEvalZero 	PUTCHAR(EAP_RESPONSE, outp);
1068*10465441SEvalZero 	PUTCHAR(id, outp);
1069*10465441SEvalZero 	pcb->eap.es_client.ea_id = id;
1070*10465441SEvalZero 	PUTSHORT(msglen, outp);
1071*10465441SEvalZero 	PUTCHAR(EAPT_MD5CHAP, outp);
1072*10465441SEvalZero 	PUTCHAR(MD5_SIGNATURE_SIZE, outp);
1073*10465441SEvalZero 	MEMCPY(outp, hash, MD5_SIGNATURE_SIZE);
1074*10465441SEvalZero 	INCPTR(MD5_SIGNATURE_SIZE, outp);
1075*10465441SEvalZero 	if (namelen > 0) {
1076*10465441SEvalZero 		MEMCPY(outp, name, namelen);
1077*10465441SEvalZero 	}
1078*10465441SEvalZero 
1079*10465441SEvalZero 	ppp_write(pcb, p);
1080*10465441SEvalZero }
1081*10465441SEvalZero 
1082*10465441SEvalZero #ifdef USE_SRP
1083*10465441SEvalZero /*
1084*10465441SEvalZero  * Format and send a SRP EAP Response message.
1085*10465441SEvalZero  */
1086*10465441SEvalZero static void
eap_srp_response(esp,id,subtypenum,str,lenstr)1087*10465441SEvalZero eap_srp_response(esp, id, subtypenum, str, lenstr)
1088*10465441SEvalZero eap_state *esp;
1089*10465441SEvalZero u_char id;
1090*10465441SEvalZero u_char subtypenum;
1091*10465441SEvalZero u_char *str;
1092*10465441SEvalZero int lenstr;
1093*10465441SEvalZero {
1094*10465441SEvalZero 	ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit];
1095*10465441SEvalZero 	struct pbuf *p;
1096*10465441SEvalZero 	u_char *outp;
1097*10465441SEvalZero 	int msglen;
1098*10465441SEvalZero 
1099*10465441SEvalZero 	msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr;
1100*10465441SEvalZero 	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1101*10465441SEvalZero 	if(NULL == p)
1102*10465441SEvalZero 		return;
1103*10465441SEvalZero 	if(p->tot_len != p->len) {
1104*10465441SEvalZero 		pbuf_free(p);
1105*10465441SEvalZero 		return;
1106*10465441SEvalZero 	}
1107*10465441SEvalZero 
1108*10465441SEvalZero 	outp = p->payload;
1109*10465441SEvalZero 
1110*10465441SEvalZero 	MAKEHEADER(outp, PPP_EAP);
1111*10465441SEvalZero 
1112*10465441SEvalZero 	PUTCHAR(EAP_RESPONSE, outp);
1113*10465441SEvalZero 	PUTCHAR(id, outp);
1114*10465441SEvalZero 	pcb->eap.es_client.ea_id = id;
1115*10465441SEvalZero 	PUTSHORT(msglen, outp);
1116*10465441SEvalZero 	PUTCHAR(EAPT_SRP, outp);
1117*10465441SEvalZero 	PUTCHAR(subtypenum, outp);
1118*10465441SEvalZero 	if (lenstr > 0) {
1119*10465441SEvalZero 		MEMCPY(outp, str, lenstr);
1120*10465441SEvalZero 	}
1121*10465441SEvalZero 
1122*10465441SEvalZero 	ppp_write(pcb, p);
1123*10465441SEvalZero }
1124*10465441SEvalZero 
1125*10465441SEvalZero /*
1126*10465441SEvalZero  * Format and send a SRP EAP Client Validator Response message.
1127*10465441SEvalZero  */
1128*10465441SEvalZero static void
eap_srpval_response(esp,id,flags,str)1129*10465441SEvalZero eap_srpval_response(esp, id, flags, str)
1130*10465441SEvalZero eap_state *esp;
1131*10465441SEvalZero u_char id;
1132*10465441SEvalZero u32_t flags;
1133*10465441SEvalZero u_char *str;
1134*10465441SEvalZero {
1135*10465441SEvalZero 	ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit];
1136*10465441SEvalZero 	struct pbuf *p;
1137*10465441SEvalZero 	u_char *outp;
1138*10465441SEvalZero 	int msglen;
1139*10465441SEvalZero 
1140*10465441SEvalZero 	msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) +
1141*10465441SEvalZero 	    SHA_DIGESTSIZE;
1142*10465441SEvalZero 	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1143*10465441SEvalZero 	if(NULL == p)
1144*10465441SEvalZero 		return;
1145*10465441SEvalZero 	if(p->tot_len != p->len) {
1146*10465441SEvalZero 		pbuf_free(p);
1147*10465441SEvalZero 		return;
1148*10465441SEvalZero 	}
1149*10465441SEvalZero 
1150*10465441SEvalZero 	outp = p->payload;
1151*10465441SEvalZero 
1152*10465441SEvalZero 	MAKEHEADER(outp, PPP_EAP);
1153*10465441SEvalZero 
1154*10465441SEvalZero 	PUTCHAR(EAP_RESPONSE, outp);
1155*10465441SEvalZero 	PUTCHAR(id, outp);
1156*10465441SEvalZero 	pcb->eap.es_client.ea_id = id;
1157*10465441SEvalZero 	PUTSHORT(msglen, outp);
1158*10465441SEvalZero 	PUTCHAR(EAPT_SRP, outp);
1159*10465441SEvalZero 	PUTCHAR(EAPSRP_CVALIDATOR, outp);
1160*10465441SEvalZero 	PUTLONG(flags, outp);
1161*10465441SEvalZero 	MEMCPY(outp, str, SHA_DIGESTSIZE);
1162*10465441SEvalZero 
1163*10465441SEvalZero 	ppp_write(pcb, p);
1164*10465441SEvalZero }
1165*10465441SEvalZero #endif /* USE_SRP */
1166*10465441SEvalZero 
eap_send_nak(ppp_pcb * pcb,u_char id,u_char type)1167*10465441SEvalZero static void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) {
1168*10465441SEvalZero 	struct pbuf *p;
1169*10465441SEvalZero 	u_char *outp;
1170*10465441SEvalZero 	int msglen;
1171*10465441SEvalZero 
1172*10465441SEvalZero 	msglen = EAP_HEADERLEN + 2 * sizeof (u_char);
1173*10465441SEvalZero 	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1174*10465441SEvalZero 	if(NULL == p)
1175*10465441SEvalZero 		return;
1176*10465441SEvalZero 	if(p->tot_len != p->len) {
1177*10465441SEvalZero 		pbuf_free(p);
1178*10465441SEvalZero 		return;
1179*10465441SEvalZero 	}
1180*10465441SEvalZero 
1181*10465441SEvalZero 	outp = (u_char*)p->payload;
1182*10465441SEvalZero 
1183*10465441SEvalZero 	MAKEHEADER(outp, PPP_EAP);
1184*10465441SEvalZero 
1185*10465441SEvalZero 	PUTCHAR(EAP_RESPONSE, outp);
1186*10465441SEvalZero 	PUTCHAR(id, outp);
1187*10465441SEvalZero 	pcb->eap.es_client.ea_id = id;
1188*10465441SEvalZero 	PUTSHORT(msglen, outp);
1189*10465441SEvalZero 	PUTCHAR(EAPT_NAK, outp);
1190*10465441SEvalZero 	PUTCHAR(type, outp);
1191*10465441SEvalZero 
1192*10465441SEvalZero 	ppp_write(pcb, p);
1193*10465441SEvalZero }
1194*10465441SEvalZero 
1195*10465441SEvalZero #ifdef USE_SRP
1196*10465441SEvalZero static char *
name_of_pn_file()1197*10465441SEvalZero name_of_pn_file()
1198*10465441SEvalZero {
1199*10465441SEvalZero 	char *user, *path, *file;
1200*10465441SEvalZero 	struct passwd *pw;
1201*10465441SEvalZero 	size_t pl;
1202*10465441SEvalZero 	static bool pnlogged = 0;
1203*10465441SEvalZero 
1204*10465441SEvalZero 	pw = getpwuid(getuid());
1205*10465441SEvalZero 	if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) {
1206*10465441SEvalZero 		errno = EINVAL;
1207*10465441SEvalZero 		return (NULL);
1208*10465441SEvalZero 	}
1209*10465441SEvalZero 	file = _PATH_PSEUDONYM;
1210*10465441SEvalZero 	pl = strlen(user) + strlen(file) + 2;
1211*10465441SEvalZero 	path = malloc(pl);
1212*10465441SEvalZero 	if (path == NULL)
1213*10465441SEvalZero 		return (NULL);
1214*10465441SEvalZero 	(void) slprintf(path, pl, "%s/%s", user, file);
1215*10465441SEvalZero 	if (!pnlogged) {
1216*10465441SEvalZero 		ppp_dbglog("pseudonym file: %s", path);
1217*10465441SEvalZero 		pnlogged = 1;
1218*10465441SEvalZero 	}
1219*10465441SEvalZero 	return (path);
1220*10465441SEvalZero }
1221*10465441SEvalZero 
1222*10465441SEvalZero static int
open_pn_file(modebits)1223*10465441SEvalZero open_pn_file(modebits)
1224*10465441SEvalZero mode_t modebits;
1225*10465441SEvalZero {
1226*10465441SEvalZero 	char *path;
1227*10465441SEvalZero 	int fd, err;
1228*10465441SEvalZero 
1229*10465441SEvalZero 	if ((path = name_of_pn_file()) == NULL)
1230*10465441SEvalZero 		return (-1);
1231*10465441SEvalZero 	fd = open(path, modebits, S_IRUSR | S_IWUSR);
1232*10465441SEvalZero 	err = errno;
1233*10465441SEvalZero 	free(path);
1234*10465441SEvalZero 	errno = err;
1235*10465441SEvalZero 	return (fd);
1236*10465441SEvalZero }
1237*10465441SEvalZero 
1238*10465441SEvalZero static void
remove_pn_file()1239*10465441SEvalZero remove_pn_file()
1240*10465441SEvalZero {
1241*10465441SEvalZero 	char *path;
1242*10465441SEvalZero 
1243*10465441SEvalZero 	if ((path = name_of_pn_file()) != NULL) {
1244*10465441SEvalZero 		(void) unlink(path);
1245*10465441SEvalZero 		(void) free(path);
1246*10465441SEvalZero 	}
1247*10465441SEvalZero }
1248*10465441SEvalZero 
1249*10465441SEvalZero static void
write_pseudonym(esp,inp,len,id)1250*10465441SEvalZero write_pseudonym(esp, inp, len, id)
1251*10465441SEvalZero eap_state *esp;
1252*10465441SEvalZero u_char *inp;
1253*10465441SEvalZero int len, id;
1254*10465441SEvalZero {
1255*10465441SEvalZero 	u_char val;
1256*10465441SEvalZero 	u_char *datp, *digp;
1257*10465441SEvalZero 	SHA1_CTX ctxt;
1258*10465441SEvalZero 	u_char dig[SHA_DIGESTSIZE];
1259*10465441SEvalZero 	int dsize, fd, olen = len;
1260*10465441SEvalZero 
1261*10465441SEvalZero 	/*
1262*10465441SEvalZero 	 * Do the decoding by working backwards.  This eliminates the need
1263*10465441SEvalZero 	 * to save the decoded output in a separate buffer.
1264*10465441SEvalZero 	 */
1265*10465441SEvalZero 	val = id;
1266*10465441SEvalZero 	while (len > 0) {
1267*10465441SEvalZero 		if ((dsize = len % SHA_DIGESTSIZE) == 0)
1268*10465441SEvalZero 			dsize = SHA_DIGESTSIZE;
1269*10465441SEvalZero 		len -= dsize;
1270*10465441SEvalZero 		datp = inp + len;
1271*10465441SEvalZero 		SHA1Init(&ctxt);
1272*10465441SEvalZero 		SHA1Update(&ctxt, &val, 1);
1273*10465441SEvalZero 		SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, SESSION_KEY_LEN);
1274*10465441SEvalZero 		if (len > 0) {
1275*10465441SEvalZero 			SHA1Update(&ctxt, datp, SHA_DIGESTSIZE);
1276*10465441SEvalZero 		} else {
1277*10465441SEvalZero 			SHA1Update(&ctxt, pcb->eap.es_client.ea_name,
1278*10465441SEvalZero 			    pcb->eap.es_client.ea_namelen);
1279*10465441SEvalZero 		}
1280*10465441SEvalZero 		SHA1Final(dig, &ctxt);
1281*10465441SEvalZero 		for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++)
1282*10465441SEvalZero 			*datp++ ^= *digp;
1283*10465441SEvalZero 	}
1284*10465441SEvalZero 
1285*10465441SEvalZero 	/* Now check that the result is sane */
1286*10465441SEvalZero 	if (olen <= 0 || *inp + 1 > olen) {
1287*10465441SEvalZero 		ppp_dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp);
1288*10465441SEvalZero 		return;
1289*10465441SEvalZero 	}
1290*10465441SEvalZero 
1291*10465441SEvalZero 	/* Save it away */
1292*10465441SEvalZero 	fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC);
1293*10465441SEvalZero 	if (fd < 0) {
1294*10465441SEvalZero 		ppp_dbglog("EAP: error saving pseudonym: %m");
1295*10465441SEvalZero 		return;
1296*10465441SEvalZero 	}
1297*10465441SEvalZero 	len = write(fd, inp + 1, *inp);
1298*10465441SEvalZero 	if (close(fd) != -1 && len == *inp) {
1299*10465441SEvalZero 		ppp_dbglog("EAP: saved pseudonym");
1300*10465441SEvalZero 		pcb->eap.es_usedpseudo = 0;
1301*10465441SEvalZero 	} else {
1302*10465441SEvalZero 		ppp_dbglog("EAP: failed to save pseudonym");
1303*10465441SEvalZero 		remove_pn_file();
1304*10465441SEvalZero 	}
1305*10465441SEvalZero }
1306*10465441SEvalZero #endif /* USE_SRP */
1307*10465441SEvalZero 
1308*10465441SEvalZero /*
1309*10465441SEvalZero  * eap_request - Receive EAP Request message (client mode).
1310*10465441SEvalZero  */
eap_request(ppp_pcb * pcb,u_char * inp,int id,int len)1311*10465441SEvalZero static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) {
1312*10465441SEvalZero 	u_char typenum;
1313*10465441SEvalZero 	u_char vallen;
1314*10465441SEvalZero 	int secret_len;
1315*10465441SEvalZero 	char secret[MAXSECRETLEN];
1316*10465441SEvalZero 	char rhostname[MAXNAMELEN];
1317*10465441SEvalZero 	lwip_md5_context mdContext;
1318*10465441SEvalZero 	u_char hash[MD5_SIGNATURE_SIZE];
1319*10465441SEvalZero #ifdef USE_SRP
1320*10465441SEvalZero 	struct t_client *tc;
1321*10465441SEvalZero 	struct t_num sval, gval, Nval, *Ap, Bval;
1322*10465441SEvalZero 	u_char vals[2];
1323*10465441SEvalZero 	SHA1_CTX ctxt;
1324*10465441SEvalZero 	u_char dig[SHA_DIGESTSIZE];
1325*10465441SEvalZero 	int fd;
1326*10465441SEvalZero #endif /* USE_SRP */
1327*10465441SEvalZero 
1328*10465441SEvalZero 	/*
1329*10465441SEvalZero 	 * Note: we update es_client.ea_id *only if* a Response
1330*10465441SEvalZero 	 * message is being generated.  Otherwise, we leave it the
1331*10465441SEvalZero 	 * same for duplicate detection purposes.
1332*10465441SEvalZero 	 */
1333*10465441SEvalZero 
1334*10465441SEvalZero 	pcb->eap.es_client.ea_requests++;
1335*10465441SEvalZero 	if (pcb->settings.eap_allow_req != 0 &&
1336*10465441SEvalZero 	    pcb->eap.es_client.ea_requests > pcb->settings.eap_allow_req) {
1337*10465441SEvalZero 		ppp_info("EAP: received too many Request messages");
1338*10465441SEvalZero 		if (pcb->settings.eap_req_time > 0) {
1339*10465441SEvalZero 			UNTIMEOUT(eap_client_timeout, pcb);
1340*10465441SEvalZero 		}
1341*10465441SEvalZero 		auth_withpeer_fail(pcb, PPP_EAP);
1342*10465441SEvalZero 		return;
1343*10465441SEvalZero 	}
1344*10465441SEvalZero 
1345*10465441SEvalZero 	if (len <= 0) {
1346*10465441SEvalZero 		ppp_error("EAP: empty Request message discarded");
1347*10465441SEvalZero 		return;
1348*10465441SEvalZero 	}
1349*10465441SEvalZero 
1350*10465441SEvalZero 	GETCHAR(typenum, inp);
1351*10465441SEvalZero 	len--;
1352*10465441SEvalZero 
1353*10465441SEvalZero 	switch (typenum) {
1354*10465441SEvalZero 	case EAPT_IDENTITY:
1355*10465441SEvalZero 		if (len > 0)
1356*10465441SEvalZero 			ppp_info("EAP: Identity prompt \"%.*q\"", len, inp);
1357*10465441SEvalZero #ifdef USE_SRP
1358*10465441SEvalZero 		if (pcb->eap.es_usepseudo &&
1359*10465441SEvalZero 		    (pcb->eap.es_usedpseudo == 0 ||
1360*10465441SEvalZero 			(pcb->eap.es_usedpseudo == 1 &&
1361*10465441SEvalZero 			    id == pcb->eap.es_client.ea_id))) {
1362*10465441SEvalZero 			pcb->eap.es_usedpseudo = 1;
1363*10465441SEvalZero 			/* Try to get a pseudonym */
1364*10465441SEvalZero 			if ((fd = open_pn_file(O_RDONLY)) >= 0) {
1365*10465441SEvalZero 				strcpy(rhostname, SRP_PSEUDO_ID);
1366*10465441SEvalZero 				len = read(fd, rhostname + SRP_PSEUDO_LEN,
1367*10465441SEvalZero 				    sizeof (rhostname) - SRP_PSEUDO_LEN);
1368*10465441SEvalZero 				/* XXX NAI unsupported */
1369*10465441SEvalZero 				if (len > 0) {
1370*10465441SEvalZero 					eap_send_response(pcb, id, typenum,
1371*10465441SEvalZero 					    rhostname, len + SRP_PSEUDO_LEN);
1372*10465441SEvalZero 				}
1373*10465441SEvalZero 				(void) close(fd);
1374*10465441SEvalZero 				if (len > 0)
1375*10465441SEvalZero 					break;
1376*10465441SEvalZero 			}
1377*10465441SEvalZero 		}
1378*10465441SEvalZero 		/* Stop using pseudonym now. */
1379*10465441SEvalZero 		if (pcb->eap.es_usepseudo && pcb->eap.es_usedpseudo != 2) {
1380*10465441SEvalZero 			remove_pn_file();
1381*10465441SEvalZero 			pcb->eap.es_usedpseudo = 2;
1382*10465441SEvalZero 		}
1383*10465441SEvalZero #endif /* USE_SRP */
1384*10465441SEvalZero 		eap_send_response(pcb, id, typenum, (const u_char*)pcb->eap.es_client.ea_name,
1385*10465441SEvalZero 		    pcb->eap.es_client.ea_namelen);
1386*10465441SEvalZero 		break;
1387*10465441SEvalZero 
1388*10465441SEvalZero 	case EAPT_NOTIFICATION:
1389*10465441SEvalZero 		if (len > 0)
1390*10465441SEvalZero 			ppp_info("EAP: Notification \"%.*q\"", len, inp);
1391*10465441SEvalZero 		eap_send_response(pcb, id, typenum, NULL, 0);
1392*10465441SEvalZero 		break;
1393*10465441SEvalZero 
1394*10465441SEvalZero 	case EAPT_NAK:
1395*10465441SEvalZero 		/*
1396*10465441SEvalZero 		 * Avoid the temptation to send Response Nak in reply
1397*10465441SEvalZero 		 * to Request Nak here.  It can only lead to trouble.
1398*10465441SEvalZero 		 */
1399*10465441SEvalZero 		ppp_warn("EAP: unexpected Nak in Request; ignored");
1400*10465441SEvalZero 		/* Return because we're waiting for something real. */
1401*10465441SEvalZero 		return;
1402*10465441SEvalZero 
1403*10465441SEvalZero 	case EAPT_MD5CHAP:
1404*10465441SEvalZero 		if (len < 1) {
1405*10465441SEvalZero 			ppp_error("EAP: received MD5-Challenge with no data");
1406*10465441SEvalZero 			/* Bogus request; wait for something real. */
1407*10465441SEvalZero 			return;
1408*10465441SEvalZero 		}
1409*10465441SEvalZero 		GETCHAR(vallen, inp);
1410*10465441SEvalZero 		len--;
1411*10465441SEvalZero 		if (vallen < 8 || vallen > len) {
1412*10465441SEvalZero 			ppp_error("EAP: MD5-Challenge with bad length %d (8..%d)",
1413*10465441SEvalZero 			    vallen, len);
1414*10465441SEvalZero 			/* Try something better. */
1415*10465441SEvalZero 			eap_send_nak(pcb, id, EAPT_SRP);
1416*10465441SEvalZero 			break;
1417*10465441SEvalZero 		}
1418*10465441SEvalZero 
1419*10465441SEvalZero 		/* Not so likely to happen. */
1420*10465441SEvalZero 		if (vallen >= len + sizeof (rhostname)) {
1421*10465441SEvalZero 			ppp_dbglog("EAP: trimming really long peer name down");
1422*10465441SEvalZero 			MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1);
1423*10465441SEvalZero 			rhostname[sizeof (rhostname) - 1] = '\0';
1424*10465441SEvalZero 		} else {
1425*10465441SEvalZero 			MEMCPY(rhostname, inp + vallen, len - vallen);
1426*10465441SEvalZero 			rhostname[len - vallen] = '\0';
1427*10465441SEvalZero 		}
1428*10465441SEvalZero 
1429*10465441SEvalZero #if PPP_REMOTENAME
1430*10465441SEvalZero 		/* In case the remote doesn't give us his name. */
1431*10465441SEvalZero 		if (pcb->settings.explicit_remote ||
1432*10465441SEvalZero 		    (pcb->settings.remote_name[0] != '\0' && vallen == len))
1433*10465441SEvalZero 			strlcpy(rhostname, pcb->settings.remote_name, sizeof (rhostname));
1434*10465441SEvalZero #endif /* PPP_REMOTENAME */
1435*10465441SEvalZero 
1436*10465441SEvalZero 		/*
1437*10465441SEvalZero 		 * Get the secret for authenticating ourselves with
1438*10465441SEvalZero 		 * the specified host.
1439*10465441SEvalZero 		 */
1440*10465441SEvalZero 		if (!get_secret(pcb, pcb->eap.es_client.ea_name,
1441*10465441SEvalZero 		    rhostname, secret, &secret_len, 0)) {
1442*10465441SEvalZero 			ppp_dbglog("EAP: no MD5 secret for auth to %q", rhostname);
1443*10465441SEvalZero 			eap_send_nak(pcb, id, EAPT_SRP);
1444*10465441SEvalZero 			break;
1445*10465441SEvalZero 		}
1446*10465441SEvalZero 		lwip_md5_init(&mdContext);
1447*10465441SEvalZero 		lwip_md5_starts(&mdContext);
1448*10465441SEvalZero 		typenum = id;
1449*10465441SEvalZero 		lwip_md5_update(&mdContext, &typenum, 1);
1450*10465441SEvalZero 		lwip_md5_update(&mdContext, (u_char *)secret, secret_len);
1451*10465441SEvalZero 		BZERO(secret, sizeof (secret));
1452*10465441SEvalZero 		lwip_md5_update(&mdContext, inp, vallen);
1453*10465441SEvalZero 		lwip_md5_finish(&mdContext, hash);
1454*10465441SEvalZero 		lwip_md5_free(&mdContext);
1455*10465441SEvalZero 		eap_chap_response(pcb, id, hash, pcb->eap.es_client.ea_name,
1456*10465441SEvalZero 		    pcb->eap.es_client.ea_namelen);
1457*10465441SEvalZero 		break;
1458*10465441SEvalZero 
1459*10465441SEvalZero #ifdef USE_SRP
1460*10465441SEvalZero 	case EAPT_SRP:
1461*10465441SEvalZero 		if (len < 1) {
1462*10465441SEvalZero 			ppp_error("EAP: received empty SRP Request");
1463*10465441SEvalZero 			/* Bogus request; wait for something real. */
1464*10465441SEvalZero 			return;
1465*10465441SEvalZero 		}
1466*10465441SEvalZero 
1467*10465441SEvalZero 		/* Get subtype */
1468*10465441SEvalZero 		GETCHAR(vallen, inp);
1469*10465441SEvalZero 		len--;
1470*10465441SEvalZero 		switch (vallen) {
1471*10465441SEvalZero 		case EAPSRP_CHALLENGE:
1472*10465441SEvalZero 			tc = NULL;
1473*10465441SEvalZero 			if (pcb->eap.es_client.ea_session != NULL) {
1474*10465441SEvalZero 				tc = (struct t_client *)pcb->eap.es_client.
1475*10465441SEvalZero 				    ea_session;
1476*10465441SEvalZero 				/*
1477*10465441SEvalZero 				 * If this is a new challenge, then start
1478*10465441SEvalZero 				 * over with a new client session context.
1479*10465441SEvalZero 				 * Otherwise, just resend last response.
1480*10465441SEvalZero 				 */
1481*10465441SEvalZero 				if (id != pcb->eap.es_client.ea_id) {
1482*10465441SEvalZero 					t_clientclose(tc);
1483*10465441SEvalZero 					pcb->eap.es_client.ea_session = NULL;
1484*10465441SEvalZero 					tc = NULL;
1485*10465441SEvalZero 				}
1486*10465441SEvalZero 			}
1487*10465441SEvalZero 			/* No session key just yet */
1488*10465441SEvalZero 			pcb->eap.es_client.ea_skey = NULL;
1489*10465441SEvalZero 			if (tc == NULL) {
1490*10465441SEvalZero 				int rhostnamelen;
1491*10465441SEvalZero 
1492*10465441SEvalZero 				GETCHAR(vallen, inp);
1493*10465441SEvalZero 				len--;
1494*10465441SEvalZero 				if (vallen >= len) {
1495*10465441SEvalZero 					ppp_error("EAP: badly-formed SRP Challenge"
1496*10465441SEvalZero 					    " (name)");
1497*10465441SEvalZero 					/* Ignore badly-formed messages */
1498*10465441SEvalZero 					return;
1499*10465441SEvalZero 				}
1500*10465441SEvalZero 				MEMCPY(rhostname, inp, vallen);
1501*10465441SEvalZero 				rhostname[vallen] = '\0';
1502*10465441SEvalZero 				INCPTR(vallen, inp);
1503*10465441SEvalZero 				len -= vallen;
1504*10465441SEvalZero 
1505*10465441SEvalZero 				/*
1506*10465441SEvalZero 				 * In case the remote doesn't give us his name,
1507*10465441SEvalZero 				 * use configured name.
1508*10465441SEvalZero 				 */
1509*10465441SEvalZero 				if (explicit_remote ||
1510*10465441SEvalZero 				    (remote_name[0] != '\0' && vallen == 0)) {
1511*10465441SEvalZero 					strlcpy(rhostname, remote_name,
1512*10465441SEvalZero 					    sizeof (rhostname));
1513*10465441SEvalZero 				}
1514*10465441SEvalZero 
1515*10465441SEvalZero 				rhostnamelen = (int)strlen(rhostname);
1516*10465441SEvalZero 				if (rhostnamelen > MAXNAMELEN) {
1517*10465441SEvalZero 					rhostnamelen = MAXNAMELEN;
1518*10465441SEvalZero 				}
1519*10465441SEvalZero 				MEMCPY(pcb->eap.es_client.ea_peer, rhostname, rhostnamelen);
1520*10465441SEvalZero 				pcb->eap.es_client.ea_peer[rhostnamelen] = '\0';
1521*10465441SEvalZero 				pcb->eap.es_client.ea_peerlen = rhostnamelen;
1522*10465441SEvalZero 
1523*10465441SEvalZero 				GETCHAR(vallen, inp);
1524*10465441SEvalZero 				len--;
1525*10465441SEvalZero 				if (vallen >= len) {
1526*10465441SEvalZero 					ppp_error("EAP: badly-formed SRP Challenge"
1527*10465441SEvalZero 					    " (s)");
1528*10465441SEvalZero 					/* Ignore badly-formed messages */
1529*10465441SEvalZero 					return;
1530*10465441SEvalZero 				}
1531*10465441SEvalZero 				sval.data = inp;
1532*10465441SEvalZero 				sval.len = vallen;
1533*10465441SEvalZero 				INCPTR(vallen, inp);
1534*10465441SEvalZero 				len -= vallen;
1535*10465441SEvalZero 
1536*10465441SEvalZero 				GETCHAR(vallen, inp);
1537*10465441SEvalZero 				len--;
1538*10465441SEvalZero 				if (vallen > len) {
1539*10465441SEvalZero 					ppp_error("EAP: badly-formed SRP Challenge"
1540*10465441SEvalZero 					    " (g)");
1541*10465441SEvalZero 					/* Ignore badly-formed messages */
1542*10465441SEvalZero 					return;
1543*10465441SEvalZero 				}
1544*10465441SEvalZero 				/* If no generator present, then use value 2 */
1545*10465441SEvalZero 				if (vallen == 0) {
1546*10465441SEvalZero 					gval.data = (u_char *)"\002";
1547*10465441SEvalZero 					gval.len = 1;
1548*10465441SEvalZero 				} else {
1549*10465441SEvalZero 					gval.data = inp;
1550*10465441SEvalZero 					gval.len = vallen;
1551*10465441SEvalZero 				}
1552*10465441SEvalZero 				INCPTR(vallen, inp);
1553*10465441SEvalZero 				len -= vallen;
1554*10465441SEvalZero 
1555*10465441SEvalZero 				/*
1556*10465441SEvalZero 				 * If no modulus present, then use well-known
1557*10465441SEvalZero 				 * value.
1558*10465441SEvalZero 				 */
1559*10465441SEvalZero 				if (len == 0) {
1560*10465441SEvalZero 					Nval.data = (u_char *)wkmodulus;
1561*10465441SEvalZero 					Nval.len = sizeof (wkmodulus);
1562*10465441SEvalZero 				} else {
1563*10465441SEvalZero 					Nval.data = inp;
1564*10465441SEvalZero 					Nval.len = len;
1565*10465441SEvalZero 				}
1566*10465441SEvalZero 				tc = t_clientopen(pcb->eap.es_client.ea_name,
1567*10465441SEvalZero 				    &Nval, &gval, &sval);
1568*10465441SEvalZero 				if (tc == NULL) {
1569*10465441SEvalZero 					eap_send_nak(pcb, id, EAPT_MD5CHAP);
1570*10465441SEvalZero 					break;
1571*10465441SEvalZero 				}
1572*10465441SEvalZero 				pcb->eap.es_client.ea_session = (void *)tc;
1573*10465441SEvalZero 
1574*10465441SEvalZero 				/* Add Challenge ID & type to verifier */
1575*10465441SEvalZero 				vals[0] = id;
1576*10465441SEvalZero 				vals[1] = EAPT_SRP;
1577*10465441SEvalZero 				t_clientaddexdata(tc, vals, 2);
1578*10465441SEvalZero 			}
1579*10465441SEvalZero 			Ap = t_clientgenexp(tc);
1580*10465441SEvalZero 			eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data,
1581*10465441SEvalZero 			    Ap->len);
1582*10465441SEvalZero 			break;
1583*10465441SEvalZero 
1584*10465441SEvalZero 		case EAPSRP_SKEY:
1585*10465441SEvalZero 			tc = (struct t_client *)pcb->eap.es_client.ea_session;
1586*10465441SEvalZero 			if (tc == NULL) {
1587*10465441SEvalZero 				ppp_warn("EAP: peer sent Subtype 2 without 1");
1588*10465441SEvalZero 				eap_send_nak(pcb, id, EAPT_MD5CHAP);
1589*10465441SEvalZero 				break;
1590*10465441SEvalZero 			}
1591*10465441SEvalZero 			if (pcb->eap.es_client.ea_skey != NULL) {
1592*10465441SEvalZero 				/*
1593*10465441SEvalZero 				 * ID number should not change here.  Warn
1594*10465441SEvalZero 				 * if it does (but otherwise ignore).
1595*10465441SEvalZero 				 */
1596*10465441SEvalZero 				if (id != pcb->eap.es_client.ea_id) {
1597*10465441SEvalZero 					ppp_warn("EAP: ID changed from %d to %d "
1598*10465441SEvalZero 					    "in SRP Subtype 2 rexmit",
1599*10465441SEvalZero 					    pcb->eap.es_client.ea_id, id);
1600*10465441SEvalZero 				}
1601*10465441SEvalZero 			} else {
1602*10465441SEvalZero 				if (get_srp_secret(pcb->eap.es_unit,
1603*10465441SEvalZero 				    pcb->eap.es_client.ea_name,
1604*10465441SEvalZero 				    pcb->eap.es_client.ea_peer, secret, 0) == 0) {
1605*10465441SEvalZero 					/*
1606*10465441SEvalZero 					 * Can't work with this peer because
1607*10465441SEvalZero 					 * the secret is missing.  Just give
1608*10465441SEvalZero 					 * up.
1609*10465441SEvalZero 					 */
1610*10465441SEvalZero 					eap_send_nak(pcb, id, EAPT_MD5CHAP);
1611*10465441SEvalZero 					break;
1612*10465441SEvalZero 				}
1613*10465441SEvalZero 				Bval.data = inp;
1614*10465441SEvalZero 				Bval.len = len;
1615*10465441SEvalZero 				t_clientpasswd(tc, secret);
1616*10465441SEvalZero 				BZERO(secret, sizeof (secret));
1617*10465441SEvalZero 				pcb->eap.es_client.ea_skey =
1618*10465441SEvalZero 				    t_clientgetkey(tc, &Bval);
1619*10465441SEvalZero 				if (pcb->eap.es_client.ea_skey == NULL) {
1620*10465441SEvalZero 					/* Server is rogue; stop now */
1621*10465441SEvalZero 					ppp_error("EAP: SRP server is rogue");
1622*10465441SEvalZero 					goto client_failure;
1623*10465441SEvalZero 				}
1624*10465441SEvalZero 			}
1625*10465441SEvalZero 			eap_srpval_response(esp, id, SRPVAL_EBIT,
1626*10465441SEvalZero 			    t_clientresponse(tc));
1627*10465441SEvalZero 			break;
1628*10465441SEvalZero 
1629*10465441SEvalZero 		case EAPSRP_SVALIDATOR:
1630*10465441SEvalZero 			tc = (struct t_client *)pcb->eap.es_client.ea_session;
1631*10465441SEvalZero 			if (tc == NULL || pcb->eap.es_client.ea_skey == NULL) {
1632*10465441SEvalZero 				ppp_warn("EAP: peer sent Subtype 3 without 1/2");
1633*10465441SEvalZero 				eap_send_nak(pcb, id, EAPT_MD5CHAP);
1634*10465441SEvalZero 				break;
1635*10465441SEvalZero 			}
1636*10465441SEvalZero 			/*
1637*10465441SEvalZero 			 * If we're already open, then this ought to be a
1638*10465441SEvalZero 			 * duplicate.  Otherwise, check that the server is
1639*10465441SEvalZero 			 * who we think it is.
1640*10465441SEvalZero 			 */
1641*10465441SEvalZero 			if (pcb->eap.es_client.ea_state == eapOpen) {
1642*10465441SEvalZero 				if (id != pcb->eap.es_client.ea_id) {
1643*10465441SEvalZero 					ppp_warn("EAP: ID changed from %d to %d "
1644*10465441SEvalZero 					    "in SRP Subtype 3 rexmit",
1645*10465441SEvalZero 					    pcb->eap.es_client.ea_id, id);
1646*10465441SEvalZero 				}
1647*10465441SEvalZero 			} else {
1648*10465441SEvalZero 				len -= sizeof (u32_t) + SHA_DIGESTSIZE;
1649*10465441SEvalZero 				if (len < 0 || t_clientverify(tc, inp +
1650*10465441SEvalZero 					sizeof (u32_t)) != 0) {
1651*10465441SEvalZero 					ppp_error("EAP: SRP server verification "
1652*10465441SEvalZero 					    "failed");
1653*10465441SEvalZero 					goto client_failure;
1654*10465441SEvalZero 				}
1655*10465441SEvalZero 				GETLONG(pcb->eap.es_client.ea_keyflags, inp);
1656*10465441SEvalZero 				/* Save pseudonym if user wants it. */
1657*10465441SEvalZero 				if (len > 0 && pcb->eap.es_usepseudo) {
1658*10465441SEvalZero 					INCPTR(SHA_DIGESTSIZE, inp);
1659*10465441SEvalZero 					write_pseudonym(esp, inp, len, id);
1660*10465441SEvalZero 				}
1661*10465441SEvalZero 			}
1662*10465441SEvalZero 			/*
1663*10465441SEvalZero 			 * We've verified our peer.  We're now mostly done,
1664*10465441SEvalZero 			 * except for waiting on the regular EAP Success
1665*10465441SEvalZero 			 * message.
1666*10465441SEvalZero 			 */
1667*10465441SEvalZero 			eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0);
1668*10465441SEvalZero 			break;
1669*10465441SEvalZero 
1670*10465441SEvalZero 		case EAPSRP_LWRECHALLENGE:
1671*10465441SEvalZero 			if (len < 4) {
1672*10465441SEvalZero 				ppp_warn("EAP: malformed Lightweight rechallenge");
1673*10465441SEvalZero 				return;
1674*10465441SEvalZero 			}
1675*10465441SEvalZero 			SHA1Init(&ctxt);
1676*10465441SEvalZero 			vals[0] = id;
1677*10465441SEvalZero 			SHA1Update(&ctxt, vals, 1);
1678*10465441SEvalZero 			SHA1Update(&ctxt, pcb->eap.es_client.ea_skey,
1679*10465441SEvalZero 			    SESSION_KEY_LEN);
1680*10465441SEvalZero 			SHA1Update(&ctxt, inp, len);
1681*10465441SEvalZero 			SHA1Update(&ctxt, pcb->eap.es_client.ea_name,
1682*10465441SEvalZero 			    pcb->eap.es_client.ea_namelen);
1683*10465441SEvalZero 			SHA1Final(dig, &ctxt);
1684*10465441SEvalZero 			eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig,
1685*10465441SEvalZero 			    SHA_DIGESTSIZE);
1686*10465441SEvalZero 			break;
1687*10465441SEvalZero 
1688*10465441SEvalZero 		default:
1689*10465441SEvalZero 			ppp_error("EAP: unknown SRP Subtype %d", vallen);
1690*10465441SEvalZero 			eap_send_nak(pcb, id, EAPT_MD5CHAP);
1691*10465441SEvalZero 			break;
1692*10465441SEvalZero 		}
1693*10465441SEvalZero 		break;
1694*10465441SEvalZero #endif /* USE_SRP */
1695*10465441SEvalZero 
1696*10465441SEvalZero 	default:
1697*10465441SEvalZero 		ppp_info("EAP: unknown authentication type %d; Naking", typenum);
1698*10465441SEvalZero 		eap_send_nak(pcb, id, EAPT_SRP);
1699*10465441SEvalZero 		break;
1700*10465441SEvalZero 	}
1701*10465441SEvalZero 
1702*10465441SEvalZero 	if (pcb->settings.eap_req_time > 0) {
1703*10465441SEvalZero 		UNTIMEOUT(eap_client_timeout, pcb);
1704*10465441SEvalZero 		TIMEOUT(eap_client_timeout, pcb,
1705*10465441SEvalZero 		    pcb->settings.eap_req_time);
1706*10465441SEvalZero 	}
1707*10465441SEvalZero 	return;
1708*10465441SEvalZero 
1709*10465441SEvalZero #ifdef USE_SRP
1710*10465441SEvalZero client_failure:
1711*10465441SEvalZero 	pcb->eap.es_client.ea_state = eapBadAuth;
1712*10465441SEvalZero 	if (pcb->settings.eap_req_time > 0) {
1713*10465441SEvalZero 		UNTIMEOUT(eap_client_timeout, (void *)esp);
1714*10465441SEvalZero 	}
1715*10465441SEvalZero 	pcb->eap.es_client.ea_session = NULL;
1716*10465441SEvalZero 	t_clientclose(tc);
1717*10465441SEvalZero 	auth_withpeer_fail(pcb, PPP_EAP);
1718*10465441SEvalZero #endif /* USE_SRP */
1719*10465441SEvalZero }
1720*10465441SEvalZero 
1721*10465441SEvalZero #if PPP_SERVER
1722*10465441SEvalZero /*
1723*10465441SEvalZero  * eap_response - Receive EAP Response message (server mode).
1724*10465441SEvalZero  */
eap_response(ppp_pcb * pcb,u_char * inp,int id,int len)1725*10465441SEvalZero static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) {
1726*10465441SEvalZero 	u_char typenum;
1727*10465441SEvalZero 	u_char vallen;
1728*10465441SEvalZero 	int secret_len;
1729*10465441SEvalZero 	char secret[MAXSECRETLEN];
1730*10465441SEvalZero 	char rhostname[MAXNAMELEN];
1731*10465441SEvalZero 	lwip_md5_context mdContext;
1732*10465441SEvalZero 	u_char hash[MD5_SIGNATURE_SIZE];
1733*10465441SEvalZero #ifdef USE_SRP
1734*10465441SEvalZero 	struct t_server *ts;
1735*10465441SEvalZero 	struct t_num A;
1736*10465441SEvalZero 	SHA1_CTX ctxt;
1737*10465441SEvalZero 	u_char dig[SHA_DIGESTSIZE];
1738*10465441SEvalZero #endif /* USE_SRP */
1739*10465441SEvalZero 
1740*10465441SEvalZero 	if (pcb->eap.es_server.ea_id != id) {
1741*10465441SEvalZero 		ppp_dbglog("EAP: discarding Response %d; expected ID %d", id,
1742*10465441SEvalZero 		    pcb->eap.es_server.ea_id);
1743*10465441SEvalZero 		return;
1744*10465441SEvalZero 	}
1745*10465441SEvalZero 
1746*10465441SEvalZero 	pcb->eap.es_server.ea_responses++;
1747*10465441SEvalZero 
1748*10465441SEvalZero 	if (len <= 0) {
1749*10465441SEvalZero 		ppp_error("EAP: empty Response message discarded");
1750*10465441SEvalZero 		return;
1751*10465441SEvalZero 	}
1752*10465441SEvalZero 
1753*10465441SEvalZero 	GETCHAR(typenum, inp);
1754*10465441SEvalZero 	len--;
1755*10465441SEvalZero 
1756*10465441SEvalZero 	switch (typenum) {
1757*10465441SEvalZero 	case EAPT_IDENTITY:
1758*10465441SEvalZero 		if (pcb->eap.es_server.ea_state != eapIdentify) {
1759*10465441SEvalZero 			ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len,
1760*10465441SEvalZero 			    inp);
1761*10465441SEvalZero 			break;
1762*10465441SEvalZero 		}
1763*10465441SEvalZero 		ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp);
1764*10465441SEvalZero 		if (len > MAXNAMELEN) {
1765*10465441SEvalZero 		  len = MAXNAMELEN;
1766*10465441SEvalZero 		}
1767*10465441SEvalZero 		MEMCPY(pcb->eap.es_server.ea_peer, inp, len);
1768*10465441SEvalZero 		pcb->eap.es_server.ea_peer[len] = '\0';
1769*10465441SEvalZero 		pcb->eap.es_server.ea_peerlen = len;
1770*10465441SEvalZero 		eap_figure_next_state(pcb, 0);
1771*10465441SEvalZero 		break;
1772*10465441SEvalZero 
1773*10465441SEvalZero 	case EAPT_NOTIFICATION:
1774*10465441SEvalZero 		ppp_dbglog("EAP unexpected Notification; response discarded");
1775*10465441SEvalZero 		break;
1776*10465441SEvalZero 
1777*10465441SEvalZero 	case EAPT_NAK:
1778*10465441SEvalZero 		if (len < 1) {
1779*10465441SEvalZero 			ppp_info("EAP: Nak Response with no suggested protocol");
1780*10465441SEvalZero 			eap_figure_next_state(pcb, 1);
1781*10465441SEvalZero 			break;
1782*10465441SEvalZero 		}
1783*10465441SEvalZero 
1784*10465441SEvalZero 		GETCHAR(vallen, inp);
1785*10465441SEvalZero 		len--;
1786*10465441SEvalZero 
1787*10465441SEvalZero 		if (
1788*10465441SEvalZero #if PPP_REMOTENAME
1789*10465441SEvalZero 		!pcb->explicit_remote &&
1790*10465441SEvalZero #endif /* PPP_REMOTENAME */
1791*10465441SEvalZero 		pcb->eap.es_server.ea_state == eapIdentify){
1792*10465441SEvalZero 			/* Peer cannot Nak Identify Request */
1793*10465441SEvalZero 			eap_figure_next_state(pcb, 1);
1794*10465441SEvalZero 			break;
1795*10465441SEvalZero 		}
1796*10465441SEvalZero 
1797*10465441SEvalZero 		switch (vallen) {
1798*10465441SEvalZero 		case EAPT_SRP:
1799*10465441SEvalZero 			/* Run through SRP validator selection again. */
1800*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapIdentify;
1801*10465441SEvalZero 			eap_figure_next_state(pcb, 0);
1802*10465441SEvalZero 			break;
1803*10465441SEvalZero 
1804*10465441SEvalZero 		case EAPT_MD5CHAP:
1805*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapMD5Chall;
1806*10465441SEvalZero 			break;
1807*10465441SEvalZero 
1808*10465441SEvalZero 		default:
1809*10465441SEvalZero 			ppp_dbglog("EAP: peer requesting unknown Type %d", vallen);
1810*10465441SEvalZero 			switch (pcb->eap.es_server.ea_state) {
1811*10465441SEvalZero 			case eapSRP1:
1812*10465441SEvalZero 			case eapSRP2:
1813*10465441SEvalZero 			case eapSRP3:
1814*10465441SEvalZero 				pcb->eap.es_server.ea_state = eapMD5Chall;
1815*10465441SEvalZero 				break;
1816*10465441SEvalZero 			case eapMD5Chall:
1817*10465441SEvalZero 			case eapSRP4:
1818*10465441SEvalZero 				pcb->eap.es_server.ea_state = eapIdentify;
1819*10465441SEvalZero 				eap_figure_next_state(pcb, 0);
1820*10465441SEvalZero 				break;
1821*10465441SEvalZero 			default:
1822*10465441SEvalZero 				break;
1823*10465441SEvalZero 			}
1824*10465441SEvalZero 			break;
1825*10465441SEvalZero 		}
1826*10465441SEvalZero 		break;
1827*10465441SEvalZero 
1828*10465441SEvalZero 	case EAPT_MD5CHAP:
1829*10465441SEvalZero 		if (pcb->eap.es_server.ea_state != eapMD5Chall) {
1830*10465441SEvalZero 			ppp_error("EAP: unexpected MD5-Response");
1831*10465441SEvalZero 			eap_figure_next_state(pcb, 1);
1832*10465441SEvalZero 			break;
1833*10465441SEvalZero 		}
1834*10465441SEvalZero 		if (len < 1) {
1835*10465441SEvalZero 			ppp_error("EAP: received MD5-Response with no data");
1836*10465441SEvalZero 			eap_figure_next_state(pcb, 1);
1837*10465441SEvalZero 			break;
1838*10465441SEvalZero 		}
1839*10465441SEvalZero 		GETCHAR(vallen, inp);
1840*10465441SEvalZero 		len--;
1841*10465441SEvalZero 		if (vallen != 16 || vallen > len) {
1842*10465441SEvalZero 			ppp_error("EAP: MD5-Response with bad length %d", vallen);
1843*10465441SEvalZero 			eap_figure_next_state(pcb, 1);
1844*10465441SEvalZero 			break;
1845*10465441SEvalZero 		}
1846*10465441SEvalZero 
1847*10465441SEvalZero 		/* Not so likely to happen. */
1848*10465441SEvalZero 		if (vallen >= len + sizeof (rhostname)) {
1849*10465441SEvalZero 			ppp_dbglog("EAP: trimming really long peer name down");
1850*10465441SEvalZero 			MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1);
1851*10465441SEvalZero 			rhostname[sizeof (rhostname) - 1] = '\0';
1852*10465441SEvalZero 		} else {
1853*10465441SEvalZero 			MEMCPY(rhostname, inp + vallen, len - vallen);
1854*10465441SEvalZero 			rhostname[len - vallen] = '\0';
1855*10465441SEvalZero 		}
1856*10465441SEvalZero 
1857*10465441SEvalZero #if PPP_REMOTENAME
1858*10465441SEvalZero 		/* In case the remote doesn't give us his name. */
1859*10465441SEvalZero 		if (explicit_remote ||
1860*10465441SEvalZero 		    (remote_name[0] != '\0' && vallen == len))
1861*10465441SEvalZero 			strlcpy(rhostname, remote_name, sizeof (rhostname));
1862*10465441SEvalZero #endif /* PPP_REMOTENAME */
1863*10465441SEvalZero 
1864*10465441SEvalZero 		/*
1865*10465441SEvalZero 		 * Get the secret for authenticating the specified
1866*10465441SEvalZero 		 * host.
1867*10465441SEvalZero 		 */
1868*10465441SEvalZero 		if (!get_secret(pcb, rhostname,
1869*10465441SEvalZero 		    pcb->eap.es_server.ea_name, secret, &secret_len, 1)) {
1870*10465441SEvalZero 			ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname);
1871*10465441SEvalZero 			eap_send_failure(pcb);
1872*10465441SEvalZero 			break;
1873*10465441SEvalZero 		}
1874*10465441SEvalZero 		lwip_md5_init(&mdContext);
1875*10465441SEvalZero 		lwip_md5_starts(&mdContext);
1876*10465441SEvalZero 		lwip_md5_update(&mdContext, &pcb->eap.es_server.ea_id, 1);
1877*10465441SEvalZero 		lwip_md5_update(&mdContext, (u_char *)secret, secret_len);
1878*10465441SEvalZero 		BZERO(secret, sizeof (secret));
1879*10465441SEvalZero 		lwip_md5_update(&mdContext, pcb->eap.es_challenge, pcb->eap.es_challen);
1880*10465441SEvalZero 		lwip_md5_finish(&mdContext, hash);
1881*10465441SEvalZero 		lwip_md5_free(&mdContext);
1882*10465441SEvalZero 		if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) {
1883*10465441SEvalZero 			eap_send_failure(pcb);
1884*10465441SEvalZero 			break;
1885*10465441SEvalZero 		}
1886*10465441SEvalZero 		pcb->eap.es_server.ea_type = EAPT_MD5CHAP;
1887*10465441SEvalZero 		eap_send_success(pcb);
1888*10465441SEvalZero 		eap_figure_next_state(pcb, 0);
1889*10465441SEvalZero 		if (pcb->eap.es_rechallenge != 0)
1890*10465441SEvalZero 			TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge);
1891*10465441SEvalZero 		break;
1892*10465441SEvalZero 
1893*10465441SEvalZero #ifdef USE_SRP
1894*10465441SEvalZero 	case EAPT_SRP:
1895*10465441SEvalZero 		if (len < 1) {
1896*10465441SEvalZero 			ppp_error("EAP: empty SRP Response");
1897*10465441SEvalZero 			eap_figure_next_state(pcb, 1);
1898*10465441SEvalZero 			break;
1899*10465441SEvalZero 		}
1900*10465441SEvalZero 		GETCHAR(typenum, inp);
1901*10465441SEvalZero 		len--;
1902*10465441SEvalZero 		switch (typenum) {
1903*10465441SEvalZero 		case EAPSRP_CKEY:
1904*10465441SEvalZero 			if (pcb->eap.es_server.ea_state != eapSRP1) {
1905*10465441SEvalZero 				ppp_error("EAP: unexpected SRP Subtype 1 Response");
1906*10465441SEvalZero 				eap_figure_next_state(pcb, 1);
1907*10465441SEvalZero 				break;
1908*10465441SEvalZero 			}
1909*10465441SEvalZero 			A.data = inp;
1910*10465441SEvalZero 			A.len = len;
1911*10465441SEvalZero 			ts = (struct t_server *)pcb->eap.es_server.ea_session;
1912*10465441SEvalZero 			assert(ts != NULL);
1913*10465441SEvalZero 			pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A);
1914*10465441SEvalZero 			if (pcb->eap.es_server.ea_skey == NULL) {
1915*10465441SEvalZero 				/* Client's A value is bogus; terminate now */
1916*10465441SEvalZero 				ppp_error("EAP: bogus A value from client");
1917*10465441SEvalZero 				eap_send_failure(pcb);
1918*10465441SEvalZero 			} else {
1919*10465441SEvalZero 				eap_figure_next_state(pcb, 0);
1920*10465441SEvalZero 			}
1921*10465441SEvalZero 			break;
1922*10465441SEvalZero 
1923*10465441SEvalZero 		case EAPSRP_CVALIDATOR:
1924*10465441SEvalZero 			if (pcb->eap.es_server.ea_state != eapSRP2) {
1925*10465441SEvalZero 				ppp_error("EAP: unexpected SRP Subtype 2 Response");
1926*10465441SEvalZero 				eap_figure_next_state(pcb, 1);
1927*10465441SEvalZero 				break;
1928*10465441SEvalZero 			}
1929*10465441SEvalZero 			if (len < sizeof (u32_t) + SHA_DIGESTSIZE) {
1930*10465441SEvalZero 				ppp_error("EAP: M1 length %d < %d", len,
1931*10465441SEvalZero 				    sizeof (u32_t) + SHA_DIGESTSIZE);
1932*10465441SEvalZero 				eap_figure_next_state(pcb, 1);
1933*10465441SEvalZero 				break;
1934*10465441SEvalZero 			}
1935*10465441SEvalZero 			GETLONG(pcb->eap.es_server.ea_keyflags, inp);
1936*10465441SEvalZero 			ts = (struct t_server *)pcb->eap.es_server.ea_session;
1937*10465441SEvalZero 			assert(ts != NULL);
1938*10465441SEvalZero 			if (t_serververify(ts, inp)) {
1939*10465441SEvalZero 				ppp_info("EAP: unable to validate client identity");
1940*10465441SEvalZero 				eap_send_failure(pcb);
1941*10465441SEvalZero 				break;
1942*10465441SEvalZero 			}
1943*10465441SEvalZero 			eap_figure_next_state(pcb, 0);
1944*10465441SEvalZero 			break;
1945*10465441SEvalZero 
1946*10465441SEvalZero 		case EAPSRP_ACK:
1947*10465441SEvalZero 			if (pcb->eap.es_server.ea_state != eapSRP3) {
1948*10465441SEvalZero 				ppp_error("EAP: unexpected SRP Subtype 3 Response");
1949*10465441SEvalZero 				eap_send_failure(esp);
1950*10465441SEvalZero 				break;
1951*10465441SEvalZero 			}
1952*10465441SEvalZero 			pcb->eap.es_server.ea_type = EAPT_SRP;
1953*10465441SEvalZero 			eap_send_success(pcb, esp);
1954*10465441SEvalZero 			eap_figure_next_state(pcb, 0);
1955*10465441SEvalZero 			if (pcb->eap.es_rechallenge != 0)
1956*10465441SEvalZero 				TIMEOUT(eap_rechallenge, pcb,
1957*10465441SEvalZero 				    pcb->eap.es_rechallenge);
1958*10465441SEvalZero 			if (pcb->eap.es_lwrechallenge != 0)
1959*10465441SEvalZero 				TIMEOUT(srp_lwrechallenge, pcb,
1960*10465441SEvalZero 				    pcb->eap.es_lwrechallenge);
1961*10465441SEvalZero 			break;
1962*10465441SEvalZero 
1963*10465441SEvalZero 		case EAPSRP_LWRECHALLENGE:
1964*10465441SEvalZero 			if (pcb->eap.es_server.ea_state != eapSRP4) {
1965*10465441SEvalZero 				ppp_info("EAP: unexpected SRP Subtype 4 Response");
1966*10465441SEvalZero 				return;
1967*10465441SEvalZero 			}
1968*10465441SEvalZero 			if (len != SHA_DIGESTSIZE) {
1969*10465441SEvalZero 				ppp_error("EAP: bad Lightweight rechallenge "
1970*10465441SEvalZero 				    "response");
1971*10465441SEvalZero 				return;
1972*10465441SEvalZero 			}
1973*10465441SEvalZero 			SHA1Init(&ctxt);
1974*10465441SEvalZero 			vallen = id;
1975*10465441SEvalZero 			SHA1Update(&ctxt, &vallen, 1);
1976*10465441SEvalZero 			SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
1977*10465441SEvalZero 			    SESSION_KEY_LEN);
1978*10465441SEvalZero 			SHA1Update(&ctxt, pcb->eap.es_challenge, pcb->eap.es_challen);
1979*10465441SEvalZero 			SHA1Update(&ctxt, pcb->eap.es_server.ea_peer,
1980*10465441SEvalZero 			    pcb->eap.es_server.ea_peerlen);
1981*10465441SEvalZero 			SHA1Final(dig, &ctxt);
1982*10465441SEvalZero 			if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) {
1983*10465441SEvalZero 				ppp_error("EAP: failed Lightweight rechallenge");
1984*10465441SEvalZero 				eap_send_failure(pcb);
1985*10465441SEvalZero 				break;
1986*10465441SEvalZero 			}
1987*10465441SEvalZero 			pcb->eap.es_server.ea_state = eapOpen;
1988*10465441SEvalZero 			if (pcb->eap.es_lwrechallenge != 0)
1989*10465441SEvalZero 				TIMEOUT(srp_lwrechallenge, esp,
1990*10465441SEvalZero 				    pcb->eap.es_lwrechallenge);
1991*10465441SEvalZero 			break;
1992*10465441SEvalZero 		}
1993*10465441SEvalZero 		break;
1994*10465441SEvalZero #endif /* USE_SRP */
1995*10465441SEvalZero 
1996*10465441SEvalZero 	default:
1997*10465441SEvalZero 		/* This can't happen. */
1998*10465441SEvalZero 		ppp_error("EAP: unknown Response type %d; ignored", typenum);
1999*10465441SEvalZero 		return;
2000*10465441SEvalZero 	}
2001*10465441SEvalZero 
2002*10465441SEvalZero 	if (pcb->settings.eap_timeout_time > 0) {
2003*10465441SEvalZero 		UNTIMEOUT(eap_server_timeout, pcb);
2004*10465441SEvalZero 	}
2005*10465441SEvalZero 
2006*10465441SEvalZero 	if (pcb->eap.es_server.ea_state != eapBadAuth &&
2007*10465441SEvalZero 	    pcb->eap.es_server.ea_state != eapOpen) {
2008*10465441SEvalZero 		pcb->eap.es_server.ea_id++;
2009*10465441SEvalZero 		eap_send_request(pcb);
2010*10465441SEvalZero 	}
2011*10465441SEvalZero }
2012*10465441SEvalZero #endif /* PPP_SERVER */
2013*10465441SEvalZero 
2014*10465441SEvalZero /*
2015*10465441SEvalZero  * eap_success - Receive EAP Success message (client mode).
2016*10465441SEvalZero  */
eap_success(ppp_pcb * pcb,u_char * inp,int id,int len)2017*10465441SEvalZero static void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) {
2018*10465441SEvalZero 	LWIP_UNUSED_ARG(id);
2019*10465441SEvalZero 
2020*10465441SEvalZero 	if (pcb->eap.es_client.ea_state != eapOpen && !eap_client_active(pcb)) {
2021*10465441SEvalZero 		ppp_dbglog("EAP unexpected success message in state %s (%d)",
2022*10465441SEvalZero 		    eap_state_name(pcb->eap.es_client.ea_state),
2023*10465441SEvalZero 		    pcb->eap.es_client.ea_state);
2024*10465441SEvalZero 		return;
2025*10465441SEvalZero 	}
2026*10465441SEvalZero 
2027*10465441SEvalZero 	if (pcb->settings.eap_req_time > 0) {
2028*10465441SEvalZero 		UNTIMEOUT(eap_client_timeout, pcb);
2029*10465441SEvalZero 	}
2030*10465441SEvalZero 
2031*10465441SEvalZero 	if (len > 0) {
2032*10465441SEvalZero 		/* This is odd.  The spec doesn't allow for this. */
2033*10465441SEvalZero 		PRINTMSG(inp, len);
2034*10465441SEvalZero 	}
2035*10465441SEvalZero 
2036*10465441SEvalZero 	pcb->eap.es_client.ea_state = eapOpen;
2037*10465441SEvalZero 	auth_withpeer_success(pcb, PPP_EAP, 0);
2038*10465441SEvalZero }
2039*10465441SEvalZero 
2040*10465441SEvalZero /*
2041*10465441SEvalZero  * eap_failure - Receive EAP Failure message (client mode).
2042*10465441SEvalZero  */
eap_failure(ppp_pcb * pcb,u_char * inp,int id,int len)2043*10465441SEvalZero static void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) {
2044*10465441SEvalZero 	LWIP_UNUSED_ARG(id);
2045*10465441SEvalZero 
2046*10465441SEvalZero 	if (!eap_client_active(pcb)) {
2047*10465441SEvalZero 		ppp_dbglog("EAP unexpected failure message in state %s (%d)",
2048*10465441SEvalZero 		    eap_state_name(pcb->eap.es_client.ea_state),
2049*10465441SEvalZero 		    pcb->eap.es_client.ea_state);
2050*10465441SEvalZero 	}
2051*10465441SEvalZero 
2052*10465441SEvalZero 	if (pcb->settings.eap_req_time > 0) {
2053*10465441SEvalZero 		UNTIMEOUT(eap_client_timeout, pcb);
2054*10465441SEvalZero 	}
2055*10465441SEvalZero 
2056*10465441SEvalZero 	if (len > 0) {
2057*10465441SEvalZero 		/* This is odd.  The spec doesn't allow for this. */
2058*10465441SEvalZero 		PRINTMSG(inp, len);
2059*10465441SEvalZero 	}
2060*10465441SEvalZero 
2061*10465441SEvalZero 	pcb->eap.es_client.ea_state = eapBadAuth;
2062*10465441SEvalZero 
2063*10465441SEvalZero 	ppp_error("EAP: peer reports authentication failure");
2064*10465441SEvalZero 	auth_withpeer_fail(pcb, PPP_EAP);
2065*10465441SEvalZero }
2066*10465441SEvalZero 
2067*10465441SEvalZero /*
2068*10465441SEvalZero  * eap_input - Handle received EAP message.
2069*10465441SEvalZero  */
eap_input(ppp_pcb * pcb,u_char * inp,int inlen)2070*10465441SEvalZero static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) {
2071*10465441SEvalZero 	u_char code, id;
2072*10465441SEvalZero 	int len;
2073*10465441SEvalZero 
2074*10465441SEvalZero 	/*
2075*10465441SEvalZero 	 * Parse header (code, id and length).  If packet too short,
2076*10465441SEvalZero 	 * drop it.
2077*10465441SEvalZero 	 */
2078*10465441SEvalZero 	if (inlen < EAP_HEADERLEN) {
2079*10465441SEvalZero 		ppp_error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN);
2080*10465441SEvalZero 		return;
2081*10465441SEvalZero 	}
2082*10465441SEvalZero 	GETCHAR(code, inp);
2083*10465441SEvalZero 	GETCHAR(id, inp);
2084*10465441SEvalZero 	GETSHORT(len, inp);
2085*10465441SEvalZero 	if (len < EAP_HEADERLEN || len > inlen) {
2086*10465441SEvalZero 		ppp_error("EAP: packet has illegal length field %d (%d..%d)", len,
2087*10465441SEvalZero 		    EAP_HEADERLEN, inlen);
2088*10465441SEvalZero 		return;
2089*10465441SEvalZero 	}
2090*10465441SEvalZero 	len -= EAP_HEADERLEN;
2091*10465441SEvalZero 
2092*10465441SEvalZero 	/* Dispatch based on message code */
2093*10465441SEvalZero 	switch (code) {
2094*10465441SEvalZero 	case EAP_REQUEST:
2095*10465441SEvalZero 		eap_request(pcb, inp, id, len);
2096*10465441SEvalZero 		break;
2097*10465441SEvalZero 
2098*10465441SEvalZero #if PPP_SERVER
2099*10465441SEvalZero 	case EAP_RESPONSE:
2100*10465441SEvalZero 		eap_response(pcb, inp, id, len);
2101*10465441SEvalZero 		break;
2102*10465441SEvalZero #endif /* PPP_SERVER */
2103*10465441SEvalZero 
2104*10465441SEvalZero 	case EAP_SUCCESS:
2105*10465441SEvalZero 		eap_success(pcb, inp, id, len);
2106*10465441SEvalZero 		break;
2107*10465441SEvalZero 
2108*10465441SEvalZero 	case EAP_FAILURE:
2109*10465441SEvalZero 		eap_failure(pcb, inp, id, len);
2110*10465441SEvalZero 		break;
2111*10465441SEvalZero 
2112*10465441SEvalZero 	default:				/* XXX Need code reject */
2113*10465441SEvalZero 		/* Note: it's not legal to send EAP Nak here. */
2114*10465441SEvalZero 		ppp_warn("EAP: unknown code %d received", code);
2115*10465441SEvalZero 		break;
2116*10465441SEvalZero 	}
2117*10465441SEvalZero }
2118*10465441SEvalZero 
2119*10465441SEvalZero #if PRINTPKT_SUPPORT
2120*10465441SEvalZero /*
2121*10465441SEvalZero  * eap_printpkt - print the contents of an EAP packet.
2122*10465441SEvalZero  */
2123*10465441SEvalZero static const char* const eap_codenames[] = {
2124*10465441SEvalZero 	"Request", "Response", "Success", "Failure"
2125*10465441SEvalZero };
2126*10465441SEvalZero 
2127*10465441SEvalZero static const char* const eap_typenames[] = {
2128*10465441SEvalZero 	"Identity", "Notification", "Nak", "MD5-Challenge",
2129*10465441SEvalZero 	"OTP", "Generic-Token", NULL, NULL,
2130*10465441SEvalZero 	"RSA", "DSS", "KEA", "KEA-Validate",
2131*10465441SEvalZero 	"TLS", "Defender", "Windows 2000", "Arcot",
2132*10465441SEvalZero 	"Cisco", "Nokia", "SRP"
2133*10465441SEvalZero };
2134*10465441SEvalZero 
eap_printpkt(const u_char * inp,int inlen,void (* printer)(void *,const char *,...),void * arg)2135*10465441SEvalZero static int eap_printpkt(const u_char *inp, int inlen, void (*printer) (void *, const char *, ...), void *arg) {
2136*10465441SEvalZero 	int code, id, len, rtype, vallen;
2137*10465441SEvalZero 	const u_char *pstart;
2138*10465441SEvalZero 	u32_t uval;
2139*10465441SEvalZero 
2140*10465441SEvalZero 	if (inlen < EAP_HEADERLEN)
2141*10465441SEvalZero 		return (0);
2142*10465441SEvalZero 	pstart = inp;
2143*10465441SEvalZero 	GETCHAR(code, inp);
2144*10465441SEvalZero 	GETCHAR(id, inp);
2145*10465441SEvalZero 	GETSHORT(len, inp);
2146*10465441SEvalZero 	if (len < EAP_HEADERLEN || len > inlen)
2147*10465441SEvalZero 		return (0);
2148*10465441SEvalZero 
2149*10465441SEvalZero 	if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(eap_codenames))
2150*10465441SEvalZero 		printer(arg, " %s", eap_codenames[code-1]);
2151*10465441SEvalZero 	else
2152*10465441SEvalZero 		printer(arg, " code=0x%x", code);
2153*10465441SEvalZero 	printer(arg, " id=0x%x", id);
2154*10465441SEvalZero 	len -= EAP_HEADERLEN;
2155*10465441SEvalZero 	switch (code) {
2156*10465441SEvalZero 	case EAP_REQUEST:
2157*10465441SEvalZero 		if (len < 1) {
2158*10465441SEvalZero 			printer(arg, " <missing type>");
2159*10465441SEvalZero 			break;
2160*10465441SEvalZero 		}
2161*10465441SEvalZero 		GETCHAR(rtype, inp);
2162*10465441SEvalZero 		len--;
2163*10465441SEvalZero 		if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames))
2164*10465441SEvalZero 			printer(arg, " %s", eap_typenames[rtype-1]);
2165*10465441SEvalZero 		else
2166*10465441SEvalZero 			printer(arg, " type=0x%x", rtype);
2167*10465441SEvalZero 		switch (rtype) {
2168*10465441SEvalZero 		case EAPT_IDENTITY:
2169*10465441SEvalZero 		case EAPT_NOTIFICATION:
2170*10465441SEvalZero 			if (len > 0) {
2171*10465441SEvalZero 				printer(arg, " <Message ");
2172*10465441SEvalZero 				ppp_print_string(inp, len, printer, arg);
2173*10465441SEvalZero 				printer(arg, ">");
2174*10465441SEvalZero 				INCPTR(len, inp);
2175*10465441SEvalZero 				len = 0;
2176*10465441SEvalZero 			} else {
2177*10465441SEvalZero 				printer(arg, " <No message>");
2178*10465441SEvalZero 			}
2179*10465441SEvalZero 			break;
2180*10465441SEvalZero 
2181*10465441SEvalZero 		case EAPT_MD5CHAP:
2182*10465441SEvalZero 			if (len <= 0)
2183*10465441SEvalZero 				break;
2184*10465441SEvalZero 			GETCHAR(vallen, inp);
2185*10465441SEvalZero 			len--;
2186*10465441SEvalZero 			if (vallen > len)
2187*10465441SEvalZero 				goto truncated;
2188*10465441SEvalZero 			printer(arg, " <Value%.*B>", vallen, inp);
2189*10465441SEvalZero 			INCPTR(vallen, inp);
2190*10465441SEvalZero 			len -= vallen;
2191*10465441SEvalZero 			if (len > 0) {
2192*10465441SEvalZero 				printer(arg, " <Name ");
2193*10465441SEvalZero 				ppp_print_string(inp, len, printer, arg);
2194*10465441SEvalZero 				printer(arg, ">");
2195*10465441SEvalZero 				INCPTR(len, inp);
2196*10465441SEvalZero 				len = 0;
2197*10465441SEvalZero 			} else {
2198*10465441SEvalZero 				printer(arg, " <No name>");
2199*10465441SEvalZero 			}
2200*10465441SEvalZero 			break;
2201*10465441SEvalZero 
2202*10465441SEvalZero 		case EAPT_SRP:
2203*10465441SEvalZero 			if (len < 3)
2204*10465441SEvalZero 				goto truncated;
2205*10465441SEvalZero 			GETCHAR(vallen, inp);
2206*10465441SEvalZero 			len--;
2207*10465441SEvalZero 			printer(arg, "-%d", vallen);
2208*10465441SEvalZero 			switch (vallen) {
2209*10465441SEvalZero 			case EAPSRP_CHALLENGE:
2210*10465441SEvalZero 				GETCHAR(vallen, inp);
2211*10465441SEvalZero 				len--;
2212*10465441SEvalZero 				if (vallen >= len)
2213*10465441SEvalZero 					goto truncated;
2214*10465441SEvalZero 				if (vallen > 0) {
2215*10465441SEvalZero 					printer(arg, " <Name ");
2216*10465441SEvalZero 					ppp_print_string(inp, vallen, printer,
2217*10465441SEvalZero 					    arg);
2218*10465441SEvalZero 					printer(arg, ">");
2219*10465441SEvalZero 				} else {
2220*10465441SEvalZero 					printer(arg, " <No name>");
2221*10465441SEvalZero 				}
2222*10465441SEvalZero 				INCPTR(vallen, inp);
2223*10465441SEvalZero 				len -= vallen;
2224*10465441SEvalZero 				GETCHAR(vallen, inp);
2225*10465441SEvalZero 				len--;
2226*10465441SEvalZero 				if (vallen >= len)
2227*10465441SEvalZero 					goto truncated;
2228*10465441SEvalZero 				printer(arg, " <s%.*B>", vallen, inp);
2229*10465441SEvalZero 				INCPTR(vallen, inp);
2230*10465441SEvalZero 				len -= vallen;
2231*10465441SEvalZero 				GETCHAR(vallen, inp);
2232*10465441SEvalZero 				len--;
2233*10465441SEvalZero 				if (vallen > len)
2234*10465441SEvalZero 					goto truncated;
2235*10465441SEvalZero 				if (vallen == 0) {
2236*10465441SEvalZero 					printer(arg, " <Default g=2>");
2237*10465441SEvalZero 				} else {
2238*10465441SEvalZero 					printer(arg, " <g%.*B>", vallen, inp);
2239*10465441SEvalZero 				}
2240*10465441SEvalZero 				INCPTR(vallen, inp);
2241*10465441SEvalZero 				len -= vallen;
2242*10465441SEvalZero 				if (len == 0) {
2243*10465441SEvalZero 					printer(arg, " <Default N>");
2244*10465441SEvalZero 				} else {
2245*10465441SEvalZero 					printer(arg, " <N%.*B>", len, inp);
2246*10465441SEvalZero 					INCPTR(len, inp);
2247*10465441SEvalZero 					len = 0;
2248*10465441SEvalZero 				}
2249*10465441SEvalZero 				break;
2250*10465441SEvalZero 
2251*10465441SEvalZero 			case EAPSRP_SKEY:
2252*10465441SEvalZero 				printer(arg, " <B%.*B>", len, inp);
2253*10465441SEvalZero 				INCPTR(len, inp);
2254*10465441SEvalZero 				len = 0;
2255*10465441SEvalZero 				break;
2256*10465441SEvalZero 
2257*10465441SEvalZero 			case EAPSRP_SVALIDATOR:
2258*10465441SEvalZero 				if (len < (int)sizeof (u32_t))
2259*10465441SEvalZero 					break;
2260*10465441SEvalZero 				GETLONG(uval, inp);
2261*10465441SEvalZero 				len -= sizeof (u32_t);
2262*10465441SEvalZero 				if (uval & SRPVAL_EBIT) {
2263*10465441SEvalZero 					printer(arg, " E");
2264*10465441SEvalZero 					uval &= ~SRPVAL_EBIT;
2265*10465441SEvalZero 				}
2266*10465441SEvalZero 				if (uval != 0) {
2267*10465441SEvalZero 					printer(arg, " f<%X>", uval);
2268*10465441SEvalZero 				}
2269*10465441SEvalZero 				if ((vallen = len) > SHA_DIGESTSIZE)
2270*10465441SEvalZero 					vallen = SHA_DIGESTSIZE;
2271*10465441SEvalZero 				printer(arg, " <M2%.*B%s>", len, inp,
2272*10465441SEvalZero 				    len < SHA_DIGESTSIZE ? "?" : "");
2273*10465441SEvalZero 				INCPTR(vallen, inp);
2274*10465441SEvalZero 				len -= vallen;
2275*10465441SEvalZero 				if (len > 0) {
2276*10465441SEvalZero 					printer(arg, " <PN%.*B>", len, inp);
2277*10465441SEvalZero 					INCPTR(len, inp);
2278*10465441SEvalZero 					len = 0;
2279*10465441SEvalZero 				}
2280*10465441SEvalZero 				break;
2281*10465441SEvalZero 
2282*10465441SEvalZero 			case EAPSRP_LWRECHALLENGE:
2283*10465441SEvalZero 				printer(arg, " <Challenge%.*B>", len, inp);
2284*10465441SEvalZero 				INCPTR(len, inp);
2285*10465441SEvalZero 				len = 0;
2286*10465441SEvalZero 				break;
2287*10465441SEvalZero 			default:
2288*10465441SEvalZero 				break;
2289*10465441SEvalZero 			}
2290*10465441SEvalZero 			break;
2291*10465441SEvalZero 		default:
2292*10465441SEvalZero 			break;
2293*10465441SEvalZero 		}
2294*10465441SEvalZero 		break;
2295*10465441SEvalZero 
2296*10465441SEvalZero 	case EAP_RESPONSE:
2297*10465441SEvalZero 		if (len < 1)
2298*10465441SEvalZero 			break;
2299*10465441SEvalZero 		GETCHAR(rtype, inp);
2300*10465441SEvalZero 		len--;
2301*10465441SEvalZero 		if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames))
2302*10465441SEvalZero 			printer(arg, " %s", eap_typenames[rtype-1]);
2303*10465441SEvalZero 		else
2304*10465441SEvalZero 			printer(arg, " type=0x%x", rtype);
2305*10465441SEvalZero 		switch (rtype) {
2306*10465441SEvalZero 		case EAPT_IDENTITY:
2307*10465441SEvalZero 			if (len > 0) {
2308*10465441SEvalZero 				printer(arg, " <Name ");
2309*10465441SEvalZero 				ppp_print_string(inp, len, printer, arg);
2310*10465441SEvalZero 				printer(arg, ">");
2311*10465441SEvalZero 				INCPTR(len, inp);
2312*10465441SEvalZero 				len = 0;
2313*10465441SEvalZero 			}
2314*10465441SEvalZero 			break;
2315*10465441SEvalZero 
2316*10465441SEvalZero 		case EAPT_NAK:
2317*10465441SEvalZero 			if (len <= 0) {
2318*10465441SEvalZero 				printer(arg, " <missing hint>");
2319*10465441SEvalZero 				break;
2320*10465441SEvalZero 			}
2321*10465441SEvalZero 			GETCHAR(rtype, inp);
2322*10465441SEvalZero 			len--;
2323*10465441SEvalZero 			printer(arg, " <Suggested-type %02X", rtype);
2324*10465441SEvalZero 			if (rtype >= 1 && rtype < (int)LWIP_ARRAYSIZE(eap_typenames))
2325*10465441SEvalZero 				printer(arg, " (%s)", eap_typenames[rtype-1]);
2326*10465441SEvalZero 			printer(arg, ">");
2327*10465441SEvalZero 			break;
2328*10465441SEvalZero 
2329*10465441SEvalZero 		case EAPT_MD5CHAP:
2330*10465441SEvalZero 			if (len <= 0) {
2331*10465441SEvalZero 				printer(arg, " <missing length>");
2332*10465441SEvalZero 				break;
2333*10465441SEvalZero 			}
2334*10465441SEvalZero 			GETCHAR(vallen, inp);
2335*10465441SEvalZero 			len--;
2336*10465441SEvalZero 			if (vallen > len)
2337*10465441SEvalZero 				goto truncated;
2338*10465441SEvalZero 			printer(arg, " <Value%.*B>", vallen, inp);
2339*10465441SEvalZero 			INCPTR(vallen, inp);
2340*10465441SEvalZero 			len -= vallen;
2341*10465441SEvalZero 			if (len > 0) {
2342*10465441SEvalZero 				printer(arg, " <Name ");
2343*10465441SEvalZero 				ppp_print_string(inp, len, printer, arg);
2344*10465441SEvalZero 				printer(arg, ">");
2345*10465441SEvalZero 				INCPTR(len, inp);
2346*10465441SEvalZero 				len = 0;
2347*10465441SEvalZero 			} else {
2348*10465441SEvalZero 				printer(arg, " <No name>");
2349*10465441SEvalZero 			}
2350*10465441SEvalZero 			break;
2351*10465441SEvalZero 
2352*10465441SEvalZero 		case EAPT_SRP:
2353*10465441SEvalZero 			if (len < 1)
2354*10465441SEvalZero 				goto truncated;
2355*10465441SEvalZero 			GETCHAR(vallen, inp);
2356*10465441SEvalZero 			len--;
2357*10465441SEvalZero 			printer(arg, "-%d", vallen);
2358*10465441SEvalZero 			switch (vallen) {
2359*10465441SEvalZero 			case EAPSRP_CKEY:
2360*10465441SEvalZero 				printer(arg, " <A%.*B>", len, inp);
2361*10465441SEvalZero 				INCPTR(len, inp);
2362*10465441SEvalZero 				len = 0;
2363*10465441SEvalZero 				break;
2364*10465441SEvalZero 
2365*10465441SEvalZero 			case EAPSRP_CVALIDATOR:
2366*10465441SEvalZero 				if (len < (int)sizeof (u32_t))
2367*10465441SEvalZero 					break;
2368*10465441SEvalZero 				GETLONG(uval, inp);
2369*10465441SEvalZero 				len -= sizeof (u32_t);
2370*10465441SEvalZero 				if (uval & SRPVAL_EBIT) {
2371*10465441SEvalZero 					printer(arg, " E");
2372*10465441SEvalZero 					uval &= ~SRPVAL_EBIT;
2373*10465441SEvalZero 				}
2374*10465441SEvalZero 				if (uval != 0) {
2375*10465441SEvalZero 					printer(arg, " f<%X>", uval);
2376*10465441SEvalZero 				}
2377*10465441SEvalZero 				printer(arg, " <M1%.*B%s>", len, inp,
2378*10465441SEvalZero 				    len == SHA_DIGESTSIZE ? "" : "?");
2379*10465441SEvalZero 				INCPTR(len, inp);
2380*10465441SEvalZero 				len = 0;
2381*10465441SEvalZero 				break;
2382*10465441SEvalZero 
2383*10465441SEvalZero 			case EAPSRP_ACK:
2384*10465441SEvalZero 				break;
2385*10465441SEvalZero 
2386*10465441SEvalZero 			case EAPSRP_LWRECHALLENGE:
2387*10465441SEvalZero 				printer(arg, " <Response%.*B%s>", len, inp,
2388*10465441SEvalZero 				    len == SHA_DIGESTSIZE ? "" : "?");
2389*10465441SEvalZero 				if ((vallen = len) > SHA_DIGESTSIZE)
2390*10465441SEvalZero 					vallen = SHA_DIGESTSIZE;
2391*10465441SEvalZero 				INCPTR(vallen, inp);
2392*10465441SEvalZero 				len -= vallen;
2393*10465441SEvalZero 				break;
2394*10465441SEvalZero 			default:
2395*10465441SEvalZero 				break;
2396*10465441SEvalZero 			}
2397*10465441SEvalZero 			break;
2398*10465441SEvalZero 		default:
2399*10465441SEvalZero 			break;
2400*10465441SEvalZero 		}
2401*10465441SEvalZero 		break;
2402*10465441SEvalZero 
2403*10465441SEvalZero 	case EAP_SUCCESS:	/* No payload expected for these! */
2404*10465441SEvalZero 	case EAP_FAILURE:
2405*10465441SEvalZero 	default:
2406*10465441SEvalZero 		break;
2407*10465441SEvalZero 
2408*10465441SEvalZero 	truncated:
2409*10465441SEvalZero 		printer(arg, " <truncated>");
2410*10465441SEvalZero 		break;
2411*10465441SEvalZero 	}
2412*10465441SEvalZero 
2413*10465441SEvalZero 	if (len > 8)
2414*10465441SEvalZero 		printer(arg, "%8B...", inp);
2415*10465441SEvalZero 	else if (len > 0)
2416*10465441SEvalZero 		printer(arg, "%.*B", len, inp);
2417*10465441SEvalZero 	INCPTR(len, inp);
2418*10465441SEvalZero 
2419*10465441SEvalZero 	return (inp - pstart);
2420*10465441SEvalZero }
2421*10465441SEvalZero #endif /* PRINTPKT_SUPPORT */
2422*10465441SEvalZero 
2423*10465441SEvalZero #endif /* PPP_SUPPORT && EAP_SUPPORT */
2424