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