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