1195972f6Sopenharmony_ci/*
2195972f6Sopenharmony_ci * eap.c - Extensible Authentication Protocol for PPP (RFC 2284)
3195972f6Sopenharmony_ci *
4195972f6Sopenharmony_ci * Copyright (c) 2001 by Sun Microsystems, Inc.
5195972f6Sopenharmony_ci * All rights reserved.
6195972f6Sopenharmony_ci *
7195972f6Sopenharmony_ci * Non-exclusive rights to redistribute, modify, translate, and use
8195972f6Sopenharmony_ci * this software in source and binary forms, in whole or in part, is
9195972f6Sopenharmony_ci * hereby granted, provided that the above copyright notice is
10195972f6Sopenharmony_ci * duplicated in any source form, and that neither the name of the
11195972f6Sopenharmony_ci * copyright holder nor the author is used to endorse or promote
12195972f6Sopenharmony_ci * products derived from this software.
13195972f6Sopenharmony_ci *
14195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15195972f6Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16195972f6Sopenharmony_ci * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17195972f6Sopenharmony_ci *
18195972f6Sopenharmony_ci * Original version by James Carlson
19195972f6Sopenharmony_ci *
20195972f6Sopenharmony_ci * This implementation of EAP supports MD5-Challenge and SRP-SHA1
21195972f6Sopenharmony_ci * authentication styles.  Note that support of MD5-Challenge is a
22195972f6Sopenharmony_ci * requirement of RFC 2284, and that it's essentially just a
23195972f6Sopenharmony_ci * reimplementation of regular RFC 1994 CHAP using EAP messages.
24195972f6Sopenharmony_ci *
25195972f6Sopenharmony_ci * As an authenticator ("server"), there are multiple phases for each
26195972f6Sopenharmony_ci * style.  In the first phase of each style, the unauthenticated peer
27195972f6Sopenharmony_ci * name is queried using the EAP Identity request type.  If the
28195972f6Sopenharmony_ci * "remotename" option is used, then this phase is skipped, because
29195972f6Sopenharmony_ci * the peer's name is presumed to be known.
30195972f6Sopenharmony_ci *
31195972f6Sopenharmony_ci * For MD5-Challenge, there are two phases, and the second phase
32195972f6Sopenharmony_ci * consists of sending the challenge itself and handling the
33195972f6Sopenharmony_ci * associated response.
34195972f6Sopenharmony_ci *
35195972f6Sopenharmony_ci * For SRP-SHA1, there are four phases.  The second sends 's', 'N',
36195972f6Sopenharmony_ci * and 'g'.  The reply contains 'A'.  The third sends 'B', and the
37195972f6Sopenharmony_ci * reply contains 'M1'.  The forth sends the 'M2' value.
38195972f6Sopenharmony_ci *
39195972f6Sopenharmony_ci * As an authenticatee ("client"), there's just a single phase --
40195972f6Sopenharmony_ci * responding to the queries generated by the peer.  EAP is an
41195972f6Sopenharmony_ci * authenticator-driven protocol.
42195972f6Sopenharmony_ci *
43195972f6Sopenharmony_ci * Based on draft-ietf-pppext-eap-srp-03.txt.
44195972f6Sopenharmony_ci */
45195972f6Sopenharmony_ci
46195972f6Sopenharmony_ci#include "netif/ppp/ppp_opts.h"
47195972f6Sopenharmony_ci#if PPP_SUPPORT && EAP_SUPPORT  /* don't build if not configured for use in lwipopts.h */
48195972f6Sopenharmony_ci
49195972f6Sopenharmony_ci#include "netif/ppp/ppp_impl.h"
50195972f6Sopenharmony_ci#include "netif/ppp/eap.h"
51195972f6Sopenharmony_ci#include "netif/ppp/magic.h"
52195972f6Sopenharmony_ci#include "netif/ppp/pppcrypt.h"
53195972f6Sopenharmony_ci
54195972f6Sopenharmony_ci#ifdef USE_SRP
55195972f6Sopenharmony_ci#include <t_pwd.h>
56195972f6Sopenharmony_ci#include <t_server.h>
57195972f6Sopenharmony_ci#include <t_client.h>
58195972f6Sopenharmony_ci#endif /* USE_SRP */
59195972f6Sopenharmony_ci
60195972f6Sopenharmony_ci#ifndef SHA_DIGESTSIZE
61195972f6Sopenharmony_ci#define	SHA_DIGESTSIZE 20
62195972f6Sopenharmony_ci#endif
63195972f6Sopenharmony_ci
64195972f6Sopenharmony_ci#ifdef USE_SRP
65195972f6Sopenharmony_cistatic char *pn_secret = NULL;		/* Pseudonym generating secret */
66195972f6Sopenharmony_ci#endif
67195972f6Sopenharmony_ci
68195972f6Sopenharmony_ci#if PPP_OPTIONS
69195972f6Sopenharmony_ci/*
70195972f6Sopenharmony_ci * Command-line options.
71195972f6Sopenharmony_ci */
72195972f6Sopenharmony_cistatic option_t eap_option_list[] = {
73195972f6Sopenharmony_ci    { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout,
74195972f6Sopenharmony_ci      "Set retransmit timeout for EAP Requests (server)" },
75195972f6Sopenharmony_ci    { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests,
76195972f6Sopenharmony_ci      "Set max number of EAP Requests sent (server)" },
77195972f6Sopenharmony_ci    { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout,
78195972f6Sopenharmony_ci      "Set time limit for peer EAP authentication" },
79195972f6Sopenharmony_ci    { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests,
80195972f6Sopenharmony_ci      "Set max number of EAP Requests allows (client)" },
81195972f6Sopenharmony_ci    { "eap-interval", o_int, &eap_states[0].es_rechallenge,
82195972f6Sopenharmony_ci      "Set interval for EAP rechallenge" },
83195972f6Sopenharmony_ci#ifdef USE_SRP
84195972f6Sopenharmony_ci    { "srp-interval", o_int, &eap_states[0].es_lwrechallenge,
85195972f6Sopenharmony_ci      "Set interval for SRP lightweight rechallenge" },
86195972f6Sopenharmony_ci    { "srp-pn-secret", o_string, &pn_secret,
87195972f6Sopenharmony_ci      "Long term pseudonym generation secret" },
88195972f6Sopenharmony_ci    { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo,
89195972f6Sopenharmony_ci      "Use pseudonym if offered one by server", 1 },
90195972f6Sopenharmony_ci#endif
91195972f6Sopenharmony_ci    { NULL }
92195972f6Sopenharmony_ci};
93195972f6Sopenharmony_ci#endif /* PPP_OPTIONS */
94195972f6Sopenharmony_ci
95195972f6Sopenharmony_ci/*
96195972f6Sopenharmony_ci * Protocol entry points.
97195972f6Sopenharmony_ci */
98195972f6Sopenharmony_cistatic void eap_init(ppp_pcb *pcb);
99195972f6Sopenharmony_cistatic void eap_input(ppp_pcb *pcb, u_char *inp, int inlen);
100195972f6Sopenharmony_cistatic void eap_protrej(ppp_pcb *pcb);
101195972f6Sopenharmony_cistatic void eap_lowerup(ppp_pcb *pcb);
102195972f6Sopenharmony_cistatic void eap_lowerdown(ppp_pcb *pcb);
103195972f6Sopenharmony_ci#if PRINTPKT_SUPPORT
104195972f6Sopenharmony_cistatic int  eap_printpkt(const u_char *inp, int inlen,
105195972f6Sopenharmony_ci    void (*)(void *arg, const char *fmt, ...), void *arg);
106195972f6Sopenharmony_ci#endif /* PRINTPKT_SUPPORT */
107195972f6Sopenharmony_ci
108195972f6Sopenharmony_ciconst struct protent eap_protent = {
109195972f6Sopenharmony_ci	PPP_EAP,		/* protocol number */
110195972f6Sopenharmony_ci	eap_init,		/* initialization procedure */
111195972f6Sopenharmony_ci	eap_input,		/* process a received packet */
112195972f6Sopenharmony_ci	eap_protrej,		/* process a received protocol-reject */
113195972f6Sopenharmony_ci	eap_lowerup,		/* lower layer has gone up */
114195972f6Sopenharmony_ci	eap_lowerdown,		/* lower layer has gone down */
115195972f6Sopenharmony_ci	NULL,			/* open the protocol */
116195972f6Sopenharmony_ci	NULL,			/* close the protocol */
117195972f6Sopenharmony_ci#if PRINTPKT_SUPPORT
118195972f6Sopenharmony_ci	eap_printpkt,		/* print a packet in readable form */
119195972f6Sopenharmony_ci#endif /* PRINTPKT_SUPPORT */
120195972f6Sopenharmony_ci#if PPP_DATAINPUT
121195972f6Sopenharmony_ci	NULL,			/* process a received data packet */
122195972f6Sopenharmony_ci#endif /* PPP_DATAINPUT */
123195972f6Sopenharmony_ci#if PRINTPKT_SUPPORT
124195972f6Sopenharmony_ci	"EAP",			/* text name of protocol */
125195972f6Sopenharmony_ci	NULL,			/* text name of corresponding data protocol */
126195972f6Sopenharmony_ci#endif /* PRINTPKT_SUPPORT */
127195972f6Sopenharmony_ci#if PPP_OPTIONS
128195972f6Sopenharmony_ci	eap_option_list,	/* list of command-line options */
129195972f6Sopenharmony_ci	NULL,			/* check requested options; assign defaults */
130195972f6Sopenharmony_ci#endif /* PPP_OPTIONS */
131195972f6Sopenharmony_ci#if DEMAND_SUPPORT
132195972f6Sopenharmony_ci	NULL,			/* configure interface for demand-dial */
133195972f6Sopenharmony_ci	NULL			/* say whether to bring up link for this pkt */
134195972f6Sopenharmony_ci#endif /* DEMAND_SUPPORT */
135195972f6Sopenharmony_ci};
136195972f6Sopenharmony_ci
137195972f6Sopenharmony_ci#ifdef USE_SRP
138195972f6Sopenharmony_ci/*
139195972f6Sopenharmony_ci * A well-known 2048 bit modulus.
140195972f6Sopenharmony_ci */
141195972f6Sopenharmony_cistatic const u_char wkmodulus[] = {
142195972f6Sopenharmony_ci	0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B,
143195972f6Sopenharmony_ci	0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F,
144195972f6Sopenharmony_ci	0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07,
145195972f6Sopenharmony_ci	0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50,
146195972f6Sopenharmony_ci	0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED,
147195972f6Sopenharmony_ci	0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D,
148195972f6Sopenharmony_ci	0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D,
149195972f6Sopenharmony_ci	0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50,
150195972f6Sopenharmony_ci	0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0,
151195972f6Sopenharmony_ci	0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3,
152195972f6Sopenharmony_ci	0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8,
153195972f6Sopenharmony_ci	0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8,
154195972f6Sopenharmony_ci	0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA,
155195972f6Sopenharmony_ci	0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74,
156195972f6Sopenharmony_ci	0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7,
157195972f6Sopenharmony_ci	0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B,
158195972f6Sopenharmony_ci	0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16,
159195972f6Sopenharmony_ci	0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81,
160195972f6Sopenharmony_ci	0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A,
161195972f6Sopenharmony_ci	0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48,
162195972f6Sopenharmony_ci	0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D,
163195972f6Sopenharmony_ci	0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA,
164195972f6Sopenharmony_ci	0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78,
165195972f6Sopenharmony_ci	0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6,
166195972f6Sopenharmony_ci	0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29,
167195972f6Sopenharmony_ci	0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8,
168195972f6Sopenharmony_ci	0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82,
169195972f6Sopenharmony_ci	0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6,
170195972f6Sopenharmony_ci	0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4,
171195972f6Sopenharmony_ci	0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75,
172195972f6Sopenharmony_ci	0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2,
173195972f6Sopenharmony_ci	0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73
174195972f6Sopenharmony_ci};
175195972f6Sopenharmony_ci#endif
176195972f6Sopenharmony_ci
177195972f6Sopenharmony_ci#if PPP_SERVER
178195972f6Sopenharmony_ci/* Local forward declarations. */
179195972f6Sopenharmony_cistatic void eap_server_timeout(void *arg);
180195972f6Sopenharmony_ci#endif /* PPP_SERVER */
181195972f6Sopenharmony_ci
182195972f6Sopenharmony_ci/*
183195972f6Sopenharmony_ci * Convert EAP state code to printable string for debug.
184195972f6Sopenharmony_ci */
185195972f6Sopenharmony_cistatic const char * eap_state_name(enum eap_state_code esc)
186195972f6Sopenharmony_ci{
187195972f6Sopenharmony_ci	static const char *state_names[] = { EAP_STATES };
188195972f6Sopenharmony_ci
189195972f6Sopenharmony_ci	return (state_names[(int)esc]);
190195972f6Sopenharmony_ci}
191195972f6Sopenharmony_ci
192195972f6Sopenharmony_ci/*
193195972f6Sopenharmony_ci * eap_init - Initialize state for an EAP user.  This is currently
194195972f6Sopenharmony_ci * called once by main() during start-up.
195195972f6Sopenharmony_ci */
196195972f6Sopenharmony_cistatic void eap_init(ppp_pcb *pcb) {
197195972f6Sopenharmony_ci
198195972f6Sopenharmony_ci	BZERO(&pcb->eap, sizeof(eap_state));
199195972f6Sopenharmony_ci#if PPP_SERVER
200195972f6Sopenharmony_ci	pcb->eap.es_server.ea_id = magic();
201195972f6Sopenharmony_ci#endif /* PPP_SERVER */
202195972f6Sopenharmony_ci}
203195972f6Sopenharmony_ci
204195972f6Sopenharmony_ci/*
205195972f6Sopenharmony_ci * eap_client_timeout - Give up waiting for the peer to send any
206195972f6Sopenharmony_ci * Request messages.
207195972f6Sopenharmony_ci */
208195972f6Sopenharmony_cistatic void eap_client_timeout(void *arg) {
209195972f6Sopenharmony_ci	ppp_pcb *pcb = (ppp_pcb*)arg;
210195972f6Sopenharmony_ci
211195972f6Sopenharmony_ci	if (!eap_client_active(pcb))
212195972f6Sopenharmony_ci		return;
213195972f6Sopenharmony_ci
214195972f6Sopenharmony_ci	ppp_error("EAP: timeout waiting for Request from peer");
215195972f6Sopenharmony_ci	auth_withpeer_fail(pcb, PPP_EAP);
216195972f6Sopenharmony_ci	pcb->eap.es_client.ea_state = eapBadAuth;
217195972f6Sopenharmony_ci}
218195972f6Sopenharmony_ci
219195972f6Sopenharmony_ci/*
220195972f6Sopenharmony_ci * eap_authwithpeer - Authenticate to our peer (behave as client).
221195972f6Sopenharmony_ci *
222195972f6Sopenharmony_ci * Start client state and wait for requests.  This is called only
223195972f6Sopenharmony_ci * after eap_lowerup.
224195972f6Sopenharmony_ci */
225195972f6Sopenharmony_civoid eap_authwithpeer(ppp_pcb *pcb, const char *localname) {
226195972f6Sopenharmony_ci
227195972f6Sopenharmony_ci	if(NULL == localname)
228195972f6Sopenharmony_ci		return;
229195972f6Sopenharmony_ci
230195972f6Sopenharmony_ci	/* Save the peer name we're given */
231195972f6Sopenharmony_ci	pcb->eap.es_client.ea_name = localname;
232195972f6Sopenharmony_ci	pcb->eap.es_client.ea_namelen = strlen(localname);
233195972f6Sopenharmony_ci
234195972f6Sopenharmony_ci	pcb->eap.es_client.ea_state = eapListen;
235195972f6Sopenharmony_ci
236195972f6Sopenharmony_ci	/*
237195972f6Sopenharmony_ci	 * Start a timer so that if the other end just goes
238195972f6Sopenharmony_ci	 * silent, we don't sit here waiting forever.
239195972f6Sopenharmony_ci	 */
240195972f6Sopenharmony_ci	if (pcb->settings.eap_req_time > 0)
241195972f6Sopenharmony_ci		TIMEOUT(eap_client_timeout, pcb,
242195972f6Sopenharmony_ci		    pcb->settings.eap_req_time);
243195972f6Sopenharmony_ci}
244195972f6Sopenharmony_ci
245195972f6Sopenharmony_ci#if PPP_SERVER
246195972f6Sopenharmony_ci/*
247195972f6Sopenharmony_ci * Format a standard EAP Failure message and send it to the peer.
248195972f6Sopenharmony_ci * (Server operation)
249195972f6Sopenharmony_ci */
250195972f6Sopenharmony_cistatic void eap_send_failure(ppp_pcb *pcb) {
251195972f6Sopenharmony_ci	struct pbuf *p;
252195972f6Sopenharmony_ci	u_char *outp;
253195972f6Sopenharmony_ci
254195972f6Sopenharmony_ci	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE);
255195972f6Sopenharmony_ci	if(NULL == p)
256195972f6Sopenharmony_ci		return;
257195972f6Sopenharmony_ci	if(p->tot_len != p->len) {
258195972f6Sopenharmony_ci		pbuf_free(p);
259195972f6Sopenharmony_ci		return;
260195972f6Sopenharmony_ci	}
261195972f6Sopenharmony_ci
262195972f6Sopenharmony_ci	outp = (u_char*)p->payload;
263195972f6Sopenharmony_ci
264195972f6Sopenharmony_ci	MAKEHEADER(outp, PPP_EAP);
265195972f6Sopenharmony_ci
266195972f6Sopenharmony_ci	PUTCHAR(EAP_FAILURE, outp);
267195972f6Sopenharmony_ci	pcb->eap.es_server.ea_id++;
268195972f6Sopenharmony_ci	PUTCHAR(pcb->eap.es_server.ea_id, outp);
269195972f6Sopenharmony_ci	PUTSHORT(EAP_HEADERLEN, outp);
270195972f6Sopenharmony_ci
271195972f6Sopenharmony_ci	ppp_write(pcb, p);
272195972f6Sopenharmony_ci
273195972f6Sopenharmony_ci	pcb->eap.es_server.ea_state = eapBadAuth;
274195972f6Sopenharmony_ci	auth_peer_fail(pcb, PPP_EAP);
275195972f6Sopenharmony_ci}
276195972f6Sopenharmony_ci
277195972f6Sopenharmony_ci/*
278195972f6Sopenharmony_ci * Format a standard EAP Success message and send it to the peer.
279195972f6Sopenharmony_ci * (Server operation)
280195972f6Sopenharmony_ci */
281195972f6Sopenharmony_cistatic void eap_send_success(ppp_pcb *pcb) {
282195972f6Sopenharmony_ci	struct pbuf *p;
283195972f6Sopenharmony_ci	u_char *outp;
284195972f6Sopenharmony_ci
285195972f6Sopenharmony_ci	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE);
286195972f6Sopenharmony_ci	if(NULL == p)
287195972f6Sopenharmony_ci		return;
288195972f6Sopenharmony_ci	if(p->tot_len != p->len) {
289195972f6Sopenharmony_ci		pbuf_free(p);
290195972f6Sopenharmony_ci		return;
291195972f6Sopenharmony_ci	}
292195972f6Sopenharmony_ci
293195972f6Sopenharmony_ci	outp = (u_char*)p->payload;
294195972f6Sopenharmony_ci
295195972f6Sopenharmony_ci	MAKEHEADER(outp, PPP_EAP);
296195972f6Sopenharmony_ci
297195972f6Sopenharmony_ci	PUTCHAR(EAP_SUCCESS, outp);
298195972f6Sopenharmony_ci	pcb->eap.es_server.ea_id++;
299195972f6Sopenharmony_ci	PUTCHAR(pcb->eap.es_server.ea_id, outp);
300195972f6Sopenharmony_ci	PUTSHORT(EAP_HEADERLEN, outp);
301195972f6Sopenharmony_ci
302195972f6Sopenharmony_ci	ppp_write(pcb, p);
303195972f6Sopenharmony_ci
304195972f6Sopenharmony_ci	auth_peer_success(pcb, PPP_EAP, 0,
305195972f6Sopenharmony_ci	    pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen);
306195972f6Sopenharmony_ci}
307195972f6Sopenharmony_ci#endif /* PPP_SERVER */
308195972f6Sopenharmony_ci
309195972f6Sopenharmony_ci#ifdef USE_SRP
310195972f6Sopenharmony_ci/*
311195972f6Sopenharmony_ci * Set DES key according to pseudonym-generating secret and current
312195972f6Sopenharmony_ci * date.
313195972f6Sopenharmony_ci */
314195972f6Sopenharmony_cistatic bool
315195972f6Sopenharmony_cipncrypt_setkey(int timeoffs)
316195972f6Sopenharmony_ci{
317195972f6Sopenharmony_ci	struct tm *tp;
318195972f6Sopenharmony_ci	char tbuf[9];
319195972f6Sopenharmony_ci	SHA1_CTX ctxt;
320195972f6Sopenharmony_ci	u_char dig[SHA_DIGESTSIZE];
321195972f6Sopenharmony_ci	time_t reftime;
322195972f6Sopenharmony_ci
323195972f6Sopenharmony_ci	if (pn_secret == NULL)
324195972f6Sopenharmony_ci		return (0);
325195972f6Sopenharmony_ci	reftime = time(NULL) + timeoffs;
326195972f6Sopenharmony_ci	tp = localtime(&reftime);
327195972f6Sopenharmony_ci	SHA1Init(&ctxt);
328195972f6Sopenharmony_ci	SHA1Update(&ctxt, pn_secret, strlen(pn_secret));
329195972f6Sopenharmony_ci	strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp);
330195972f6Sopenharmony_ci	SHA1Update(&ctxt, tbuf, strlen(tbuf));
331195972f6Sopenharmony_ci	SHA1Final(dig, &ctxt);
332195972f6Sopenharmony_ci	/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
333195972f6Sopenharmony_ci	return (DesSetkey(dig));
334195972f6Sopenharmony_ci}
335195972f6Sopenharmony_ci
336195972f6Sopenharmony_cistatic char base64[] =
337195972f6Sopenharmony_ci"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
338195972f6Sopenharmony_ci
339195972f6Sopenharmony_cistruct b64state {
340195972f6Sopenharmony_ci	u32_t bs_bits;
341195972f6Sopenharmony_ci	int bs_offs;
342195972f6Sopenharmony_ci};
343195972f6Sopenharmony_ci
344195972f6Sopenharmony_cistatic int
345195972f6Sopenharmony_cib64enc(bs, inp, inlen, outp)
346195972f6Sopenharmony_cistruct b64state *bs;
347195972f6Sopenharmony_ciu_char *inp;
348195972f6Sopenharmony_ciint inlen;
349195972f6Sopenharmony_ciu_char *outp;
350195972f6Sopenharmony_ci{
351195972f6Sopenharmony_ci	int outlen = 0;
352195972f6Sopenharmony_ci
353195972f6Sopenharmony_ci	while (inlen > 0) {
354195972f6Sopenharmony_ci		bs->bs_bits = (bs->bs_bits << 8) | *inp++;
355195972f6Sopenharmony_ci		inlen--;
356195972f6Sopenharmony_ci		bs->bs_offs += 8;
357195972f6Sopenharmony_ci		if (bs->bs_offs >= 24) {
358195972f6Sopenharmony_ci			*outp++ = base64[(bs->bs_bits >> 18) & 0x3F];
359195972f6Sopenharmony_ci			*outp++ = base64[(bs->bs_bits >> 12) & 0x3F];
360195972f6Sopenharmony_ci			*outp++ = base64[(bs->bs_bits >> 6) & 0x3F];
361195972f6Sopenharmony_ci			*outp++ = base64[bs->bs_bits & 0x3F];
362195972f6Sopenharmony_ci			outlen += 4;
363195972f6Sopenharmony_ci			bs->bs_offs = 0;
364195972f6Sopenharmony_ci			bs->bs_bits = 0;
365195972f6Sopenharmony_ci		}
366195972f6Sopenharmony_ci	}
367195972f6Sopenharmony_ci	return (outlen);
368195972f6Sopenharmony_ci}
369195972f6Sopenharmony_ci
370195972f6Sopenharmony_cistatic int
371195972f6Sopenharmony_cib64flush(bs, outp)
372195972f6Sopenharmony_cistruct b64state *bs;
373195972f6Sopenharmony_ciu_char *outp;
374195972f6Sopenharmony_ci{
375195972f6Sopenharmony_ci	int outlen = 0;
376195972f6Sopenharmony_ci
377195972f6Sopenharmony_ci	if (bs->bs_offs == 8) {
378195972f6Sopenharmony_ci		*outp++ = base64[(bs->bs_bits >> 2) & 0x3F];
379195972f6Sopenharmony_ci		*outp++ = base64[(bs->bs_bits << 4) & 0x3F];
380195972f6Sopenharmony_ci		outlen = 2;
381195972f6Sopenharmony_ci	} else if (bs->bs_offs == 16) {
382195972f6Sopenharmony_ci		*outp++ = base64[(bs->bs_bits >> 10) & 0x3F];
383195972f6Sopenharmony_ci		*outp++ = base64[(bs->bs_bits >> 4) & 0x3F];
384195972f6Sopenharmony_ci		*outp++ = base64[(bs->bs_bits << 2) & 0x3F];
385195972f6Sopenharmony_ci		outlen = 3;
386195972f6Sopenharmony_ci	}
387195972f6Sopenharmony_ci	bs->bs_offs = 0;
388195972f6Sopenharmony_ci	bs->bs_bits = 0;
389195972f6Sopenharmony_ci	return (outlen);
390195972f6Sopenharmony_ci}
391195972f6Sopenharmony_ci
392195972f6Sopenharmony_cistatic int
393195972f6Sopenharmony_cib64dec(bs, inp, inlen, outp)
394195972f6Sopenharmony_cistruct b64state *bs;
395195972f6Sopenharmony_ciu_char *inp;
396195972f6Sopenharmony_ciint inlen;
397195972f6Sopenharmony_ciu_char *outp;
398195972f6Sopenharmony_ci{
399195972f6Sopenharmony_ci	int outlen = 0;
400195972f6Sopenharmony_ci	char *cp;
401195972f6Sopenharmony_ci
402195972f6Sopenharmony_ci	while (inlen > 0) {
403195972f6Sopenharmony_ci		if ((cp = strchr(base64, *inp++)) == NULL)
404195972f6Sopenharmony_ci			break;
405195972f6Sopenharmony_ci		bs->bs_bits = (bs->bs_bits << 6) | (cp - base64);
406195972f6Sopenharmony_ci		inlen--;
407195972f6Sopenharmony_ci		bs->bs_offs += 6;
408195972f6Sopenharmony_ci		if (bs->bs_offs >= 8) {
409195972f6Sopenharmony_ci			*outp++ = bs->bs_bits >> (bs->bs_offs - 8);
410195972f6Sopenharmony_ci			outlen++;
411195972f6Sopenharmony_ci			bs->bs_offs -= 8;
412195972f6Sopenharmony_ci		}
413195972f6Sopenharmony_ci	}
414195972f6Sopenharmony_ci	return (outlen);
415195972f6Sopenharmony_ci}
416195972f6Sopenharmony_ci#endif /* USE_SRP */
417195972f6Sopenharmony_ci
418195972f6Sopenharmony_ci#if PPP_SERVER
419195972f6Sopenharmony_ci/*
420195972f6Sopenharmony_ci * Assume that current waiting server state is complete and figure
421195972f6Sopenharmony_ci * next state to use based on available authentication data.  'status'
422195972f6Sopenharmony_ci * indicates if there was an error in handling the last query.  It is
423195972f6Sopenharmony_ci * 0 for success and non-zero for failure.
424195972f6Sopenharmony_ci */
425195972f6Sopenharmony_cistatic void eap_figure_next_state(ppp_pcb *pcb, int status) {
426195972f6Sopenharmony_ci#ifdef USE_SRP
427195972f6Sopenharmony_ci	unsigned char secbuf[MAXSECRETLEN], clear[8], *sp, *dp;
428195972f6Sopenharmony_ci	struct t_pw tpw;
429195972f6Sopenharmony_ci	struct t_confent *tce, mytce;
430195972f6Sopenharmony_ci	char *cp, *cp2;
431195972f6Sopenharmony_ci	struct t_server *ts;
432195972f6Sopenharmony_ci	int id, i, plen, toffs;
433195972f6Sopenharmony_ci	u_char vals[2];
434195972f6Sopenharmony_ci	struct b64state bs;
435195972f6Sopenharmony_ci#endif /* USE_SRP */
436195972f6Sopenharmony_ci
437195972f6Sopenharmony_ci	pcb->settings.eap_timeout_time = pcb->eap.es_savedtime;
438195972f6Sopenharmony_ci	switch (pcb->eap.es_server.ea_state) {
439195972f6Sopenharmony_ci	case eapBadAuth:
440195972f6Sopenharmony_ci		return;
441195972f6Sopenharmony_ci
442195972f6Sopenharmony_ci	case eapIdentify:
443195972f6Sopenharmony_ci#ifdef USE_SRP
444195972f6Sopenharmony_ci		/* Discard any previous session. */
445195972f6Sopenharmony_ci		ts = (struct t_server *)pcb->eap.es_server.ea_session;
446195972f6Sopenharmony_ci		if (ts != NULL) {
447195972f6Sopenharmony_ci			t_serverclose(ts);
448195972f6Sopenharmony_ci			pcb->eap.es_server.ea_session = NULL;
449195972f6Sopenharmony_ci			pcb->eap.es_server.ea_skey = NULL;
450195972f6Sopenharmony_ci		}
451195972f6Sopenharmony_ci#endif /* USE_SRP */
452195972f6Sopenharmony_ci		if (status != 0) {
453195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapBadAuth;
454195972f6Sopenharmony_ci			break;
455195972f6Sopenharmony_ci		}
456195972f6Sopenharmony_ci#ifdef USE_SRP
457195972f6Sopenharmony_ci		/* If we've got a pseudonym, try to decode to real name. */
458195972f6Sopenharmony_ci		if (pcb->eap.es_server.ea_peerlen > SRP_PSEUDO_LEN &&
459195972f6Sopenharmony_ci		    strncmp(pcb->eap.es_server.ea_peer, SRP_PSEUDO_ID,
460195972f6Sopenharmony_ci			SRP_PSEUDO_LEN) == 0 &&
461195972f6Sopenharmony_ci		    (pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 <
462195972f6Sopenharmony_ci		    sizeof (secbuf)) {
463195972f6Sopenharmony_ci			BZERO(&bs, sizeof (bs));
464195972f6Sopenharmony_ci			plen = b64dec(&bs,
465195972f6Sopenharmony_ci			    pcb->eap.es_server.ea_peer + SRP_PSEUDO_LEN,
466195972f6Sopenharmony_ci			    pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN,
467195972f6Sopenharmony_ci			    secbuf);
468195972f6Sopenharmony_ci			toffs = 0;
469195972f6Sopenharmony_ci			for (i = 0; i < 5; i++) {
470195972f6Sopenharmony_ci				pncrypt_setkey(toffs);
471195972f6Sopenharmony_ci				toffs -= 86400;
472195972f6Sopenharmony_ci				/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
473195972f6Sopenharmony_ci				if (!DesDecrypt(secbuf, clear)) {
474195972f6Sopenharmony_ci					ppp_dbglog("no DES here; cannot decode "
475195972f6Sopenharmony_ci					    "pseudonym");
476195972f6Sopenharmony_ci					return;
477195972f6Sopenharmony_ci				}
478195972f6Sopenharmony_ci				id = *(unsigned char *)clear;
479195972f6Sopenharmony_ci				if (id + 1 <= plen && id + 9 > plen)
480195972f6Sopenharmony_ci					break;
481195972f6Sopenharmony_ci			}
482195972f6Sopenharmony_ci			if (plen % 8 == 0 && i < 5) {
483195972f6Sopenharmony_ci				/*
484195972f6Sopenharmony_ci				 * Note that this is always shorter than the
485195972f6Sopenharmony_ci				 * original stored string, so there's no need
486195972f6Sopenharmony_ci				 * to realloc.
487195972f6Sopenharmony_ci				 */
488195972f6Sopenharmony_ci				if ((i = plen = *(unsigned char *)clear) > 7)
489195972f6Sopenharmony_ci					i = 7;
490195972f6Sopenharmony_ci				pcb->eap.es_server.ea_peerlen = plen;
491195972f6Sopenharmony_ci				dp = (unsigned char *)pcb->eap.es_server.ea_peer;
492195972f6Sopenharmony_ci				MEMCPY(dp, clear + 1, i);
493195972f6Sopenharmony_ci				plen -= i;
494195972f6Sopenharmony_ci				dp += i;
495195972f6Sopenharmony_ci				sp = secbuf + 8;
496195972f6Sopenharmony_ci				while (plen > 0) {
497195972f6Sopenharmony_ci					/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
498195972f6Sopenharmony_ci					(void) DesDecrypt(sp, dp);
499195972f6Sopenharmony_ci					sp += 8;
500195972f6Sopenharmony_ci					dp += 8;
501195972f6Sopenharmony_ci					plen -= 8;
502195972f6Sopenharmony_ci				}
503195972f6Sopenharmony_ci				pcb->eap.es_server.ea_peer[
504195972f6Sopenharmony_ci					pcb->eap.es_server.ea_peerlen] = '\0';
505195972f6Sopenharmony_ci				ppp_dbglog("decoded pseudonym to \"%.*q\"",
506195972f6Sopenharmony_ci				    pcb->eap.es_server.ea_peerlen,
507195972f6Sopenharmony_ci				    pcb->eap.es_server.ea_peer);
508195972f6Sopenharmony_ci			} else {
509195972f6Sopenharmony_ci				ppp_dbglog("failed to decode real name");
510195972f6Sopenharmony_ci				/* Stay in eapIdentfy state; requery */
511195972f6Sopenharmony_ci				break;
512195972f6Sopenharmony_ci			}
513195972f6Sopenharmony_ci		}
514195972f6Sopenharmony_ci		/* Look up user in secrets database. */
515195972f6Sopenharmony_ci		if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_server.ea_peer,
516195972f6Sopenharmony_ci		    pcb->eap.es_server.ea_name, (char *)secbuf, 1) != 0) {
517195972f6Sopenharmony_ci			/* Set up default in case SRP entry is bad */
518195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapMD5Chall;
519195972f6Sopenharmony_ci			/* Get t_confent based on index in srp-secrets */
520195972f6Sopenharmony_ci			id = strtol((char *)secbuf, &cp, 10);
521195972f6Sopenharmony_ci			if (*cp++ != ':' || id < 0)
522195972f6Sopenharmony_ci				break;
523195972f6Sopenharmony_ci			if (id == 0) {
524195972f6Sopenharmony_ci				mytce.index = 0;
525195972f6Sopenharmony_ci				mytce.modulus.data = (u_char *)wkmodulus;
526195972f6Sopenharmony_ci				mytce.modulus.len = sizeof (wkmodulus);
527195972f6Sopenharmony_ci				mytce.generator.data = (u_char *)"\002";
528195972f6Sopenharmony_ci				mytce.generator.len = 1;
529195972f6Sopenharmony_ci				tce = &mytce;
530195972f6Sopenharmony_ci			} else if ((tce = gettcid(id)) != NULL) {
531195972f6Sopenharmony_ci				/*
532195972f6Sopenharmony_ci				 * Client will have to verify this modulus/
533195972f6Sopenharmony_ci				 * generator combination, and that will take
534195972f6Sopenharmony_ci				 * a while.  Lengthen the timeout here.
535195972f6Sopenharmony_ci				 */
536195972f6Sopenharmony_ci				if (pcb->settings.eap_timeout_time > 0 &&
537195972f6Sopenharmony_ci				    pcb->settings.eap_timeout_time < 30)
538195972f6Sopenharmony_ci					pcb->settings.eap_timeout_time = 30;
539195972f6Sopenharmony_ci			} else {
540195972f6Sopenharmony_ci				break;
541195972f6Sopenharmony_ci			}
542195972f6Sopenharmony_ci			if ((cp2 = strchr(cp, ':')) == NULL)
543195972f6Sopenharmony_ci				break;
544195972f6Sopenharmony_ci			*cp2++ = '\0';
545195972f6Sopenharmony_ci			tpw.pebuf.name = pcb->eap.es_server.ea_peer;
546195972f6Sopenharmony_ci			tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf,
547195972f6Sopenharmony_ci			    cp);
548195972f6Sopenharmony_ci			tpw.pebuf.password.data = tpw.pwbuf;
549195972f6Sopenharmony_ci			tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf,
550195972f6Sopenharmony_ci			    cp2);
551195972f6Sopenharmony_ci			tpw.pebuf.salt.data = tpw.saltbuf;
552195972f6Sopenharmony_ci			if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL)
553195972f6Sopenharmony_ci				break;
554195972f6Sopenharmony_ci			pcb->eap.es_server.ea_session = (void *)ts;
555195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapSRP1;
556195972f6Sopenharmony_ci			vals[0] = pcb->eap.es_server.ea_id + 1;
557195972f6Sopenharmony_ci			vals[1] = EAPT_SRP;
558195972f6Sopenharmony_ci			t_serveraddexdata(ts, vals, 2);
559195972f6Sopenharmony_ci			/* Generate B; must call before t_servergetkey() */
560195972f6Sopenharmony_ci			t_servergenexp(ts);
561195972f6Sopenharmony_ci			break;
562195972f6Sopenharmony_ci		}
563195972f6Sopenharmony_ci#endif /* USE_SRP */
564195972f6Sopenharmony_ci		pcb->eap.es_server.ea_state = eapMD5Chall;
565195972f6Sopenharmony_ci		break;
566195972f6Sopenharmony_ci
567195972f6Sopenharmony_ci	case eapSRP1:
568195972f6Sopenharmony_ci#ifdef USE_SRP
569195972f6Sopenharmony_ci		ts = (struct t_server *)pcb->eap.es_server.ea_session;
570195972f6Sopenharmony_ci		if (ts != NULL && status != 0) {
571195972f6Sopenharmony_ci			t_serverclose(ts);
572195972f6Sopenharmony_ci			pcb->eap.es_server.ea_session = NULL;
573195972f6Sopenharmony_ci			pcb->eap.es_server.ea_skey = NULL;
574195972f6Sopenharmony_ci		}
575195972f6Sopenharmony_ci#endif /* USE_SRP */
576195972f6Sopenharmony_ci		if (status == 1) {
577195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapMD5Chall;
578195972f6Sopenharmony_ci		} else if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
579195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapBadAuth;
580195972f6Sopenharmony_ci		} else {
581195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapSRP2;
582195972f6Sopenharmony_ci		}
583195972f6Sopenharmony_ci		break;
584195972f6Sopenharmony_ci
585195972f6Sopenharmony_ci	case eapSRP2:
586195972f6Sopenharmony_ci#ifdef USE_SRP
587195972f6Sopenharmony_ci		ts = (struct t_server *)pcb->eap.es_server.ea_session;
588195972f6Sopenharmony_ci		if (ts != NULL && status != 0) {
589195972f6Sopenharmony_ci			t_serverclose(ts);
590195972f6Sopenharmony_ci			pcb->eap.es_server.ea_session = NULL;
591195972f6Sopenharmony_ci			pcb->eap.es_server.ea_skey = NULL;
592195972f6Sopenharmony_ci		}
593195972f6Sopenharmony_ci#endif /* USE_SRP */
594195972f6Sopenharmony_ci		if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
595195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapBadAuth;
596195972f6Sopenharmony_ci		} else {
597195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapSRP3;
598195972f6Sopenharmony_ci		}
599195972f6Sopenharmony_ci		break;
600195972f6Sopenharmony_ci
601195972f6Sopenharmony_ci	case eapSRP3:
602195972f6Sopenharmony_ci	case eapSRP4:
603195972f6Sopenharmony_ci#ifdef USE_SRP
604195972f6Sopenharmony_ci		ts = (struct t_server *)pcb->eap.es_server.ea_session;
605195972f6Sopenharmony_ci		if (ts != NULL && status != 0) {
606195972f6Sopenharmony_ci			t_serverclose(ts);
607195972f6Sopenharmony_ci			pcb->eap.es_server.ea_session = NULL;
608195972f6Sopenharmony_ci			pcb->eap.es_server.ea_skey = NULL;
609195972f6Sopenharmony_ci		}
610195972f6Sopenharmony_ci#endif /* USE_SRP */
611195972f6Sopenharmony_ci		if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
612195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapBadAuth;
613195972f6Sopenharmony_ci		} else {
614195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapOpen;
615195972f6Sopenharmony_ci		}
616195972f6Sopenharmony_ci		break;
617195972f6Sopenharmony_ci
618195972f6Sopenharmony_ci	case eapMD5Chall:
619195972f6Sopenharmony_ci		if (status != 0) {
620195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapBadAuth;
621195972f6Sopenharmony_ci		} else {
622195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapOpen;
623195972f6Sopenharmony_ci		}
624195972f6Sopenharmony_ci		break;
625195972f6Sopenharmony_ci
626195972f6Sopenharmony_ci	default:
627195972f6Sopenharmony_ci		pcb->eap.es_server.ea_state = eapBadAuth;
628195972f6Sopenharmony_ci		break;
629195972f6Sopenharmony_ci	}
630195972f6Sopenharmony_ci	if (pcb->eap.es_server.ea_state == eapBadAuth)
631195972f6Sopenharmony_ci		eap_send_failure(pcb);
632195972f6Sopenharmony_ci}
633195972f6Sopenharmony_ci
634195972f6Sopenharmony_ci/*
635195972f6Sopenharmony_ci * Format an EAP Request message and send it to the peer.  Message
636195972f6Sopenharmony_ci * type depends on current state.  (Server operation)
637195972f6Sopenharmony_ci */
638195972f6Sopenharmony_cistatic void eap_send_request(ppp_pcb *pcb) {
639195972f6Sopenharmony_ci	struct pbuf *p;
640195972f6Sopenharmony_ci	u_char *outp;
641195972f6Sopenharmony_ci	u_char *lenloc;
642195972f6Sopenharmony_ci	int outlen;
643195972f6Sopenharmony_ci	int len;
644195972f6Sopenharmony_ci	const char *str;
645195972f6Sopenharmony_ci#ifdef USE_SRP
646195972f6Sopenharmony_ci	struct t_server *ts;
647195972f6Sopenharmony_ci	u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp;
648195972f6Sopenharmony_ci	int i, j;
649195972f6Sopenharmony_ci	struct b64state b64;
650195972f6Sopenharmony_ci	SHA1_CTX ctxt;
651195972f6Sopenharmony_ci#endif /* USE_SRP */
652195972f6Sopenharmony_ci
653195972f6Sopenharmony_ci	/* Handle both initial auth and restart */
654195972f6Sopenharmony_ci	if (pcb->eap.es_server.ea_state < eapIdentify &&
655195972f6Sopenharmony_ci	    pcb->eap.es_server.ea_state != eapInitial) {
656195972f6Sopenharmony_ci		pcb->eap.es_server.ea_state = eapIdentify;
657195972f6Sopenharmony_ci#if PPP_REMOTENAME
658195972f6Sopenharmony_ci		if (pcb->settings.explicit_remote && pcb->remote_name) {
659195972f6Sopenharmony_ci			/*
660195972f6Sopenharmony_ci			 * If we already know the peer's
661195972f6Sopenharmony_ci			 * unauthenticated name, then there's no
662195972f6Sopenharmony_ci			 * reason to ask.  Go to next state instead.
663195972f6Sopenharmony_ci			 */
664195972f6Sopenharmony_ci			int len = (int)strlen(pcb->remote_name);
665195972f6Sopenharmony_ci			if (len > MAXNAMELEN) {
666195972f6Sopenharmony_ci				len = MAXNAMELEN;
667195972f6Sopenharmony_ci			}
668195972f6Sopenharmony_ci			MEMCPY(pcb->eap.es_server.ea_peer, pcb->remote_name, len);
669195972f6Sopenharmony_ci			pcb->eap.es_server.ea_peer[len] = '\0';
670195972f6Sopenharmony_ci			pcb->eap.es_server.ea_peerlen = len;
671195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 0);
672195972f6Sopenharmony_ci		}
673195972f6Sopenharmony_ci#endif /* PPP_REMOTENAME */
674195972f6Sopenharmony_ci	}
675195972f6Sopenharmony_ci
676195972f6Sopenharmony_ci	if (pcb->settings.eap_max_transmits > 0 &&
677195972f6Sopenharmony_ci	    pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) {
678195972f6Sopenharmony_ci		if (pcb->eap.es_server.ea_responses > 0)
679195972f6Sopenharmony_ci			ppp_error("EAP: too many Requests sent");
680195972f6Sopenharmony_ci		else
681195972f6Sopenharmony_ci			ppp_error("EAP: no response to Requests");
682195972f6Sopenharmony_ci		eap_send_failure(pcb);
683195972f6Sopenharmony_ci		return;
684195972f6Sopenharmony_ci	}
685195972f6Sopenharmony_ci
686195972f6Sopenharmony_ci	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE);
687195972f6Sopenharmony_ci	if(NULL == p)
688195972f6Sopenharmony_ci		return;
689195972f6Sopenharmony_ci	if(p->tot_len != p->len) {
690195972f6Sopenharmony_ci		pbuf_free(p);
691195972f6Sopenharmony_ci		return;
692195972f6Sopenharmony_ci	}
693195972f6Sopenharmony_ci
694195972f6Sopenharmony_ci	outp = (u_char*)p->payload;
695195972f6Sopenharmony_ci
696195972f6Sopenharmony_ci	MAKEHEADER(outp, PPP_EAP);
697195972f6Sopenharmony_ci
698195972f6Sopenharmony_ci	PUTCHAR(EAP_REQUEST, outp);
699195972f6Sopenharmony_ci	PUTCHAR(pcb->eap.es_server.ea_id, outp);
700195972f6Sopenharmony_ci	lenloc = outp;
701195972f6Sopenharmony_ci	INCPTR(2, outp);
702195972f6Sopenharmony_ci
703195972f6Sopenharmony_ci	switch (pcb->eap.es_server.ea_state) {
704195972f6Sopenharmony_ci	case eapIdentify:
705195972f6Sopenharmony_ci		PUTCHAR(EAPT_IDENTITY, outp);
706195972f6Sopenharmony_ci		str = "Name";
707195972f6Sopenharmony_ci		len = strlen(str);
708195972f6Sopenharmony_ci		MEMCPY(outp, str, len);
709195972f6Sopenharmony_ci		INCPTR(len, outp);
710195972f6Sopenharmony_ci		break;
711195972f6Sopenharmony_ci
712195972f6Sopenharmony_ci	case eapMD5Chall:
713195972f6Sopenharmony_ci		PUTCHAR(EAPT_MD5CHAP, outp);
714195972f6Sopenharmony_ci		/*
715195972f6Sopenharmony_ci		 * pick a random challenge length between
716195972f6Sopenharmony_ci		 * EAP_MIN_CHALLENGE_LENGTH and EAP_MAX_CHALLENGE_LENGTH
717195972f6Sopenharmony_ci		 */
718195972f6Sopenharmony_ci		pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH +
719195972f6Sopenharmony_ci		    magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH);
720195972f6Sopenharmony_ci		PUTCHAR(pcb->eap.es_challen, outp);
721195972f6Sopenharmony_ci		magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen);
722195972f6Sopenharmony_ci		MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen);
723195972f6Sopenharmony_ci		INCPTR(pcb->eap.es_challen, outp);
724195972f6Sopenharmony_ci		MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen);
725195972f6Sopenharmony_ci		INCPTR(pcb->eap.es_server.ea_namelen, outp);
726195972f6Sopenharmony_ci		break;
727195972f6Sopenharmony_ci
728195972f6Sopenharmony_ci#ifdef USE_SRP
729195972f6Sopenharmony_ci	case eapSRP1:
730195972f6Sopenharmony_ci		PUTCHAR(EAPT_SRP, outp);
731195972f6Sopenharmony_ci		PUTCHAR(EAPSRP_CHALLENGE, outp);
732195972f6Sopenharmony_ci
733195972f6Sopenharmony_ci		PUTCHAR(pcb->eap.es_server.ea_namelen, outp);
734195972f6Sopenharmony_ci		MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen);
735195972f6Sopenharmony_ci		INCPTR(pcb->eap.es_server.ea_namelen, outp);
736195972f6Sopenharmony_ci
737195972f6Sopenharmony_ci		ts = (struct t_server *)pcb->eap.es_server.ea_session;
738195972f6Sopenharmony_ci		assert(ts != NULL);
739195972f6Sopenharmony_ci		PUTCHAR(ts->s.len, outp);
740195972f6Sopenharmony_ci		MEMCPY(outp, ts->s.data, ts->s.len);
741195972f6Sopenharmony_ci		INCPTR(ts->s.len, outp);
742195972f6Sopenharmony_ci
743195972f6Sopenharmony_ci		if (ts->g.len == 1 && ts->g.data[0] == 2) {
744195972f6Sopenharmony_ci			PUTCHAR(0, outp);
745195972f6Sopenharmony_ci		} else {
746195972f6Sopenharmony_ci			PUTCHAR(ts->g.len, outp);
747195972f6Sopenharmony_ci			MEMCPY(outp, ts->g.data, ts->g.len);
748195972f6Sopenharmony_ci			INCPTR(ts->g.len, outp);
749195972f6Sopenharmony_ci		}
750195972f6Sopenharmony_ci
751195972f6Sopenharmony_ci		if (ts->n.len != sizeof (wkmodulus) ||
752195972f6Sopenharmony_ci		    BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) {
753195972f6Sopenharmony_ci			MEMCPY(outp, ts->n.data, ts->n.len);
754195972f6Sopenharmony_ci			INCPTR(ts->n.len, outp);
755195972f6Sopenharmony_ci		}
756195972f6Sopenharmony_ci		break;
757195972f6Sopenharmony_ci
758195972f6Sopenharmony_ci	case eapSRP2:
759195972f6Sopenharmony_ci		PUTCHAR(EAPT_SRP, outp);
760195972f6Sopenharmony_ci		PUTCHAR(EAPSRP_SKEY, outp);
761195972f6Sopenharmony_ci
762195972f6Sopenharmony_ci		ts = (struct t_server *)pcb->eap.es_server.ea_session;
763195972f6Sopenharmony_ci		assert(ts != NULL);
764195972f6Sopenharmony_ci		MEMCPY(outp, ts->B.data, ts->B.len);
765195972f6Sopenharmony_ci		INCPTR(ts->B.len, outp);
766195972f6Sopenharmony_ci		break;
767195972f6Sopenharmony_ci
768195972f6Sopenharmony_ci	case eapSRP3:
769195972f6Sopenharmony_ci		PUTCHAR(EAPT_SRP, outp);
770195972f6Sopenharmony_ci		PUTCHAR(EAPSRP_SVALIDATOR, outp);
771195972f6Sopenharmony_ci		PUTLONG(SRPVAL_EBIT, outp);
772195972f6Sopenharmony_ci		ts = (struct t_server *)pcb->eap.es_server.ea_session;
773195972f6Sopenharmony_ci		assert(ts != NULL);
774195972f6Sopenharmony_ci		MEMCPY(outp, t_serverresponse(ts), SHA_DIGESTSIZE);
775195972f6Sopenharmony_ci		INCPTR(SHA_DIGESTSIZE, outp);
776195972f6Sopenharmony_ci
777195972f6Sopenharmony_ci		if (pncrypt_setkey(0)) {
778195972f6Sopenharmony_ci			/* Generate pseudonym */
779195972f6Sopenharmony_ci			optr = outp;
780195972f6Sopenharmony_ci			cp = (unsigned char *)pcb->eap.es_server.ea_peer;
781195972f6Sopenharmony_ci			if ((j = i = pcb->eap.es_server.ea_peerlen) > 7)
782195972f6Sopenharmony_ci				j = 7;
783195972f6Sopenharmony_ci			clear[0] = i;
784195972f6Sopenharmony_ci			MEMCPY(clear + 1, cp, j);
785195972f6Sopenharmony_ci			i -= j;
786195972f6Sopenharmony_ci			cp += j;
787195972f6Sopenharmony_ci			/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
788195972f6Sopenharmony_ci			if (!DesEncrypt(clear, cipher)) {
789195972f6Sopenharmony_ci				ppp_dbglog("no DES here; not generating pseudonym");
790195972f6Sopenharmony_ci				break;
791195972f6Sopenharmony_ci			}
792195972f6Sopenharmony_ci			BZERO(&b64, sizeof (b64));
793195972f6Sopenharmony_ci			outp++;		/* space for pseudonym length */
794195972f6Sopenharmony_ci			outp += b64enc(&b64, cipher, 8, outp);
795195972f6Sopenharmony_ci			while (i >= 8) {
796195972f6Sopenharmony_ci				/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
797195972f6Sopenharmony_ci				(void) DesEncrypt(cp, cipher);
798195972f6Sopenharmony_ci				outp += b64enc(&b64, cipher, 8, outp);
799195972f6Sopenharmony_ci				cp += 8;
800195972f6Sopenharmony_ci				i -= 8;
801195972f6Sopenharmony_ci			}
802195972f6Sopenharmony_ci			if (i > 0) {
803195972f6Sopenharmony_ci				MEMCPY(clear, cp, i);
804195972f6Sopenharmony_ci				cp += i;
805195972f6Sopenharmony_ci				magic_random_bytes(cp, 8-i);
806195972f6Sopenharmony_ci				/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
807195972f6Sopenharmony_ci				(void) DesEncrypt(clear, cipher);
808195972f6Sopenharmony_ci				outp += b64enc(&b64, cipher, 8, outp);
809195972f6Sopenharmony_ci			}
810195972f6Sopenharmony_ci			outp += b64flush(&b64, outp);
811195972f6Sopenharmony_ci
812195972f6Sopenharmony_ci			/* Set length and pad out to next 20 octet boundary */
813195972f6Sopenharmony_ci			i = outp - optr - 1;
814195972f6Sopenharmony_ci			*optr = i;
815195972f6Sopenharmony_ci			i %= SHA_DIGESTSIZE;
816195972f6Sopenharmony_ci			if (i != 0) {
817195972f6Sopenharmony_ci				magic_random_bytes(outp, SHA_DIGESTSIZE-i);
818195972f6Sopenharmony_ci				INCPTR(SHA_DIGESTSIZE-i, outp);
819195972f6Sopenharmony_ci			}
820195972f6Sopenharmony_ci
821195972f6Sopenharmony_ci			/* Obscure the pseudonym with SHA1 hash */
822195972f6Sopenharmony_ci			SHA1Init(&ctxt);
823195972f6Sopenharmony_ci			SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1);
824195972f6Sopenharmony_ci			SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
825195972f6Sopenharmony_ci			    SESSION_KEY_LEN);
826195972f6Sopenharmony_ci			SHA1Update(&ctxt, pcb->eap.es_server.ea_peer,
827195972f6Sopenharmony_ci			    pcb->eap.es_server.ea_peerlen);
828195972f6Sopenharmony_ci			while (optr < outp) {
829195972f6Sopenharmony_ci				SHA1Final(dig, &ctxt);
830195972f6Sopenharmony_ci				cp = dig;
831195972f6Sopenharmony_ci				while (cp < dig + SHA_DIGESTSIZE)
832195972f6Sopenharmony_ci					*optr++ ^= *cp++;
833195972f6Sopenharmony_ci				SHA1Init(&ctxt);
834195972f6Sopenharmony_ci				SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1);
835195972f6Sopenharmony_ci				SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
836195972f6Sopenharmony_ci				    SESSION_KEY_LEN);
837195972f6Sopenharmony_ci				SHA1Update(&ctxt, optr - SHA_DIGESTSIZE,
838195972f6Sopenharmony_ci				    SHA_DIGESTSIZE);
839195972f6Sopenharmony_ci			}
840195972f6Sopenharmony_ci		}
841195972f6Sopenharmony_ci		break;
842195972f6Sopenharmony_ci
843195972f6Sopenharmony_ci	case eapSRP4:
844195972f6Sopenharmony_ci		PUTCHAR(EAPT_SRP, outp);
845195972f6Sopenharmony_ci		PUTCHAR(EAPSRP_LWRECHALLENGE, outp);
846195972f6Sopenharmony_ci		pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH +
847195972f6Sopenharmony_ci		    magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH);
848195972f6Sopenharmony_ci		magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen);
849195972f6Sopenharmony_ci		MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen);
850195972f6Sopenharmony_ci		INCPTR(pcb->eap.es_challen, outp);
851195972f6Sopenharmony_ci		break;
852195972f6Sopenharmony_ci#endif /* USE_SRP */
853195972f6Sopenharmony_ci
854195972f6Sopenharmony_ci	default:
855195972f6Sopenharmony_ci		return;
856195972f6Sopenharmony_ci	}
857195972f6Sopenharmony_ci
858195972f6Sopenharmony_ci	outlen = (outp - (unsigned char*)p->payload) - PPP_HDRLEN;
859195972f6Sopenharmony_ci	PUTSHORT(outlen, lenloc);
860195972f6Sopenharmony_ci
861195972f6Sopenharmony_ci	pbuf_realloc(p, outlen + PPP_HDRLEN);
862195972f6Sopenharmony_ci	ppp_write(pcb, p);
863195972f6Sopenharmony_ci
864195972f6Sopenharmony_ci	pcb->eap.es_server.ea_requests++;
865195972f6Sopenharmony_ci
866195972f6Sopenharmony_ci	if (pcb->settings.eap_timeout_time > 0)
867195972f6Sopenharmony_ci		TIMEOUT(eap_server_timeout, pcb, pcb->settings.eap_timeout_time);
868195972f6Sopenharmony_ci}
869195972f6Sopenharmony_ci
870195972f6Sopenharmony_ci/*
871195972f6Sopenharmony_ci * eap_authpeer - Authenticate our peer (behave as server).
872195972f6Sopenharmony_ci *
873195972f6Sopenharmony_ci * Start server state and send first request.  This is called only
874195972f6Sopenharmony_ci * after eap_lowerup.
875195972f6Sopenharmony_ci */
876195972f6Sopenharmony_civoid eap_authpeer(ppp_pcb *pcb, const char *localname) {
877195972f6Sopenharmony_ci
878195972f6Sopenharmony_ci	/* Save the name we're given. */
879195972f6Sopenharmony_ci	pcb->eap.es_server.ea_name = localname;
880195972f6Sopenharmony_ci	pcb->eap.es_server.ea_namelen = strlen(localname);
881195972f6Sopenharmony_ci
882195972f6Sopenharmony_ci	pcb->eap.es_savedtime = pcb->settings.eap_timeout_time;
883195972f6Sopenharmony_ci
884195972f6Sopenharmony_ci	/* Lower layer up yet? */
885195972f6Sopenharmony_ci	if (pcb->eap.es_server.ea_state == eapInitial ||
886195972f6Sopenharmony_ci	    pcb->eap.es_server.ea_state == eapPending) {
887195972f6Sopenharmony_ci		pcb->eap.es_server.ea_state = eapPending;
888195972f6Sopenharmony_ci		return;
889195972f6Sopenharmony_ci	}
890195972f6Sopenharmony_ci
891195972f6Sopenharmony_ci	pcb->eap.es_server.ea_state = eapPending;
892195972f6Sopenharmony_ci
893195972f6Sopenharmony_ci	/* ID number not updated here intentionally; hashed into M1 */
894195972f6Sopenharmony_ci	eap_send_request(pcb);
895195972f6Sopenharmony_ci}
896195972f6Sopenharmony_ci
897195972f6Sopenharmony_ci/*
898195972f6Sopenharmony_ci * eap_server_timeout - Retransmission timer for sending Requests
899195972f6Sopenharmony_ci * expired.
900195972f6Sopenharmony_ci */
901195972f6Sopenharmony_cistatic void eap_server_timeout(void *arg) {
902195972f6Sopenharmony_ci	ppp_pcb *pcb = (ppp_pcb*)arg;
903195972f6Sopenharmony_ci
904195972f6Sopenharmony_ci	if (!eap_server_active(pcb))
905195972f6Sopenharmony_ci		return;
906195972f6Sopenharmony_ci
907195972f6Sopenharmony_ci	/* EAP ID number must not change on timeout. */
908195972f6Sopenharmony_ci	eap_send_request(pcb);
909195972f6Sopenharmony_ci}
910195972f6Sopenharmony_ci
911195972f6Sopenharmony_ci/*
912195972f6Sopenharmony_ci * When it's time to send rechallenge the peer, this timeout is
913195972f6Sopenharmony_ci * called.  Once the rechallenge is successful, the response handler
914195972f6Sopenharmony_ci * will restart the timer.  If it fails, then the link is dropped.
915195972f6Sopenharmony_ci */
916195972f6Sopenharmony_cistatic void eap_rechallenge(void *arg) {
917195972f6Sopenharmony_ci	ppp_pcb *pcb = (ppp_pcb*)arg;
918195972f6Sopenharmony_ci
919195972f6Sopenharmony_ci	if (pcb->eap.es_server.ea_state != eapOpen &&
920195972f6Sopenharmony_ci	    pcb->eap.es_server.ea_state != eapSRP4)
921195972f6Sopenharmony_ci		return;
922195972f6Sopenharmony_ci
923195972f6Sopenharmony_ci	pcb->eap.es_server.ea_requests = 0;
924195972f6Sopenharmony_ci	pcb->eap.es_server.ea_state = eapIdentify;
925195972f6Sopenharmony_ci	eap_figure_next_state(pcb, 0);
926195972f6Sopenharmony_ci	pcb->eap.es_server.ea_id++;
927195972f6Sopenharmony_ci	eap_send_request(pcb);
928195972f6Sopenharmony_ci}
929195972f6Sopenharmony_ci
930195972f6Sopenharmony_cistatic void srp_lwrechallenge(void *arg) {
931195972f6Sopenharmony_ci	ppp_pcb *pcb = (ppp_pcb*)arg;
932195972f6Sopenharmony_ci
933195972f6Sopenharmony_ci	if (pcb->eap.es_server.ea_state != eapOpen ||
934195972f6Sopenharmony_ci	    pcb->eap.es_server.ea_type != EAPT_SRP)
935195972f6Sopenharmony_ci		return;
936195972f6Sopenharmony_ci
937195972f6Sopenharmony_ci	pcb->eap.es_server.ea_requests = 0;
938195972f6Sopenharmony_ci	pcb->eap.es_server.ea_state = eapSRP4;
939195972f6Sopenharmony_ci	pcb->eap.es_server.ea_id++;
940195972f6Sopenharmony_ci	eap_send_request(pcb);
941195972f6Sopenharmony_ci}
942195972f6Sopenharmony_ci#endif /* PPP_SERVER */
943195972f6Sopenharmony_ci
944195972f6Sopenharmony_ci/*
945195972f6Sopenharmony_ci * eap_lowerup - The lower layer is now up.
946195972f6Sopenharmony_ci *
947195972f6Sopenharmony_ci * This is called before either eap_authpeer or eap_authwithpeer.  See
948195972f6Sopenharmony_ci * link_established() in auth.c.  All that's necessary here is to
949195972f6Sopenharmony_ci * return to closed state so that those two routines will do the right
950195972f6Sopenharmony_ci * thing.
951195972f6Sopenharmony_ci */
952195972f6Sopenharmony_cistatic void eap_lowerup(ppp_pcb *pcb) {
953195972f6Sopenharmony_ci	pcb->eap.es_client.ea_state = eapClosed;
954195972f6Sopenharmony_ci#if PPP_SERVER
955195972f6Sopenharmony_ci	pcb->eap.es_server.ea_state = eapClosed;
956195972f6Sopenharmony_ci#endif /* PPP_SERVER */
957195972f6Sopenharmony_ci}
958195972f6Sopenharmony_ci
959195972f6Sopenharmony_ci/*
960195972f6Sopenharmony_ci * eap_lowerdown - The lower layer is now down.
961195972f6Sopenharmony_ci *
962195972f6Sopenharmony_ci * Cancel all timeouts and return to initial state.
963195972f6Sopenharmony_ci */
964195972f6Sopenharmony_cistatic void eap_lowerdown(ppp_pcb *pcb) {
965195972f6Sopenharmony_ci
966195972f6Sopenharmony_ci	if (eap_client_active(pcb) && pcb->settings.eap_req_time > 0) {
967195972f6Sopenharmony_ci		UNTIMEOUT(eap_client_timeout, pcb);
968195972f6Sopenharmony_ci	}
969195972f6Sopenharmony_ci#if PPP_SERVER
970195972f6Sopenharmony_ci	if (eap_server_active(pcb)) {
971195972f6Sopenharmony_ci		if (pcb->settings.eap_timeout_time > 0) {
972195972f6Sopenharmony_ci			UNTIMEOUT(eap_server_timeout, pcb);
973195972f6Sopenharmony_ci		}
974195972f6Sopenharmony_ci	} else {
975195972f6Sopenharmony_ci		if ((pcb->eap.es_server.ea_state == eapOpen ||
976195972f6Sopenharmony_ci		    pcb->eap.es_server.ea_state == eapSRP4) &&
977195972f6Sopenharmony_ci		    pcb->eap.es_rechallenge > 0) {
978195972f6Sopenharmony_ci			UNTIMEOUT(eap_rechallenge, (void *)pcb);
979195972f6Sopenharmony_ci		}
980195972f6Sopenharmony_ci		if (pcb->eap.es_server.ea_state == eapOpen &&
981195972f6Sopenharmony_ci		    pcb->eap.es_lwrechallenge > 0) {
982195972f6Sopenharmony_ci			UNTIMEOUT(srp_lwrechallenge, (void *)pcb);
983195972f6Sopenharmony_ci		}
984195972f6Sopenharmony_ci	}
985195972f6Sopenharmony_ci
986195972f6Sopenharmony_ci	pcb->eap.es_client.ea_state = pcb->eap.es_server.ea_state = eapInitial;
987195972f6Sopenharmony_ci	pcb->eap.es_client.ea_requests = pcb->eap.es_server.ea_requests = 0;
988195972f6Sopenharmony_ci#endif /* PPP_SERVER */
989195972f6Sopenharmony_ci}
990195972f6Sopenharmony_ci
991195972f6Sopenharmony_ci/*
992195972f6Sopenharmony_ci * eap_protrej - Peer doesn't speak this protocol.
993195972f6Sopenharmony_ci *
994195972f6Sopenharmony_ci * This shouldn't happen.  If it does, it represents authentication
995195972f6Sopenharmony_ci * failure.
996195972f6Sopenharmony_ci */
997195972f6Sopenharmony_cistatic void eap_protrej(ppp_pcb *pcb) {
998195972f6Sopenharmony_ci
999195972f6Sopenharmony_ci	if (eap_client_active(pcb)) {
1000195972f6Sopenharmony_ci		ppp_error("EAP authentication failed due to Protocol-Reject");
1001195972f6Sopenharmony_ci		auth_withpeer_fail(pcb, PPP_EAP);
1002195972f6Sopenharmony_ci	}
1003195972f6Sopenharmony_ci#if PPP_SERVER
1004195972f6Sopenharmony_ci	if (eap_server_active(pcb)) {
1005195972f6Sopenharmony_ci		ppp_error("EAP authentication of peer failed on Protocol-Reject");
1006195972f6Sopenharmony_ci		auth_peer_fail(pcb, PPP_EAP);
1007195972f6Sopenharmony_ci	}
1008195972f6Sopenharmony_ci#endif /* PPP_SERVER */
1009195972f6Sopenharmony_ci	eap_lowerdown(pcb);
1010195972f6Sopenharmony_ci}
1011195972f6Sopenharmony_ci
1012195972f6Sopenharmony_ci/*
1013195972f6Sopenharmony_ci * Format and send a regular EAP Response message.
1014195972f6Sopenharmony_ci */
1015195972f6Sopenharmony_cistatic void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, const u_char *str, int lenstr) {
1016195972f6Sopenharmony_ci	struct pbuf *p;
1017195972f6Sopenharmony_ci	u_char *outp;
1018195972f6Sopenharmony_ci	int msglen;
1019195972f6Sopenharmony_ci
1020195972f6Sopenharmony_ci	msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr;
1021195972f6Sopenharmony_ci	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1022195972f6Sopenharmony_ci	if(NULL == p)
1023195972f6Sopenharmony_ci		return;
1024195972f6Sopenharmony_ci	if(p->tot_len != p->len) {
1025195972f6Sopenharmony_ci		pbuf_free(p);
1026195972f6Sopenharmony_ci		return;
1027195972f6Sopenharmony_ci	}
1028195972f6Sopenharmony_ci
1029195972f6Sopenharmony_ci	outp = (u_char*)p->payload;
1030195972f6Sopenharmony_ci
1031195972f6Sopenharmony_ci	MAKEHEADER(outp, PPP_EAP);
1032195972f6Sopenharmony_ci
1033195972f6Sopenharmony_ci	PUTCHAR(EAP_RESPONSE, outp);
1034195972f6Sopenharmony_ci	PUTCHAR(id, outp);
1035195972f6Sopenharmony_ci	pcb->eap.es_client.ea_id = id;
1036195972f6Sopenharmony_ci	PUTSHORT(msglen, outp);
1037195972f6Sopenharmony_ci	PUTCHAR(typenum, outp);
1038195972f6Sopenharmony_ci	if (lenstr > 0) {
1039195972f6Sopenharmony_ci		MEMCPY(outp, str, lenstr);
1040195972f6Sopenharmony_ci	}
1041195972f6Sopenharmony_ci
1042195972f6Sopenharmony_ci	ppp_write(pcb, p);
1043195972f6Sopenharmony_ci}
1044195972f6Sopenharmony_ci
1045195972f6Sopenharmony_ci/*
1046195972f6Sopenharmony_ci * Format and send an MD5-Challenge EAP Response message.
1047195972f6Sopenharmony_ci */
1048195972f6Sopenharmony_cistatic void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, const char *name, int namelen) {
1049195972f6Sopenharmony_ci	struct pbuf *p;
1050195972f6Sopenharmony_ci	u_char *outp;
1051195972f6Sopenharmony_ci	int msglen;
1052195972f6Sopenharmony_ci
1053195972f6Sopenharmony_ci	msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE +
1054195972f6Sopenharmony_ci	    namelen;
1055195972f6Sopenharmony_ci	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1056195972f6Sopenharmony_ci	if(NULL == p)
1057195972f6Sopenharmony_ci		return;
1058195972f6Sopenharmony_ci	if(p->tot_len != p->len) {
1059195972f6Sopenharmony_ci		pbuf_free(p);
1060195972f6Sopenharmony_ci		return;
1061195972f6Sopenharmony_ci	}
1062195972f6Sopenharmony_ci
1063195972f6Sopenharmony_ci	outp = (u_char*)p->payload;
1064195972f6Sopenharmony_ci
1065195972f6Sopenharmony_ci	MAKEHEADER(outp, PPP_EAP);
1066195972f6Sopenharmony_ci
1067195972f6Sopenharmony_ci	PUTCHAR(EAP_RESPONSE, outp);
1068195972f6Sopenharmony_ci	PUTCHAR(id, outp);
1069195972f6Sopenharmony_ci	pcb->eap.es_client.ea_id = id;
1070195972f6Sopenharmony_ci	PUTSHORT(msglen, outp);
1071195972f6Sopenharmony_ci	PUTCHAR(EAPT_MD5CHAP, outp);
1072195972f6Sopenharmony_ci	PUTCHAR(MD5_SIGNATURE_SIZE, outp);
1073195972f6Sopenharmony_ci	MEMCPY(outp, hash, MD5_SIGNATURE_SIZE);
1074195972f6Sopenharmony_ci	INCPTR(MD5_SIGNATURE_SIZE, outp);
1075195972f6Sopenharmony_ci	if (namelen > 0) {
1076195972f6Sopenharmony_ci		MEMCPY(outp, name, namelen);
1077195972f6Sopenharmony_ci	}
1078195972f6Sopenharmony_ci
1079195972f6Sopenharmony_ci	ppp_write(pcb, p);
1080195972f6Sopenharmony_ci}
1081195972f6Sopenharmony_ci
1082195972f6Sopenharmony_ci#ifdef USE_SRP
1083195972f6Sopenharmony_ci/*
1084195972f6Sopenharmony_ci * Format and send a SRP EAP Response message.
1085195972f6Sopenharmony_ci */
1086195972f6Sopenharmony_cistatic void
1087195972f6Sopenharmony_cieap_srp_response(esp, id, subtypenum, str, lenstr)
1088195972f6Sopenharmony_cieap_state *esp;
1089195972f6Sopenharmony_ciu_char id;
1090195972f6Sopenharmony_ciu_char subtypenum;
1091195972f6Sopenharmony_ciu_char *str;
1092195972f6Sopenharmony_ciint lenstr;
1093195972f6Sopenharmony_ci{
1094195972f6Sopenharmony_ci	ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit];
1095195972f6Sopenharmony_ci	struct pbuf *p;
1096195972f6Sopenharmony_ci	u_char *outp;
1097195972f6Sopenharmony_ci	int msglen;
1098195972f6Sopenharmony_ci
1099195972f6Sopenharmony_ci	msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr;
1100195972f6Sopenharmony_ci	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1101195972f6Sopenharmony_ci	if(NULL == p)
1102195972f6Sopenharmony_ci		return;
1103195972f6Sopenharmony_ci	if(p->tot_len != p->len) {
1104195972f6Sopenharmony_ci		pbuf_free(p);
1105195972f6Sopenharmony_ci		return;
1106195972f6Sopenharmony_ci	}
1107195972f6Sopenharmony_ci
1108195972f6Sopenharmony_ci	outp = p->payload;
1109195972f6Sopenharmony_ci
1110195972f6Sopenharmony_ci	MAKEHEADER(outp, PPP_EAP);
1111195972f6Sopenharmony_ci
1112195972f6Sopenharmony_ci	PUTCHAR(EAP_RESPONSE, outp);
1113195972f6Sopenharmony_ci	PUTCHAR(id, outp);
1114195972f6Sopenharmony_ci	pcb->eap.es_client.ea_id = id;
1115195972f6Sopenharmony_ci	PUTSHORT(msglen, outp);
1116195972f6Sopenharmony_ci	PUTCHAR(EAPT_SRP, outp);
1117195972f6Sopenharmony_ci	PUTCHAR(subtypenum, outp);
1118195972f6Sopenharmony_ci	if (lenstr > 0) {
1119195972f6Sopenharmony_ci		MEMCPY(outp, str, lenstr);
1120195972f6Sopenharmony_ci	}
1121195972f6Sopenharmony_ci
1122195972f6Sopenharmony_ci	ppp_write(pcb, p);
1123195972f6Sopenharmony_ci}
1124195972f6Sopenharmony_ci
1125195972f6Sopenharmony_ci/*
1126195972f6Sopenharmony_ci * Format and send a SRP EAP Client Validator Response message.
1127195972f6Sopenharmony_ci */
1128195972f6Sopenharmony_cistatic void
1129195972f6Sopenharmony_cieap_srpval_response(esp, id, flags, str)
1130195972f6Sopenharmony_cieap_state *esp;
1131195972f6Sopenharmony_ciu_char id;
1132195972f6Sopenharmony_ciu32_t flags;
1133195972f6Sopenharmony_ciu_char *str;
1134195972f6Sopenharmony_ci{
1135195972f6Sopenharmony_ci	ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit];
1136195972f6Sopenharmony_ci	struct pbuf *p;
1137195972f6Sopenharmony_ci	u_char *outp;
1138195972f6Sopenharmony_ci	int msglen;
1139195972f6Sopenharmony_ci
1140195972f6Sopenharmony_ci	msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) +
1141195972f6Sopenharmony_ci	    SHA_DIGESTSIZE;
1142195972f6Sopenharmony_ci	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1143195972f6Sopenharmony_ci	if(NULL == p)
1144195972f6Sopenharmony_ci		return;
1145195972f6Sopenharmony_ci	if(p->tot_len != p->len) {
1146195972f6Sopenharmony_ci		pbuf_free(p);
1147195972f6Sopenharmony_ci		return;
1148195972f6Sopenharmony_ci	}
1149195972f6Sopenharmony_ci
1150195972f6Sopenharmony_ci	outp = p->payload;
1151195972f6Sopenharmony_ci
1152195972f6Sopenharmony_ci	MAKEHEADER(outp, PPP_EAP);
1153195972f6Sopenharmony_ci
1154195972f6Sopenharmony_ci	PUTCHAR(EAP_RESPONSE, outp);
1155195972f6Sopenharmony_ci	PUTCHAR(id, outp);
1156195972f6Sopenharmony_ci	pcb->eap.es_client.ea_id = id;
1157195972f6Sopenharmony_ci	PUTSHORT(msglen, outp);
1158195972f6Sopenharmony_ci	PUTCHAR(EAPT_SRP, outp);
1159195972f6Sopenharmony_ci	PUTCHAR(EAPSRP_CVALIDATOR, outp);
1160195972f6Sopenharmony_ci	PUTLONG(flags, outp);
1161195972f6Sopenharmony_ci	MEMCPY(outp, str, SHA_DIGESTSIZE);
1162195972f6Sopenharmony_ci
1163195972f6Sopenharmony_ci	ppp_write(pcb, p);
1164195972f6Sopenharmony_ci}
1165195972f6Sopenharmony_ci#endif /* USE_SRP */
1166195972f6Sopenharmony_ci
1167195972f6Sopenharmony_cistatic void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) {
1168195972f6Sopenharmony_ci	struct pbuf *p;
1169195972f6Sopenharmony_ci	u_char *outp;
1170195972f6Sopenharmony_ci	int msglen;
1171195972f6Sopenharmony_ci
1172195972f6Sopenharmony_ci	msglen = EAP_HEADERLEN + 2 * sizeof (u_char);
1173195972f6Sopenharmony_ci	p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
1174195972f6Sopenharmony_ci	if(NULL == p)
1175195972f6Sopenharmony_ci		return;
1176195972f6Sopenharmony_ci	if(p->tot_len != p->len) {
1177195972f6Sopenharmony_ci		pbuf_free(p);
1178195972f6Sopenharmony_ci		return;
1179195972f6Sopenharmony_ci	}
1180195972f6Sopenharmony_ci
1181195972f6Sopenharmony_ci	outp = (u_char*)p->payload;
1182195972f6Sopenharmony_ci
1183195972f6Sopenharmony_ci	MAKEHEADER(outp, PPP_EAP);
1184195972f6Sopenharmony_ci
1185195972f6Sopenharmony_ci	PUTCHAR(EAP_RESPONSE, outp);
1186195972f6Sopenharmony_ci	PUTCHAR(id, outp);
1187195972f6Sopenharmony_ci	pcb->eap.es_client.ea_id = id;
1188195972f6Sopenharmony_ci	PUTSHORT(msglen, outp);
1189195972f6Sopenharmony_ci	PUTCHAR(EAPT_NAK, outp);
1190195972f6Sopenharmony_ci	PUTCHAR(type, outp);
1191195972f6Sopenharmony_ci
1192195972f6Sopenharmony_ci	ppp_write(pcb, p);
1193195972f6Sopenharmony_ci}
1194195972f6Sopenharmony_ci
1195195972f6Sopenharmony_ci#ifdef USE_SRP
1196195972f6Sopenharmony_cistatic char *
1197195972f6Sopenharmony_ciname_of_pn_file()
1198195972f6Sopenharmony_ci{
1199195972f6Sopenharmony_ci	char *user, *path, *file;
1200195972f6Sopenharmony_ci	struct passwd *pw;
1201195972f6Sopenharmony_ci	size_t pl;
1202195972f6Sopenharmony_ci	static bool pnlogged = 0;
1203195972f6Sopenharmony_ci
1204195972f6Sopenharmony_ci	pw = getpwuid(getuid());
1205195972f6Sopenharmony_ci	if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) {
1206195972f6Sopenharmony_ci		errno = EINVAL;
1207195972f6Sopenharmony_ci		return (NULL);
1208195972f6Sopenharmony_ci	}
1209195972f6Sopenharmony_ci	file = _PATH_PSEUDONYM;
1210195972f6Sopenharmony_ci	pl = strlen(user) + strlen(file) + 2;
1211195972f6Sopenharmony_ci	path = malloc(pl);
1212195972f6Sopenharmony_ci	if (path == NULL)
1213195972f6Sopenharmony_ci		return (NULL);
1214195972f6Sopenharmony_ci	(void) slprintf(path, pl, "%s/%s", user, file);
1215195972f6Sopenharmony_ci	if (!pnlogged) {
1216195972f6Sopenharmony_ci		ppp_dbglog("pseudonym file: %s", path);
1217195972f6Sopenharmony_ci		pnlogged = 1;
1218195972f6Sopenharmony_ci	}
1219195972f6Sopenharmony_ci	return (path);
1220195972f6Sopenharmony_ci}
1221195972f6Sopenharmony_ci
1222195972f6Sopenharmony_cistatic int
1223195972f6Sopenharmony_ciopen_pn_file(modebits)
1224195972f6Sopenharmony_cimode_t modebits;
1225195972f6Sopenharmony_ci{
1226195972f6Sopenharmony_ci	char *path;
1227195972f6Sopenharmony_ci	int fd, err;
1228195972f6Sopenharmony_ci
1229195972f6Sopenharmony_ci	if ((path = name_of_pn_file()) == NULL)
1230195972f6Sopenharmony_ci		return (-1);
1231195972f6Sopenharmony_ci	fd = open(path, modebits, S_IRUSR | S_IWUSR);
1232195972f6Sopenharmony_ci	err = errno;
1233195972f6Sopenharmony_ci	free(path);
1234195972f6Sopenharmony_ci	errno = err;
1235195972f6Sopenharmony_ci	return (fd);
1236195972f6Sopenharmony_ci}
1237195972f6Sopenharmony_ci
1238195972f6Sopenharmony_cistatic void
1239195972f6Sopenharmony_ciremove_pn_file()
1240195972f6Sopenharmony_ci{
1241195972f6Sopenharmony_ci	char *path;
1242195972f6Sopenharmony_ci
1243195972f6Sopenharmony_ci	if ((path = name_of_pn_file()) != NULL) {
1244195972f6Sopenharmony_ci		(void) unlink(path);
1245195972f6Sopenharmony_ci		(void) free(path);
1246195972f6Sopenharmony_ci	}
1247195972f6Sopenharmony_ci}
1248195972f6Sopenharmony_ci
1249195972f6Sopenharmony_cistatic void
1250195972f6Sopenharmony_ciwrite_pseudonym(esp, inp, len, id)
1251195972f6Sopenharmony_cieap_state *esp;
1252195972f6Sopenharmony_ciu_char *inp;
1253195972f6Sopenharmony_ciint len, id;
1254195972f6Sopenharmony_ci{
1255195972f6Sopenharmony_ci	u_char val;
1256195972f6Sopenharmony_ci	u_char *datp, *digp;
1257195972f6Sopenharmony_ci	SHA1_CTX ctxt;
1258195972f6Sopenharmony_ci	u_char dig[SHA_DIGESTSIZE];
1259195972f6Sopenharmony_ci	int dsize, fd, olen = len;
1260195972f6Sopenharmony_ci
1261195972f6Sopenharmony_ci	/*
1262195972f6Sopenharmony_ci	 * Do the decoding by working backwards.  This eliminates the need
1263195972f6Sopenharmony_ci	 * to save the decoded output in a separate buffer.
1264195972f6Sopenharmony_ci	 */
1265195972f6Sopenharmony_ci	val = id;
1266195972f6Sopenharmony_ci	while (len > 0) {
1267195972f6Sopenharmony_ci		if ((dsize = len % SHA_DIGESTSIZE) == 0)
1268195972f6Sopenharmony_ci			dsize = SHA_DIGESTSIZE;
1269195972f6Sopenharmony_ci		len -= dsize;
1270195972f6Sopenharmony_ci		datp = inp + len;
1271195972f6Sopenharmony_ci		SHA1Init(&ctxt);
1272195972f6Sopenharmony_ci		SHA1Update(&ctxt, &val, 1);
1273195972f6Sopenharmony_ci		SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, SESSION_KEY_LEN);
1274195972f6Sopenharmony_ci		if (len > 0) {
1275195972f6Sopenharmony_ci			SHA1Update(&ctxt, datp, SHA_DIGESTSIZE);
1276195972f6Sopenharmony_ci		} else {
1277195972f6Sopenharmony_ci			SHA1Update(&ctxt, pcb->eap.es_client.ea_name,
1278195972f6Sopenharmony_ci			    pcb->eap.es_client.ea_namelen);
1279195972f6Sopenharmony_ci		}
1280195972f6Sopenharmony_ci		SHA1Final(dig, &ctxt);
1281195972f6Sopenharmony_ci		for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++)
1282195972f6Sopenharmony_ci			*datp++ ^= *digp;
1283195972f6Sopenharmony_ci	}
1284195972f6Sopenharmony_ci
1285195972f6Sopenharmony_ci	/* Now check that the result is sane */
1286195972f6Sopenharmony_ci	if (olen <= 0 || *inp + 1 > olen) {
1287195972f6Sopenharmony_ci		ppp_dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp);
1288195972f6Sopenharmony_ci		return;
1289195972f6Sopenharmony_ci	}
1290195972f6Sopenharmony_ci
1291195972f6Sopenharmony_ci	/* Save it away */
1292195972f6Sopenharmony_ci	fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC);
1293195972f6Sopenharmony_ci	if (fd < 0) {
1294195972f6Sopenharmony_ci		ppp_dbglog("EAP: error saving pseudonym: %m");
1295195972f6Sopenharmony_ci		return;
1296195972f6Sopenharmony_ci	}
1297195972f6Sopenharmony_ci	len = write(fd, inp + 1, *inp);
1298195972f6Sopenharmony_ci	if (close(fd) != -1 && len == *inp) {
1299195972f6Sopenharmony_ci		ppp_dbglog("EAP: saved pseudonym");
1300195972f6Sopenharmony_ci		pcb->eap.es_usedpseudo = 0;
1301195972f6Sopenharmony_ci	} else {
1302195972f6Sopenharmony_ci		ppp_dbglog("EAP: failed to save pseudonym");
1303195972f6Sopenharmony_ci		remove_pn_file();
1304195972f6Sopenharmony_ci	}
1305195972f6Sopenharmony_ci}
1306195972f6Sopenharmony_ci#endif /* USE_SRP */
1307195972f6Sopenharmony_ci
1308195972f6Sopenharmony_ci/*
1309195972f6Sopenharmony_ci * eap_request - Receive EAP Request message (client mode).
1310195972f6Sopenharmony_ci */
1311195972f6Sopenharmony_cistatic void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) {
1312195972f6Sopenharmony_ci	u_char typenum;
1313195972f6Sopenharmony_ci	u_char vallen;
1314195972f6Sopenharmony_ci	int secret_len;
1315195972f6Sopenharmony_ci	char secret[MAXSECRETLEN];
1316195972f6Sopenharmony_ci	char rhostname[MAXNAMELEN];
1317195972f6Sopenharmony_ci	lwip_md5_context mdContext;
1318195972f6Sopenharmony_ci	u_char hash[MD5_SIGNATURE_SIZE];
1319195972f6Sopenharmony_ci#ifdef USE_SRP
1320195972f6Sopenharmony_ci	struct t_client *tc;
1321195972f6Sopenharmony_ci	struct t_num sval, gval, Nval, *Ap, Bval;
1322195972f6Sopenharmony_ci	u_char vals[2];
1323195972f6Sopenharmony_ci	SHA1_CTX ctxt;
1324195972f6Sopenharmony_ci	u_char dig[SHA_DIGESTSIZE];
1325195972f6Sopenharmony_ci	int fd;
1326195972f6Sopenharmony_ci#endif /* USE_SRP */
1327195972f6Sopenharmony_ci
1328195972f6Sopenharmony_ci	/*
1329195972f6Sopenharmony_ci	 * Note: we update es_client.ea_id *only if* a Response
1330195972f6Sopenharmony_ci	 * message is being generated.  Otherwise, we leave it the
1331195972f6Sopenharmony_ci	 * same for duplicate detection purposes.
1332195972f6Sopenharmony_ci	 */
1333195972f6Sopenharmony_ci
1334195972f6Sopenharmony_ci	pcb->eap.es_client.ea_requests++;
1335195972f6Sopenharmony_ci	if (pcb->settings.eap_allow_req != 0 &&
1336195972f6Sopenharmony_ci	    pcb->eap.es_client.ea_requests > pcb->settings.eap_allow_req) {
1337195972f6Sopenharmony_ci		ppp_info("EAP: received too many Request messages");
1338195972f6Sopenharmony_ci		if (pcb->settings.eap_req_time > 0) {
1339195972f6Sopenharmony_ci			UNTIMEOUT(eap_client_timeout, pcb);
1340195972f6Sopenharmony_ci		}
1341195972f6Sopenharmony_ci		auth_withpeer_fail(pcb, PPP_EAP);
1342195972f6Sopenharmony_ci		return;
1343195972f6Sopenharmony_ci	}
1344195972f6Sopenharmony_ci
1345195972f6Sopenharmony_ci	if (len <= 0) {
1346195972f6Sopenharmony_ci		ppp_error("EAP: empty Request message discarded");
1347195972f6Sopenharmony_ci		return;
1348195972f6Sopenharmony_ci	}
1349195972f6Sopenharmony_ci
1350195972f6Sopenharmony_ci	GETCHAR(typenum, inp);
1351195972f6Sopenharmony_ci	len--;
1352195972f6Sopenharmony_ci
1353195972f6Sopenharmony_ci	switch (typenum) {
1354195972f6Sopenharmony_ci	case EAPT_IDENTITY:
1355195972f6Sopenharmony_ci		if (len > 0)
1356195972f6Sopenharmony_ci			ppp_info("EAP: Identity prompt \"%.*q\"", len, inp);
1357195972f6Sopenharmony_ci#ifdef USE_SRP
1358195972f6Sopenharmony_ci		if (pcb->eap.es_usepseudo &&
1359195972f6Sopenharmony_ci		    (pcb->eap.es_usedpseudo == 0 ||
1360195972f6Sopenharmony_ci			(pcb->eap.es_usedpseudo == 1 &&
1361195972f6Sopenharmony_ci			    id == pcb->eap.es_client.ea_id))) {
1362195972f6Sopenharmony_ci			pcb->eap.es_usedpseudo = 1;
1363195972f6Sopenharmony_ci			/* Try to get a pseudonym */
1364195972f6Sopenharmony_ci			if ((fd = open_pn_file(O_RDONLY)) >= 0) {
1365195972f6Sopenharmony_ci				strcpy(rhostname, SRP_PSEUDO_ID);
1366195972f6Sopenharmony_ci				len = read(fd, rhostname + SRP_PSEUDO_LEN,
1367195972f6Sopenharmony_ci				    sizeof (rhostname) - SRP_PSEUDO_LEN);
1368195972f6Sopenharmony_ci				/* XXX NAI unsupported */
1369195972f6Sopenharmony_ci				if (len > 0) {
1370195972f6Sopenharmony_ci					eap_send_response(pcb, id, typenum,
1371195972f6Sopenharmony_ci					    rhostname, len + SRP_PSEUDO_LEN);
1372195972f6Sopenharmony_ci				}
1373195972f6Sopenharmony_ci				(void) close(fd);
1374195972f6Sopenharmony_ci				if (len > 0)
1375195972f6Sopenharmony_ci					break;
1376195972f6Sopenharmony_ci			}
1377195972f6Sopenharmony_ci		}
1378195972f6Sopenharmony_ci		/* Stop using pseudonym now. */
1379195972f6Sopenharmony_ci		if (pcb->eap.es_usepseudo && pcb->eap.es_usedpseudo != 2) {
1380195972f6Sopenharmony_ci			remove_pn_file();
1381195972f6Sopenharmony_ci			pcb->eap.es_usedpseudo = 2;
1382195972f6Sopenharmony_ci		}
1383195972f6Sopenharmony_ci#endif /* USE_SRP */
1384195972f6Sopenharmony_ci		eap_send_response(pcb, id, typenum, (const u_char*)pcb->eap.es_client.ea_name,
1385195972f6Sopenharmony_ci		    pcb->eap.es_client.ea_namelen);
1386195972f6Sopenharmony_ci		break;
1387195972f6Sopenharmony_ci
1388195972f6Sopenharmony_ci	case EAPT_NOTIFICATION:
1389195972f6Sopenharmony_ci		if (len > 0)
1390195972f6Sopenharmony_ci			ppp_info("EAP: Notification \"%.*q\"", len, inp);
1391195972f6Sopenharmony_ci		eap_send_response(pcb, id, typenum, NULL, 0);
1392195972f6Sopenharmony_ci		break;
1393195972f6Sopenharmony_ci
1394195972f6Sopenharmony_ci	case EAPT_NAK:
1395195972f6Sopenharmony_ci		/*
1396195972f6Sopenharmony_ci		 * Avoid the temptation to send Response Nak in reply
1397195972f6Sopenharmony_ci		 * to Request Nak here.  It can only lead to trouble.
1398195972f6Sopenharmony_ci		 */
1399195972f6Sopenharmony_ci		ppp_warn("EAP: unexpected Nak in Request; ignored");
1400195972f6Sopenharmony_ci		/* Return because we're waiting for something real. */
1401195972f6Sopenharmony_ci		return;
1402195972f6Sopenharmony_ci
1403195972f6Sopenharmony_ci	case EAPT_MD5CHAP:
1404195972f6Sopenharmony_ci		if (len < 1) {
1405195972f6Sopenharmony_ci			ppp_error("EAP: received MD5-Challenge with no data");
1406195972f6Sopenharmony_ci			/* Bogus request; wait for something real. */
1407195972f6Sopenharmony_ci			return;
1408195972f6Sopenharmony_ci		}
1409195972f6Sopenharmony_ci		GETCHAR(vallen, inp);
1410195972f6Sopenharmony_ci		len--;
1411195972f6Sopenharmony_ci		if (vallen < 8 || vallen > len) {
1412195972f6Sopenharmony_ci			ppp_error("EAP: MD5-Challenge with bad length %d (8..%d)",
1413195972f6Sopenharmony_ci			    vallen, len);
1414195972f6Sopenharmony_ci			/* Try something better. */
1415195972f6Sopenharmony_ci			eap_send_nak(pcb, id, EAPT_SRP);
1416195972f6Sopenharmony_ci			break;
1417195972f6Sopenharmony_ci		}
1418195972f6Sopenharmony_ci
1419195972f6Sopenharmony_ci		/* Not so likely to happen. */
1420195972f6Sopenharmony_ci		if (vallen >= len + sizeof (rhostname)) {
1421195972f6Sopenharmony_ci			ppp_dbglog("EAP: trimming really long peer name down");
1422195972f6Sopenharmony_ci			MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1);
1423195972f6Sopenharmony_ci			rhostname[sizeof (rhostname) - 1] = '\0';
1424195972f6Sopenharmony_ci		} else {
1425195972f6Sopenharmony_ci			MEMCPY(rhostname, inp + vallen, len - vallen);
1426195972f6Sopenharmony_ci			rhostname[len - vallen] = '\0';
1427195972f6Sopenharmony_ci		}
1428195972f6Sopenharmony_ci
1429195972f6Sopenharmony_ci#if PPP_REMOTENAME
1430195972f6Sopenharmony_ci		/* In case the remote doesn't give us his name. */
1431195972f6Sopenharmony_ci		if (pcb->settings.explicit_remote ||
1432195972f6Sopenharmony_ci		    (pcb->settings.remote_name[0] != '\0' && vallen == len))
1433195972f6Sopenharmony_ci			strlcpy(rhostname, pcb->settings.remote_name, sizeof (rhostname));
1434195972f6Sopenharmony_ci#endif /* PPP_REMOTENAME */
1435195972f6Sopenharmony_ci
1436195972f6Sopenharmony_ci		/*
1437195972f6Sopenharmony_ci		 * Get the secret for authenticating ourselves with
1438195972f6Sopenharmony_ci		 * the specified host.
1439195972f6Sopenharmony_ci		 */
1440195972f6Sopenharmony_ci		if (!get_secret(pcb, pcb->eap.es_client.ea_name,
1441195972f6Sopenharmony_ci		    rhostname, secret, &secret_len, 0)) {
1442195972f6Sopenharmony_ci			ppp_dbglog("EAP: no MD5 secret for auth to %q", rhostname);
1443195972f6Sopenharmony_ci			eap_send_nak(pcb, id, EAPT_SRP);
1444195972f6Sopenharmony_ci			break;
1445195972f6Sopenharmony_ci		}
1446195972f6Sopenharmony_ci		lwip_md5_init(&mdContext);
1447195972f6Sopenharmony_ci		lwip_md5_starts(&mdContext);
1448195972f6Sopenharmony_ci		typenum = id;
1449195972f6Sopenharmony_ci		lwip_md5_update(&mdContext, &typenum, 1);
1450195972f6Sopenharmony_ci		lwip_md5_update(&mdContext, (u_char *)secret, secret_len);
1451195972f6Sopenharmony_ci		BZERO(secret, sizeof (secret));
1452195972f6Sopenharmony_ci		lwip_md5_update(&mdContext, inp, vallen);
1453195972f6Sopenharmony_ci		lwip_md5_finish(&mdContext, hash);
1454195972f6Sopenharmony_ci		lwip_md5_free(&mdContext);
1455195972f6Sopenharmony_ci		eap_chap_response(pcb, id, hash, pcb->eap.es_client.ea_name,
1456195972f6Sopenharmony_ci		    pcb->eap.es_client.ea_namelen);
1457195972f6Sopenharmony_ci		break;
1458195972f6Sopenharmony_ci
1459195972f6Sopenharmony_ci#ifdef USE_SRP
1460195972f6Sopenharmony_ci	case EAPT_SRP:
1461195972f6Sopenharmony_ci		if (len < 1) {
1462195972f6Sopenharmony_ci			ppp_error("EAP: received empty SRP Request");
1463195972f6Sopenharmony_ci			/* Bogus request; wait for something real. */
1464195972f6Sopenharmony_ci			return;
1465195972f6Sopenharmony_ci		}
1466195972f6Sopenharmony_ci
1467195972f6Sopenharmony_ci		/* Get subtype */
1468195972f6Sopenharmony_ci		GETCHAR(vallen, inp);
1469195972f6Sopenharmony_ci		len--;
1470195972f6Sopenharmony_ci		switch (vallen) {
1471195972f6Sopenharmony_ci		case EAPSRP_CHALLENGE:
1472195972f6Sopenharmony_ci			tc = NULL;
1473195972f6Sopenharmony_ci			if (pcb->eap.es_client.ea_session != NULL) {
1474195972f6Sopenharmony_ci				tc = (struct t_client *)pcb->eap.es_client.
1475195972f6Sopenharmony_ci				    ea_session;
1476195972f6Sopenharmony_ci				/*
1477195972f6Sopenharmony_ci				 * If this is a new challenge, then start
1478195972f6Sopenharmony_ci				 * over with a new client session context.
1479195972f6Sopenharmony_ci				 * Otherwise, just resend last response.
1480195972f6Sopenharmony_ci				 */
1481195972f6Sopenharmony_ci				if (id != pcb->eap.es_client.ea_id) {
1482195972f6Sopenharmony_ci					t_clientclose(tc);
1483195972f6Sopenharmony_ci					pcb->eap.es_client.ea_session = NULL;
1484195972f6Sopenharmony_ci					tc = NULL;
1485195972f6Sopenharmony_ci				}
1486195972f6Sopenharmony_ci			}
1487195972f6Sopenharmony_ci			/* No session key just yet */
1488195972f6Sopenharmony_ci			pcb->eap.es_client.ea_skey = NULL;
1489195972f6Sopenharmony_ci			if (tc == NULL) {
1490195972f6Sopenharmony_ci				int rhostnamelen;
1491195972f6Sopenharmony_ci
1492195972f6Sopenharmony_ci				GETCHAR(vallen, inp);
1493195972f6Sopenharmony_ci				len--;
1494195972f6Sopenharmony_ci				if (vallen >= len) {
1495195972f6Sopenharmony_ci					ppp_error("EAP: badly-formed SRP Challenge"
1496195972f6Sopenharmony_ci					    " (name)");
1497195972f6Sopenharmony_ci					/* Ignore badly-formed messages */
1498195972f6Sopenharmony_ci					return;
1499195972f6Sopenharmony_ci				}
1500195972f6Sopenharmony_ci				MEMCPY(rhostname, inp, vallen);
1501195972f6Sopenharmony_ci				rhostname[vallen] = '\0';
1502195972f6Sopenharmony_ci				INCPTR(vallen, inp);
1503195972f6Sopenharmony_ci				len -= vallen;
1504195972f6Sopenharmony_ci
1505195972f6Sopenharmony_ci				/*
1506195972f6Sopenharmony_ci				 * In case the remote doesn't give us his name,
1507195972f6Sopenharmony_ci				 * use configured name.
1508195972f6Sopenharmony_ci				 */
1509195972f6Sopenharmony_ci				if (explicit_remote ||
1510195972f6Sopenharmony_ci				    (remote_name[0] != '\0' && vallen == 0)) {
1511195972f6Sopenharmony_ci					strlcpy(rhostname, remote_name,
1512195972f6Sopenharmony_ci					    sizeof (rhostname));
1513195972f6Sopenharmony_ci				}
1514195972f6Sopenharmony_ci
1515195972f6Sopenharmony_ci				rhostnamelen = (int)strlen(rhostname);
1516195972f6Sopenharmony_ci				if (rhostnamelen > MAXNAMELEN) {
1517195972f6Sopenharmony_ci					rhostnamelen = MAXNAMELEN;
1518195972f6Sopenharmony_ci				}
1519195972f6Sopenharmony_ci				MEMCPY(pcb->eap.es_client.ea_peer, rhostname, rhostnamelen);
1520195972f6Sopenharmony_ci				pcb->eap.es_client.ea_peer[rhostnamelen] = '\0';
1521195972f6Sopenharmony_ci				pcb->eap.es_client.ea_peerlen = rhostnamelen;
1522195972f6Sopenharmony_ci
1523195972f6Sopenharmony_ci				GETCHAR(vallen, inp);
1524195972f6Sopenharmony_ci				len--;
1525195972f6Sopenharmony_ci				if (vallen >= len) {
1526195972f6Sopenharmony_ci					ppp_error("EAP: badly-formed SRP Challenge"
1527195972f6Sopenharmony_ci					    " (s)");
1528195972f6Sopenharmony_ci					/* Ignore badly-formed messages */
1529195972f6Sopenharmony_ci					return;
1530195972f6Sopenharmony_ci				}
1531195972f6Sopenharmony_ci				sval.data = inp;
1532195972f6Sopenharmony_ci				sval.len = vallen;
1533195972f6Sopenharmony_ci				INCPTR(vallen, inp);
1534195972f6Sopenharmony_ci				len -= vallen;
1535195972f6Sopenharmony_ci
1536195972f6Sopenharmony_ci				GETCHAR(vallen, inp);
1537195972f6Sopenharmony_ci				len--;
1538195972f6Sopenharmony_ci				if (vallen > len) {
1539195972f6Sopenharmony_ci					ppp_error("EAP: badly-formed SRP Challenge"
1540195972f6Sopenharmony_ci					    " (g)");
1541195972f6Sopenharmony_ci					/* Ignore badly-formed messages */
1542195972f6Sopenharmony_ci					return;
1543195972f6Sopenharmony_ci				}
1544195972f6Sopenharmony_ci				/* If no generator present, then use value 2 */
1545195972f6Sopenharmony_ci				if (vallen == 0) {
1546195972f6Sopenharmony_ci					gval.data = (u_char *)"\002";
1547195972f6Sopenharmony_ci					gval.len = 1;
1548195972f6Sopenharmony_ci				} else {
1549195972f6Sopenharmony_ci					gval.data = inp;
1550195972f6Sopenharmony_ci					gval.len = vallen;
1551195972f6Sopenharmony_ci				}
1552195972f6Sopenharmony_ci				INCPTR(vallen, inp);
1553195972f6Sopenharmony_ci				len -= vallen;
1554195972f6Sopenharmony_ci
1555195972f6Sopenharmony_ci				/*
1556195972f6Sopenharmony_ci				 * If no modulus present, then use well-known
1557195972f6Sopenharmony_ci				 * value.
1558195972f6Sopenharmony_ci				 */
1559195972f6Sopenharmony_ci				if (len == 0) {
1560195972f6Sopenharmony_ci					Nval.data = (u_char *)wkmodulus;
1561195972f6Sopenharmony_ci					Nval.len = sizeof (wkmodulus);
1562195972f6Sopenharmony_ci				} else {
1563195972f6Sopenharmony_ci					Nval.data = inp;
1564195972f6Sopenharmony_ci					Nval.len = len;
1565195972f6Sopenharmony_ci				}
1566195972f6Sopenharmony_ci				tc = t_clientopen(pcb->eap.es_client.ea_name,
1567195972f6Sopenharmony_ci				    &Nval, &gval, &sval);
1568195972f6Sopenharmony_ci				if (tc == NULL) {
1569195972f6Sopenharmony_ci					eap_send_nak(pcb, id, EAPT_MD5CHAP);
1570195972f6Sopenharmony_ci					break;
1571195972f6Sopenharmony_ci				}
1572195972f6Sopenharmony_ci				pcb->eap.es_client.ea_session = (void *)tc;
1573195972f6Sopenharmony_ci
1574195972f6Sopenharmony_ci				/* Add Challenge ID & type to verifier */
1575195972f6Sopenharmony_ci				vals[0] = id;
1576195972f6Sopenharmony_ci				vals[1] = EAPT_SRP;
1577195972f6Sopenharmony_ci				t_clientaddexdata(tc, vals, 2);
1578195972f6Sopenharmony_ci			}
1579195972f6Sopenharmony_ci			Ap = t_clientgenexp(tc);
1580195972f6Sopenharmony_ci			eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data,
1581195972f6Sopenharmony_ci			    Ap->len);
1582195972f6Sopenharmony_ci			break;
1583195972f6Sopenharmony_ci
1584195972f6Sopenharmony_ci		case EAPSRP_SKEY:
1585195972f6Sopenharmony_ci			tc = (struct t_client *)pcb->eap.es_client.ea_session;
1586195972f6Sopenharmony_ci			if (tc == NULL) {
1587195972f6Sopenharmony_ci				ppp_warn("EAP: peer sent Subtype 2 without 1");
1588195972f6Sopenharmony_ci				eap_send_nak(pcb, id, EAPT_MD5CHAP);
1589195972f6Sopenharmony_ci				break;
1590195972f6Sopenharmony_ci			}
1591195972f6Sopenharmony_ci			if (pcb->eap.es_client.ea_skey != NULL) {
1592195972f6Sopenharmony_ci				/*
1593195972f6Sopenharmony_ci				 * ID number should not change here.  Warn
1594195972f6Sopenharmony_ci				 * if it does (but otherwise ignore).
1595195972f6Sopenharmony_ci				 */
1596195972f6Sopenharmony_ci				if (id != pcb->eap.es_client.ea_id) {
1597195972f6Sopenharmony_ci					ppp_warn("EAP: ID changed from %d to %d "
1598195972f6Sopenharmony_ci					    "in SRP Subtype 2 rexmit",
1599195972f6Sopenharmony_ci					    pcb->eap.es_client.ea_id, id);
1600195972f6Sopenharmony_ci				}
1601195972f6Sopenharmony_ci			} else {
1602195972f6Sopenharmony_ci				if (get_srp_secret(pcb->eap.es_unit,
1603195972f6Sopenharmony_ci				    pcb->eap.es_client.ea_name,
1604195972f6Sopenharmony_ci				    pcb->eap.es_client.ea_peer, secret, 0) == 0) {
1605195972f6Sopenharmony_ci					/*
1606195972f6Sopenharmony_ci					 * Can't work with this peer because
1607195972f6Sopenharmony_ci					 * the secret is missing.  Just give
1608195972f6Sopenharmony_ci					 * up.
1609195972f6Sopenharmony_ci					 */
1610195972f6Sopenharmony_ci					eap_send_nak(pcb, id, EAPT_MD5CHAP);
1611195972f6Sopenharmony_ci					break;
1612195972f6Sopenharmony_ci				}
1613195972f6Sopenharmony_ci				Bval.data = inp;
1614195972f6Sopenharmony_ci				Bval.len = len;
1615195972f6Sopenharmony_ci				t_clientpasswd(tc, secret);
1616195972f6Sopenharmony_ci				BZERO(secret, sizeof (secret));
1617195972f6Sopenharmony_ci				pcb->eap.es_client.ea_skey =
1618195972f6Sopenharmony_ci				    t_clientgetkey(tc, &Bval);
1619195972f6Sopenharmony_ci				if (pcb->eap.es_client.ea_skey == NULL) {
1620195972f6Sopenharmony_ci					/* Server is rogue; stop now */
1621195972f6Sopenharmony_ci					ppp_error("EAP: SRP server is rogue");
1622195972f6Sopenharmony_ci					goto client_failure;
1623195972f6Sopenharmony_ci				}
1624195972f6Sopenharmony_ci			}
1625195972f6Sopenharmony_ci			eap_srpval_response(esp, id, SRPVAL_EBIT,
1626195972f6Sopenharmony_ci			    t_clientresponse(tc));
1627195972f6Sopenharmony_ci			break;
1628195972f6Sopenharmony_ci
1629195972f6Sopenharmony_ci		case EAPSRP_SVALIDATOR:
1630195972f6Sopenharmony_ci			tc = (struct t_client *)pcb->eap.es_client.ea_session;
1631195972f6Sopenharmony_ci			if (tc == NULL || pcb->eap.es_client.ea_skey == NULL) {
1632195972f6Sopenharmony_ci				ppp_warn("EAP: peer sent Subtype 3 without 1/2");
1633195972f6Sopenharmony_ci				eap_send_nak(pcb, id, EAPT_MD5CHAP);
1634195972f6Sopenharmony_ci				break;
1635195972f6Sopenharmony_ci			}
1636195972f6Sopenharmony_ci			/*
1637195972f6Sopenharmony_ci			 * If we're already open, then this ought to be a
1638195972f6Sopenharmony_ci			 * duplicate.  Otherwise, check that the server is
1639195972f6Sopenharmony_ci			 * who we think it is.
1640195972f6Sopenharmony_ci			 */
1641195972f6Sopenharmony_ci			if (pcb->eap.es_client.ea_state == eapOpen) {
1642195972f6Sopenharmony_ci				if (id != pcb->eap.es_client.ea_id) {
1643195972f6Sopenharmony_ci					ppp_warn("EAP: ID changed from %d to %d "
1644195972f6Sopenharmony_ci					    "in SRP Subtype 3 rexmit",
1645195972f6Sopenharmony_ci					    pcb->eap.es_client.ea_id, id);
1646195972f6Sopenharmony_ci				}
1647195972f6Sopenharmony_ci			} else {
1648195972f6Sopenharmony_ci				len -= sizeof (u32_t) + SHA_DIGESTSIZE;
1649195972f6Sopenharmony_ci				if (len < 0 || t_clientverify(tc, inp +
1650195972f6Sopenharmony_ci					sizeof (u32_t)) != 0) {
1651195972f6Sopenharmony_ci					ppp_error("EAP: SRP server verification "
1652195972f6Sopenharmony_ci					    "failed");
1653195972f6Sopenharmony_ci					goto client_failure;
1654195972f6Sopenharmony_ci				}
1655195972f6Sopenharmony_ci				GETLONG(pcb->eap.es_client.ea_keyflags, inp);
1656195972f6Sopenharmony_ci				/* Save pseudonym if user wants it. */
1657195972f6Sopenharmony_ci				if (len > 0 && pcb->eap.es_usepseudo) {
1658195972f6Sopenharmony_ci					INCPTR(SHA_DIGESTSIZE, inp);
1659195972f6Sopenharmony_ci					write_pseudonym(esp, inp, len, id);
1660195972f6Sopenharmony_ci				}
1661195972f6Sopenharmony_ci			}
1662195972f6Sopenharmony_ci			/*
1663195972f6Sopenharmony_ci			 * We've verified our peer.  We're now mostly done,
1664195972f6Sopenharmony_ci			 * except for waiting on the regular EAP Success
1665195972f6Sopenharmony_ci			 * message.
1666195972f6Sopenharmony_ci			 */
1667195972f6Sopenharmony_ci			eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0);
1668195972f6Sopenharmony_ci			break;
1669195972f6Sopenharmony_ci
1670195972f6Sopenharmony_ci		case EAPSRP_LWRECHALLENGE:
1671195972f6Sopenharmony_ci			if (len < 4) {
1672195972f6Sopenharmony_ci				ppp_warn("EAP: malformed Lightweight rechallenge");
1673195972f6Sopenharmony_ci				return;
1674195972f6Sopenharmony_ci			}
1675195972f6Sopenharmony_ci			SHA1Init(&ctxt);
1676195972f6Sopenharmony_ci			vals[0] = id;
1677195972f6Sopenharmony_ci			SHA1Update(&ctxt, vals, 1);
1678195972f6Sopenharmony_ci			SHA1Update(&ctxt, pcb->eap.es_client.ea_skey,
1679195972f6Sopenharmony_ci			    SESSION_KEY_LEN);
1680195972f6Sopenharmony_ci			SHA1Update(&ctxt, inp, len);
1681195972f6Sopenharmony_ci			SHA1Update(&ctxt, pcb->eap.es_client.ea_name,
1682195972f6Sopenharmony_ci			    pcb->eap.es_client.ea_namelen);
1683195972f6Sopenharmony_ci			SHA1Final(dig, &ctxt);
1684195972f6Sopenharmony_ci			eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig,
1685195972f6Sopenharmony_ci			    SHA_DIGESTSIZE);
1686195972f6Sopenharmony_ci			break;
1687195972f6Sopenharmony_ci
1688195972f6Sopenharmony_ci		default:
1689195972f6Sopenharmony_ci			ppp_error("EAP: unknown SRP Subtype %d", vallen);
1690195972f6Sopenharmony_ci			eap_send_nak(pcb, id, EAPT_MD5CHAP);
1691195972f6Sopenharmony_ci			break;
1692195972f6Sopenharmony_ci		}
1693195972f6Sopenharmony_ci		break;
1694195972f6Sopenharmony_ci#endif /* USE_SRP */
1695195972f6Sopenharmony_ci
1696195972f6Sopenharmony_ci	default:
1697195972f6Sopenharmony_ci		ppp_info("EAP: unknown authentication type %d; Naking", typenum);
1698195972f6Sopenharmony_ci		eap_send_nak(pcb, id, EAPT_SRP);
1699195972f6Sopenharmony_ci		break;
1700195972f6Sopenharmony_ci	}
1701195972f6Sopenharmony_ci
1702195972f6Sopenharmony_ci	if (pcb->settings.eap_req_time > 0) {
1703195972f6Sopenharmony_ci		UNTIMEOUT(eap_client_timeout, pcb);
1704195972f6Sopenharmony_ci		TIMEOUT(eap_client_timeout, pcb,
1705195972f6Sopenharmony_ci		    pcb->settings.eap_req_time);
1706195972f6Sopenharmony_ci	}
1707195972f6Sopenharmony_ci	return;
1708195972f6Sopenharmony_ci
1709195972f6Sopenharmony_ci#ifdef USE_SRP
1710195972f6Sopenharmony_ciclient_failure:
1711195972f6Sopenharmony_ci	pcb->eap.es_client.ea_state = eapBadAuth;
1712195972f6Sopenharmony_ci	if (pcb->settings.eap_req_time > 0) {
1713195972f6Sopenharmony_ci		UNTIMEOUT(eap_client_timeout, (void *)esp);
1714195972f6Sopenharmony_ci	}
1715195972f6Sopenharmony_ci	pcb->eap.es_client.ea_session = NULL;
1716195972f6Sopenharmony_ci	t_clientclose(tc);
1717195972f6Sopenharmony_ci	auth_withpeer_fail(pcb, PPP_EAP);
1718195972f6Sopenharmony_ci#endif /* USE_SRP */
1719195972f6Sopenharmony_ci}
1720195972f6Sopenharmony_ci
1721195972f6Sopenharmony_ci#if PPP_SERVER
1722195972f6Sopenharmony_ci/*
1723195972f6Sopenharmony_ci * eap_response - Receive EAP Response message (server mode).
1724195972f6Sopenharmony_ci */
1725195972f6Sopenharmony_cistatic void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) {
1726195972f6Sopenharmony_ci	u_char typenum;
1727195972f6Sopenharmony_ci	u_char vallen;
1728195972f6Sopenharmony_ci	int secret_len;
1729195972f6Sopenharmony_ci	char secret[MAXSECRETLEN];
1730195972f6Sopenharmony_ci	char rhostname[MAXNAMELEN];
1731195972f6Sopenharmony_ci	lwip_md5_context mdContext;
1732195972f6Sopenharmony_ci	u_char hash[MD5_SIGNATURE_SIZE];
1733195972f6Sopenharmony_ci#ifdef USE_SRP
1734195972f6Sopenharmony_ci	struct t_server *ts;
1735195972f6Sopenharmony_ci	struct t_num A;
1736195972f6Sopenharmony_ci	SHA1_CTX ctxt;
1737195972f6Sopenharmony_ci	u_char dig[SHA_DIGESTSIZE];
1738195972f6Sopenharmony_ci#endif /* USE_SRP */
1739195972f6Sopenharmony_ci
1740195972f6Sopenharmony_ci	if (pcb->eap.es_server.ea_id != id) {
1741195972f6Sopenharmony_ci		ppp_dbglog("EAP: discarding Response %d; expected ID %d", id,
1742195972f6Sopenharmony_ci		    pcb->eap.es_server.ea_id);
1743195972f6Sopenharmony_ci		return;
1744195972f6Sopenharmony_ci	}
1745195972f6Sopenharmony_ci
1746195972f6Sopenharmony_ci	pcb->eap.es_server.ea_responses++;
1747195972f6Sopenharmony_ci
1748195972f6Sopenharmony_ci	if (len <= 0) {
1749195972f6Sopenharmony_ci		ppp_error("EAP: empty Response message discarded");
1750195972f6Sopenharmony_ci		return;
1751195972f6Sopenharmony_ci	}
1752195972f6Sopenharmony_ci
1753195972f6Sopenharmony_ci	GETCHAR(typenum, inp);
1754195972f6Sopenharmony_ci	len--;
1755195972f6Sopenharmony_ci
1756195972f6Sopenharmony_ci	switch (typenum) {
1757195972f6Sopenharmony_ci	case EAPT_IDENTITY:
1758195972f6Sopenharmony_ci		if (pcb->eap.es_server.ea_state != eapIdentify) {
1759195972f6Sopenharmony_ci			ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len,
1760195972f6Sopenharmony_ci			    inp);
1761195972f6Sopenharmony_ci			break;
1762195972f6Sopenharmony_ci		}
1763195972f6Sopenharmony_ci		ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp);
1764195972f6Sopenharmony_ci		if (len > MAXNAMELEN) {
1765195972f6Sopenharmony_ci		  len = MAXNAMELEN;
1766195972f6Sopenharmony_ci		}
1767195972f6Sopenharmony_ci		MEMCPY(pcb->eap.es_server.ea_peer, inp, len);
1768195972f6Sopenharmony_ci		pcb->eap.es_server.ea_peer[len] = '\0';
1769195972f6Sopenharmony_ci		pcb->eap.es_server.ea_peerlen = len;
1770195972f6Sopenharmony_ci		eap_figure_next_state(pcb, 0);
1771195972f6Sopenharmony_ci		break;
1772195972f6Sopenharmony_ci
1773195972f6Sopenharmony_ci	case EAPT_NOTIFICATION:
1774195972f6Sopenharmony_ci		ppp_dbglog("EAP unexpected Notification; response discarded");
1775195972f6Sopenharmony_ci		break;
1776195972f6Sopenharmony_ci
1777195972f6Sopenharmony_ci	case EAPT_NAK:
1778195972f6Sopenharmony_ci		if (len < 1) {
1779195972f6Sopenharmony_ci			ppp_info("EAP: Nak Response with no suggested protocol");
1780195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 1);
1781195972f6Sopenharmony_ci			break;
1782195972f6Sopenharmony_ci		}
1783195972f6Sopenharmony_ci
1784195972f6Sopenharmony_ci		GETCHAR(vallen, inp);
1785195972f6Sopenharmony_ci		len--;
1786195972f6Sopenharmony_ci
1787195972f6Sopenharmony_ci		if (
1788195972f6Sopenharmony_ci#if PPP_REMOTENAME
1789195972f6Sopenharmony_ci		!pcb->explicit_remote &&
1790195972f6Sopenharmony_ci#endif /* PPP_REMOTENAME */
1791195972f6Sopenharmony_ci		pcb->eap.es_server.ea_state == eapIdentify){
1792195972f6Sopenharmony_ci			/* Peer cannot Nak Identify Request */
1793195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 1);
1794195972f6Sopenharmony_ci			break;
1795195972f6Sopenharmony_ci		}
1796195972f6Sopenharmony_ci
1797195972f6Sopenharmony_ci		switch (vallen) {
1798195972f6Sopenharmony_ci		case EAPT_SRP:
1799195972f6Sopenharmony_ci			/* Run through SRP validator selection again. */
1800195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapIdentify;
1801195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 0);
1802195972f6Sopenharmony_ci			break;
1803195972f6Sopenharmony_ci
1804195972f6Sopenharmony_ci		case EAPT_MD5CHAP:
1805195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapMD5Chall;
1806195972f6Sopenharmony_ci			break;
1807195972f6Sopenharmony_ci
1808195972f6Sopenharmony_ci		default:
1809195972f6Sopenharmony_ci			ppp_dbglog("EAP: peer requesting unknown Type %d", vallen);
1810195972f6Sopenharmony_ci			switch (pcb->eap.es_server.ea_state) {
1811195972f6Sopenharmony_ci			case eapSRP1:
1812195972f6Sopenharmony_ci			case eapSRP2:
1813195972f6Sopenharmony_ci			case eapSRP3:
1814195972f6Sopenharmony_ci				pcb->eap.es_server.ea_state = eapMD5Chall;
1815195972f6Sopenharmony_ci				break;
1816195972f6Sopenharmony_ci			case eapMD5Chall:
1817195972f6Sopenharmony_ci			case eapSRP4:
1818195972f6Sopenharmony_ci				pcb->eap.es_server.ea_state = eapIdentify;
1819195972f6Sopenharmony_ci				eap_figure_next_state(pcb, 0);
1820195972f6Sopenharmony_ci				break;
1821195972f6Sopenharmony_ci			default:
1822195972f6Sopenharmony_ci				break;
1823195972f6Sopenharmony_ci			}
1824195972f6Sopenharmony_ci			break;
1825195972f6Sopenharmony_ci		}
1826195972f6Sopenharmony_ci		break;
1827195972f6Sopenharmony_ci
1828195972f6Sopenharmony_ci	case EAPT_MD5CHAP:
1829195972f6Sopenharmony_ci		if (pcb->eap.es_server.ea_state != eapMD5Chall) {
1830195972f6Sopenharmony_ci			ppp_error("EAP: unexpected MD5-Response");
1831195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 1);
1832195972f6Sopenharmony_ci			break;
1833195972f6Sopenharmony_ci		}
1834195972f6Sopenharmony_ci		if (len < 1) {
1835195972f6Sopenharmony_ci			ppp_error("EAP: received MD5-Response with no data");
1836195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 1);
1837195972f6Sopenharmony_ci			break;
1838195972f6Sopenharmony_ci		}
1839195972f6Sopenharmony_ci		GETCHAR(vallen, inp);
1840195972f6Sopenharmony_ci		len--;
1841195972f6Sopenharmony_ci		if (vallen != 16 || vallen > len) {
1842195972f6Sopenharmony_ci			ppp_error("EAP: MD5-Response with bad length %d", vallen);
1843195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 1);
1844195972f6Sopenharmony_ci			break;
1845195972f6Sopenharmony_ci		}
1846195972f6Sopenharmony_ci
1847195972f6Sopenharmony_ci		/* Not so likely to happen. */
1848195972f6Sopenharmony_ci		if (vallen >= len + sizeof (rhostname)) {
1849195972f6Sopenharmony_ci			ppp_dbglog("EAP: trimming really long peer name down");
1850195972f6Sopenharmony_ci			MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1);
1851195972f6Sopenharmony_ci			rhostname[sizeof (rhostname) - 1] = '\0';
1852195972f6Sopenharmony_ci		} else {
1853195972f6Sopenharmony_ci			MEMCPY(rhostname, inp + vallen, len - vallen);
1854195972f6Sopenharmony_ci			rhostname[len - vallen] = '\0';
1855195972f6Sopenharmony_ci		}
1856195972f6Sopenharmony_ci
1857195972f6Sopenharmony_ci#if PPP_REMOTENAME
1858195972f6Sopenharmony_ci		/* In case the remote doesn't give us his name. */
1859195972f6Sopenharmony_ci		if (explicit_remote ||
1860195972f6Sopenharmony_ci		    (remote_name[0] != '\0' && vallen == len))
1861195972f6Sopenharmony_ci			strlcpy(rhostname, remote_name, sizeof (rhostname));
1862195972f6Sopenharmony_ci#endif /* PPP_REMOTENAME */
1863195972f6Sopenharmony_ci
1864195972f6Sopenharmony_ci		/*
1865195972f6Sopenharmony_ci		 * Get the secret for authenticating the specified
1866195972f6Sopenharmony_ci		 * host.
1867195972f6Sopenharmony_ci		 */
1868195972f6Sopenharmony_ci		if (!get_secret(pcb, rhostname,
1869195972f6Sopenharmony_ci		    pcb->eap.es_server.ea_name, secret, &secret_len, 1)) {
1870195972f6Sopenharmony_ci			ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname);
1871195972f6Sopenharmony_ci			eap_send_failure(pcb);
1872195972f6Sopenharmony_ci			break;
1873195972f6Sopenharmony_ci		}
1874195972f6Sopenharmony_ci		lwip_md5_init(&mdContext);
1875195972f6Sopenharmony_ci		lwip_md5_starts(&mdContext);
1876195972f6Sopenharmony_ci		lwip_md5_update(&mdContext, &pcb->eap.es_server.ea_id, 1);
1877195972f6Sopenharmony_ci		lwip_md5_update(&mdContext, (u_char *)secret, secret_len);
1878195972f6Sopenharmony_ci		BZERO(secret, sizeof (secret));
1879195972f6Sopenharmony_ci		lwip_md5_update(&mdContext, pcb->eap.es_challenge, pcb->eap.es_challen);
1880195972f6Sopenharmony_ci		lwip_md5_finish(&mdContext, hash);
1881195972f6Sopenharmony_ci		lwip_md5_free(&mdContext);
1882195972f6Sopenharmony_ci		if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) {
1883195972f6Sopenharmony_ci			eap_send_failure(pcb);
1884195972f6Sopenharmony_ci			break;
1885195972f6Sopenharmony_ci		}
1886195972f6Sopenharmony_ci		pcb->eap.es_server.ea_type = EAPT_MD5CHAP;
1887195972f6Sopenharmony_ci		eap_send_success(pcb);
1888195972f6Sopenharmony_ci		eap_figure_next_state(pcb, 0);
1889195972f6Sopenharmony_ci		if (pcb->eap.es_rechallenge != 0)
1890195972f6Sopenharmony_ci			TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge);
1891195972f6Sopenharmony_ci		break;
1892195972f6Sopenharmony_ci
1893195972f6Sopenharmony_ci#ifdef USE_SRP
1894195972f6Sopenharmony_ci	case EAPT_SRP:
1895195972f6Sopenharmony_ci		if (len < 1) {
1896195972f6Sopenharmony_ci			ppp_error("EAP: empty SRP Response");
1897195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 1);
1898195972f6Sopenharmony_ci			break;
1899195972f6Sopenharmony_ci		}
1900195972f6Sopenharmony_ci		GETCHAR(typenum, inp);
1901195972f6Sopenharmony_ci		len--;
1902195972f6Sopenharmony_ci		switch (typenum) {
1903195972f6Sopenharmony_ci		case EAPSRP_CKEY:
1904195972f6Sopenharmony_ci			if (pcb->eap.es_server.ea_state != eapSRP1) {
1905195972f6Sopenharmony_ci				ppp_error("EAP: unexpected SRP Subtype 1 Response");
1906195972f6Sopenharmony_ci				eap_figure_next_state(pcb, 1);
1907195972f6Sopenharmony_ci				break;
1908195972f6Sopenharmony_ci			}
1909195972f6Sopenharmony_ci			A.data = inp;
1910195972f6Sopenharmony_ci			A.len = len;
1911195972f6Sopenharmony_ci			ts = (struct t_server *)pcb->eap.es_server.ea_session;
1912195972f6Sopenharmony_ci			assert(ts != NULL);
1913195972f6Sopenharmony_ci			pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A);
1914195972f6Sopenharmony_ci			if (pcb->eap.es_server.ea_skey == NULL) {
1915195972f6Sopenharmony_ci				/* Client's A value is bogus; terminate now */
1916195972f6Sopenharmony_ci				ppp_error("EAP: bogus A value from client");
1917195972f6Sopenharmony_ci				eap_send_failure(pcb);
1918195972f6Sopenharmony_ci			} else {
1919195972f6Sopenharmony_ci				eap_figure_next_state(pcb, 0);
1920195972f6Sopenharmony_ci			}
1921195972f6Sopenharmony_ci			break;
1922195972f6Sopenharmony_ci
1923195972f6Sopenharmony_ci		case EAPSRP_CVALIDATOR:
1924195972f6Sopenharmony_ci			if (pcb->eap.es_server.ea_state != eapSRP2) {
1925195972f6Sopenharmony_ci				ppp_error("EAP: unexpected SRP Subtype 2 Response");
1926195972f6Sopenharmony_ci				eap_figure_next_state(pcb, 1);
1927195972f6Sopenharmony_ci				break;
1928195972f6Sopenharmony_ci			}
1929195972f6Sopenharmony_ci			if (len < sizeof (u32_t) + SHA_DIGESTSIZE) {
1930195972f6Sopenharmony_ci				ppp_error("EAP: M1 length %d < %d", len,
1931195972f6Sopenharmony_ci				    sizeof (u32_t) + SHA_DIGESTSIZE);
1932195972f6Sopenharmony_ci				eap_figure_next_state(pcb, 1);
1933195972f6Sopenharmony_ci				break;
1934195972f6Sopenharmony_ci			}
1935195972f6Sopenharmony_ci			GETLONG(pcb->eap.es_server.ea_keyflags, inp);
1936195972f6Sopenharmony_ci			ts = (struct t_server *)pcb->eap.es_server.ea_session;
1937195972f6Sopenharmony_ci			assert(ts != NULL);
1938195972f6Sopenharmony_ci			if (t_serververify(ts, inp)) {
1939195972f6Sopenharmony_ci				ppp_info("EAP: unable to validate client identity");
1940195972f6Sopenharmony_ci				eap_send_failure(pcb);
1941195972f6Sopenharmony_ci				break;
1942195972f6Sopenharmony_ci			}
1943195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 0);
1944195972f6Sopenharmony_ci			break;
1945195972f6Sopenharmony_ci
1946195972f6Sopenharmony_ci		case EAPSRP_ACK:
1947195972f6Sopenharmony_ci			if (pcb->eap.es_server.ea_state != eapSRP3) {
1948195972f6Sopenharmony_ci				ppp_error("EAP: unexpected SRP Subtype 3 Response");
1949195972f6Sopenharmony_ci				eap_send_failure(esp);
1950195972f6Sopenharmony_ci				break;
1951195972f6Sopenharmony_ci			}
1952195972f6Sopenharmony_ci			pcb->eap.es_server.ea_type = EAPT_SRP;
1953195972f6Sopenharmony_ci			eap_send_success(pcb, esp);
1954195972f6Sopenharmony_ci			eap_figure_next_state(pcb, 0);
1955195972f6Sopenharmony_ci			if (pcb->eap.es_rechallenge != 0)
1956195972f6Sopenharmony_ci				TIMEOUT(eap_rechallenge, pcb,
1957195972f6Sopenharmony_ci				    pcb->eap.es_rechallenge);
1958195972f6Sopenharmony_ci			if (pcb->eap.es_lwrechallenge != 0)
1959195972f6Sopenharmony_ci				TIMEOUT(srp_lwrechallenge, pcb,
1960195972f6Sopenharmony_ci				    pcb->eap.es_lwrechallenge);
1961195972f6Sopenharmony_ci			break;
1962195972f6Sopenharmony_ci
1963195972f6Sopenharmony_ci		case EAPSRP_LWRECHALLENGE:
1964195972f6Sopenharmony_ci			if (pcb->eap.es_server.ea_state != eapSRP4) {
1965195972f6Sopenharmony_ci				ppp_info("EAP: unexpected SRP Subtype 4 Response");
1966195972f6Sopenharmony_ci				return;
1967195972f6Sopenharmony_ci			}
1968195972f6Sopenharmony_ci			if (len != SHA_DIGESTSIZE) {
1969195972f6Sopenharmony_ci				ppp_error("EAP: bad Lightweight rechallenge "
1970195972f6Sopenharmony_ci				    "response");
1971195972f6Sopenharmony_ci				return;
1972195972f6Sopenharmony_ci			}
1973195972f6Sopenharmony_ci			SHA1Init(&ctxt);
1974195972f6Sopenharmony_ci			vallen = id;
1975195972f6Sopenharmony_ci			SHA1Update(&ctxt, &vallen, 1);
1976195972f6Sopenharmony_ci			SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
1977195972f6Sopenharmony_ci			    SESSION_KEY_LEN);
1978195972f6Sopenharmony_ci			SHA1Update(&ctxt, pcb->eap.es_challenge, pcb->eap.es_challen);
1979195972f6Sopenharmony_ci			SHA1Update(&ctxt, pcb->eap.es_server.ea_peer,
1980195972f6Sopenharmony_ci			    pcb->eap.es_server.ea_peerlen);
1981195972f6Sopenharmony_ci			SHA1Final(dig, &ctxt);
1982195972f6Sopenharmony_ci			if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) {
1983195972f6Sopenharmony_ci				ppp_error("EAP: failed Lightweight rechallenge");
1984195972f6Sopenharmony_ci				eap_send_failure(pcb);
1985195972f6Sopenharmony_ci				break;
1986195972f6Sopenharmony_ci			}
1987195972f6Sopenharmony_ci			pcb->eap.es_server.ea_state = eapOpen;
1988195972f6Sopenharmony_ci			if (pcb->eap.es_lwrechallenge != 0)
1989195972f6Sopenharmony_ci				TIMEOUT(srp_lwrechallenge, esp,
1990195972f6Sopenharmony_ci				    pcb->eap.es_lwrechallenge);
1991195972f6Sopenharmony_ci			break;
1992195972f6Sopenharmony_ci		}
1993195972f6Sopenharmony_ci		break;
1994195972f6Sopenharmony_ci#endif /* USE_SRP */
1995195972f6Sopenharmony_ci
1996195972f6Sopenharmony_ci	default:
1997195972f6Sopenharmony_ci		/* This can't happen. */
1998195972f6Sopenharmony_ci		ppp_error("EAP: unknown Response type %d; ignored", typenum);
1999195972f6Sopenharmony_ci		return;
2000195972f6Sopenharmony_ci	}
2001195972f6Sopenharmony_ci
2002195972f6Sopenharmony_ci	if (pcb->settings.eap_timeout_time > 0) {
2003195972f6Sopenharmony_ci		UNTIMEOUT(eap_server_timeout, pcb);
2004195972f6Sopenharmony_ci	}
2005195972f6Sopenharmony_ci
2006195972f6Sopenharmony_ci	if (pcb->eap.es_server.ea_state != eapBadAuth &&
2007195972f6Sopenharmony_ci	    pcb->eap.es_server.ea_state != eapOpen) {
2008195972f6Sopenharmony_ci		pcb->eap.es_server.ea_id++;
2009195972f6Sopenharmony_ci		eap_send_request(pcb);
2010195972f6Sopenharmony_ci	}
2011195972f6Sopenharmony_ci}
2012195972f6Sopenharmony_ci#endif /* PPP_SERVER */
2013195972f6Sopenharmony_ci
2014195972f6Sopenharmony_ci/*
2015195972f6Sopenharmony_ci * eap_success - Receive EAP Success message (client mode).
2016195972f6Sopenharmony_ci */
2017195972f6Sopenharmony_cistatic void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) {
2018195972f6Sopenharmony_ci	LWIP_UNUSED_ARG(id);
2019195972f6Sopenharmony_ci
2020195972f6Sopenharmony_ci	if (pcb->eap.es_client.ea_state != eapOpen && !eap_client_active(pcb)) {
2021195972f6Sopenharmony_ci		ppp_dbglog("EAP unexpected success message in state %s (%d)",
2022195972f6Sopenharmony_ci		    eap_state_name(pcb->eap.es_client.ea_state),
2023195972f6Sopenharmony_ci		    pcb->eap.es_client.ea_state);
2024195972f6Sopenharmony_ci		return;
2025195972f6Sopenharmony_ci	}
2026195972f6Sopenharmony_ci
2027195972f6Sopenharmony_ci	if (pcb->settings.eap_req_time > 0) {
2028195972f6Sopenharmony_ci		UNTIMEOUT(eap_client_timeout, pcb);
2029195972f6Sopenharmony_ci	}
2030195972f6Sopenharmony_ci
2031195972f6Sopenharmony_ci	if (len > 0) {
2032195972f6Sopenharmony_ci		/* This is odd.  The spec doesn't allow for this. */
2033195972f6Sopenharmony_ci		PRINTMSG(inp, len);
2034195972f6Sopenharmony_ci	}
2035195972f6Sopenharmony_ci
2036195972f6Sopenharmony_ci	pcb->eap.es_client.ea_state = eapOpen;
2037195972f6Sopenharmony_ci	auth_withpeer_success(pcb, PPP_EAP, 0);
2038195972f6Sopenharmony_ci}
2039195972f6Sopenharmony_ci
2040195972f6Sopenharmony_ci/*
2041195972f6Sopenharmony_ci * eap_failure - Receive EAP Failure message (client mode).
2042195972f6Sopenharmony_ci */
2043195972f6Sopenharmony_cistatic void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) {
2044195972f6Sopenharmony_ci	LWIP_UNUSED_ARG(id);
2045195972f6Sopenharmony_ci
2046195972f6Sopenharmony_ci	if (!eap_client_active(pcb)) {
2047195972f6Sopenharmony_ci		ppp_dbglog("EAP unexpected failure message in state %s (%d)",
2048195972f6Sopenharmony_ci		    eap_state_name(pcb->eap.es_client.ea_state),
2049195972f6Sopenharmony_ci		    pcb->eap.es_client.ea_state);
2050195972f6Sopenharmony_ci	}
2051195972f6Sopenharmony_ci
2052195972f6Sopenharmony_ci	if (pcb->settings.eap_req_time > 0) {
2053195972f6Sopenharmony_ci		UNTIMEOUT(eap_client_timeout, pcb);
2054195972f6Sopenharmony_ci	}
2055195972f6Sopenharmony_ci
2056195972f6Sopenharmony_ci	if (len > 0) {
2057195972f6Sopenharmony_ci		/* This is odd.  The spec doesn't allow for this. */
2058195972f6Sopenharmony_ci		PRINTMSG(inp, len);
2059195972f6Sopenharmony_ci	}
2060195972f6Sopenharmony_ci
2061195972f6Sopenharmony_ci	pcb->eap.es_client.ea_state = eapBadAuth;
2062195972f6Sopenharmony_ci
2063195972f6Sopenharmony_ci	ppp_error("EAP: peer reports authentication failure");
2064195972f6Sopenharmony_ci	auth_withpeer_fail(pcb, PPP_EAP);
2065195972f6Sopenharmony_ci}
2066195972f6Sopenharmony_ci
2067195972f6Sopenharmony_ci/*
2068195972f6Sopenharmony_ci * eap_input - Handle received EAP message.
2069195972f6Sopenharmony_ci */
2070195972f6Sopenharmony_cistatic void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) {
2071195972f6Sopenharmony_ci	u_char code, id;
2072195972f6Sopenharmony_ci	int len;
2073195972f6Sopenharmony_ci
2074195972f6Sopenharmony_ci	/*
2075195972f6Sopenharmony_ci	 * Parse header (code, id and length).  If packet too short,
2076195972f6Sopenharmony_ci	 * drop it.
2077195972f6Sopenharmony_ci	 */
2078195972f6Sopenharmony_ci	if (inlen < EAP_HEADERLEN) {
2079195972f6Sopenharmony_ci		ppp_error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN);
2080195972f6Sopenharmony_ci		return;
2081195972f6Sopenharmony_ci	}
2082195972f6Sopenharmony_ci	GETCHAR(code, inp);
2083195972f6Sopenharmony_ci	GETCHAR(id, inp);
2084195972f6Sopenharmony_ci	GETSHORT(len, inp);
2085195972f6Sopenharmony_ci	if (len < EAP_HEADERLEN || len > inlen) {
2086195972f6Sopenharmony_ci		ppp_error("EAP: packet has illegal length field %d (%d..%d)", len,
2087195972f6Sopenharmony_ci		    EAP_HEADERLEN, inlen);
2088195972f6Sopenharmony_ci		return;
2089195972f6Sopenharmony_ci	}
2090195972f6Sopenharmony_ci	len -= EAP_HEADERLEN;
2091195972f6Sopenharmony_ci
2092195972f6Sopenharmony_ci	/* Dispatch based on message code */
2093195972f6Sopenharmony_ci	switch (code) {
2094195972f6Sopenharmony_ci	case EAP_REQUEST:
2095195972f6Sopenharmony_ci		eap_request(pcb, inp, id, len);
2096195972f6Sopenharmony_ci		break;
2097195972f6Sopenharmony_ci
2098195972f6Sopenharmony_ci#if PPP_SERVER
2099195972f6Sopenharmony_ci	case EAP_RESPONSE:
2100195972f6Sopenharmony_ci		eap_response(pcb, inp, id, len);
2101195972f6Sopenharmony_ci		break;
2102195972f6Sopenharmony_ci#endif /* PPP_SERVER */
2103195972f6Sopenharmony_ci
2104195972f6Sopenharmony_ci	case EAP_SUCCESS:
2105195972f6Sopenharmony_ci		eap_success(pcb, inp, id, len);
2106195972f6Sopenharmony_ci		break;
2107195972f6Sopenharmony_ci
2108195972f6Sopenharmony_ci	case EAP_FAILURE:
2109195972f6Sopenharmony_ci		eap_failure(pcb, inp, id, len);
2110195972f6Sopenharmony_ci		break;
2111195972f6Sopenharmony_ci
2112195972f6Sopenharmony_ci	default:				/* XXX Need code reject */
2113195972f6Sopenharmony_ci		/* Note: it's not legal to send EAP Nak here. */
2114195972f6Sopenharmony_ci		ppp_warn("EAP: unknown code %d received", code);
2115195972f6Sopenharmony_ci		break;
2116195972f6Sopenharmony_ci	}
2117195972f6Sopenharmony_ci}
2118195972f6Sopenharmony_ci
2119195972f6Sopenharmony_ci#if PRINTPKT_SUPPORT
2120195972f6Sopenharmony_ci/*
2121195972f6Sopenharmony_ci * eap_printpkt - print the contents of an EAP packet.
2122195972f6Sopenharmony_ci */
2123195972f6Sopenharmony_cistatic const char* const eap_codenames[] = {
2124195972f6Sopenharmony_ci	"Request", "Response", "Success", "Failure"
2125195972f6Sopenharmony_ci};
2126195972f6Sopenharmony_ci
2127195972f6Sopenharmony_cistatic const char* const eap_typenames[] = {
2128195972f6Sopenharmony_ci	"Identity", "Notification", "Nak", "MD5-Challenge",
2129195972f6Sopenharmony_ci	"OTP", "Generic-Token", NULL, NULL,
2130195972f6Sopenharmony_ci	"RSA", "DSS", "KEA", "KEA-Validate",
2131195972f6Sopenharmony_ci	"TLS", "Defender", "Windows 2000", "Arcot",
2132195972f6Sopenharmony_ci	"Cisco", "Nokia", "SRP"
2133195972f6Sopenharmony_ci};
2134195972f6Sopenharmony_ci
2135195972f6Sopenharmony_cistatic int eap_printpkt(const u_char *inp, int inlen, void (*printer) (void *, const char *, ...), void *arg) {
2136195972f6Sopenharmony_ci	int code, id, len, rtype, vallen;
2137195972f6Sopenharmony_ci	const u_char *pstart;
2138195972f6Sopenharmony_ci	u32_t uval;
2139195972f6Sopenharmony_ci
2140195972f6Sopenharmony_ci	if (inlen < EAP_HEADERLEN)
2141195972f6Sopenharmony_ci		return (0);
2142195972f6Sopenharmony_ci	pstart = inp;
2143195972f6Sopenharmony_ci	GETCHAR(code, inp);
2144195972f6Sopenharmony_ci	GETCHAR(id, inp);
2145195972f6Sopenharmony_ci	GETSHORT(len, inp);
2146195972f6Sopenharmony_ci	if (len < EAP_HEADERLEN || len > inlen)
2147195972f6Sopenharmony_ci		return (0);
2148195972f6Sopenharmony_ci
2149195972f6Sopenharmony_ci	if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(eap_codenames))
2150195972f6Sopenharmony_ci		printer(arg, " %s", eap_codenames[code-1]);
2151195972f6Sopenharmony_ci	else
2152195972f6Sopenharmony_ci		printer(arg, " code=0x%x", code);
2153195972f6Sopenharmony_ci	printer(arg, " id=0x%x", id);
2154195972f6Sopenharmony_ci	len -= EAP_HEADERLEN;
2155195972f6Sopenharmony_ci	switch (code) {
2156195972f6Sopenharmony_ci	case EAP_REQUEST:
2157195972f6Sopenharmony_ci		if (len < 1) {
2158195972f6Sopenharmony_ci			printer(arg, " <missing type>");
2159195972f6Sopenharmony_ci			break;
2160195972f6Sopenharmony_ci		}
2161195972f6Sopenharmony_ci		GETCHAR(rtype, inp);
2162195972f6Sopenharmony_ci		len--;
2163195972f6Sopenharmony_ci		if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames))
2164195972f6Sopenharmony_ci			printer(arg, " %s", eap_typenames[rtype-1]);
2165195972f6Sopenharmony_ci		else
2166195972f6Sopenharmony_ci			printer(arg, " type=0x%x", rtype);
2167195972f6Sopenharmony_ci		switch (rtype) {
2168195972f6Sopenharmony_ci		case EAPT_IDENTITY:
2169195972f6Sopenharmony_ci		case EAPT_NOTIFICATION:
2170195972f6Sopenharmony_ci			if (len > 0) {
2171195972f6Sopenharmony_ci				printer(arg, " <Message ");
2172195972f6Sopenharmony_ci				ppp_print_string(inp, len, printer, arg);
2173195972f6Sopenharmony_ci				printer(arg, ">");
2174195972f6Sopenharmony_ci				INCPTR(len, inp);
2175195972f6Sopenharmony_ci				len = 0;
2176195972f6Sopenharmony_ci			} else {
2177195972f6Sopenharmony_ci				printer(arg, " <No message>");
2178195972f6Sopenharmony_ci			}
2179195972f6Sopenharmony_ci			break;
2180195972f6Sopenharmony_ci
2181195972f6Sopenharmony_ci		case EAPT_MD5CHAP:
2182195972f6Sopenharmony_ci			if (len <= 0)
2183195972f6Sopenharmony_ci				break;
2184195972f6Sopenharmony_ci			GETCHAR(vallen, inp);
2185195972f6Sopenharmony_ci			len--;
2186195972f6Sopenharmony_ci			if (vallen > len)
2187195972f6Sopenharmony_ci				goto truncated;
2188195972f6Sopenharmony_ci			printer(arg, " <Value%.*B>", vallen, inp);
2189195972f6Sopenharmony_ci			INCPTR(vallen, inp);
2190195972f6Sopenharmony_ci			len -= vallen;
2191195972f6Sopenharmony_ci			if (len > 0) {
2192195972f6Sopenharmony_ci				printer(arg, " <Name ");
2193195972f6Sopenharmony_ci				ppp_print_string(inp, len, printer, arg);
2194195972f6Sopenharmony_ci				printer(arg, ">");
2195195972f6Sopenharmony_ci				INCPTR(len, inp);
2196195972f6Sopenharmony_ci				len = 0;
2197195972f6Sopenharmony_ci			} else {
2198195972f6Sopenharmony_ci				printer(arg, " <No name>");
2199195972f6Sopenharmony_ci			}
2200195972f6Sopenharmony_ci			break;
2201195972f6Sopenharmony_ci
2202195972f6Sopenharmony_ci		case EAPT_SRP:
2203195972f6Sopenharmony_ci			if (len < 3)
2204195972f6Sopenharmony_ci				goto truncated;
2205195972f6Sopenharmony_ci			GETCHAR(vallen, inp);
2206195972f6Sopenharmony_ci			len--;
2207195972f6Sopenharmony_ci			printer(arg, "-%d", vallen);
2208195972f6Sopenharmony_ci			switch (vallen) {
2209195972f6Sopenharmony_ci			case EAPSRP_CHALLENGE:
2210195972f6Sopenharmony_ci				GETCHAR(vallen, inp);
2211195972f6Sopenharmony_ci				len--;
2212195972f6Sopenharmony_ci				if (vallen >= len)
2213195972f6Sopenharmony_ci					goto truncated;
2214195972f6Sopenharmony_ci				if (vallen > 0) {
2215195972f6Sopenharmony_ci					printer(arg, " <Name ");
2216195972f6Sopenharmony_ci					ppp_print_string(inp, vallen, printer,
2217195972f6Sopenharmony_ci					    arg);
2218195972f6Sopenharmony_ci					printer(arg, ">");
2219195972f6Sopenharmony_ci				} else {
2220195972f6Sopenharmony_ci					printer(arg, " <No name>");
2221195972f6Sopenharmony_ci				}
2222195972f6Sopenharmony_ci				INCPTR(vallen, inp);
2223195972f6Sopenharmony_ci				len -= vallen;
2224195972f6Sopenharmony_ci				GETCHAR(vallen, inp);
2225195972f6Sopenharmony_ci				len--;
2226195972f6Sopenharmony_ci				if (vallen >= len)
2227195972f6Sopenharmony_ci					goto truncated;
2228195972f6Sopenharmony_ci				printer(arg, " <s%.*B>", vallen, inp);
2229195972f6Sopenharmony_ci				INCPTR(vallen, inp);
2230195972f6Sopenharmony_ci				len -= vallen;
2231195972f6Sopenharmony_ci				GETCHAR(vallen, inp);
2232195972f6Sopenharmony_ci				len--;
2233195972f6Sopenharmony_ci				if (vallen > len)
2234195972f6Sopenharmony_ci					goto truncated;
2235195972f6Sopenharmony_ci				if (vallen == 0) {
2236195972f6Sopenharmony_ci					printer(arg, " <Default g=2>");
2237195972f6Sopenharmony_ci				} else {
2238195972f6Sopenharmony_ci					printer(arg, " <g%.*B>", vallen, inp);
2239195972f6Sopenharmony_ci				}
2240195972f6Sopenharmony_ci				INCPTR(vallen, inp);
2241195972f6Sopenharmony_ci				len -= vallen;
2242195972f6Sopenharmony_ci				if (len == 0) {
2243195972f6Sopenharmony_ci					printer(arg, " <Default N>");
2244195972f6Sopenharmony_ci				} else {
2245195972f6Sopenharmony_ci					printer(arg, " <N%.*B>", len, inp);
2246195972f6Sopenharmony_ci					INCPTR(len, inp);
2247195972f6Sopenharmony_ci					len = 0;
2248195972f6Sopenharmony_ci				}
2249195972f6Sopenharmony_ci				break;
2250195972f6Sopenharmony_ci
2251195972f6Sopenharmony_ci			case EAPSRP_SKEY:
2252195972f6Sopenharmony_ci				printer(arg, " <B%.*B>", len, inp);
2253195972f6Sopenharmony_ci				INCPTR(len, inp);
2254195972f6Sopenharmony_ci				len = 0;
2255195972f6Sopenharmony_ci				break;
2256195972f6Sopenharmony_ci
2257195972f6Sopenharmony_ci			case EAPSRP_SVALIDATOR:
2258195972f6Sopenharmony_ci				if (len < (int)sizeof (u32_t))
2259195972f6Sopenharmony_ci					break;
2260195972f6Sopenharmony_ci				GETLONG(uval, inp);
2261195972f6Sopenharmony_ci				len -= sizeof (u32_t);
2262195972f6Sopenharmony_ci				if (uval & SRPVAL_EBIT) {
2263195972f6Sopenharmony_ci					printer(arg, " E");
2264195972f6Sopenharmony_ci					uval &= ~SRPVAL_EBIT;
2265195972f6Sopenharmony_ci				}
2266195972f6Sopenharmony_ci				if (uval != 0) {
2267195972f6Sopenharmony_ci					printer(arg, " f<%X>", uval);
2268195972f6Sopenharmony_ci				}
2269195972f6Sopenharmony_ci				if ((vallen = len) > SHA_DIGESTSIZE)
2270195972f6Sopenharmony_ci					vallen = SHA_DIGESTSIZE;
2271195972f6Sopenharmony_ci				printer(arg, " <M2%.*B%s>", len, inp,
2272195972f6Sopenharmony_ci				    len < SHA_DIGESTSIZE ? "?" : "");
2273195972f6Sopenharmony_ci				INCPTR(vallen, inp);
2274195972f6Sopenharmony_ci				len -= vallen;
2275195972f6Sopenharmony_ci				if (len > 0) {
2276195972f6Sopenharmony_ci					printer(arg, " <PN%.*B>", len, inp);
2277195972f6Sopenharmony_ci					INCPTR(len, inp);
2278195972f6Sopenharmony_ci					len = 0;
2279195972f6Sopenharmony_ci				}
2280195972f6Sopenharmony_ci				break;
2281195972f6Sopenharmony_ci
2282195972f6Sopenharmony_ci			case EAPSRP_LWRECHALLENGE:
2283195972f6Sopenharmony_ci				printer(arg, " <Challenge%.*B>", len, inp);
2284195972f6Sopenharmony_ci				INCPTR(len, inp);
2285195972f6Sopenharmony_ci				len = 0;
2286195972f6Sopenharmony_ci				break;
2287195972f6Sopenharmony_ci			default:
2288195972f6Sopenharmony_ci				break;
2289195972f6Sopenharmony_ci			}
2290195972f6Sopenharmony_ci			break;
2291195972f6Sopenharmony_ci		default:
2292195972f6Sopenharmony_ci			break;
2293195972f6Sopenharmony_ci		}
2294195972f6Sopenharmony_ci		break;
2295195972f6Sopenharmony_ci
2296195972f6Sopenharmony_ci	case EAP_RESPONSE:
2297195972f6Sopenharmony_ci		if (len < 1)
2298195972f6Sopenharmony_ci			break;
2299195972f6Sopenharmony_ci		GETCHAR(rtype, inp);
2300195972f6Sopenharmony_ci		len--;
2301195972f6Sopenharmony_ci		if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames))
2302195972f6Sopenharmony_ci			printer(arg, " %s", eap_typenames[rtype-1]);
2303195972f6Sopenharmony_ci		else
2304195972f6Sopenharmony_ci			printer(arg, " type=0x%x", rtype);
2305195972f6Sopenharmony_ci		switch (rtype) {
2306195972f6Sopenharmony_ci		case EAPT_IDENTITY:
2307195972f6Sopenharmony_ci			if (len > 0) {
2308195972f6Sopenharmony_ci				printer(arg, " <Name ");
2309195972f6Sopenharmony_ci				ppp_print_string(inp, len, printer, arg);
2310195972f6Sopenharmony_ci				printer(arg, ">");
2311195972f6Sopenharmony_ci				INCPTR(len, inp);
2312195972f6Sopenharmony_ci				len = 0;
2313195972f6Sopenharmony_ci			}
2314195972f6Sopenharmony_ci			break;
2315195972f6Sopenharmony_ci
2316195972f6Sopenharmony_ci		case EAPT_NAK:
2317195972f6Sopenharmony_ci			if (len <= 0) {
2318195972f6Sopenharmony_ci				printer(arg, " <missing hint>");
2319195972f6Sopenharmony_ci				break;
2320195972f6Sopenharmony_ci			}
2321195972f6Sopenharmony_ci			GETCHAR(rtype, inp);
2322195972f6Sopenharmony_ci			len--;
2323195972f6Sopenharmony_ci			printer(arg, " <Suggested-type %02X", rtype);
2324195972f6Sopenharmony_ci			if (rtype >= 1 && rtype < (int)LWIP_ARRAYSIZE(eap_typenames))
2325195972f6Sopenharmony_ci				printer(arg, " (%s)", eap_typenames[rtype-1]);
2326195972f6Sopenharmony_ci			printer(arg, ">");
2327195972f6Sopenharmony_ci			break;
2328195972f6Sopenharmony_ci
2329195972f6Sopenharmony_ci		case EAPT_MD5CHAP:
2330195972f6Sopenharmony_ci			if (len <= 0) {
2331195972f6Sopenharmony_ci				printer(arg, " <missing length>");
2332195972f6Sopenharmony_ci				break;
2333195972f6Sopenharmony_ci			}
2334195972f6Sopenharmony_ci			GETCHAR(vallen, inp);
2335195972f6Sopenharmony_ci			len--;
2336195972f6Sopenharmony_ci			if (vallen > len)
2337195972f6Sopenharmony_ci				goto truncated;
2338195972f6Sopenharmony_ci			printer(arg, " <Value%.*B>", vallen, inp);
2339195972f6Sopenharmony_ci			INCPTR(vallen, inp);
2340195972f6Sopenharmony_ci			len -= vallen;
2341195972f6Sopenharmony_ci			if (len > 0) {
2342195972f6Sopenharmony_ci				printer(arg, " <Name ");
2343195972f6Sopenharmony_ci				ppp_print_string(inp, len, printer, arg);
2344195972f6Sopenharmony_ci				printer(arg, ">");
2345195972f6Sopenharmony_ci				INCPTR(len, inp);
2346195972f6Sopenharmony_ci				len = 0;
2347195972f6Sopenharmony_ci			} else {
2348195972f6Sopenharmony_ci				printer(arg, " <No name>");
2349195972f6Sopenharmony_ci			}
2350195972f6Sopenharmony_ci			break;
2351195972f6Sopenharmony_ci
2352195972f6Sopenharmony_ci		case EAPT_SRP:
2353195972f6Sopenharmony_ci			if (len < 1)
2354195972f6Sopenharmony_ci				goto truncated;
2355195972f6Sopenharmony_ci			GETCHAR(vallen, inp);
2356195972f6Sopenharmony_ci			len--;
2357195972f6Sopenharmony_ci			printer(arg, "-%d", vallen);
2358195972f6Sopenharmony_ci			switch (vallen) {
2359195972f6Sopenharmony_ci			case EAPSRP_CKEY:
2360195972f6Sopenharmony_ci				printer(arg, " <A%.*B>", len, inp);
2361195972f6Sopenharmony_ci				INCPTR(len, inp);
2362195972f6Sopenharmony_ci				len = 0;
2363195972f6Sopenharmony_ci				break;
2364195972f6Sopenharmony_ci
2365195972f6Sopenharmony_ci			case EAPSRP_CVALIDATOR:
2366195972f6Sopenharmony_ci				if (len < (int)sizeof (u32_t))
2367195972f6Sopenharmony_ci					break;
2368195972f6Sopenharmony_ci				GETLONG(uval, inp);
2369195972f6Sopenharmony_ci				len -= sizeof (u32_t);
2370195972f6Sopenharmony_ci				if (uval & SRPVAL_EBIT) {
2371195972f6Sopenharmony_ci					printer(arg, " E");
2372195972f6Sopenharmony_ci					uval &= ~SRPVAL_EBIT;
2373195972f6Sopenharmony_ci				}
2374195972f6Sopenharmony_ci				if (uval != 0) {
2375195972f6Sopenharmony_ci					printer(arg, " f<%X>", uval);
2376195972f6Sopenharmony_ci				}
2377195972f6Sopenharmony_ci				printer(arg, " <M1%.*B%s>", len, inp,
2378195972f6Sopenharmony_ci				    len == SHA_DIGESTSIZE ? "" : "?");
2379195972f6Sopenharmony_ci				INCPTR(len, inp);
2380195972f6Sopenharmony_ci				len = 0;
2381195972f6Sopenharmony_ci				break;
2382195972f6Sopenharmony_ci
2383195972f6Sopenharmony_ci			case EAPSRP_ACK:
2384195972f6Sopenharmony_ci				break;
2385195972f6Sopenharmony_ci
2386195972f6Sopenharmony_ci			case EAPSRP_LWRECHALLENGE:
2387195972f6Sopenharmony_ci				printer(arg, " <Response%.*B%s>", len, inp,
2388195972f6Sopenharmony_ci				    len == SHA_DIGESTSIZE ? "" : "?");
2389195972f6Sopenharmony_ci				if ((vallen = len) > SHA_DIGESTSIZE)
2390195972f6Sopenharmony_ci					vallen = SHA_DIGESTSIZE;
2391195972f6Sopenharmony_ci				INCPTR(vallen, inp);
2392195972f6Sopenharmony_ci				len -= vallen;
2393195972f6Sopenharmony_ci				break;
2394195972f6Sopenharmony_ci			default:
2395195972f6Sopenharmony_ci				break;
2396195972f6Sopenharmony_ci			}
2397195972f6Sopenharmony_ci			break;
2398195972f6Sopenharmony_ci		default:
2399195972f6Sopenharmony_ci			break;
2400195972f6Sopenharmony_ci		}
2401195972f6Sopenharmony_ci		break;
2402195972f6Sopenharmony_ci
2403195972f6Sopenharmony_ci	case EAP_SUCCESS:	/* No payload expected for these! */
2404195972f6Sopenharmony_ci	case EAP_FAILURE:
2405195972f6Sopenharmony_ci	default:
2406195972f6Sopenharmony_ci		break;
2407195972f6Sopenharmony_ci
2408195972f6Sopenharmony_ci	truncated:
2409195972f6Sopenharmony_ci		printer(arg, " <truncated>");
2410195972f6Sopenharmony_ci		break;
2411195972f6Sopenharmony_ci	}
2412195972f6Sopenharmony_ci
2413195972f6Sopenharmony_ci	if (len > 8)
2414195972f6Sopenharmony_ci		printer(arg, "%8B...", inp);
2415195972f6Sopenharmony_ci	else if (len > 0)
2416195972f6Sopenharmony_ci		printer(arg, "%.*B", len, inp);
2417195972f6Sopenharmony_ci	INCPTR(len, inp);
2418195972f6Sopenharmony_ci
2419195972f6Sopenharmony_ci	return (inp - pstart);
2420195972f6Sopenharmony_ci}
2421195972f6Sopenharmony_ci#endif /* PRINTPKT_SUPPORT */
2422195972f6Sopenharmony_ci
2423195972f6Sopenharmony_ci#endif /* PPP_SUPPORT && EAP_SUPPORT */
2424