1 1.5 christos /* $NetBSD: eap.c,v 1.7 2025/01/08 19:59:39 christos Exp $ */ 2 1.1 christos /* 3 1.1 christos * eap.c - Extensible Authentication Protocol for PPP (RFC 2284) 4 1.1 christos * 5 1.1 christos * Copyright (c) 2001 by Sun Microsystems, Inc. 6 1.1 christos * All rights reserved. 7 1.1 christos * 8 1.1 christos * Non-exclusive rights to redistribute, modify, translate, and use 9 1.1 christos * this software in source and binary forms, in whole or in part, is 10 1.1 christos * hereby granted, provided that the above copyright notice is 11 1.1 christos * duplicated in any source form, and that neither the name of the 12 1.1 christos * copyright holder nor the author is used to endorse or promote 13 1.1 christos * products derived from this software. 14 1.1 christos * 15 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 16 1.1 christos * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 17 1.1 christos * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 18 1.1 christos * 19 1.1 christos * Original version by James Carlson 20 1.1 christos * 21 1.1 christos * This implementation of EAP supports MD5-Challenge and SRP-SHA1 22 1.1 christos * authentication styles. Note that support of MD5-Challenge is a 23 1.1 christos * requirement of RFC 2284, and that it's essentially just a 24 1.1 christos * reimplementation of regular RFC 1994 CHAP using EAP messages. 25 1.1 christos * 26 1.1 christos * As an authenticator ("server"), there are multiple phases for each 27 1.1 christos * style. In the first phase of each style, the unauthenticated peer 28 1.1 christos * name is queried using the EAP Identity request type. If the 29 1.1 christos * "remotename" option is used, then this phase is skipped, because 30 1.1 christos * the peer's name is presumed to be known. 31 1.1 christos * 32 1.1 christos * For MD5-Challenge, there are two phases, and the second phase 33 1.1 christos * consists of sending the challenge itself and handling the 34 1.1 christos * associated response. 35 1.1 christos * 36 1.1 christos * For SRP-SHA1, there are four phases. The second sends 's', 'N', 37 1.1 christos * and 'g'. The reply contains 'A'. The third sends 'B', and the 38 1.1 christos * reply contains 'M1'. The forth sends the 'M2' value. 39 1.1 christos * 40 1.1 christos * As an authenticatee ("client"), there's just a single phase -- 41 1.1 christos * responding to the queries generated by the peer. EAP is an 42 1.1 christos * authenticator-driven protocol. 43 1.1 christos * 44 1.1 christos * Based on draft-ietf-pppext-eap-srp-03.txt. 45 1.1 christos */ 46 1.1 christos 47 1.2 christos #include <sys/cdefs.h> 48 1.5 christos __RCSID("$NetBSD: eap.c,v 1.7 2025/01/08 19:59:39 christos Exp $"); 49 1.1 christos 50 1.1 christos /* 51 1.6 christos * Modification by Beniamino Galvani, Mar 2005 52 1.6 christos * Implemented EAP-TLS authentication 53 1.1 christos */ 54 1.1 christos 55 1.7 christos #ifdef HAVE_CONFIG_H 56 1.7 christos #include "config.h" 57 1.7 christos #endif 58 1.7 christos 59 1.1 christos #include <stdio.h> 60 1.1 christos #include <stdlib.h> 61 1.1 christos #include <string.h> 62 1.1 christos #include <unistd.h> 63 1.1 christos #include <pwd.h> 64 1.1 christos #include <sys/types.h> 65 1.1 christos #include <sys/stat.h> 66 1.1 christos #include <fcntl.h> 67 1.1 christos #include <assert.h> 68 1.1 christos #include <errno.h> 69 1.2 christos #include <md5.h> 70 1.1 christos 71 1.7 christos #include "pppd-private.h" 72 1.7 christos #include "options.h" 73 1.1 christos #include "pathnames.h" 74 1.7 christos #include "crypto.h" 75 1.7 christos #include "crypto_ms.h" 76 1.1 christos #include "eap.h" 77 1.7 christos #ifdef PPP_WITH_PEAP 78 1.7 christos #include "peap.h" 79 1.7 christos #endif /* PPP_WITH_PEAP */ 80 1.7 christos 81 1.7 christos #ifdef PPP_WITH_SRP 82 1.7 christos #ifdef HAVE_TIME_H 83 1.7 christos #include <time.h> 84 1.6 christos #endif 85 1.1 christos #include <t_pwd.h> 86 1.1 christos #include <t_server.h> 87 1.1 christos #include <t_client.h> 88 1.7 christos #endif /* PPP_WITH_SRP */ 89 1.1 christos 90 1.7 christos #ifdef PPP_WITH_EAPTLS 91 1.7 christos #include "eap-tls.h" 92 1.7 christos #endif /* PPP_WITH_EAPTLS */ 93 1.1 christos 94 1.7 christos #ifdef PPP_WITH_CHAPMS 95 1.7 christos #include "chap.h" 96 1.6 christos #include "chap_ms.h" 97 1.7 christos 98 1.7 christos extern int chapms_strip_domain; 99 1.7 christos #endif /* PPP_WITH_CHAPMS */ 100 1.1 christos 101 1.1 christos eap_state eap_states[NUM_PPP]; /* EAP state; one for each unit */ 102 1.7 christos #ifdef PPP_WITH_SRP 103 1.1 christos static char *pn_secret = NULL; /* Pseudonym generating secret */ 104 1.1 christos #endif 105 1.1 christos 106 1.1 christos /* 107 1.1 christos * Command-line options. 108 1.1 christos */ 109 1.7 christos static struct option eap_option_list[] = { 110 1.1 christos { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout, 111 1.1 christos "Set retransmit timeout for EAP Requests (server)" }, 112 1.1 christos { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests, 113 1.1 christos "Set max number of EAP Requests sent (server)" }, 114 1.1 christos { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout, 115 1.1 christos "Set time limit for peer EAP authentication" }, 116 1.1 christos { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests, 117 1.1 christos "Set max number of EAP Requests allows (client)" }, 118 1.1 christos { "eap-interval", o_int, &eap_states[0].es_rechallenge, 119 1.1 christos "Set interval for EAP rechallenge" }, 120 1.7 christos #ifdef PPP_WITH_SRP 121 1.1 christos { "srp-interval", o_int, &eap_states[0].es_lwrechallenge, 122 1.1 christos "Set interval for SRP lightweight rechallenge" }, 123 1.1 christos { "srp-pn-secret", o_string, &pn_secret, 124 1.1 christos "Long term pseudonym generation secret" }, 125 1.1 christos { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo, 126 1.1 christos "Use pseudonym if offered one by server", 1 }, 127 1.1 christos #endif 128 1.1 christos { NULL } 129 1.1 christos }; 130 1.1 christos 131 1.1 christos /* 132 1.1 christos * Protocol entry points. 133 1.1 christos */ 134 1.6 christos static void eap_init (int unit); 135 1.6 christos static void eap_input (int unit, u_char *inp, int inlen); 136 1.6 christos static void eap_protrej (int unit); 137 1.6 christos static void eap_lowerup (int unit); 138 1.6 christos static void eap_lowerdown (int unit); 139 1.6 christos static int eap_printpkt (u_char *inp, int inlen, 140 1.6 christos void (*)(void *arg, char *fmt, ...), void *arg); 141 1.1 christos 142 1.1 christos struct protent eap_protent = { 143 1.1 christos PPP_EAP, /* protocol number */ 144 1.1 christos eap_init, /* initialization procedure */ 145 1.1 christos eap_input, /* process a received packet */ 146 1.1 christos eap_protrej, /* process a received protocol-reject */ 147 1.1 christos eap_lowerup, /* lower layer has gone up */ 148 1.1 christos eap_lowerdown, /* lower layer has gone down */ 149 1.1 christos NULL, /* open the protocol */ 150 1.1 christos NULL, /* close the protocol */ 151 1.1 christos eap_printpkt, /* print a packet in readable form */ 152 1.1 christos NULL, /* process a received data packet */ 153 1.1 christos 1, /* protocol enabled */ 154 1.1 christos "EAP", /* text name of protocol */ 155 1.1 christos NULL, /* text name of corresponding data protocol */ 156 1.1 christos eap_option_list, /* list of command-line options */ 157 1.1 christos NULL, /* check requested options; assign defaults */ 158 1.1 christos NULL, /* configure interface for demand-dial */ 159 1.1 christos NULL /* say whether to bring up link for this pkt */ 160 1.1 christos }; 161 1.1 christos 162 1.7 christos #ifdef PPP_WITH_SRP 163 1.1 christos /* 164 1.1 christos * A well-known 2048 bit modulus. 165 1.1 christos */ 166 1.1 christos static const u_char wkmodulus[] = { 167 1.1 christos 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, 168 1.1 christos 0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F, 169 1.1 christos 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, 170 1.1 christos 0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50, 171 1.1 christos 0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED, 172 1.1 christos 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D, 173 1.1 christos 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, 174 1.1 christos 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50, 175 1.1 christos 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0, 176 1.1 christos 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, 177 1.1 christos 0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, 178 1.1 christos 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8, 179 1.1 christos 0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, 180 1.1 christos 0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74, 181 1.1 christos 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7, 182 1.1 christos 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B, 183 1.1 christos 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16, 184 1.1 christos 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81, 185 1.1 christos 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, 186 1.1 christos 0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48, 187 1.1 christos 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, 188 1.1 christos 0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA, 189 1.1 christos 0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78, 190 1.1 christos 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6, 191 1.1 christos 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, 192 1.1 christos 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8, 193 1.1 christos 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82, 194 1.1 christos 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, 195 1.1 christos 0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, 196 1.1 christos 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75, 197 1.1 christos 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, 198 1.1 christos 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73 199 1.1 christos }; 200 1.7 christos #endif /* PPP_WITH_SRP */ 201 1.1 christos 202 1.1 christos /* Local forward declarations. */ 203 1.6 christos static void eap_server_timeout (void *arg); 204 1.1 christos 205 1.1 christos /* 206 1.1 christos * Convert EAP state code to printable string for debug. 207 1.1 christos */ 208 1.1 christos static const char * 209 1.6 christos eap_state_name(enum eap_state_code esc) 210 1.1 christos { 211 1.1 christos static const char *state_names[] = { EAP_STATES }; 212 1.1 christos 213 1.1 christos return (state_names[(int)esc]); 214 1.1 christos } 215 1.1 christos 216 1.1 christos /* 217 1.1 christos * eap_init - Initialize state for an EAP user. This is currently 218 1.1 christos * called once by main() during start-up. 219 1.1 christos */ 220 1.1 christos static void 221 1.6 christos eap_init(int unit) 222 1.1 christos { 223 1.1 christos eap_state *esp = &eap_states[unit]; 224 1.1 christos 225 1.1 christos BZERO(esp, sizeof (*esp)); 226 1.1 christos esp->es_unit = unit; 227 1.1 christos esp->es_server.ea_timeout = EAP_DEFTIMEOUT; 228 1.1 christos esp->es_server.ea_maxrequests = EAP_DEFTRANSMITS; 229 1.1 christos esp->es_server.ea_id = (u_char)(drand48() * 0x100); 230 1.1 christos esp->es_client.ea_timeout = EAP_DEFREQTIME; 231 1.1 christos esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ; 232 1.7 christos #ifdef PPP_WITH_EAPTLS 233 1.6 christos esp->es_client.ea_using_eaptls = 0; 234 1.7 christos #endif /* PPP_WITH_EAPTLS */ 235 1.7 christos #ifdef PPP_WITH_CHAPMS 236 1.7 christos esp->es_client.digest = chap_find_digest(CHAP_MICROSOFT_V2); 237 1.7 christos esp->es_server.digest = chap_find_digest(CHAP_MICROSOFT_V2); 238 1.6 christos #endif 239 1.1 christos } 240 1.1 christos 241 1.1 christos /* 242 1.1 christos * eap_client_timeout - Give up waiting for the peer to send any 243 1.1 christos * Request messages. 244 1.1 christos */ 245 1.1 christos static void 246 1.6 christos eap_client_timeout(void *arg) 247 1.1 christos { 248 1.1 christos eap_state *esp = (eap_state *) arg; 249 1.1 christos 250 1.1 christos if (!eap_client_active(esp)) 251 1.1 christos return; 252 1.1 christos 253 1.1 christos error("EAP: timeout waiting for Request from peer"); 254 1.1 christos auth_withpeer_fail(esp->es_unit, PPP_EAP); 255 1.1 christos esp->es_client.ea_state = eapBadAuth; 256 1.1 christos } 257 1.1 christos 258 1.1 christos /* 259 1.1 christos * eap_authwithpeer - Authenticate to our peer (behave as client). 260 1.1 christos * 261 1.1 christos * Start client state and wait for requests. This is called only 262 1.1 christos * after eap_lowerup. 263 1.1 christos */ 264 1.1 christos void 265 1.6 christos eap_authwithpeer(int unit, char *localname) 266 1.1 christos { 267 1.1 christos eap_state *esp = &eap_states[unit]; 268 1.1 christos 269 1.1 christos /* Save the peer name we're given */ 270 1.1 christos esp->es_client.ea_name = localname; 271 1.1 christos esp->es_client.ea_namelen = strlen(localname); 272 1.1 christos 273 1.1 christos esp->es_client.ea_state = eapListen; 274 1.1 christos 275 1.1 christos /* 276 1.1 christos * Start a timer so that if the other end just goes 277 1.1 christos * silent, we don't sit here waiting forever. 278 1.1 christos */ 279 1.1 christos if (esp->es_client.ea_timeout > 0) 280 1.1 christos TIMEOUT(eap_client_timeout, (void *)esp, 281 1.1 christos esp->es_client.ea_timeout); 282 1.1 christos } 283 1.1 christos 284 1.1 christos /* 285 1.1 christos * Format a standard EAP Failure message and send it to the peer. 286 1.1 christos * (Server operation) 287 1.1 christos */ 288 1.1 christos static void 289 1.6 christos eap_send_failure(eap_state *esp) 290 1.1 christos { 291 1.1 christos u_char *outp; 292 1.1 christos 293 1.1 christos outp = outpacket_buf; 294 1.1 christos 295 1.1 christos MAKEHEADER(outp, PPP_EAP); 296 1.1 christos 297 1.1 christos PUTCHAR(EAP_FAILURE, outp); 298 1.1 christos esp->es_server.ea_id++; 299 1.1 christos PUTCHAR(esp->es_server.ea_id, outp); 300 1.1 christos PUTSHORT(EAP_HEADERLEN, outp); 301 1.1 christos 302 1.1 christos output(esp->es_unit, outpacket_buf, EAP_HEADERLEN + PPP_HDRLEN); 303 1.1 christos 304 1.1 christos esp->es_server.ea_state = eapBadAuth; 305 1.1 christos auth_peer_fail(esp->es_unit, PPP_EAP); 306 1.1 christos } 307 1.1 christos 308 1.1 christos /* 309 1.1 christos * Format a standard EAP Success message and send it to the peer. 310 1.1 christos * (Server operation) 311 1.1 christos */ 312 1.1 christos static void 313 1.6 christos eap_send_success(eap_state *esp) 314 1.1 christos { 315 1.1 christos u_char *outp; 316 1.1 christos 317 1.1 christos outp = outpacket_buf; 318 1.1 christos 319 1.1 christos MAKEHEADER(outp, PPP_EAP); 320 1.1 christos 321 1.1 christos PUTCHAR(EAP_SUCCESS, outp); 322 1.1 christos esp->es_server.ea_id++; 323 1.1 christos PUTCHAR(esp->es_server.ea_id, outp); 324 1.1 christos PUTSHORT(EAP_HEADERLEN, outp); 325 1.1 christos 326 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + EAP_HEADERLEN); 327 1.1 christos 328 1.1 christos auth_peer_success(esp->es_unit, PPP_EAP, 0, 329 1.1 christos esp->es_server.ea_peer, esp->es_server.ea_peerlen); 330 1.1 christos } 331 1.1 christos 332 1.7 christos #ifdef PPP_WITH_SRP 333 1.1 christos /* 334 1.1 christos * Set DES key according to pseudonym-generating secret and current 335 1.1 christos * date. 336 1.1 christos */ 337 1.1 christos static bool 338 1.7 christos pncrypt_getkey(int timeoffs, unsigned char *key, int keylen) 339 1.1 christos { 340 1.1 christos struct tm *tp; 341 1.1 christos char tbuf[9]; 342 1.7 christos PPP_MD_CTX *ctxt; 343 1.1 christos time_t reftime; 344 1.1 christos 345 1.1 christos if (pn_secret == NULL) 346 1.1 christos return (0); 347 1.1 christos reftime = time(NULL) + timeoffs; 348 1.1 christos tp = localtime(&reftime); 349 1.7 christos 350 1.7 christos ctxt = PPP_MD_CTX_new(); 351 1.7 christos if (ctxt) { 352 1.7 christos 353 1.7 christos strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp); 354 1.7 christos 355 1.7 christos PPP_DigestInit(ctxt, PPP_sha1()); 356 1.7 christos PPP_DigestUpdate(ctxt, pn_secret, strlen(pn_secret)); 357 1.7 christos PPP_DigestUpdate(ctxt, tbuf, strlen(tbuf)); 358 1.7 christos PPP_DigestFinal(ctxt, key, &keylen); 359 1.7 christos 360 1.7 christos PPP_MD_CTX_free(ctxt); 361 1.7 christos return 1; 362 1.7 christos } 363 1.7 christos 364 1.7 christos return (0); 365 1.1 christos } 366 1.1 christos 367 1.1 christos static char base64[] = 368 1.1 christos "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 369 1.1 christos 370 1.1 christos struct b64state { 371 1.1 christos u_int32_t bs_bits; 372 1.1 christos int bs_offs; 373 1.1 christos }; 374 1.1 christos 375 1.1 christos static int 376 1.6 christos b64enc(struct b64state *bs, u_char *inp, int inlen, u_char *outp) 377 1.1 christos { 378 1.1 christos int outlen = 0; 379 1.1 christos 380 1.1 christos while (inlen > 0) { 381 1.1 christos bs->bs_bits = (bs->bs_bits << 8) | *inp++; 382 1.1 christos inlen--; 383 1.1 christos bs->bs_offs += 8; 384 1.1 christos if (bs->bs_offs >= 24) { 385 1.1 christos *outp++ = base64[(bs->bs_bits >> 18) & 0x3F]; 386 1.1 christos *outp++ = base64[(bs->bs_bits >> 12) & 0x3F]; 387 1.1 christos *outp++ = base64[(bs->bs_bits >> 6) & 0x3F]; 388 1.1 christos *outp++ = base64[bs->bs_bits & 0x3F]; 389 1.1 christos outlen += 4; 390 1.1 christos bs->bs_offs = 0; 391 1.1 christos bs->bs_bits = 0; 392 1.1 christos } 393 1.1 christos } 394 1.1 christos return (outlen); 395 1.1 christos } 396 1.1 christos 397 1.1 christos static int 398 1.6 christos b64flush(struct b64state *bs, u_char *outp) 399 1.1 christos { 400 1.1 christos int outlen = 0; 401 1.1 christos 402 1.1 christos if (bs->bs_offs == 8) { 403 1.1 christos *outp++ = base64[(bs->bs_bits >> 2) & 0x3F]; 404 1.1 christos *outp++ = base64[(bs->bs_bits << 4) & 0x3F]; 405 1.1 christos outlen = 2; 406 1.1 christos } else if (bs->bs_offs == 16) { 407 1.1 christos *outp++ = base64[(bs->bs_bits >> 10) & 0x3F]; 408 1.1 christos *outp++ = base64[(bs->bs_bits >> 4) & 0x3F]; 409 1.1 christos *outp++ = base64[(bs->bs_bits << 2) & 0x3F]; 410 1.1 christos outlen = 3; 411 1.1 christos } 412 1.1 christos bs->bs_offs = 0; 413 1.1 christos bs->bs_bits = 0; 414 1.1 christos return (outlen); 415 1.1 christos } 416 1.1 christos 417 1.1 christos static int 418 1.6 christos b64dec(struct b64state *bs, u_char *inp, int inlen, u_char *outp) 419 1.1 christos { 420 1.1 christos int outlen = 0; 421 1.1 christos char *cp; 422 1.1 christos 423 1.1 christos while (inlen > 0) { 424 1.1 christos if ((cp = strchr(base64, *inp++)) == NULL) 425 1.1 christos break; 426 1.1 christos bs->bs_bits = (bs->bs_bits << 6) | (cp - base64); 427 1.1 christos inlen--; 428 1.1 christos bs->bs_offs += 6; 429 1.1 christos if (bs->bs_offs >= 8) { 430 1.1 christos *outp++ = bs->bs_bits >> (bs->bs_offs - 8); 431 1.1 christos outlen++; 432 1.1 christos bs->bs_offs -= 8; 433 1.1 christos } 434 1.1 christos } 435 1.1 christos return (outlen); 436 1.1 christos } 437 1.7 christos #endif /* PPP_WITH_SRP */ 438 1.1 christos 439 1.1 christos /* 440 1.1 christos * Assume that current waiting server state is complete and figure 441 1.1 christos * next state to use based on available authentication data. 'status' 442 1.1 christos * indicates if there was an error in handling the last query. It is 443 1.1 christos * 0 for success and non-zero for failure. 444 1.1 christos */ 445 1.1 christos static void 446 1.6 christos eap_figure_next_state(eap_state *esp, int status) 447 1.1 christos { 448 1.7 christos #ifdef PPP_WITH_SRP 449 1.7 christos unsigned char secbuf[MAXWORDLEN], clear[8], *sp, *dp, key[SHA_DIGEST_LENGTH]; 450 1.1 christos struct t_pw tpw; 451 1.1 christos struct t_confent *tce, mytce; 452 1.1 christos char *cp, *cp2; 453 1.1 christos struct t_server *ts; 454 1.7 christos int id, i, plen, clen, toffs, keylen; 455 1.1 christos u_char vals[2]; 456 1.1 christos struct b64state bs; 457 1.7 christos #endif /* PPP_WITH_SRP */ 458 1.7 christos #ifdef PPP_WITH_EAPTLS 459 1.6 christos struct eaptls_session *ets; 460 1.6 christos int secret_len; 461 1.6 christos char secret[MAXWORDLEN]; 462 1.7 christos #endif /* PPP_WITH_EAPTLS */ 463 1.1 christos 464 1.1 christos esp->es_server.ea_timeout = esp->es_savedtime; 465 1.7 christos #ifdef PPP_WITH_EAPTLS 466 1.6 christos esp->es_server.ea_prev_state = esp->es_server.ea_state; 467 1.7 christos #endif /* PPP_WITH_EAPTLS */ 468 1.1 christos switch (esp->es_server.ea_state) { 469 1.1 christos case eapBadAuth: 470 1.1 christos return; 471 1.1 christos 472 1.1 christos case eapIdentify: 473 1.7 christos #ifdef PPP_WITH_SRP 474 1.1 christos /* Discard any previous session. */ 475 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 476 1.1 christos if (ts != NULL) { 477 1.1 christos t_serverclose(ts); 478 1.1 christos esp->es_server.ea_session = NULL; 479 1.1 christos esp->es_server.ea_skey = NULL; 480 1.1 christos } 481 1.7 christos #endif /* PPP_WITH_SRP */ 482 1.1 christos if (status != 0) { 483 1.1 christos esp->es_server.ea_state = eapBadAuth; 484 1.1 christos break; 485 1.1 christos } 486 1.7 christos #ifdef PPP_WITH_SRP 487 1.1 christos /* If we've got a pseudonym, try to decode to real name. */ 488 1.1 christos if (esp->es_server.ea_peerlen > SRP_PSEUDO_LEN && 489 1.1 christos strncmp(esp->es_server.ea_peer, SRP_PSEUDO_ID, 490 1.1 christos SRP_PSEUDO_LEN) == 0 && 491 1.1 christos (esp->es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 < 492 1.1 christos sizeof (secbuf)) { 493 1.1 christos BZERO(&bs, sizeof (bs)); 494 1.1 christos plen = b64dec(&bs, 495 1.1 christos esp->es_server.ea_peer + SRP_PSEUDO_LEN, 496 1.1 christos esp->es_server.ea_peerlen - SRP_PSEUDO_LEN, 497 1.1 christos secbuf); 498 1.1 christos toffs = 0; 499 1.1 christos for (i = 0; i < 5; i++) { 500 1.7 christos pncrypt_getkey(toffs, key, keylen); 501 1.1 christos toffs -= 86400; 502 1.7 christos 503 1.7 christos if (!DesDecrypt(secbuf, key, clear)) { 504 1.1 christos dbglog("no DES here; cannot decode " 505 1.7 christos "pseudonym"); 506 1.1 christos return; 507 1.1 christos } 508 1.1 christos id = *(unsigned char *)clear; 509 1.1 christos if (id + 1 <= plen && id + 9 > plen) 510 1.1 christos break; 511 1.1 christos } 512 1.1 christos if (plen % 8 == 0 && i < 5) { 513 1.1 christos /* 514 1.1 christos * Note that this is always shorter than the 515 1.1 christos * original stored string, so there's no need 516 1.1 christos * to realloc. 517 1.1 christos */ 518 1.1 christos if ((i = plen = *(unsigned char *)clear) > 7) 519 1.1 christos i = 7; 520 1.1 christos esp->es_server.ea_peerlen = plen; 521 1.1 christos dp = (unsigned char *)esp->es_server.ea_peer; 522 1.1 christos BCOPY(clear + 1, dp, i); 523 1.1 christos plen -= i; 524 1.1 christos dp += i; 525 1.1 christos sp = secbuf + 8; 526 1.1 christos while (plen > 0) { 527 1.7 christos DesDecrypt(sp, key, dp); 528 1.1 christos sp += 8; 529 1.1 christos dp += 8; 530 1.1 christos plen -= 8; 531 1.1 christos } 532 1.1 christos esp->es_server.ea_peer[ 533 1.1 christos esp->es_server.ea_peerlen] = '\0'; 534 1.1 christos dbglog("decoded pseudonym to \"%.*q\"", 535 1.1 christos esp->es_server.ea_peerlen, 536 1.1 christos esp->es_server.ea_peer); 537 1.1 christos } else { 538 1.1 christos dbglog("failed to decode real name"); 539 1.1 christos /* Stay in eapIdentfy state; requery */ 540 1.1 christos break; 541 1.1 christos } 542 1.1 christos } 543 1.1 christos /* Look up user in secrets database. */ 544 1.1 christos if (get_srp_secret(esp->es_unit, esp->es_server.ea_peer, 545 1.1 christos esp->es_server.ea_name, (char *)secbuf, 1) != 0) { 546 1.1 christos /* Set up default in case SRP entry is bad */ 547 1.1 christos esp->es_server.ea_state = eapMD5Chall; 548 1.1 christos /* Get t_confent based on index in srp-secrets */ 549 1.1 christos id = strtol((char *)secbuf, &cp, 10); 550 1.1 christos if (*cp++ != ':' || id < 0) 551 1.1 christos break; 552 1.1 christos if (id == 0) { 553 1.1 christos mytce.index = 0; 554 1.1 christos mytce.modulus.data = (u_char *)wkmodulus; 555 1.1 christos mytce.modulus.len = sizeof (wkmodulus); 556 1.1 christos mytce.generator.data = (u_char *)"\002"; 557 1.1 christos mytce.generator.len = 1; 558 1.1 christos tce = &mytce; 559 1.1 christos } else if ((tce = gettcid(id)) != NULL) { 560 1.1 christos /* 561 1.1 christos * Client will have to verify this modulus/ 562 1.1 christos * generator combination, and that will take 563 1.1 christos * a while. Lengthen the timeout here. 564 1.1 christos */ 565 1.1 christos if (esp->es_server.ea_timeout > 0 && 566 1.1 christos esp->es_server.ea_timeout < 30) 567 1.1 christos esp->es_server.ea_timeout = 30; 568 1.1 christos } else { 569 1.1 christos break; 570 1.1 christos } 571 1.1 christos if ((cp2 = strchr(cp, ':')) == NULL) 572 1.1 christos break; 573 1.1 christos *cp2++ = '\0'; 574 1.1 christos tpw.pebuf.name = esp->es_server.ea_peer; 575 1.1 christos tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf, 576 1.1 christos cp); 577 1.7 christos tpw.pebuf.password.data = (char*) tpw.pwbuf; 578 1.1 christos tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf, 579 1.1 christos cp2); 580 1.1 christos tpw.pebuf.salt.data = tpw.saltbuf; 581 1.1 christos if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL) 582 1.1 christos break; 583 1.1 christos esp->es_server.ea_session = (void *)ts; 584 1.1 christos esp->es_server.ea_state = eapSRP1; 585 1.1 christos vals[0] = esp->es_server.ea_id + 1; 586 1.1 christos vals[1] = EAPT_SRP; 587 1.1 christos t_serveraddexdata(ts, vals, 2); 588 1.1 christos /* Generate B; must call before t_servergetkey() */ 589 1.1 christos t_servergenexp(ts); 590 1.1 christos break; 591 1.1 christos } 592 1.7 christos #endif /* PPP_WITH_SRP */ 593 1.7 christos #ifdef PPP_WITH_EAPTLS 594 1.6 christos if (!get_secret(esp->es_unit, esp->es_server.ea_peer, 595 1.6 christos esp->es_server.ea_name, secret, &secret_len, 1)) { 596 1.6 christos 597 1.6 christos esp->es_server.ea_state = eapTlsStart; 598 1.6 christos break; 599 1.6 christos } 600 1.7 christos #endif /* PPP_WITH_EAPTLS */ 601 1.6 christos 602 1.1 christos esp->es_server.ea_state = eapMD5Chall; 603 1.1 christos break; 604 1.1 christos 605 1.7 christos #ifdef PPP_WITH_EAPTLS 606 1.6 christos case eapTlsStart: 607 1.6 christos /* Initialize ssl session */ 608 1.6 christos if(!eaptls_init_ssl_server(esp)) { 609 1.6 christos esp->es_server.ea_state = eapBadAuth; 610 1.6 christos break; 611 1.6 christos } 612 1.6 christos 613 1.6 christos esp->es_server.ea_state = eapTlsRecv; 614 1.6 christos break; 615 1.6 christos 616 1.6 christos case eapTlsRecv: 617 1.6 christos ets = (struct eaptls_session *) esp->es_server.ea_session; 618 1.6 christos 619 1.6 christos if(ets->alert_sent) { 620 1.6 christos esp->es_server.ea_state = eapTlsSendAlert; 621 1.6 christos break; 622 1.6 christos } 623 1.6 christos 624 1.6 christos if (status) { 625 1.6 christos esp->es_server.ea_state = eapBadAuth; 626 1.6 christos break; 627 1.6 christos } 628 1.6 christos ets = (struct eaptls_session *) esp->es_server.ea_session; 629 1.6 christos 630 1.6 christos if(ets->frag) 631 1.6 christos esp->es_server.ea_state = eapTlsSendAck; 632 1.6 christos else 633 1.6 christos esp->es_server.ea_state = eapTlsSend; 634 1.6 christos break; 635 1.6 christos 636 1.6 christos case eapTlsSend: 637 1.6 christos ets = (struct eaptls_session *) esp->es_server.ea_session; 638 1.6 christos 639 1.6 christos if(ets->frag) 640 1.6 christos esp->es_server.ea_state = eapTlsRecvAck; 641 1.6 christos else 642 1.6 christos if(SSL_is_init_finished(ets->ssl)) 643 1.6 christos esp->es_server.ea_state = eapTlsRecvClient; 644 1.6 christos else 645 1.6 christos /* JJK Add "TLS empty record" message here ??? */ 646 1.6 christos esp->es_server.ea_state = eapTlsRecv; 647 1.6 christos break; 648 1.6 christos 649 1.6 christos case eapTlsSendAck: 650 1.6 christos esp->es_server.ea_state = eapTlsRecv; 651 1.6 christos break; 652 1.6 christos 653 1.6 christos case eapTlsRecvAck: 654 1.6 christos if (status) 655 1.6 christos { 656 1.6 christos esp->es_server.ea_state = eapBadAuth; 657 1.6 christos break; 658 1.6 christos } 659 1.6 christos 660 1.6 christos esp->es_server.ea_state = eapTlsSend; 661 1.6 christos break; 662 1.6 christos 663 1.6 christos case eapTlsSendAlert: 664 1.6 christos esp->es_server.ea_state = eapTlsRecvAlertAck; 665 1.6 christos break; 666 1.7 christos #endif /* PPP_WITH_EAPTLS */ 667 1.6 christos 668 1.1 christos case eapSRP1: 669 1.7 christos #ifdef PPP_WITH_SRP 670 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 671 1.1 christos if (ts != NULL && status != 0) { 672 1.1 christos t_serverclose(ts); 673 1.1 christos esp->es_server.ea_session = NULL; 674 1.1 christos esp->es_server.ea_skey = NULL; 675 1.1 christos } 676 1.7 christos #endif /* PPP_WITH_SRP */ 677 1.1 christos if (status == 1) { 678 1.1 christos esp->es_server.ea_state = eapMD5Chall; 679 1.1 christos } else if (status != 0 || esp->es_server.ea_session == NULL) { 680 1.1 christos esp->es_server.ea_state = eapBadAuth; 681 1.1 christos } else { 682 1.1 christos esp->es_server.ea_state = eapSRP2; 683 1.1 christos } 684 1.1 christos break; 685 1.1 christos 686 1.1 christos case eapSRP2: 687 1.7 christos #ifdef PPP_WITH_SRP 688 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 689 1.1 christos if (ts != NULL && status != 0) { 690 1.1 christos t_serverclose(ts); 691 1.1 christos esp->es_server.ea_session = NULL; 692 1.1 christos esp->es_server.ea_skey = NULL; 693 1.1 christos } 694 1.7 christos #endif /* PPP_WITH_SRP */ 695 1.1 christos if (status != 0 || esp->es_server.ea_session == NULL) { 696 1.1 christos esp->es_server.ea_state = eapBadAuth; 697 1.1 christos } else { 698 1.1 christos esp->es_server.ea_state = eapSRP3; 699 1.1 christos } 700 1.1 christos break; 701 1.1 christos 702 1.1 christos case eapSRP3: 703 1.1 christos case eapSRP4: 704 1.7 christos #ifdef PPP_WITH_SRP 705 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 706 1.1 christos if (ts != NULL && status != 0) { 707 1.1 christos t_serverclose(ts); 708 1.1 christos esp->es_server.ea_session = NULL; 709 1.1 christos esp->es_server.ea_skey = NULL; 710 1.1 christos } 711 1.7 christos #endif /* PPP_WITH_SRP */ 712 1.1 christos if (status != 0 || esp->es_server.ea_session == NULL) { 713 1.1 christos esp->es_server.ea_state = eapBadAuth; 714 1.1 christos } else { 715 1.1 christos esp->es_server.ea_state = eapOpen; 716 1.1 christos } 717 1.1 christos break; 718 1.1 christos 719 1.7 christos #ifdef PPP_WITH_CHAPMS 720 1.6 christos case eapMSCHAPv2Chall: 721 1.6 christos #endif 722 1.1 christos case eapMD5Chall: 723 1.1 christos if (status != 0) { 724 1.1 christos esp->es_server.ea_state = eapBadAuth; 725 1.1 christos } else { 726 1.1 christos esp->es_server.ea_state = eapOpen; 727 1.1 christos } 728 1.1 christos break; 729 1.1 christos 730 1.1 christos default: 731 1.1 christos esp->es_server.ea_state = eapBadAuth; 732 1.1 christos break; 733 1.1 christos } 734 1.1 christos if (esp->es_server.ea_state == eapBadAuth) 735 1.1 christos eap_send_failure(esp); 736 1.6 christos 737 1.7 christos #ifdef PPP_WITH_EAPTLS 738 1.6 christos dbglog("EAP id=0x%2x '%s' -> '%s'", esp->es_server.ea_id, eap_state_name(esp->es_server.ea_prev_state), eap_state_name(esp->es_server.ea_state)); 739 1.7 christos #endif /* PPP_WITH_EAPTLS */ 740 1.6 christos } 741 1.6 christos 742 1.7 christos #if PPP_WITH_CHAPMS 743 1.6 christos /* 744 1.6 christos * eap_chap_verify_response - check whether the peer's response matches 745 1.6 christos * what we think it should be. Returns 1 if it does (authentication 746 1.6 christos * succeeded), or 0 if it doesn't. 747 1.6 christos */ 748 1.6 christos static int 749 1.6 christos eap_chap_verify_response(char *name, char *ourname, int id, 750 1.6 christos struct chap_digest_type *digest, 751 1.6 christos unsigned char *challenge, unsigned char *response, 752 1.6 christos char *message, int message_space) 753 1.6 christos { 754 1.6 christos int ok; 755 1.6 christos unsigned char secret[MAXSECRETLEN]; 756 1.6 christos int secret_len; 757 1.6 christos 758 1.6 christos /* Get the secret that the peer is supposed to know */ 759 1.6 christos if (!get_secret(0, name, ourname, (char *)secret, &secret_len, 1)) { 760 1.6 christos error("No CHAP secret found for authenticating %q", name); 761 1.6 christos return 0; 762 1.6 christos } 763 1.6 christos 764 1.6 christos ok = digest->verify_response(id, name, secret, secret_len, challenge, 765 1.6 christos response, message, message_space); 766 1.6 christos memset(secret, 0, sizeof(secret)); 767 1.6 christos 768 1.6 christos return ok; 769 1.1 christos } 770 1.1 christos 771 1.1 christos /* 772 1.6 christos * Format and send an CHAPV2-Success/Failure EAP Request message. 773 1.6 christos */ 774 1.6 christos static void 775 1.6 christos eap_chapms2_send_request(eap_state *esp, u_char id, 776 1.6 christos u_char opcode, u_char chapid, 777 1.6 christos char *message, int message_len) 778 1.6 christos { 779 1.6 christos u_char *outp; 780 1.6 christos int msglen; 781 1.6 christos 782 1.6 christos outp = outpacket_buf; 783 1.6 christos 784 1.6 christos MAKEHEADER(outp, PPP_EAP); 785 1.6 christos 786 1.6 christos msglen = EAP_HEADERLEN + 5 * sizeof (u_char); 787 1.6 christos msglen += message_len; 788 1.6 christos 789 1.6 christos PUTCHAR(EAP_REQUEST, outp); 790 1.6 christos PUTCHAR(id, outp); 791 1.6 christos PUTSHORT(msglen, outp); 792 1.6 christos PUTCHAR(EAPT_MSCHAPV2, outp); 793 1.6 christos PUTCHAR(opcode, outp); 794 1.6 christos PUTCHAR(chapid, outp); 795 1.6 christos /* MS len */ 796 1.6 christos PUTSHORT(msglen - 5, outp); 797 1.6 christos BCOPY(message, outp, message_len); 798 1.6 christos 799 1.6 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); 800 1.6 christos 801 1.6 christos if (opcode == CHAP_SUCCESS) { 802 1.6 christos auth_peer_success(esp->es_unit, PPP_EAP, 0, 803 1.6 christos esp->es_server.ea_peer, esp->es_server.ea_peerlen); 804 1.6 christos } 805 1.6 christos else { 806 1.6 christos esp->es_server.ea_state = eapBadAuth; 807 1.6 christos auth_peer_fail(esp->es_unit, PPP_EAP); 808 1.6 christos } 809 1.6 christos } 810 1.7 christos #endif /* PPP_WITH_CHAPMS */ 811 1.6 christos 812 1.6 christos /* 813 1.1 christos * Format an EAP Request message and send it to the peer. Message 814 1.1 christos * type depends on current state. (Server operation) 815 1.1 christos */ 816 1.1 christos static void 817 1.6 christos eap_send_request(eap_state *esp) 818 1.1 christos { 819 1.1 christos u_char *outp; 820 1.1 christos u_char *lenloc; 821 1.1 christos u_char *ptr; 822 1.1 christos int outlen; 823 1.1 christos int challen; 824 1.1 christos char *str; 825 1.7 christos #ifdef PPP_WITH_SRP 826 1.1 christos struct t_server *ts; 827 1.7 christos u_char clear[8], cipher[8], dig[SHA_DIGEST_LENGTH], *optr, *cp, key[SHA_DIGEST_LENGTH]; 828 1.7 christos int i, j, diglen, clen, keylen = sizeof(key); 829 1.1 christos struct b64state b64; 830 1.7 christos PPP_MD_CTX *ctxt; 831 1.7 christos #endif /* PPP_WITH_SRP */ 832 1.1 christos 833 1.1 christos /* Handle both initial auth and restart */ 834 1.1 christos if (esp->es_server.ea_state < eapIdentify && 835 1.1 christos esp->es_server.ea_state != eapInitial) { 836 1.1 christos esp->es_server.ea_state = eapIdentify; 837 1.1 christos if (explicit_remote) { 838 1.1 christos /* 839 1.1 christos * If we already know the peer's 840 1.1 christos * unauthenticated name, then there's no 841 1.1 christos * reason to ask. Go to next state instead. 842 1.1 christos */ 843 1.1 christos esp->es_server.ea_peer = remote_name; 844 1.1 christos esp->es_server.ea_peerlen = strlen(remote_name); 845 1.1 christos eap_figure_next_state(esp, 0); 846 1.1 christos } 847 1.1 christos } 848 1.1 christos 849 1.1 christos if (esp->es_server.ea_maxrequests > 0 && 850 1.1 christos esp->es_server.ea_requests >= esp->es_server.ea_maxrequests) { 851 1.1 christos if (esp->es_server.ea_responses > 0) 852 1.1 christos error("EAP: too many Requests sent"); 853 1.1 christos else 854 1.1 christos error("EAP: no response to Requests"); 855 1.1 christos eap_send_failure(esp); 856 1.1 christos return; 857 1.1 christos } 858 1.1 christos 859 1.1 christos outp = outpacket_buf; 860 1.1 christos 861 1.1 christos MAKEHEADER(outp, PPP_EAP); 862 1.1 christos 863 1.1 christos PUTCHAR(EAP_REQUEST, outp); 864 1.1 christos PUTCHAR(esp->es_server.ea_id, outp); 865 1.1 christos lenloc = outp; 866 1.1 christos INCPTR(2, outp); 867 1.1 christos 868 1.1 christos switch (esp->es_server.ea_state) { 869 1.1 christos case eapIdentify: 870 1.1 christos PUTCHAR(EAPT_IDENTITY, outp); 871 1.1 christos str = "Name"; 872 1.1 christos challen = strlen(str); 873 1.1 christos BCOPY(str, outp, challen); 874 1.1 christos INCPTR(challen, outp); 875 1.1 christos break; 876 1.1 christos 877 1.1 christos case eapMD5Chall: 878 1.1 christos PUTCHAR(EAPT_MD5CHAP, outp); 879 1.1 christos /* 880 1.1 christos * pick a random challenge length between 881 1.1 christos * MIN_CHALLENGE_LENGTH and MAX_CHALLENGE_LENGTH 882 1.1 christos */ 883 1.1 christos challen = (drand48() * 884 1.1 christos (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) + 885 1.1 christos MIN_CHALLENGE_LENGTH; 886 1.1 christos PUTCHAR(challen, outp); 887 1.1 christos esp->es_challen = challen; 888 1.1 christos ptr = esp->es_challenge; 889 1.1 christos while (--challen >= 0) 890 1.1 christos *ptr++ = (u_char) (drand48() * 0x100); 891 1.1 christos BCOPY(esp->es_challenge, outp, esp->es_challen); 892 1.1 christos INCPTR(esp->es_challen, outp); 893 1.1 christos BCOPY(esp->es_server.ea_name, outp, esp->es_server.ea_namelen); 894 1.1 christos INCPTR(esp->es_server.ea_namelen, outp); 895 1.1 christos break; 896 1.1 christos 897 1.7 christos #ifdef PPP_WITH_CHAPMS 898 1.6 christos case eapMSCHAPv2Chall: 899 1.7 christos esp->es_server.digest->generate_challenge(esp->es_challenge); 900 1.7 christos challen = esp->es_challenge[0]; 901 1.6 christos esp->es_challen = challen; 902 1.6 christos 903 1.6 christos PUTCHAR(EAPT_MSCHAPV2, outp); 904 1.6 christos PUTCHAR(CHAP_CHALLENGE, outp); 905 1.6 christos PUTCHAR(esp->es_server.ea_id, outp); 906 1.6 christos /* MS len */ 907 1.6 christos PUTSHORT(5 + challen + 908 1.6 christos esp->es_server.ea_namelen, 909 1.6 christos outp); 910 1.6 christos /* challen + challenge */ 911 1.6 christos BCOPY(esp->es_challenge, outp, challen+1); 912 1.6 christos INCPTR(challen+1, outp); 913 1.6 christos BCOPY(esp->es_server.ea_name, 914 1.6 christos outp, 915 1.6 christos esp->es_server.ea_namelen); 916 1.6 christos INCPTR(esp->es_server.ea_namelen, outp); 917 1.6 christos break; 918 1.7 christos #endif /* PPP_WITH_CHAPMS */ 919 1.6 christos 920 1.7 christos #ifdef PPP_WITH_EAPTLS 921 1.6 christos case eapTlsStart: 922 1.6 christos PUTCHAR(EAPT_TLS, outp); 923 1.6 christos PUTCHAR(EAP_TLS_FLAGS_START, outp); 924 1.6 christos eap_figure_next_state(esp, 0); 925 1.6 christos break; 926 1.6 christos 927 1.6 christos case eapTlsSend: 928 1.6 christos eaptls_send(esp->es_server.ea_session, &outp); 929 1.6 christos eap_figure_next_state(esp, 0); 930 1.6 christos break; 931 1.6 christos 932 1.6 christos case eapTlsSendAck: 933 1.6 christos PUTCHAR(EAPT_TLS, outp); 934 1.6 christos PUTCHAR(0, outp); 935 1.6 christos eap_figure_next_state(esp, 0); 936 1.6 christos break; 937 1.6 christos 938 1.6 christos case eapTlsSendAlert: 939 1.6 christos eaptls_send(esp->es_server.ea_session, &outp); 940 1.6 christos eap_figure_next_state(esp, 0); 941 1.6 christos break; 942 1.7 christos #endif /* PPP_WITH_EAPTLS */ 943 1.6 christos 944 1.7 christos #ifdef PPP_WITH_SRP 945 1.1 christos case eapSRP1: 946 1.1 christos PUTCHAR(EAPT_SRP, outp); 947 1.1 christos PUTCHAR(EAPSRP_CHALLENGE, outp); 948 1.1 christos 949 1.1 christos PUTCHAR(esp->es_server.ea_namelen, outp); 950 1.1 christos BCOPY(esp->es_server.ea_name, outp, esp->es_server.ea_namelen); 951 1.1 christos INCPTR(esp->es_server.ea_namelen, outp); 952 1.1 christos 953 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 954 1.1 christos assert(ts != NULL); 955 1.1 christos PUTCHAR(ts->s.len, outp); 956 1.1 christos BCOPY(ts->s.data, outp, ts->s.len); 957 1.1 christos INCPTR(ts->s.len, outp); 958 1.1 christos 959 1.1 christos if (ts->g.len == 1 && ts->g.data[0] == 2) { 960 1.1 christos PUTCHAR(0, outp); 961 1.1 christos } else { 962 1.1 christos PUTCHAR(ts->g.len, outp); 963 1.1 christos BCOPY(ts->g.data, outp, ts->g.len); 964 1.1 christos INCPTR(ts->g.len, outp); 965 1.1 christos } 966 1.1 christos 967 1.1 christos if (ts->n.len != sizeof (wkmodulus) || 968 1.1 christos BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) { 969 1.1 christos BCOPY(ts->n.data, outp, ts->n.len); 970 1.1 christos INCPTR(ts->n.len, outp); 971 1.1 christos } 972 1.1 christos break; 973 1.1 christos 974 1.1 christos case eapSRP2: 975 1.1 christos PUTCHAR(EAPT_SRP, outp); 976 1.1 christos PUTCHAR(EAPSRP_SKEY, outp); 977 1.1 christos 978 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 979 1.1 christos assert(ts != NULL); 980 1.1 christos BCOPY(ts->B.data, outp, ts->B.len); 981 1.1 christos INCPTR(ts->B.len, outp); 982 1.1 christos break; 983 1.1 christos 984 1.1 christos case eapSRP3: 985 1.1 christos PUTCHAR(EAPT_SRP, outp); 986 1.1 christos PUTCHAR(EAPSRP_SVALIDATOR, outp); 987 1.1 christos PUTLONG(SRPVAL_EBIT, outp); 988 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 989 1.1 christos assert(ts != NULL); 990 1.7 christos BCOPY(t_serverresponse(ts), outp, SHA_DIGEST_LENGTH); 991 1.7 christos INCPTR(SHA_DIGEST_LENGTH, outp); 992 1.1 christos 993 1.7 christos if (pncrypt_getkey(0, key, keylen)) { 994 1.1 christos /* Generate pseudonym */ 995 1.1 christos optr = outp; 996 1.1 christos cp = (unsigned char *)esp->es_server.ea_peer; 997 1.1 christos if ((j = i = esp->es_server.ea_peerlen) > 7) 998 1.1 christos j = 7; 999 1.1 christos clear[0] = i; 1000 1.1 christos BCOPY(cp, clear + 1, j); 1001 1.1 christos i -= j; 1002 1.1 christos cp += j; 1003 1.7 christos 1004 1.7 christos if (!DesEncrypt(clear, key, cipher)) { 1005 1.1 christos dbglog("no DES here; not generating pseudonym"); 1006 1.1 christos break; 1007 1.7 christos } 1008 1.7 christos 1009 1.1 christos BZERO(&b64, sizeof (b64)); 1010 1.1 christos outp++; /* space for pseudonym length */ 1011 1.1 christos outp += b64enc(&b64, cipher, 8, outp); 1012 1.1 christos while (i >= 8) { 1013 1.7 christos DesEncrypt(cp, key, cipher); 1014 1.1 christos outp += b64enc(&b64, cipher, 8, outp); 1015 1.1 christos cp += 8; 1016 1.1 christos i -= 8; 1017 1.1 christos } 1018 1.1 christos if (i > 0) { 1019 1.1 christos BCOPY(cp, clear, i); 1020 1.1 christos cp += i; 1021 1.1 christos while (i < 8) { 1022 1.1 christos *cp++ = drand48() * 0x100; 1023 1.1 christos i++; 1024 1.1 christos } 1025 1.7 christos 1026 1.7 christos DesEncrypt(clear, key, cipher); 1027 1.1 christos outp += b64enc(&b64, cipher, 8, outp); 1028 1.1 christos } 1029 1.1 christos outp += b64flush(&b64, outp); 1030 1.1 christos 1031 1.1 christos /* Set length and pad out to next 20 octet boundary */ 1032 1.1 christos i = outp - optr - 1; 1033 1.1 christos *optr = i; 1034 1.7 christos i %= SHA_DIGEST_LENGTH; 1035 1.1 christos if (i != 0) { 1036 1.7 christos while (i < SHA_DIGEST_LENGTH) { 1037 1.1 christos *outp++ = drand48() * 0x100; 1038 1.1 christos i++; 1039 1.1 christos } 1040 1.1 christos } 1041 1.1 christos 1042 1.1 christos /* Obscure the pseudonym with SHA1 hash */ 1043 1.7 christos ctxt = PPP_MD_CTX_new(); 1044 1.7 christos if (ctxt) { 1045 1.7 christos 1046 1.7 christos PPP_DigestInit(ctxt, PPP_sha1()); 1047 1.7 christos PPP_DigestUpdate(ctxt, &esp->es_server.ea_id, 1); 1048 1.7 christos PPP_DigestUpdate(ctxt, &esp->es_server.ea_skey, 1049 1.7 christos SESSION_KEY_LEN); 1050 1.7 christos PPP_DigestUpdate(ctxt, esp->es_server.ea_peer, 1051 1.7 christos esp->es_server.ea_peerlen); 1052 1.7 christos while (optr < outp) { 1053 1.7 christos diglen = SHA_DIGEST_LENGTH; 1054 1.7 christos PPP_DigestFinal(ctxt, dig, &diglen); 1055 1.7 christos cp = dig; 1056 1.7 christos while (cp < dig + SHA_DIGEST_LENGTH) 1057 1.7 christos *optr++ ^= *cp++; 1058 1.7 christos 1059 1.7 christos PPP_DigestInit(ctxt, PPP_sha1()); 1060 1.7 christos PPP_DigestUpdate(ctxt, &esp->es_server.ea_id, 1); 1061 1.7 christos PPP_DigestUpdate(ctxt, esp->es_server.ea_skey, 1062 1.7 christos SESSION_KEY_LEN); 1063 1.7 christos PPP_DigestUpdate(ctxt, optr - SHA_DIGEST_LENGTH, 1064 1.7 christos SHA_DIGEST_LENGTH); 1065 1.7 christos } 1066 1.7 christos 1067 1.7 christos PPP_MD_CTX_free(ctxt); 1068 1.1 christos } 1069 1.1 christos } 1070 1.1 christos break; 1071 1.1 christos 1072 1.1 christos case eapSRP4: 1073 1.1 christos PUTCHAR(EAPT_SRP, outp); 1074 1.1 christos PUTCHAR(EAPSRP_LWRECHALLENGE, outp); 1075 1.1 christos challen = MIN_CHALLENGE_LENGTH + 1076 1.1 christos ((MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH) * drand48()); 1077 1.1 christos esp->es_challen = challen; 1078 1.1 christos ptr = esp->es_challenge; 1079 1.1 christos while (--challen >= 0) 1080 1.1 christos *ptr++ = drand48() * 0x100; 1081 1.1 christos BCOPY(esp->es_challenge, outp, esp->es_challen); 1082 1.1 christos INCPTR(esp->es_challen, outp); 1083 1.1 christos break; 1084 1.7 christos #endif /* PPP_WITH_SRP */ 1085 1.1 christos 1086 1.1 christos default: 1087 1.1 christos return; 1088 1.1 christos } 1089 1.1 christos 1090 1.1 christos outlen = (outp - outpacket_buf) - PPP_HDRLEN; 1091 1.1 christos PUTSHORT(outlen, lenloc); 1092 1.1 christos 1093 1.1 christos output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN); 1094 1.1 christos 1095 1.1 christos esp->es_server.ea_requests++; 1096 1.1 christos 1097 1.1 christos if (esp->es_server.ea_timeout > 0) 1098 1.1 christos TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout); 1099 1.1 christos } 1100 1.1 christos 1101 1.1 christos /* 1102 1.1 christos * eap_authpeer - Authenticate our peer (behave as server). 1103 1.1 christos * 1104 1.1 christos * Start server state and send first request. This is called only 1105 1.1 christos * after eap_lowerup. 1106 1.1 christos */ 1107 1.1 christos void 1108 1.6 christos eap_authpeer(int unit, char *localname) 1109 1.1 christos { 1110 1.1 christos eap_state *esp = &eap_states[unit]; 1111 1.1 christos 1112 1.1 christos /* Save the name we're given. */ 1113 1.1 christos esp->es_server.ea_name = localname; 1114 1.1 christos esp->es_server.ea_namelen = strlen(localname); 1115 1.1 christos 1116 1.1 christos esp->es_savedtime = esp->es_server.ea_timeout; 1117 1.1 christos 1118 1.1 christos /* Lower layer up yet? */ 1119 1.1 christos if (esp->es_server.ea_state == eapInitial || 1120 1.1 christos esp->es_server.ea_state == eapPending) { 1121 1.1 christos esp->es_server.ea_state = eapPending; 1122 1.1 christos return; 1123 1.1 christos } 1124 1.1 christos 1125 1.1 christos esp->es_server.ea_state = eapPending; 1126 1.1 christos 1127 1.1 christos /* ID number not updated here intentionally; hashed into M1 */ 1128 1.1 christos eap_send_request(esp); 1129 1.1 christos } 1130 1.1 christos 1131 1.1 christos /* 1132 1.1 christos * eap_server_timeout - Retransmission timer for sending Requests 1133 1.1 christos * expired. 1134 1.1 christos */ 1135 1.1 christos static void 1136 1.6 christos eap_server_timeout(void *arg) 1137 1.1 christos { 1138 1.7 christos #ifdef PPP_WITH_EAPTLS 1139 1.6 christos u_char *outp; 1140 1.6 christos u_char *lenloc; 1141 1.6 christos int outlen; 1142 1.7 christos #endif /* PPP_WITH_EAPTLS */ 1143 1.6 christos 1144 1.1 christos eap_state *esp = (eap_state *) arg; 1145 1.1 christos 1146 1.1 christos if (!eap_server_active(esp)) 1147 1.1 christos return; 1148 1.1 christos 1149 1.7 christos #ifdef PPP_WITH_EAPTLS 1150 1.6 christos switch(esp->es_server.ea_prev_state) { 1151 1.6 christos 1152 1.6 christos /* 1153 1.6 christos * In eap-tls the state changes after a request, so we return to 1154 1.6 christos * previous state ... 1155 1.6 christos */ 1156 1.6 christos case(eapTlsStart): 1157 1.6 christos case(eapTlsSendAck): 1158 1.6 christos esp->es_server.ea_state = esp->es_server.ea_prev_state; 1159 1.6 christos break; 1160 1.6 christos 1161 1.6 christos /* 1162 1.6 christos * ... or resend the stored data 1163 1.6 christos */ 1164 1.6 christos case(eapTlsSend): 1165 1.6 christos case(eapTlsSendAlert): 1166 1.6 christos outp = outpacket_buf; 1167 1.6 christos MAKEHEADER(outp, PPP_EAP); 1168 1.6 christos PUTCHAR(EAP_REQUEST, outp); 1169 1.6 christos PUTCHAR(esp->es_server.ea_id, outp); 1170 1.6 christos lenloc = outp; 1171 1.6 christos INCPTR(2, outp); 1172 1.6 christos 1173 1.6 christos eaptls_retransmit(esp->es_server.ea_session, &outp); 1174 1.6 christos 1175 1.6 christos outlen = (outp - outpacket_buf) - PPP_HDRLEN; 1176 1.6 christos PUTSHORT(outlen, lenloc); 1177 1.6 christos output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN); 1178 1.6 christos esp->es_server.ea_requests++; 1179 1.6 christos 1180 1.6 christos if (esp->es_server.ea_timeout > 0) 1181 1.6 christos TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout); 1182 1.6 christos 1183 1.6 christos return; 1184 1.6 christos default: 1185 1.6 christos break; 1186 1.6 christos } 1187 1.7 christos #endif /* PPP_WITH_EAPTLS */ 1188 1.6 christos 1189 1.1 christos /* EAP ID number must not change on timeout. */ 1190 1.1 christos eap_send_request(esp); 1191 1.1 christos } 1192 1.1 christos 1193 1.1 christos /* 1194 1.1 christos * When it's time to send rechallenge the peer, this timeout is 1195 1.1 christos * called. Once the rechallenge is successful, the response handler 1196 1.1 christos * will restart the timer. If it fails, then the link is dropped. 1197 1.1 christos */ 1198 1.1 christos static void 1199 1.6 christos eap_rechallenge(void *arg) 1200 1.1 christos { 1201 1.1 christos eap_state *esp = (eap_state *)arg; 1202 1.1 christos 1203 1.1 christos if (esp->es_server.ea_state != eapOpen && 1204 1.1 christos esp->es_server.ea_state != eapSRP4) 1205 1.1 christos return; 1206 1.1 christos 1207 1.1 christos esp->es_server.ea_requests = 0; 1208 1.1 christos esp->es_server.ea_state = eapIdentify; 1209 1.1 christos eap_figure_next_state(esp, 0); 1210 1.1 christos esp->es_server.ea_id++; 1211 1.1 christos eap_send_request(esp); 1212 1.1 christos } 1213 1.1 christos 1214 1.1 christos static void 1215 1.6 christos srp_lwrechallenge(void *arg) 1216 1.1 christos { 1217 1.1 christos eap_state *esp = (eap_state *)arg; 1218 1.1 christos 1219 1.1 christos if (esp->es_server.ea_state != eapOpen || 1220 1.1 christos esp->es_server.ea_type != EAPT_SRP) 1221 1.1 christos return; 1222 1.1 christos 1223 1.1 christos esp->es_server.ea_requests = 0; 1224 1.1 christos esp->es_server.ea_state = eapSRP4; 1225 1.1 christos esp->es_server.ea_id++; 1226 1.1 christos eap_send_request(esp); 1227 1.1 christos } 1228 1.1 christos 1229 1.1 christos /* 1230 1.1 christos * eap_lowerup - The lower layer is now up. 1231 1.1 christos * 1232 1.1 christos * This is called before either eap_authpeer or eap_authwithpeer. See 1233 1.1 christos * link_established() in auth.c. All that's necessary here is to 1234 1.1 christos * return to closed state so that those two routines will do the right 1235 1.1 christos * thing. 1236 1.1 christos */ 1237 1.1 christos static void 1238 1.6 christos eap_lowerup(int unit) 1239 1.1 christos { 1240 1.1 christos eap_state *esp = &eap_states[unit]; 1241 1.1 christos 1242 1.1 christos /* Discard any (possibly authenticated) peer name. */ 1243 1.1 christos if (esp->es_server.ea_peer != NULL && 1244 1.1 christos esp->es_server.ea_peer != remote_name) 1245 1.1 christos free(esp->es_server.ea_peer); 1246 1.1 christos esp->es_server.ea_peer = NULL; 1247 1.1 christos if (esp->es_client.ea_peer != NULL) 1248 1.1 christos free(esp->es_client.ea_peer); 1249 1.1 christos esp->es_client.ea_peer = NULL; 1250 1.1 christos 1251 1.1 christos esp->es_client.ea_state = eapClosed; 1252 1.1 christos esp->es_server.ea_state = eapClosed; 1253 1.1 christos } 1254 1.1 christos 1255 1.1 christos /* 1256 1.1 christos * eap_lowerdown - The lower layer is now down. 1257 1.1 christos * 1258 1.1 christos * Cancel all timeouts and return to initial state. 1259 1.1 christos */ 1260 1.1 christos static void 1261 1.6 christos eap_lowerdown(int unit) 1262 1.1 christos { 1263 1.1 christos eap_state *esp = &eap_states[unit]; 1264 1.1 christos 1265 1.1 christos if (eap_client_active(esp) && esp->es_client.ea_timeout > 0) { 1266 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp); 1267 1.1 christos } 1268 1.1 christos if (eap_server_active(esp)) { 1269 1.1 christos if (esp->es_server.ea_timeout > 0) { 1270 1.1 christos UNTIMEOUT(eap_server_timeout, (void *)esp); 1271 1.1 christos } 1272 1.1 christos } else { 1273 1.1 christos if ((esp->es_server.ea_state == eapOpen || 1274 1.1 christos esp->es_server.ea_state == eapSRP4) && 1275 1.1 christos esp->es_rechallenge > 0) { 1276 1.1 christos UNTIMEOUT(eap_rechallenge, (void *)esp); 1277 1.1 christos } 1278 1.1 christos if (esp->es_server.ea_state == eapOpen && 1279 1.1 christos esp->es_lwrechallenge > 0) { 1280 1.1 christos UNTIMEOUT(srp_lwrechallenge, (void *)esp); 1281 1.1 christos } 1282 1.1 christos } 1283 1.1 christos 1284 1.1 christos esp->es_client.ea_state = esp->es_server.ea_state = eapInitial; 1285 1.1 christos esp->es_client.ea_requests = esp->es_server.ea_requests = 0; 1286 1.1 christos } 1287 1.1 christos 1288 1.1 christos /* 1289 1.1 christos * eap_protrej - Peer doesn't speak this protocol. 1290 1.1 christos * 1291 1.1 christos * This shouldn't happen. If it does, it represents authentication 1292 1.1 christos * failure. 1293 1.1 christos */ 1294 1.1 christos static void 1295 1.6 christos eap_protrej(int unit) 1296 1.1 christos { 1297 1.1 christos eap_state *esp = &eap_states[unit]; 1298 1.1 christos 1299 1.1 christos if (eap_client_active(esp)) { 1300 1.1 christos error("EAP authentication failed due to Protocol-Reject"); 1301 1.1 christos auth_withpeer_fail(unit, PPP_EAP); 1302 1.1 christos } 1303 1.1 christos if (eap_server_active(esp)) { 1304 1.1 christos error("EAP authentication of peer failed on Protocol-Reject"); 1305 1.1 christos auth_peer_fail(unit, PPP_EAP); 1306 1.1 christos } 1307 1.1 christos eap_lowerdown(unit); 1308 1.1 christos } 1309 1.1 christos 1310 1.1 christos /* 1311 1.1 christos * Format and send a regular EAP Response message. 1312 1.1 christos */ 1313 1.1 christos static void 1314 1.2 christos eap_send_response(eap_state *esp, u_char id, u_char typenum, 1315 1.6 christos u_char *str, int lenstr) 1316 1.1 christos { 1317 1.1 christos u_char *outp; 1318 1.1 christos int msglen; 1319 1.1 christos 1320 1.1 christos outp = outpacket_buf; 1321 1.1 christos 1322 1.1 christos MAKEHEADER(outp, PPP_EAP); 1323 1.1 christos 1324 1.1 christos PUTCHAR(EAP_RESPONSE, outp); 1325 1.1 christos PUTCHAR(id, outp); 1326 1.1 christos esp->es_client.ea_id = id; 1327 1.1 christos msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr; 1328 1.1 christos PUTSHORT(msglen, outp); 1329 1.1 christos PUTCHAR(typenum, outp); 1330 1.1 christos if (lenstr > 0) { 1331 1.1 christos BCOPY(str, outp, lenstr); 1332 1.1 christos } 1333 1.1 christos 1334 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); 1335 1.1 christos } 1336 1.1 christos 1337 1.1 christos /* 1338 1.1 christos * Format and send an MD5-Challenge EAP Response message. 1339 1.1 christos */ 1340 1.1 christos static void 1341 1.6 christos eap_chap_response(eap_state *esp, u_char id, u_char *hash, 1342 1.6 christos char *name, int namelen) 1343 1.1 christos { 1344 1.1 christos u_char *outp; 1345 1.1 christos int msglen; 1346 1.1 christos 1347 1.1 christos outp = outpacket_buf; 1348 1.7 christos 1349 1.1 christos MAKEHEADER(outp, PPP_EAP); 1350 1.1 christos 1351 1.1 christos PUTCHAR(EAP_RESPONSE, outp); 1352 1.1 christos PUTCHAR(id, outp); 1353 1.1 christos esp->es_client.ea_id = id; 1354 1.7 christos msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_DIGEST_LENGTH + 1355 1.1 christos namelen; 1356 1.1 christos PUTSHORT(msglen, outp); 1357 1.1 christos PUTCHAR(EAPT_MD5CHAP, outp); 1358 1.7 christos PUTCHAR(MD5_DIGEST_LENGTH, outp); 1359 1.7 christos BCOPY(hash, outp, MD5_DIGEST_LENGTH); 1360 1.7 christos INCPTR(MD5_DIGEST_LENGTH, outp); 1361 1.1 christos if (namelen > 0) { 1362 1.1 christos BCOPY(name, outp, namelen); 1363 1.1 christos } 1364 1.1 christos 1365 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); 1366 1.1 christos } 1367 1.1 christos 1368 1.7 christos #ifdef PPP_WITH_SRP 1369 1.1 christos /* 1370 1.1 christos * Format and send a SRP EAP Response message. 1371 1.1 christos */ 1372 1.1 christos static void 1373 1.6 christos eap_srp_response(eap_state *esp, u_char id, u_char subtypenum, 1374 1.6 christos u_char *str, int lenstr) 1375 1.1 christos { 1376 1.1 christos u_char *outp; 1377 1.1 christos int msglen; 1378 1.1 christos 1379 1.1 christos outp = outpacket_buf; 1380 1.1 christos 1381 1.1 christos MAKEHEADER(outp, PPP_EAP); 1382 1.1 christos 1383 1.1 christos PUTCHAR(EAP_RESPONSE, outp); 1384 1.1 christos PUTCHAR(id, outp); 1385 1.1 christos esp->es_client.ea_id = id; 1386 1.1 christos msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr; 1387 1.1 christos PUTSHORT(msglen, outp); 1388 1.1 christos PUTCHAR(EAPT_SRP, outp); 1389 1.1 christos PUTCHAR(subtypenum, outp); 1390 1.1 christos if (lenstr > 0) { 1391 1.1 christos BCOPY(str, outp, lenstr); 1392 1.1 christos } 1393 1.1 christos 1394 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); 1395 1.1 christos } 1396 1.1 christos 1397 1.1 christos /* 1398 1.1 christos * Format and send a SRP EAP Client Validator Response message. 1399 1.1 christos */ 1400 1.1 christos static void 1401 1.6 christos eap_srpval_response(eap_state *esp, u_char id, u_int32_t flags, u_char *str) 1402 1.1 christos { 1403 1.1 christos u_char *outp; 1404 1.1 christos int msglen; 1405 1.1 christos 1406 1.1 christos outp = outpacket_buf; 1407 1.1 christos 1408 1.1 christos MAKEHEADER(outp, PPP_EAP); 1409 1.1 christos 1410 1.1 christos PUTCHAR(EAP_RESPONSE, outp); 1411 1.1 christos PUTCHAR(id, outp); 1412 1.1 christos esp->es_client.ea_id = id; 1413 1.1 christos msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u_int32_t) + 1414 1.7 christos SHA_DIGEST_LENGTH; 1415 1.1 christos PUTSHORT(msglen, outp); 1416 1.1 christos PUTCHAR(EAPT_SRP, outp); 1417 1.1 christos PUTCHAR(EAPSRP_CVALIDATOR, outp); 1418 1.1 christos PUTLONG(flags, outp); 1419 1.7 christos BCOPY(str, outp, SHA_DIGEST_LENGTH); 1420 1.1 christos 1421 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); 1422 1.1 christos } 1423 1.7 christos #endif /* PPP_WITH_SRP */ 1424 1.1 christos 1425 1.7 christos #ifdef PPP_WITH_EAPTLS 1426 1.6 christos /* 1427 1.6 christos * Send an EAP-TLS response message with tls data 1428 1.6 christos */ 1429 1.6 christos static void 1430 1.6 christos eap_tls_response(eap_state *esp, u_char id) 1431 1.6 christos { 1432 1.6 christos u_char *outp; 1433 1.6 christos int outlen; 1434 1.6 christos u_char *lenloc; 1435 1.6 christos 1436 1.6 christos outp = outpacket_buf; 1437 1.6 christos 1438 1.6 christos MAKEHEADER(outp, PPP_EAP); 1439 1.6 christos 1440 1.6 christos PUTCHAR(EAP_RESPONSE, outp); 1441 1.6 christos PUTCHAR(id, outp); 1442 1.6 christos 1443 1.6 christos lenloc = outp; 1444 1.6 christos INCPTR(2, outp); 1445 1.6 christos 1446 1.6 christos /* 1447 1.6 christos If the id in the request is unchanged, we must retransmit 1448 1.6 christos the old data 1449 1.6 christos */ 1450 1.6 christos if(id == esp->es_client.ea_id) 1451 1.6 christos eaptls_retransmit(esp->es_client.ea_session, &outp); 1452 1.6 christos else 1453 1.6 christos eaptls_send(esp->es_client.ea_session, &outp); 1454 1.6 christos 1455 1.6 christos outlen = (outp - outpacket_buf) - PPP_HDRLEN; 1456 1.6 christos PUTSHORT(outlen, lenloc); 1457 1.6 christos 1458 1.6 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); 1459 1.6 christos 1460 1.6 christos esp->es_client.ea_id = id; 1461 1.6 christos } 1462 1.6 christos 1463 1.6 christos /* 1464 1.6 christos * Send an EAP-TLS ack 1465 1.6 christos */ 1466 1.6 christos static void 1467 1.6 christos eap_tls_sendack(eap_state *esp, u_char id) 1468 1.6 christos { 1469 1.6 christos u_char *outp; 1470 1.6 christos int outlen; 1471 1.6 christos u_char *lenloc; 1472 1.6 christos 1473 1.6 christos outp = outpacket_buf; 1474 1.6 christos 1475 1.6 christos MAKEHEADER(outp, PPP_EAP); 1476 1.6 christos 1477 1.6 christos PUTCHAR(EAP_RESPONSE, outp); 1478 1.6 christos PUTCHAR(id, outp); 1479 1.6 christos esp->es_client.ea_id = id; 1480 1.6 christos 1481 1.6 christos lenloc = outp; 1482 1.6 christos INCPTR(2, outp); 1483 1.6 christos 1484 1.6 christos PUTCHAR(EAPT_TLS, outp); 1485 1.6 christos PUTCHAR(0, outp); 1486 1.6 christos 1487 1.6 christos outlen = (outp - outpacket_buf) - PPP_HDRLEN; 1488 1.6 christos PUTSHORT(outlen, lenloc); 1489 1.6 christos 1490 1.6 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen); 1491 1.6 christos } 1492 1.7 christos #endif /* PPP_WITH_EAPTLS */ 1493 1.6 christos 1494 1.1 christos static void 1495 1.2 christos eap_send_nak(eap_state *esp, u_char id, u_char type) 1496 1.1 christos { 1497 1.1 christos u_char *outp; 1498 1.1 christos int msglen; 1499 1.1 christos 1500 1.1 christos outp = outpacket_buf; 1501 1.1 christos 1502 1.1 christos MAKEHEADER(outp, PPP_EAP); 1503 1.1 christos 1504 1.1 christos PUTCHAR(EAP_RESPONSE, outp); 1505 1.1 christos PUTCHAR(id, outp); 1506 1.1 christos esp->es_client.ea_id = id; 1507 1.1 christos msglen = EAP_HEADERLEN + 2 * sizeof (u_char); 1508 1.1 christos PUTSHORT(msglen, outp); 1509 1.1 christos PUTCHAR(EAPT_NAK, outp); 1510 1.1 christos PUTCHAR(type, outp); 1511 1.1 christos 1512 1.1 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); 1513 1.1 christos } 1514 1.1 christos 1515 1.7 christos #ifdef PPP_WITH_SRP 1516 1.1 christos static char * 1517 1.6 christos name_of_pn_file(void) 1518 1.1 christos { 1519 1.1 christos char *user, *path, *file; 1520 1.1 christos struct passwd *pw; 1521 1.1 christos size_t pl; 1522 1.1 christos static bool pnlogged = 0; 1523 1.1 christos 1524 1.1 christos pw = getpwuid(getuid()); 1525 1.1 christos if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) { 1526 1.1 christos errno = EINVAL; 1527 1.1 christos return (NULL); 1528 1.1 christos } 1529 1.7 christos file = PPP_PATH_PSEUDONYM; 1530 1.1 christos pl = strlen(user) + strlen(file) + 2; 1531 1.1 christos path = malloc(pl); 1532 1.1 christos if (path == NULL) 1533 1.1 christos return (NULL); 1534 1.1 christos (void) slprintf(path, pl, "%s/%s", user, file); 1535 1.1 christos if (!pnlogged) { 1536 1.1 christos dbglog("pseudonym file: %s", path); 1537 1.1 christos pnlogged = 1; 1538 1.1 christos } 1539 1.1 christos return (path); 1540 1.1 christos } 1541 1.1 christos 1542 1.1 christos static int 1543 1.6 christos open_pn_file(mode_t modebits) 1544 1.1 christos { 1545 1.1 christos char *path; 1546 1.1 christos int fd, err; 1547 1.1 christos 1548 1.1 christos if ((path = name_of_pn_file()) == NULL) 1549 1.1 christos return (-1); 1550 1.1 christos fd = open(path, modebits, S_IRUSR | S_IWUSR); 1551 1.1 christos err = errno; 1552 1.1 christos free(path); 1553 1.1 christos errno = err; 1554 1.1 christos return (fd); 1555 1.1 christos } 1556 1.1 christos 1557 1.1 christos static void 1558 1.6 christos remove_pn_file(void) 1559 1.1 christos { 1560 1.1 christos char *path; 1561 1.1 christos 1562 1.1 christos if ((path = name_of_pn_file()) != NULL) { 1563 1.1 christos (void) unlink(path); 1564 1.1 christos (void) free(path); 1565 1.1 christos } 1566 1.1 christos } 1567 1.1 christos 1568 1.1 christos static void 1569 1.6 christos write_pseudonym(eap_state *esp, u_char *inp, int len, int id) 1570 1.1 christos { 1571 1.1 christos u_char val; 1572 1.1 christos u_char *datp, *digp; 1573 1.7 christos PPP_MD_CTX *ctxt; 1574 1.7 christos u_char dig[SHA_DIGEST_LENGTH]; 1575 1.7 christos int dsize, fd, olen = len, diglen = sizeof(dig); 1576 1.1 christos 1577 1.1 christos /* 1578 1.1 christos * Do the decoding by working backwards. This eliminates the need 1579 1.1 christos * to save the decoded output in a separate buffer. 1580 1.1 christos */ 1581 1.1 christos val = id; 1582 1.1 christos while (len > 0) { 1583 1.7 christos if ((dsize = len % SHA_DIGEST_LENGTH) == 0) 1584 1.7 christos dsize = SHA_DIGEST_LENGTH; 1585 1.1 christos len -= dsize; 1586 1.1 christos datp = inp + len; 1587 1.7 christos ctxt = PPP_MD_CTX_new(); 1588 1.7 christos if (ctxt) { 1589 1.7 christos 1590 1.7 christos PPP_DigestInit(ctxt, PPP_sha1()); 1591 1.7 christos PPP_DigestUpdate(ctxt, &val, 1); 1592 1.7 christos PPP_DigestUpdate(ctxt, esp->es_client.ea_skey, 1593 1.7 christos SESSION_KEY_LEN); 1594 1.7 christos if (len > 0) { 1595 1.7 christos PPP_DigestUpdate(ctxt, datp, SHA_DIGEST_LENGTH); 1596 1.7 christos } else { 1597 1.7 christos PPP_DigestUpdate(ctxt, esp->es_client.ea_name, 1598 1.7 christos esp->es_client.ea_namelen); 1599 1.7 christos } 1600 1.7 christos PPP_DigestFinal(ctxt, dig, &diglen); 1601 1.7 christos 1602 1.7 christos for (digp = dig; digp < dig + SHA_DIGEST_LENGTH; digp++) 1603 1.7 christos *datp++ ^= *digp; 1604 1.7 christos 1605 1.7 christos PPP_MD_CTX_free(ctxt); 1606 1.1 christos } 1607 1.1 christos } 1608 1.1 christos 1609 1.1 christos /* Now check that the result is sane */ 1610 1.1 christos if (olen <= 0 || *inp + 1 > olen) { 1611 1.1 christos dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp); 1612 1.1 christos return; 1613 1.1 christos } 1614 1.1 christos 1615 1.1 christos /* Save it away */ 1616 1.1 christos fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC); 1617 1.1 christos if (fd < 0) { 1618 1.1 christos dbglog("EAP: error saving pseudonym: %m"); 1619 1.1 christos return; 1620 1.1 christos } 1621 1.1 christos len = write(fd, inp + 1, *inp); 1622 1.1 christos if (close(fd) != -1 && len == *inp) { 1623 1.1 christos dbglog("EAP: saved pseudonym"); 1624 1.1 christos esp->es_usedpseudo = 0; 1625 1.1 christos } else { 1626 1.1 christos dbglog("EAP: failed to save pseudonym"); 1627 1.1 christos remove_pn_file(); 1628 1.1 christos } 1629 1.1 christos } 1630 1.7 christos #endif /* PPP_WITH_SRP */ 1631 1.1 christos 1632 1.7 christos #if PPP_WITH_CHAPMS 1633 1.6 christos /* 1634 1.6 christos * Format and send an CHAPV2-Challenge EAP Response message. 1635 1.6 christos */ 1636 1.6 christos static void 1637 1.6 christos eap_chapv2_response(eap_state *esp, u_char id, u_char chapid, u_char *response, char *user, int user_len) 1638 1.6 christos { 1639 1.6 christos u_char *outp; 1640 1.6 christos int msglen; 1641 1.6 christos 1642 1.6 christos outp = outpacket_buf; 1643 1.6 christos 1644 1.6 christos MAKEHEADER(outp, PPP_EAP); 1645 1.6 christos 1646 1.6 christos PUTCHAR(EAP_RESPONSE, outp); 1647 1.6 christos PUTCHAR(id, outp); 1648 1.6 christos esp->es_client.ea_id = id; 1649 1.6 christos msglen = EAP_HEADERLEN + 6 * sizeof (u_char) + MS_CHAP2_RESPONSE_LEN + user_len; 1650 1.6 christos PUTSHORT(msglen, outp); 1651 1.6 christos PUTCHAR(EAPT_MSCHAPV2, outp); 1652 1.6 christos PUTCHAR(CHAP_RESPONSE, outp); 1653 1.6 christos PUTCHAR(chapid, outp); 1654 1.6 christos PUTCHAR(0, outp); 1655 1.6 christos /* len */ 1656 1.6 christos PUTCHAR(5 + user_len + MS_CHAP2_RESPONSE_LEN, outp); 1657 1.6 christos BCOPY(response, outp, MS_CHAP2_RESPONSE_LEN+1); // VLEN + VALUE 1658 1.6 christos INCPTR(MS_CHAP2_RESPONSE_LEN+1, outp); 1659 1.6 christos BCOPY(user, outp, user_len); 1660 1.6 christos 1661 1.6 christos output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen); 1662 1.6 christos } 1663 1.6 christos #endif 1664 1.6 christos 1665 1.1 christos /* 1666 1.1 christos * eap_request - Receive EAP Request message (client mode). 1667 1.1 christos */ 1668 1.1 christos static void 1669 1.6 christos eap_request(eap_state *esp, u_char *inp, int id, int len) 1670 1.1 christos { 1671 1.1 christos u_char typenum; 1672 1.1 christos u_char vallen; 1673 1.1 christos int secret_len; 1674 1.1 christos char secret[MAXWORDLEN]; 1675 1.1 christos char rhostname[256]; 1676 1.7 christos PPP_MD_CTX *mdctx; 1677 1.7 christos u_char hash[MD5_DIGEST_LENGTH]; 1678 1.7 christos int hashlen = MD5_DIGEST_LENGTH; 1679 1.7 christos #ifdef PPP_WITH_EAPTLS 1680 1.6 christos u_char flags; 1681 1.6 christos struct eaptls_session *ets = esp->es_client.ea_session; 1682 1.7 christos #endif /* PPP_WITH_EAPTLS */ 1683 1.6 christos 1684 1.7 christos #ifdef PPP_WITH_SRP 1685 1.1 christos struct t_client *tc; 1686 1.1 christos struct t_num sval, gval, Nval, *Ap, Bval; 1687 1.1 christos u_char vals[2]; 1688 1.7 christos PPP_MD_CTX *ctxt; 1689 1.7 christos u_char dig[SHA_DIGEST_LENGTH]; 1690 1.7 christos int diglen = sizeof(dig); 1691 1.1 christos int fd; 1692 1.7 christos #endif /* PPP_WITH_SRP */ 1693 1.1 christos 1694 1.1 christos /* 1695 1.6 christos * Ignore requests if we're not open 1696 1.6 christos */ 1697 1.6 christos if (esp->es_client.ea_state <= eapClosed) 1698 1.6 christos return; 1699 1.6 christos 1700 1.6 christos /* 1701 1.1 christos * Note: we update es_client.ea_id *only if* a Response 1702 1.1 christos * message is being generated. Otherwise, we leave it the 1703 1.1 christos * same for duplicate detection purposes. 1704 1.1 christos */ 1705 1.1 christos 1706 1.1 christos esp->es_client.ea_requests++; 1707 1.1 christos if (esp->es_client.ea_maxrequests != 0 && 1708 1.1 christos esp->es_client.ea_requests > esp->es_client.ea_maxrequests) { 1709 1.1 christos info("EAP: received too many Request messages"); 1710 1.1 christos if (esp->es_client.ea_timeout > 0) { 1711 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp); 1712 1.1 christos } 1713 1.1 christos auth_withpeer_fail(esp->es_unit, PPP_EAP); 1714 1.1 christos return; 1715 1.1 christos } 1716 1.1 christos 1717 1.1 christos if (len <= 0) { 1718 1.1 christos error("EAP: empty Request message discarded"); 1719 1.1 christos return; 1720 1.1 christos } 1721 1.1 christos 1722 1.1 christos GETCHAR(typenum, inp); 1723 1.1 christos len--; 1724 1.1 christos 1725 1.1 christos switch (typenum) { 1726 1.1 christos case EAPT_IDENTITY: 1727 1.1 christos if (len > 0) 1728 1.1 christos info("EAP: Identity prompt \"%.*q\"", len, inp); 1729 1.7 christos #ifdef PPP_WITH_SRP 1730 1.1 christos if (esp->es_usepseudo && 1731 1.1 christos (esp->es_usedpseudo == 0 || 1732 1.1 christos (esp->es_usedpseudo == 1 && 1733 1.1 christos id == esp->es_client.ea_id))) { 1734 1.1 christos esp->es_usedpseudo = 1; 1735 1.1 christos /* Try to get a pseudonym */ 1736 1.1 christos if ((fd = open_pn_file(O_RDONLY)) >= 0) { 1737 1.1 christos strcpy(rhostname, SRP_PSEUDO_ID); 1738 1.1 christos len = read(fd, rhostname + SRP_PSEUDO_LEN, 1739 1.1 christos sizeof (rhostname) - SRP_PSEUDO_LEN); 1740 1.1 christos /* XXX NAI unsupported */ 1741 1.1 christos if (len > 0) { 1742 1.1 christos eap_send_response(esp, id, typenum, 1743 1.1 christos rhostname, len + SRP_PSEUDO_LEN); 1744 1.1 christos } 1745 1.1 christos (void) close(fd); 1746 1.1 christos if (len > 0) 1747 1.1 christos break; 1748 1.1 christos } 1749 1.1 christos } 1750 1.1 christos /* Stop using pseudonym now. */ 1751 1.1 christos if (esp->es_usepseudo && esp->es_usedpseudo != 2) { 1752 1.1 christos remove_pn_file(); 1753 1.1 christos esp->es_usedpseudo = 2; 1754 1.1 christos } 1755 1.7 christos #endif /* PPP_WITH_SRP */ 1756 1.6 christos eap_send_response(esp, id, typenum, (u_char *)esp->es_client.ea_name, 1757 1.1 christos esp->es_client.ea_namelen); 1758 1.1 christos break; 1759 1.1 christos 1760 1.1 christos case EAPT_NOTIFICATION: 1761 1.1 christos if (len > 0) 1762 1.1 christos info("EAP: Notification \"%.*q\"", len, inp); 1763 1.1 christos eap_send_response(esp, id, typenum, NULL, 0); 1764 1.1 christos break; 1765 1.1 christos 1766 1.1 christos case EAPT_NAK: 1767 1.1 christos /* 1768 1.1 christos * Avoid the temptation to send Response Nak in reply 1769 1.1 christos * to Request Nak here. It can only lead to trouble. 1770 1.1 christos */ 1771 1.1 christos warn("EAP: unexpected Nak in Request; ignored"); 1772 1.1 christos /* Return because we're waiting for something real. */ 1773 1.1 christos return; 1774 1.1 christos 1775 1.1 christos case EAPT_MD5CHAP: 1776 1.1 christos if (len < 1) { 1777 1.1 christos error("EAP: received MD5-Challenge with no data"); 1778 1.1 christos /* Bogus request; wait for something real. */ 1779 1.1 christos return; 1780 1.1 christos } 1781 1.1 christos GETCHAR(vallen, inp); 1782 1.1 christos len--; 1783 1.1 christos if (vallen < 8 || vallen > len) { 1784 1.1 christos error("EAP: MD5-Challenge with bad length %d (8..%d)", 1785 1.1 christos vallen, len); 1786 1.1 christos /* Try something better. */ 1787 1.1 christos eap_send_nak(esp, id, EAPT_SRP); 1788 1.1 christos break; 1789 1.1 christos } 1790 1.1 christos 1791 1.1 christos /* Not so likely to happen. */ 1792 1.5 christos if (len - vallen >= sizeof (rhostname)) { 1793 1.1 christos dbglog("EAP: trimming really long peer name down"); 1794 1.1 christos BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1); 1795 1.1 christos rhostname[sizeof (rhostname) - 1] = '\0'; 1796 1.1 christos } else { 1797 1.1 christos BCOPY(inp + vallen, rhostname, len - vallen); 1798 1.1 christos rhostname[len - vallen] = '\0'; 1799 1.1 christos } 1800 1.1 christos 1801 1.1 christos /* In case the remote doesn't give us his name. */ 1802 1.1 christos if (explicit_remote || 1803 1.1 christos (remote_name[0] != '\0' && vallen == len)) 1804 1.1 christos strlcpy(rhostname, remote_name, sizeof (rhostname)); 1805 1.1 christos 1806 1.1 christos /* 1807 1.1 christos * Get the secret for authenticating ourselves with 1808 1.1 christos * the specified host. 1809 1.1 christos */ 1810 1.1 christos if (!get_secret(esp->es_unit, esp->es_client.ea_name, 1811 1.1 christos rhostname, secret, &secret_len, 0)) { 1812 1.1 christos dbglog("EAP: no MD5 secret for auth to %q", rhostname); 1813 1.1 christos eap_send_nak(esp, id, EAPT_SRP); 1814 1.1 christos break; 1815 1.1 christos } 1816 1.7 christos 1817 1.7 christos mdctx = PPP_MD_CTX_new(); 1818 1.7 christos if (mdctx != NULL) { 1819 1.7 christos if (PPP_DigestInit(mdctx, PPP_md5())) { 1820 1.7 christos typenum = id; 1821 1.7 christos if (PPP_DigestUpdate(mdctx, &typenum, 1)) { 1822 1.7 christos if (PPP_DigestUpdate(mdctx, secret, secret_len)) { 1823 1.7 christos BZERO(secret, sizeof(secret)); 1824 1.7 christos if (PPP_DigestUpdate(mdctx, inp, vallen)) { 1825 1.7 christos if (PPP_DigestFinal(mdctx, hash, &hashlen)) { 1826 1.7 christos eap_chap_response(esp, id, hash, esp->es_client.ea_name, 1827 1.7 christos esp->es_client.ea_namelen); 1828 1.7 christos PPP_MD_CTX_free(mdctx); 1829 1.7 christos break; 1830 1.7 christos } 1831 1.7 christos } 1832 1.7 christos } 1833 1.7 christos } 1834 1.7 christos } 1835 1.7 christos PPP_MD_CTX_free(mdctx); 1836 1.7 christos } 1837 1.7 christos dbglog("EAP: Invalid MD5 checksum"); 1838 1.7 christos eap_send_nak(esp, id, EAPT_SRP); 1839 1.1 christos break; 1840 1.1 christos 1841 1.7 christos #ifdef PPP_WITH_EAPTLS 1842 1.6 christos case EAPT_TLS: 1843 1.6 christos 1844 1.6 christos switch(esp->es_client.ea_state) { 1845 1.6 christos 1846 1.6 christos case eapListen: 1847 1.6 christos 1848 1.6 christos if (len < 1) { 1849 1.6 christos error("EAP: received EAP-TLS Listen packet with no data"); 1850 1.6 christos /* Bogus request; wait for something real. */ 1851 1.6 christos return; 1852 1.6 christos } 1853 1.6 christos GETCHAR(flags, inp); 1854 1.6 christos if(flags & EAP_TLS_FLAGS_START){ 1855 1.6 christos 1856 1.6 christos esp->es_client.ea_using_eaptls = 1; 1857 1.6 christos 1858 1.6 christos if (explicit_remote){ 1859 1.6 christos esp->es_client.ea_peer = strdup(remote_name); 1860 1.6 christos esp->es_client.ea_peerlen = strlen(remote_name); 1861 1.6 christos } else 1862 1.6 christos esp->es_client.ea_peer = NULL; 1863 1.6 christos 1864 1.6 christos /* Init ssl session */ 1865 1.6 christos if(!eaptls_init_ssl_client(esp)) { 1866 1.6 christos dbglog("cannot init ssl"); 1867 1.6 christos eap_send_nak(esp, id, EAPT_MSCHAPV2); 1868 1.6 christos esp->es_client.ea_using_eaptls = 0; 1869 1.6 christos break; 1870 1.6 christos } 1871 1.6 christos 1872 1.6 christos ets = esp->es_client.ea_session; 1873 1.6 christos eap_tls_response(esp, id); 1874 1.6 christos esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); 1875 1.6 christos break; 1876 1.6 christos } 1877 1.6 christos 1878 1.6 christos /* The server has sent a bad start packet. */ 1879 1.6 christos eap_send_nak(esp, id, EAPT_MSCHAPV2); 1880 1.6 christos break; 1881 1.6 christos 1882 1.6 christos case eapTlsRecvAck: 1883 1.6 christos eap_tls_response(esp, id); 1884 1.6 christos esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); 1885 1.6 christos break; 1886 1.6 christos 1887 1.6 christos case eapTlsRecv: 1888 1.6 christos if (len < 1) { 1889 1.6 christos error("EAP: discarding EAP-TLS Receive packet with no data"); 1890 1.6 christos /* Bogus request; wait for something real. */ 1891 1.6 christos return; 1892 1.6 christos } 1893 1.6 christos eaptls_receive(ets, inp, len); 1894 1.6 christos 1895 1.6 christos if(ets->frag) { 1896 1.6 christos eap_tls_sendack(esp, id); 1897 1.6 christos esp->es_client.ea_state = eapTlsRecv; 1898 1.6 christos break; 1899 1.6 christos } 1900 1.6 christos 1901 1.6 christos if(ets->alert_recv) { 1902 1.6 christos eap_tls_sendack(esp, id); 1903 1.6 christos esp->es_client.ea_state = eapTlsRecvFailure; 1904 1.6 christos break; 1905 1.6 christos } 1906 1.6 christos 1907 1.6 christos /* Check if TLS handshake is finished */ 1908 1.6 christos if(eaptls_is_init_finished(ets)) { 1909 1.7 christos #ifdef PPP_WITH_MPPE 1910 1.6 christos eaptls_gen_mppe_keys(ets, 1); 1911 1.6 christos #endif 1912 1.6 christos eaptls_free_session(ets); 1913 1.6 christos eap_tls_sendack(esp, id); 1914 1.6 christos esp->es_client.ea_state = eapTlsRecvSuccess; 1915 1.6 christos break; 1916 1.6 christos } 1917 1.6 christos 1918 1.6 christos eap_tls_response(esp,id); 1919 1.6 christos esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv); 1920 1.6 christos break; 1921 1.6 christos 1922 1.6 christos default: 1923 1.6 christos eap_send_nak(esp, id, EAPT_MSCHAPV2); 1924 1.6 christos esp->es_client.ea_using_eaptls = 0; 1925 1.6 christos break; 1926 1.6 christos } 1927 1.6 christos 1928 1.6 christos break; 1929 1.7 christos #endif /* PPP_WITH_EAPTLS */ 1930 1.6 christos 1931 1.7 christos #ifdef PPP_WITH_SRP 1932 1.1 christos case EAPT_SRP: 1933 1.1 christos if (len < 1) { 1934 1.1 christos error("EAP: received empty SRP Request"); 1935 1.1 christos /* Bogus request; wait for something real. */ 1936 1.1 christos return; 1937 1.1 christos } 1938 1.1 christos 1939 1.1 christos /* Get subtype */ 1940 1.1 christos GETCHAR(vallen, inp); 1941 1.1 christos len--; 1942 1.1 christos switch (vallen) { 1943 1.1 christos case EAPSRP_CHALLENGE: 1944 1.1 christos tc = NULL; 1945 1.1 christos if (esp->es_client.ea_session != NULL) { 1946 1.1 christos tc = (struct t_client *)esp->es_client. 1947 1.1 christos ea_session; 1948 1.1 christos /* 1949 1.1 christos * If this is a new challenge, then start 1950 1.1 christos * over with a new client session context. 1951 1.1 christos * Otherwise, just resend last response. 1952 1.1 christos */ 1953 1.1 christos if (id != esp->es_client.ea_id) { 1954 1.1 christos t_clientclose(tc); 1955 1.1 christos esp->es_client.ea_session = NULL; 1956 1.1 christos tc = NULL; 1957 1.1 christos } 1958 1.1 christos } 1959 1.1 christos /* No session key just yet */ 1960 1.1 christos esp->es_client.ea_skey = NULL; 1961 1.1 christos if (tc == NULL) { 1962 1.1 christos GETCHAR(vallen, inp); 1963 1.1 christos len--; 1964 1.1 christos if (vallen >= len) { 1965 1.1 christos error("EAP: badly-formed SRP Challenge" 1966 1.1 christos " (name)"); 1967 1.1 christos /* Ignore badly-formed messages */ 1968 1.1 christos return; 1969 1.1 christos } 1970 1.1 christos BCOPY(inp, rhostname, vallen); 1971 1.1 christos rhostname[vallen] = '\0'; 1972 1.1 christos INCPTR(vallen, inp); 1973 1.1 christos len -= vallen; 1974 1.1 christos 1975 1.1 christos /* 1976 1.1 christos * In case the remote doesn't give us his name, 1977 1.1 christos * use configured name. 1978 1.1 christos */ 1979 1.1 christos if (explicit_remote || 1980 1.1 christos (remote_name[0] != '\0' && vallen == 0)) { 1981 1.1 christos strlcpy(rhostname, remote_name, 1982 1.1 christos sizeof (rhostname)); 1983 1.1 christos } 1984 1.1 christos 1985 1.1 christos if (esp->es_client.ea_peer != NULL) 1986 1.1 christos free(esp->es_client.ea_peer); 1987 1.1 christos esp->es_client.ea_peer = strdup(rhostname); 1988 1.1 christos esp->es_client.ea_peerlen = strlen(rhostname); 1989 1.1 christos 1990 1.1 christos GETCHAR(vallen, inp); 1991 1.1 christos len--; 1992 1.1 christos if (vallen >= len) { 1993 1.1 christos error("EAP: badly-formed SRP Challenge" 1994 1.1 christos " (s)"); 1995 1.1 christos /* Ignore badly-formed messages */ 1996 1.1 christos return; 1997 1.1 christos } 1998 1.1 christos sval.data = inp; 1999 1.1 christos sval.len = vallen; 2000 1.1 christos INCPTR(vallen, inp); 2001 1.1 christos len -= vallen; 2002 1.1 christos 2003 1.1 christos GETCHAR(vallen, inp); 2004 1.1 christos len--; 2005 1.1 christos if (vallen > len) { 2006 1.1 christos error("EAP: badly-formed SRP Challenge" 2007 1.1 christos " (g)"); 2008 1.1 christos /* Ignore badly-formed messages */ 2009 1.1 christos return; 2010 1.1 christos } 2011 1.1 christos /* If no generator present, then use value 2 */ 2012 1.1 christos if (vallen == 0) { 2013 1.1 christos gval.data = (u_char *)"\002"; 2014 1.1 christos gval.len = 1; 2015 1.1 christos } else { 2016 1.1 christos gval.data = inp; 2017 1.1 christos gval.len = vallen; 2018 1.1 christos } 2019 1.1 christos INCPTR(vallen, inp); 2020 1.1 christos len -= vallen; 2021 1.1 christos 2022 1.1 christos /* 2023 1.1 christos * If no modulus present, then use well-known 2024 1.1 christos * value. 2025 1.1 christos */ 2026 1.1 christos if (len == 0) { 2027 1.1 christos Nval.data = (u_char *)wkmodulus; 2028 1.1 christos Nval.len = sizeof (wkmodulus); 2029 1.1 christos } else { 2030 1.1 christos Nval.data = inp; 2031 1.1 christos Nval.len = len; 2032 1.1 christos } 2033 1.1 christos tc = t_clientopen(esp->es_client.ea_name, 2034 1.1 christos &Nval, &gval, &sval); 2035 1.1 christos if (tc == NULL) { 2036 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP); 2037 1.1 christos break; 2038 1.1 christos } 2039 1.1 christos esp->es_client.ea_session = (void *)tc; 2040 1.1 christos 2041 1.1 christos /* Add Challenge ID & type to verifier */ 2042 1.1 christos vals[0] = id; 2043 1.1 christos vals[1] = EAPT_SRP; 2044 1.1 christos t_clientaddexdata(tc, vals, 2); 2045 1.1 christos } 2046 1.1 christos Ap = t_clientgenexp(tc); 2047 1.1 christos eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data, 2048 1.1 christos Ap->len); 2049 1.1 christos break; 2050 1.1 christos 2051 1.1 christos case EAPSRP_SKEY: 2052 1.1 christos tc = (struct t_client *)esp->es_client.ea_session; 2053 1.1 christos if (tc == NULL) { 2054 1.1 christos warn("EAP: peer sent Subtype 2 without 1"); 2055 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP); 2056 1.1 christos break; 2057 1.1 christos } 2058 1.1 christos if (esp->es_client.ea_skey != NULL) { 2059 1.1 christos /* 2060 1.1 christos * ID number should not change here. Warn 2061 1.1 christos * if it does (but otherwise ignore). 2062 1.1 christos */ 2063 1.1 christos if (id != esp->es_client.ea_id) { 2064 1.1 christos warn("EAP: ID changed from %d to %d " 2065 1.1 christos "in SRP Subtype 2 rexmit", 2066 1.1 christos esp->es_client.ea_id, id); 2067 1.1 christos } 2068 1.1 christos } else { 2069 1.1 christos if (get_srp_secret(esp->es_unit, 2070 1.1 christos esp->es_client.ea_name, 2071 1.1 christos esp->es_client.ea_peer, secret, 0) == 0) { 2072 1.1 christos /* 2073 1.1 christos * Can't work with this peer because 2074 1.1 christos * the secret is missing. Just give 2075 1.1 christos * up. 2076 1.1 christos */ 2077 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP); 2078 1.1 christos break; 2079 1.1 christos } 2080 1.1 christos Bval.data = inp; 2081 1.1 christos Bval.len = len; 2082 1.1 christos t_clientpasswd(tc, secret); 2083 1.1 christos BZERO(secret, sizeof (secret)); 2084 1.1 christos esp->es_client.ea_skey = 2085 1.1 christos t_clientgetkey(tc, &Bval); 2086 1.1 christos if (esp->es_client.ea_skey == NULL) { 2087 1.1 christos /* Server is rogue; stop now */ 2088 1.1 christos error("EAP: SRP server is rogue"); 2089 1.1 christos goto client_failure; 2090 1.1 christos } 2091 1.1 christos } 2092 1.1 christos eap_srpval_response(esp, id, SRPVAL_EBIT, 2093 1.1 christos t_clientresponse(tc)); 2094 1.1 christos break; 2095 1.1 christos 2096 1.1 christos case EAPSRP_SVALIDATOR: 2097 1.1 christos tc = (struct t_client *)esp->es_client.ea_session; 2098 1.1 christos if (tc == NULL || esp->es_client.ea_skey == NULL) { 2099 1.1 christos warn("EAP: peer sent Subtype 3 without 1/2"); 2100 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP); 2101 1.1 christos break; 2102 1.1 christos } 2103 1.1 christos /* 2104 1.1 christos * If we're already open, then this ought to be a 2105 1.1 christos * duplicate. Otherwise, check that the server is 2106 1.1 christos * who we think it is. 2107 1.1 christos */ 2108 1.1 christos if (esp->es_client.ea_state == eapOpen) { 2109 1.1 christos if (id != esp->es_client.ea_id) { 2110 1.1 christos warn("EAP: ID changed from %d to %d " 2111 1.1 christos "in SRP Subtype 3 rexmit", 2112 1.1 christos esp->es_client.ea_id, id); 2113 1.1 christos } 2114 1.1 christos } else { 2115 1.7 christos len -= sizeof (u_int32_t) + SHA_DIGEST_LENGTH; 2116 1.1 christos if (len < 0 || t_clientverify(tc, inp + 2117 1.1 christos sizeof (u_int32_t)) != 0) { 2118 1.1 christos error("EAP: SRP server verification " 2119 1.1 christos "failed"); 2120 1.1 christos goto client_failure; 2121 1.1 christos } 2122 1.1 christos GETLONG(esp->es_client.ea_keyflags, inp); 2123 1.1 christos /* Save pseudonym if user wants it. */ 2124 1.1 christos if (len > 0 && esp->es_usepseudo) { 2125 1.7 christos INCPTR(SHA_DIGEST_LENGTH, inp); 2126 1.1 christos write_pseudonym(esp, inp, len, id); 2127 1.1 christos } 2128 1.1 christos } 2129 1.1 christos /* 2130 1.1 christos * We've verified our peer. We're now mostly done, 2131 1.1 christos * except for waiting on the regular EAP Success 2132 1.1 christos * message. 2133 1.1 christos */ 2134 1.1 christos eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0); 2135 1.1 christos break; 2136 1.1 christos 2137 1.1 christos case EAPSRP_LWRECHALLENGE: 2138 1.1 christos if (len < 4) { 2139 1.1 christos warn("EAP: malformed Lightweight rechallenge"); 2140 1.1 christos return; 2141 1.1 christos } 2142 1.7 christos ctxt = PPP_MD_CTX_new(); 2143 1.7 christos if (ctxt) { 2144 1.7 christos 2145 1.7 christos vals[0] = id; 2146 1.7 christos PPP_DigestInit(ctxt, PPP_sha1()); 2147 1.7 christos PPP_DigestUpdate(ctxt, vals, 1); 2148 1.7 christos PPP_DigestUpdate(ctxt, esp->es_client.ea_skey, 2149 1.7 christos SESSION_KEY_LEN); 2150 1.7 christos PPP_DigestUpdate(ctxt, inp, len); 2151 1.7 christos PPP_DigestUpdate(ctxt, esp->es_client.ea_name, 2152 1.7 christos esp->es_client.ea_namelen); 2153 1.7 christos PPP_DigestFinal(ctxt, dig, &diglen); 2154 1.7 christos 2155 1.7 christos PPP_MD_CTX_free(ctxt); 2156 1.7 christos 2157 1.7 christos eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig, 2158 1.7 christos SHA_DIGEST_LENGTH); 2159 1.7 christos } 2160 1.1 christos break; 2161 1.1 christos 2162 1.1 christos default: 2163 1.1 christos error("EAP: unknown SRP Subtype %d", vallen); 2164 1.1 christos eap_send_nak(esp, id, EAPT_MD5CHAP); 2165 1.1 christos break; 2166 1.1 christos } 2167 1.1 christos break; 2168 1.7 christos #endif /* PPP_WITH_SRP */ 2169 1.7 christos 2170 1.7 christos #ifdef PPP_WITH_CHAPMS 2171 1.6 christos case EAPT_MSCHAPV2: 2172 1.6 christos if (len < 4) { 2173 1.6 christos error("EAP: received invalid MSCHAPv2 packet, too short"); 2174 1.6 christos return; 2175 1.6 christos } 2176 1.6 christos unsigned char opcode; 2177 1.6 christos GETCHAR(opcode, inp); 2178 1.6 christos unsigned char chapid; /* Chapv2-ID */ 2179 1.6 christos GETCHAR(chapid, inp); 2180 1.6 christos short mssize; 2181 1.6 christos GETSHORT(mssize, inp); 2182 1.6 christos 2183 1.6 christos /* Validate the mssize field */ 2184 1.6 christos if (len != mssize) { 2185 1.6 christos error("EAP: received invalid MSCHAPv2 packet, invalid length"); 2186 1.6 christos return; 2187 1.6 christos } 2188 1.6 christos len -= 4; 2189 1.6 christos 2190 1.6 christos /* If MSCHAPv2 digest was not found, NAK the packet */ 2191 1.6 christos if (!esp->es_client.digest) { 2192 1.6 christos error("EAP MSCHAPv2 not supported"); 2193 1.6 christos eap_send_nak(esp, id, EAPT_SRP); 2194 1.6 christos return; 2195 1.6 christos } 2196 1.6 christos 2197 1.6 christos switch (opcode) { 2198 1.6 christos case CHAP_CHALLENGE: { 2199 1.6 christos 2200 1.6 christos /* make_response() expects: VLEN + VALUE */ 2201 1.6 christos u_char *challenge = inp; 2202 1.6 christos 2203 1.6 christos unsigned char vsize; 2204 1.6 christos GETCHAR(vsize, inp); 2205 1.6 christos len -= 1; 2206 1.6 christos 2207 1.6 christos /* Validate the VALUE field */ 2208 1.6 christos if (vsize != MS_CHAP2_PEER_CHAL_LEN || len < MS_CHAP2_PEER_CHAL_LEN) { 2209 1.6 christos error("EAP: received invalid MSCHAPv2 packet, invalid value-length: %d", vsize); 2210 1.6 christos return; 2211 1.6 christos } 2212 1.6 christos 2213 1.6 christos /* Increment past the VALUE field */ 2214 1.6 christos INCPTR(MS_CHAP2_PEER_CHAL_LEN, inp); 2215 1.6 christos len -= MS_CHAP2_PEER_CHAL_LEN; 2216 1.6 christos 2217 1.6 christos /* Extract the hostname */ 2218 1.6 christos rhostname[0] = '\0'; 2219 1.6 christos if (len > 0) { 2220 1.6 christos if (len >= sizeof (rhostname)) { 2221 1.6 christos dbglog("EAP: trimming really long peer name down"); 2222 1.6 christos len = sizeof(rhostname) - 1; 2223 1.6 christos } 2224 1.6 christos BCOPY(inp, rhostname, len); 2225 1.6 christos rhostname[len] = '\0'; 2226 1.6 christos } 2227 1.6 christos 2228 1.6 christos /* In case the remote doesn't give us his name. */ 2229 1.6 christos if (explicit_remote || (remote_name[0] != '\0' && len == 0)) 2230 1.6 christos strlcpy(rhostname, remote_name, sizeof(rhostname)); 2231 1.6 christos 2232 1.6 christos /* Get the secret for authenticating ourselves with the specified host. */ 2233 1.6 christos if (!get_secret(esp->es_unit, esp->es_client.ea_name, 2234 1.6 christos rhostname, secret, &secret_len, 0)) { 2235 1.6 christos dbglog("EAP: no CHAP secret for auth to %q", rhostname); 2236 1.6 christos eap_send_nak(esp, id, EAPT_SRP); 2237 1.6 christos break; 2238 1.6 christos } 2239 1.7 christos esp->es_client.ea_namelen = strlen(esp->es_client.ea_name); 2240 1.6 christos 2241 1.6 christos /* Create the MSCHAPv2 response (and add to cache) */ 2242 1.6 christos unsigned char response[MS_CHAP2_RESPONSE_LEN+1]; // VLEN + VALUE 2243 1.6 christos esp->es_client.digest->make_response(response, chapid, esp->es_client.ea_name, 2244 1.6 christos challenge, secret, secret_len, NULL); 2245 1.6 christos 2246 1.6 christos eap_chapv2_response(esp, id, chapid, response, esp->es_client.ea_name, esp->es_client.ea_namelen); 2247 1.6 christos break; 2248 1.6 christos } 2249 1.6 christos case CHAP_SUCCESS: { 2250 1.6 christos 2251 1.6 christos /* Check response for mutual authentication */ 2252 1.6 christos u_char status = CHAP_FAILURE; 2253 1.6 christos if (esp->es_client.digest->check_success(chapid, inp, len) == 1) { 2254 1.6 christos info("Chap authentication succeeded! %.*v", len, inp); 2255 1.6 christos status = CHAP_SUCCESS; 2256 1.6 christos } 2257 1.6 christos eap_send_response(esp, id, EAPT_MSCHAPV2, &status, sizeof(status)); 2258 1.6 christos break; 2259 1.6 christos } 2260 1.6 christos case CHAP_FAILURE: { 2261 1.6 christos 2262 1.6 christos /* Process the failure string, and log appropriate information */ 2263 1.6 christos esp->es_client.digest->handle_failure(inp, len); 2264 1.6 christos 2265 1.6 christos u_char status = CHAP_FAILURE; 2266 1.6 christos eap_send_response(esp, id, EAPT_MSCHAPV2, &status, sizeof(status)); 2267 1.6 christos goto client_failure; /* force termination */ 2268 1.6 christos } 2269 1.6 christos default: 2270 1.6 christos 2271 1.6 christos error("EAP: received invalid MSCHAPv2 packet, invalid or unsupported opcode: %d", opcode); 2272 1.6 christos eap_send_nak(esp, id, EAPT_SRP); 2273 1.6 christos } 2274 1.6 christos 2275 1.6 christos break; 2276 1.7 christos #endif /* PPP_WITH_CHAPMS */ 2277 1.7 christos #ifdef PPP_WITH_PEAP 2278 1.7 christos case EAPT_PEAP: 2279 1.7 christos 2280 1.7 christos /* Initialize the PEAP context (if not already initialized) */ 2281 1.7 christos if (!esp->ea_peap) { 2282 1.7 christos rhostname[0] = '\0'; 2283 1.7 christos if (explicit_remote || (remote_name[0] != '\0')) { 2284 1.7 christos strlcpy(rhostname, remote_name, sizeof (rhostname)); 2285 1.7 christos } 2286 1.7 christos if (peap_init(&esp->ea_peap, rhostname)) { 2287 1.7 christos eap_send_nak(esp, id, EAPT_TLS); 2288 1.7 christos break; 2289 1.7 christos } 2290 1.7 christos } 2291 1.7 christos 2292 1.7 christos /* Process the PEAP packet */ 2293 1.7 christos if (peap_process(esp, id, inp, len)) { 2294 1.7 christos eap_send_nak(esp, id, EAPT_TLS); 2295 1.7 christos } 2296 1.7 christos 2297 1.7 christos break; 2298 1.7 christos #endif // PPP_WITH_PEAP 2299 1.1 christos 2300 1.1 christos default: 2301 1.1 christos info("EAP: unknown authentication type %d; Naking", typenum); 2302 1.1 christos eap_send_nak(esp, id, EAPT_SRP); 2303 1.1 christos break; 2304 1.1 christos } 2305 1.1 christos 2306 1.1 christos if (esp->es_client.ea_timeout > 0) { 2307 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp); 2308 1.1 christos TIMEOUT(eap_client_timeout, (void *)esp, 2309 1.1 christos esp->es_client.ea_timeout); 2310 1.1 christos } 2311 1.1 christos return; 2312 1.1 christos 2313 1.1 christos client_failure: 2314 1.1 christos esp->es_client.ea_state = eapBadAuth; 2315 1.1 christos if (esp->es_client.ea_timeout > 0) { 2316 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp); 2317 1.1 christos } 2318 1.1 christos esp->es_client.ea_session = NULL; 2319 1.7 christos #ifdef PPP_WITH_SRP 2320 1.1 christos t_clientclose(tc); 2321 1.1 christos auth_withpeer_fail(esp->es_unit, PPP_EAP); 2322 1.7 christos #endif /* PPP_WITH_SRP */ 2323 1.1 christos } 2324 1.1 christos 2325 1.1 christos /* 2326 1.1 christos * eap_response - Receive EAP Response message (server mode). 2327 1.1 christos */ 2328 1.1 christos static void 2329 1.6 christos eap_response(eap_state *esp, u_char *inp, int id, int len) 2330 1.1 christos { 2331 1.1 christos u_char typenum; 2332 1.1 christos u_char vallen; 2333 1.1 christos int secret_len; 2334 1.1 christos char secret[MAXSECRETLEN]; 2335 1.1 christos char rhostname[256]; 2336 1.7 christos PPP_MD_CTX *mdctx; 2337 1.7 christos u_char hash[MD5_DIGEST_LENGTH]; 2338 1.7 christos int hashlen = MD5_DIGEST_LENGTH; 2339 1.7 christos #ifdef PPP_WITH_SRP 2340 1.1 christos struct t_server *ts; 2341 1.1 christos struct t_num A; 2342 1.7 christos PPP_MD_CTX *ctxt; 2343 1.7 christos u_char dig[SHA_DIGEST_LENGTH]; 2344 1.7 christos int diglen = sizeof(dig); 2345 1.7 christos #endif /* PPP_WITH_SRP */ 2346 1.1 christos 2347 1.7 christos #ifdef PPP_WITH_EAPTLS 2348 1.6 christos struct eaptls_session *ets; 2349 1.6 christos u_char flags; 2350 1.7 christos #endif /* PPP_WITH_EAPTLS */ 2351 1.7 christos #ifdef PPP_WITH_CHAPMS 2352 1.6 christos u_char opcode; 2353 1.7 christos chap_verify_hook_fn *chap_verifier; 2354 1.6 christos char response_message[256]; 2355 1.7 christos #endif /* PPP_WITH_CHAPMS */ 2356 1.6 christos 2357 1.6 christos /* 2358 1.6 christos * Ignore responses if we're not open 2359 1.6 christos */ 2360 1.6 christos if (esp->es_server.ea_state <= eapClosed) 2361 1.6 christos return; 2362 1.6 christos 2363 1.1 christos if (esp->es_server.ea_id != id) { 2364 1.1 christos dbglog("EAP: discarding Response %d; expected ID %d", id, 2365 1.1 christos esp->es_server.ea_id); 2366 1.1 christos return; 2367 1.1 christos } 2368 1.1 christos 2369 1.1 christos esp->es_server.ea_responses++; 2370 1.1 christos 2371 1.1 christos if (len <= 0) { 2372 1.1 christos error("EAP: empty Response message discarded"); 2373 1.1 christos return; 2374 1.1 christos } 2375 1.1 christos 2376 1.1 christos GETCHAR(typenum, inp); 2377 1.1 christos len--; 2378 1.1 christos 2379 1.1 christos switch (typenum) { 2380 1.1 christos case EAPT_IDENTITY: 2381 1.1 christos if (esp->es_server.ea_state != eapIdentify) { 2382 1.1 christos dbglog("EAP discarding unwanted Identify \"%.q\"", len, 2383 1.1 christos inp); 2384 1.1 christos break; 2385 1.1 christos } 2386 1.1 christos info("EAP: unauthenticated peer name \"%.*q\"", len, inp); 2387 1.1 christos if (esp->es_server.ea_peer != NULL && 2388 1.1 christos esp->es_server.ea_peer != remote_name) 2389 1.1 christos free(esp->es_server.ea_peer); 2390 1.1 christos esp->es_server.ea_peer = malloc(len + 1); 2391 1.1 christos if (esp->es_server.ea_peer == NULL) { 2392 1.1 christos esp->es_server.ea_peerlen = 0; 2393 1.1 christos eap_figure_next_state(esp, 1); 2394 1.1 christos break; 2395 1.1 christos } 2396 1.1 christos BCOPY(inp, esp->es_server.ea_peer, len); 2397 1.1 christos esp->es_server.ea_peer[len] = '\0'; 2398 1.1 christos esp->es_server.ea_peerlen = len; 2399 1.1 christos eap_figure_next_state(esp, 0); 2400 1.1 christos break; 2401 1.1 christos 2402 1.7 christos #ifdef PPP_WITH_EAPTLS 2403 1.6 christos case EAPT_TLS: 2404 1.6 christos switch(esp->es_server.ea_state) { 2405 1.6 christos 2406 1.6 christos case eapTlsRecv: 2407 1.6 christos 2408 1.6 christos ets = (struct eaptls_session *) esp->es_server.ea_session; 2409 1.6 christos 2410 1.6 christos eap_figure_next_state(esp, 2411 1.6 christos eaptls_receive(esp->es_server.ea_session, inp, len)); 2412 1.6 christos 2413 1.6 christos if(ets->alert_recv) { 2414 1.6 christos eap_send_failure(esp); 2415 1.6 christos break; 2416 1.6 christos } 2417 1.6 christos break; 2418 1.6 christos 2419 1.6 christos case eapTlsRecvAck: 2420 1.6 christos if(len > 1) { 2421 1.6 christos dbglog("EAP-TLS ACK with extra data"); 2422 1.6 christos } 2423 1.6 christos eap_figure_next_state(esp, 0); 2424 1.6 christos break; 2425 1.6 christos 2426 1.6 christos case eapTlsRecvClient: 2427 1.6 christos /* Receive authentication response from client */ 2428 1.6 christos if (len > 0) { 2429 1.6 christos GETCHAR(flags, inp); 2430 1.6 christos 2431 1.6 christos if(len == 1 && !flags) { /* Ack = ok */ 2432 1.7 christos #ifdef PPP_WITH_MPPE 2433 1.6 christos eaptls_gen_mppe_keys( esp->es_server.ea_session, 0 ); 2434 1.6 christos #endif 2435 1.6 christos eap_send_success(esp); 2436 1.6 christos } 2437 1.6 christos else { /* failure */ 2438 1.6 christos warn("Server authentication failed"); 2439 1.6 christos eap_send_failure(esp); 2440 1.6 christos } 2441 1.6 christos } 2442 1.6 christos else 2443 1.6 christos warn("Bogus EAP-TLS packet received from client"); 2444 1.6 christos 2445 1.6 christos eaptls_free_session(esp->es_server.ea_session); 2446 1.6 christos 2447 1.6 christos break; 2448 1.6 christos 2449 1.6 christos case eapTlsRecvAlertAck: 2450 1.6 christos eap_send_failure(esp); 2451 1.6 christos break; 2452 1.6 christos 2453 1.6 christos default: 2454 1.6 christos eap_figure_next_state(esp, 1); 2455 1.6 christos break; 2456 1.6 christos } 2457 1.6 christos break; 2458 1.7 christos #endif /* PPP_WITH_EAPTLS */ 2459 1.6 christos 2460 1.1 christos case EAPT_NOTIFICATION: 2461 1.1 christos dbglog("EAP unexpected Notification; response discarded"); 2462 1.1 christos break; 2463 1.1 christos 2464 1.1 christos case EAPT_NAK: 2465 1.1 christos if (len < 1) { 2466 1.1 christos info("EAP: Nak Response with no suggested protocol"); 2467 1.1 christos eap_figure_next_state(esp, 1); 2468 1.1 christos break; 2469 1.1 christos } 2470 1.1 christos 2471 1.1 christos GETCHAR(vallen, inp); 2472 1.1 christos len--; 2473 1.1 christos 2474 1.1 christos if (!explicit_remote && esp->es_server.ea_state == eapIdentify){ 2475 1.1 christos /* Peer cannot Nak Identify Request */ 2476 1.1 christos eap_figure_next_state(esp, 1); 2477 1.1 christos break; 2478 1.1 christos } 2479 1.1 christos 2480 1.1 christos switch (vallen) { 2481 1.1 christos case EAPT_SRP: 2482 1.1 christos /* Run through SRP validator selection again. */ 2483 1.1 christos esp->es_server.ea_state = eapIdentify; 2484 1.1 christos eap_figure_next_state(esp, 0); 2485 1.1 christos break; 2486 1.1 christos 2487 1.1 christos case EAPT_MD5CHAP: 2488 1.1 christos esp->es_server.ea_state = eapMD5Chall; 2489 1.1 christos break; 2490 1.1 christos 2491 1.7 christos #ifdef PPP_WITH_EAPTLS 2492 1.6 christos /* Send EAP-TLS start packet */ 2493 1.6 christos case EAPT_TLS: 2494 1.6 christos esp->es_server.ea_state = eapTlsStart; 2495 1.6 christos break; 2496 1.7 christos #endif /* PPP_WITH_EAPTLS */ 2497 1.6 christos 2498 1.7 christos #ifdef PPP_WITH_CHAPMS 2499 1.6 christos case EAPT_MSCHAPV2: 2500 1.6 christos info("EAP: peer proposes MSCHAPv2"); 2501 1.7 christos /* If MSCHAPv2 digest was not found, NAK the packet */ 2502 1.7 christos if (!esp->es_server.digest) { 2503 1.7 christos error("EAP MSCHAPv2 not supported"); 2504 1.7 christos eap_send_nak(esp, id, EAPT_SRP); 2505 1.7 christos break; 2506 1.7 christos } 2507 1.6 christos esp->es_server.ea_state = eapMSCHAPv2Chall; 2508 1.6 christos break; 2509 1.7 christos #endif /* PPP_WITH_CHAPMS */ 2510 1.6 christos 2511 1.1 christos default: 2512 1.1 christos dbglog("EAP: peer requesting unknown Type %d", vallen); 2513 1.1 christos switch (esp->es_server.ea_state) { 2514 1.1 christos case eapSRP1: 2515 1.1 christos case eapSRP2: 2516 1.1 christos case eapSRP3: 2517 1.1 christos esp->es_server.ea_state = eapMD5Chall; 2518 1.1 christos break; 2519 1.1 christos case eapMD5Chall: 2520 1.1 christos case eapSRP4: 2521 1.1 christos esp->es_server.ea_state = eapIdentify; 2522 1.1 christos eap_figure_next_state(esp, 0); 2523 1.1 christos break; 2524 1.1 christos default: 2525 1.1 christos break; 2526 1.1 christos } 2527 1.1 christos break; 2528 1.1 christos } 2529 1.1 christos break; 2530 1.1 christos 2531 1.1 christos case EAPT_MD5CHAP: 2532 1.1 christos if (esp->es_server.ea_state != eapMD5Chall) { 2533 1.1 christos error("EAP: unexpected MD5-Response"); 2534 1.1 christos eap_figure_next_state(esp, 1); 2535 1.1 christos break; 2536 1.1 christos } 2537 1.1 christos if (len < 1) { 2538 1.1 christos error("EAP: received MD5-Response with no data"); 2539 1.1 christos eap_figure_next_state(esp, 1); 2540 1.1 christos break; 2541 1.1 christos } 2542 1.1 christos GETCHAR(vallen, inp); 2543 1.1 christos len--; 2544 1.1 christos if (vallen != 16 || vallen > len) { 2545 1.1 christos error("EAP: MD5-Response with bad length %d", vallen); 2546 1.1 christos eap_figure_next_state(esp, 1); 2547 1.1 christos break; 2548 1.1 christos } 2549 1.1 christos 2550 1.1 christos /* Not so likely to happen. */ 2551 1.5 christos if (len - vallen >= sizeof (rhostname)) { 2552 1.1 christos dbglog("EAP: trimming really long peer name down"); 2553 1.1 christos BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1); 2554 1.1 christos rhostname[sizeof (rhostname) - 1] = '\0'; 2555 1.1 christos } else { 2556 1.1 christos BCOPY(inp + vallen, rhostname, len - vallen); 2557 1.1 christos rhostname[len - vallen] = '\0'; 2558 1.1 christos } 2559 1.1 christos 2560 1.1 christos /* In case the remote doesn't give us his name. */ 2561 1.1 christos if (explicit_remote || 2562 1.1 christos (remote_name[0] != '\0' && vallen == len)) 2563 1.1 christos strlcpy(rhostname, remote_name, sizeof (rhostname)); 2564 1.1 christos 2565 1.1 christos /* 2566 1.1 christos * Get the secret for authenticating the specified 2567 1.1 christos * host. 2568 1.1 christos */ 2569 1.1 christos if (!get_secret(esp->es_unit, rhostname, 2570 1.1 christos esp->es_server.ea_name, secret, &secret_len, 1)) { 2571 1.1 christos dbglog("EAP: no MD5 secret for auth of %q", rhostname); 2572 1.1 christos eap_send_failure(esp); 2573 1.1 christos break; 2574 1.1 christos } 2575 1.7 christos 2576 1.7 christos mdctx = PPP_MD_CTX_new(); 2577 1.7 christos if (mdctx != NULL) { 2578 1.7 christos 2579 1.7 christos if (PPP_DigestInit(mdctx, PPP_md5())) { 2580 1.7 christos 2581 1.7 christos if (PPP_DigestUpdate(mdctx, &esp->es_server.ea_id, 1)) { 2582 1.7 christos 2583 1.7 christos if (PPP_DigestUpdate(mdctx, &secret, secret_len)) { 2584 1.7 christos 2585 1.7 christos BZERO(secret, sizeof(secret)); 2586 1.7 christos if (PPP_DigestUpdate(mdctx, esp->es_challenge, esp->es_challen)) { 2587 1.7 christos 2588 1.7 christos if (PPP_DigestFinal(mdctx, hash, &hashlen)) { 2589 1.7 christos 2590 1.7 christos if (BCMP(hash, inp, MD5_DIGEST_LENGTH) == 0) { 2591 1.7 christos esp->es_server.ea_type = EAPT_MD5CHAP; 2592 1.7 christos eap_send_success(esp); 2593 1.7 christos eap_figure_next_state(esp, 0); 2594 1.7 christos 2595 1.7 christos if (esp->es_rechallenge != 0) { 2596 1.7 christos TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge); 2597 1.7 christos } 2598 1.7 christos PPP_MD_CTX_free(mdctx); 2599 1.7 christos break; 2600 1.7 christos } 2601 1.7 christos } 2602 1.7 christos } 2603 1.7 christos } 2604 1.7 christos } 2605 1.7 christos } 2606 1.7 christos 2607 1.7 christos PPP_MD_CTX_free(mdctx); 2608 1.1 christos } 2609 1.7 christos 2610 1.7 christos eap_send_failure(esp); 2611 1.1 christos break; 2612 1.1 christos 2613 1.7 christos #ifdef PPP_WITH_CHAPMS 2614 1.6 christos case EAPT_MSCHAPV2: 2615 1.6 christos if (len < 1) { 2616 1.6 christos error("EAP: received MSCHAPv2 with no data"); 2617 1.6 christos eap_figure_next_state(esp, 1); 2618 1.6 christos break; 2619 1.6 christos } 2620 1.6 christos GETCHAR(opcode, inp); 2621 1.6 christos len--; 2622 1.6 christos 2623 1.6 christos switch (opcode) { 2624 1.6 christos case CHAP_RESPONSE: 2625 1.6 christos if (esp->es_server.ea_state != eapMSCHAPv2Chall) { 2626 1.6 christos error("EAP: unexpected MSCHAPv2-Response"); 2627 1.6 christos eap_figure_next_state(esp, 1); 2628 1.6 christos break; 2629 1.6 christos } 2630 1.6 christos /* skip MS ID + len */ 2631 1.6 christos INCPTR(3, inp); 2632 1.6 christos GETCHAR(vallen, inp); 2633 1.6 christos len -= 4; 2634 1.6 christos 2635 1.6 christos if (vallen != MS_CHAP2_RESPONSE_LEN || vallen > len) { 2636 1.6 christos error("EAP: Invalid MSCHAPv2-Response " 2637 1.6 christos "length %d", vallen); 2638 1.6 christos eap_figure_next_state(esp, 1); 2639 1.6 christos break; 2640 1.6 christos } 2641 1.6 christos 2642 1.6 christos /* Not so likely to happen. */ 2643 1.6 christos if (len - vallen >= sizeof (rhostname)) { 2644 1.6 christos dbglog("EAP: trimming really long peer name down"); 2645 1.6 christos BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1); 2646 1.6 christos rhostname[sizeof (rhostname) - 1] = '\0'; 2647 1.6 christos } else { 2648 1.6 christos BCOPY(inp + vallen, rhostname, len - vallen); 2649 1.6 christos rhostname[len - vallen] = '\0'; 2650 1.6 christos } 2651 1.6 christos 2652 1.6 christos /* In case the remote doesn't give us his name. */ 2653 1.6 christos if (explicit_remote || 2654 1.6 christos (remote_name[0] != '\0' && vallen == len)) 2655 1.6 christos strlcpy(rhostname, remote_name, sizeof (rhostname)); 2656 1.6 christos 2657 1.7 christos /* strip the MS domain name */ 2658 1.7 christos if (chapms_strip_domain && strrchr(rhostname, '\\')) { 2659 1.7 christos char tmp[MAXNAMELEN+1]; 2660 1.7 christos 2661 1.7 christos strcpy(tmp, strrchr(rhostname, '\\') + 1); 2662 1.7 christos strlcpy(rhostname, tmp, sizeof(rhostname)); 2663 1.7 christos } 2664 1.7 christos 2665 1.6 christos if (chap_verify_hook) 2666 1.6 christos chap_verifier = chap_verify_hook; 2667 1.6 christos else 2668 1.6 christos chap_verifier = eap_chap_verify_response; 2669 1.6 christos 2670 1.6 christos esp->es_server.ea_id += 1; 2671 1.6 christos if ((*chap_verifier)(rhostname, 2672 1.6 christos esp->es_server.ea_name, 2673 1.6 christos id, 2674 1.7 christos esp->es_server.digest, 2675 1.6 christos esp->es_challenge, 2676 1.6 christos inp - 1, 2677 1.6 christos response_message, 2678 1.6 christos sizeof(response_message))) 2679 1.6 christos { 2680 1.6 christos info("EAP: MSCHAPv2 success for peer %q", 2681 1.6 christos rhostname); 2682 1.6 christos esp->es_server.ea_type = EAPT_MSCHAPV2; 2683 1.6 christos eap_chapms2_send_request(esp, 2684 1.6 christos esp->es_server.ea_id, 2685 1.6 christos CHAP_SUCCESS, 2686 1.6 christos esp->es_server.ea_id, 2687 1.6 christos response_message, 2688 1.6 christos strlen(response_message)); 2689 1.6 christos eap_figure_next_state(esp, 0); 2690 1.6 christos if (esp->es_rechallenge != 0) 2691 1.6 christos TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge); 2692 1.6 christos } 2693 1.6 christos else { 2694 1.6 christos warn("EAP: MSCHAPv2 failure for peer %q", 2695 1.6 christos rhostname); 2696 1.6 christos eap_chapms2_send_request(esp, 2697 1.6 christos esp->es_server.ea_id, 2698 1.6 christos CHAP_FAILURE, 2699 1.6 christos esp->es_server.ea_id, 2700 1.6 christos response_message, 2701 1.6 christos strlen(response_message)); 2702 1.6 christos } 2703 1.6 christos break; 2704 1.6 christos case CHAP_SUCCESS: 2705 1.6 christos info("EAP: MSCHAPv2 success confirmed"); 2706 1.6 christos break; 2707 1.6 christos case CHAP_FAILURE: 2708 1.6 christos info("EAP: MSCHAPv2 failure confirmed"); 2709 1.6 christos break; 2710 1.6 christos default: 2711 1.6 christos error("EAP: Unhandled MSCHAPv2 opcode %d", opcode); 2712 1.6 christos eap_send_nak(esp, id, EAPT_SRP); 2713 1.6 christos } 2714 1.6 christos 2715 1.6 christos break; 2716 1.7 christos #endif /* PPP_WITH_CHAPMS */ 2717 1.6 christos 2718 1.7 christos #ifdef PPP_WITH_SRP 2719 1.1 christos case EAPT_SRP: 2720 1.1 christos if (len < 1) { 2721 1.1 christos error("EAP: empty SRP Response"); 2722 1.1 christos eap_figure_next_state(esp, 1); 2723 1.1 christos break; 2724 1.1 christos } 2725 1.1 christos GETCHAR(typenum, inp); 2726 1.1 christos len--; 2727 1.1 christos switch (typenum) { 2728 1.1 christos case EAPSRP_CKEY: 2729 1.1 christos if (esp->es_server.ea_state != eapSRP1) { 2730 1.1 christos error("EAP: unexpected SRP Subtype 1 Response"); 2731 1.1 christos eap_figure_next_state(esp, 1); 2732 1.1 christos break; 2733 1.1 christos } 2734 1.1 christos A.data = inp; 2735 1.1 christos A.len = len; 2736 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 2737 1.1 christos assert(ts != NULL); 2738 1.1 christos esp->es_server.ea_skey = t_servergetkey(ts, &A); 2739 1.1 christos if (esp->es_server.ea_skey == NULL) { 2740 1.1 christos /* Client's A value is bogus; terminate now */ 2741 1.1 christos error("EAP: bogus A value from client"); 2742 1.1 christos eap_send_failure(esp); 2743 1.1 christos } else { 2744 1.1 christos eap_figure_next_state(esp, 0); 2745 1.1 christos } 2746 1.1 christos break; 2747 1.1 christos 2748 1.1 christos case EAPSRP_CVALIDATOR: 2749 1.1 christos if (esp->es_server.ea_state != eapSRP2) { 2750 1.1 christos error("EAP: unexpected SRP Subtype 2 Response"); 2751 1.1 christos eap_figure_next_state(esp, 1); 2752 1.1 christos break; 2753 1.1 christos } 2754 1.7 christos if (len < sizeof (u_int32_t) + SHA_DIGEST_LENGTH) { 2755 1.1 christos error("EAP: M1 length %d < %d", len, 2756 1.7 christos sizeof (u_int32_t) + SHA_DIGEST_LENGTH); 2757 1.1 christos eap_figure_next_state(esp, 1); 2758 1.1 christos break; 2759 1.1 christos } 2760 1.1 christos GETLONG(esp->es_server.ea_keyflags, inp); 2761 1.1 christos ts = (struct t_server *)esp->es_server.ea_session; 2762 1.1 christos assert(ts != NULL); 2763 1.1 christos if (t_serververify(ts, inp)) { 2764 1.1 christos info("EAP: unable to validate client identity"); 2765 1.1 christos eap_send_failure(esp); 2766 1.1 christos break; 2767 1.1 christos } 2768 1.1 christos eap_figure_next_state(esp, 0); 2769 1.1 christos break; 2770 1.1 christos 2771 1.1 christos case EAPSRP_ACK: 2772 1.1 christos if (esp->es_server.ea_state != eapSRP3) { 2773 1.1 christos error("EAP: unexpected SRP Subtype 3 Response"); 2774 1.1 christos eap_send_failure(esp); 2775 1.1 christos break; 2776 1.1 christos } 2777 1.1 christos esp->es_server.ea_type = EAPT_SRP; 2778 1.1 christos eap_send_success(esp); 2779 1.1 christos eap_figure_next_state(esp, 0); 2780 1.1 christos if (esp->es_rechallenge != 0) 2781 1.1 christos TIMEOUT(eap_rechallenge, esp, 2782 1.1 christos esp->es_rechallenge); 2783 1.1 christos if (esp->es_lwrechallenge != 0) 2784 1.1 christos TIMEOUT(srp_lwrechallenge, esp, 2785 1.1 christos esp->es_lwrechallenge); 2786 1.1 christos break; 2787 1.1 christos 2788 1.1 christos case EAPSRP_LWRECHALLENGE: 2789 1.1 christos if (esp->es_server.ea_state != eapSRP4) { 2790 1.1 christos info("EAP: unexpected SRP Subtype 4 Response"); 2791 1.1 christos return; 2792 1.1 christos } 2793 1.7 christos if (len != SHA_DIGEST_LENGTH) { 2794 1.1 christos error("EAP: bad Lightweight rechallenge " 2795 1.1 christos "response"); 2796 1.1 christos return; 2797 1.1 christos } 2798 1.7 christos ctxt = PPP_MD_CTX_new(); 2799 1.7 christos if (ctxt) { 2800 1.7 christos vallen = id; 2801 1.7 christos 2802 1.7 christos PPP_DigestInit(ctxt, PPP_sha1()); 2803 1.7 christos PPP_DigestUpdate(ctxt, &vallen, 1); 2804 1.7 christos PPP_DigestUpdate(ctxt, esp->es_server.ea_skey, 2805 1.7 christos SESSION_KEY_LEN); 2806 1.7 christos PPP_DigestUpdate(ctxt, esp->es_challenge, esp->es_challen); 2807 1.7 christos PPP_DigestUpdate(ctxt, esp->es_server.ea_peer, 2808 1.7 christos esp->es_server.ea_peerlen); 2809 1.7 christos PPP_DigestFinal(ctxt, dig, &diglen); 2810 1.7 christos 2811 1.7 christos PPP_MD_CTX_free(ctxt); 2812 1.7 christos 2813 1.7 christos if (BCMP(dig, inp, SHA_DIGEST_LENGTH) != 0) { 2814 1.7 christos error("EAP: failed Lightweight rechallenge"); 2815 1.7 christos eap_send_failure(esp); 2816 1.7 christos break; 2817 1.7 christos } 2818 1.7 christos 2819 1.7 christos esp->es_server.ea_state = eapOpen; 2820 1.7 christos if (esp->es_lwrechallenge != 0) 2821 1.7 christos TIMEOUT(srp_lwrechallenge, esp, 2822 1.7 christos esp->es_lwrechallenge); 2823 1.1 christos } 2824 1.1 christos break; 2825 1.1 christos } 2826 1.1 christos break; 2827 1.7 christos #endif /* PPP_WITH_SRP */ 2828 1.1 christos 2829 1.1 christos default: 2830 1.1 christos /* This can't happen. */ 2831 1.1 christos error("EAP: unknown Response type %d; ignored", typenum); 2832 1.1 christos return; 2833 1.1 christos } 2834 1.1 christos 2835 1.1 christos if (esp->es_server.ea_timeout > 0) { 2836 1.1 christos UNTIMEOUT(eap_server_timeout, (void *)esp); 2837 1.1 christos } 2838 1.1 christos 2839 1.1 christos if (esp->es_server.ea_state != eapBadAuth && 2840 1.1 christos esp->es_server.ea_state != eapOpen) { 2841 1.1 christos esp->es_server.ea_id++; 2842 1.1 christos eap_send_request(esp); 2843 1.1 christos } 2844 1.1 christos } 2845 1.1 christos 2846 1.1 christos /* 2847 1.1 christos * eap_success - Receive EAP Success message (client mode). 2848 1.1 christos */ 2849 1.1 christos static void 2850 1.6 christos eap_success(eap_state *esp, u_char *inp, int id, int len) 2851 1.1 christos { 2852 1.6 christos if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp) 2853 1.7 christos #ifdef PPP_WITH_EAPTLS 2854 1.6 christos && esp->es_client.ea_state != eapTlsRecvSuccess 2855 1.7 christos #endif /* PPP_WITH_EAPTLS */ 2856 1.6 christos ) { 2857 1.1 christos dbglog("EAP unexpected success message in state %s (%d)", 2858 1.1 christos eap_state_name(esp->es_client.ea_state), 2859 1.1 christos esp->es_client.ea_state); 2860 1.1 christos return; 2861 1.1 christos } 2862 1.1 christos 2863 1.7 christos #ifdef PPP_WITH_EAPTLS 2864 1.6 christos if(esp->es_client.ea_using_eaptls && esp->es_client.ea_state != 2865 1.6 christos eapTlsRecvSuccess) { 2866 1.6 christos dbglog("EAP-TLS unexpected success message in state %s (%d)", 2867 1.6 christos eap_state_name(esp->es_client.ea_state), 2868 1.6 christos esp->es_client.ea_state); 2869 1.6 christos return; 2870 1.6 christos } 2871 1.7 christos #endif /* PPP_WITH_EAPTLS */ 2872 1.6 christos 2873 1.1 christos if (esp->es_client.ea_timeout > 0) { 2874 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp); 2875 1.1 christos } 2876 1.1 christos 2877 1.1 christos if (len > 0) { 2878 1.1 christos /* This is odd. The spec doesn't allow for this. */ 2879 1.1 christos PRINTMSG(inp, len); 2880 1.1 christos } 2881 1.1 christos 2882 1.7 christos #ifdef PPP_WITH_PEAP 2883 1.7 christos peap_finish(&esp->ea_peap); 2884 1.7 christos #endif 2885 1.7 christos 2886 1.1 christos esp->es_client.ea_state = eapOpen; 2887 1.1 christos auth_withpeer_success(esp->es_unit, PPP_EAP, 0); 2888 1.1 christos } 2889 1.1 christos 2890 1.1 christos /* 2891 1.1 christos * eap_failure - Receive EAP Failure message (client mode). 2892 1.1 christos */ 2893 1.1 christos static void 2894 1.6 christos eap_failure(eap_state *esp, u_char *inp, int id, int len) 2895 1.1 christos { 2896 1.6 christos /* 2897 1.6 christos * Ignore failure messages if we're not open 2898 1.6 christos */ 2899 1.6 christos if (esp->es_client.ea_state <= eapClosed) 2900 1.6 christos return; 2901 1.6 christos 2902 1.1 christos if (!eap_client_active(esp)) { 2903 1.1 christos dbglog("EAP unexpected failure message in state %s (%d)", 2904 1.1 christos eap_state_name(esp->es_client.ea_state), 2905 1.1 christos esp->es_client.ea_state); 2906 1.1 christos } 2907 1.1 christos 2908 1.1 christos if (esp->es_client.ea_timeout > 0) { 2909 1.1 christos UNTIMEOUT(eap_client_timeout, (void *)esp); 2910 1.1 christos } 2911 1.1 christos 2912 1.1 christos if (len > 0) { 2913 1.1 christos /* This is odd. The spec doesn't allow for this. */ 2914 1.1 christos PRINTMSG(inp, len); 2915 1.1 christos } 2916 1.1 christos 2917 1.1 christos esp->es_client.ea_state = eapBadAuth; 2918 1.1 christos 2919 1.1 christos error("EAP: peer reports authentication failure"); 2920 1.7 christos 2921 1.7 christos #ifdef PPP_WITH_PEAP 2922 1.7 christos peap_finish(&esp->ea_peap); 2923 1.7 christos #endif 2924 1.7 christos 2925 1.1 christos auth_withpeer_fail(esp->es_unit, PPP_EAP); 2926 1.1 christos } 2927 1.1 christos 2928 1.1 christos /* 2929 1.1 christos * eap_input - Handle received EAP message. 2930 1.1 christos */ 2931 1.1 christos static void 2932 1.6 christos eap_input(int unit, u_char *inp, int inlen) 2933 1.1 christos { 2934 1.1 christos eap_state *esp = &eap_states[unit]; 2935 1.1 christos u_char code, id; 2936 1.1 christos int len; 2937 1.1 christos 2938 1.1 christos /* 2939 1.1 christos * Parse header (code, id and length). If packet too short, 2940 1.1 christos * drop it. 2941 1.1 christos */ 2942 1.1 christos if (inlen < EAP_HEADERLEN) { 2943 1.1 christos error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN); 2944 1.1 christos return; 2945 1.1 christos } 2946 1.1 christos GETCHAR(code, inp); 2947 1.1 christos GETCHAR(id, inp); 2948 1.1 christos GETSHORT(len, inp); 2949 1.1 christos if (len < EAP_HEADERLEN || len > inlen) { 2950 1.1 christos error("EAP: packet has illegal length field %d (%d..%d)", len, 2951 1.1 christos EAP_HEADERLEN, inlen); 2952 1.1 christos return; 2953 1.1 christos } 2954 1.1 christos len -= EAP_HEADERLEN; 2955 1.1 christos 2956 1.1 christos /* Dispatch based on message code */ 2957 1.1 christos switch (code) { 2958 1.1 christos case EAP_REQUEST: 2959 1.1 christos eap_request(esp, inp, id, len); 2960 1.1 christos break; 2961 1.1 christos 2962 1.1 christos case EAP_RESPONSE: 2963 1.1 christos eap_response(esp, inp, id, len); 2964 1.1 christos break; 2965 1.1 christos 2966 1.1 christos case EAP_SUCCESS: 2967 1.1 christos eap_success(esp, inp, id, len); 2968 1.1 christos break; 2969 1.1 christos 2970 1.1 christos case EAP_FAILURE: 2971 1.1 christos eap_failure(esp, inp, id, len); 2972 1.1 christos break; 2973 1.1 christos 2974 1.1 christos default: /* XXX Need code reject */ 2975 1.1 christos /* Note: it's not legal to send EAP Nak here. */ 2976 1.1 christos warn("EAP: unknown code %d received", code); 2977 1.1 christos break; 2978 1.1 christos } 2979 1.1 christos } 2980 1.1 christos 2981 1.1 christos /* 2982 1.1 christos * eap_printpkt - print the contents of an EAP packet. 2983 1.1 christos */ 2984 1.1 christos static char *eap_codenames[] = { 2985 1.1 christos "Request", "Response", "Success", "Failure" 2986 1.1 christos }; 2987 1.1 christos 2988 1.1 christos static char *eap_typenames[] = { 2989 1.1 christos "Identity", "Notification", "Nak", "MD5-Challenge", 2990 1.1 christos "OTP", "Generic-Token", NULL, NULL, 2991 1.1 christos "RSA", "DSS", "KEA", "KEA-Validate", 2992 1.1 christos "TLS", "Defender", "Windows 2000", "Arcot", 2993 1.6 christos "Cisco", "Nokia", "SRP", NULL, 2994 1.6 christos "TTLS", "RAS", "AKA", "3COM", "PEAP", 2995 1.6 christos "MSCHAPv2" 2996 1.1 christos }; 2997 1.1 christos 2998 1.1 christos static int 2999 1.6 christos eap_printpkt(u_char *inp, int inlen, 3000 1.6 christos void (*printer) (void *, char *, ...), void *arg) 3001 1.1 christos { 3002 1.1 christos int code, id, len, rtype, vallen; 3003 1.1 christos u_char *pstart; 3004 1.7 christos #ifdef PPP_WITH_SRP 3005 1.1 christos u_int32_t uval; 3006 1.7 christos #endif /* PPP_WITH_SRP */ 3007 1.7 christos #ifdef PPP_WITH_EAPTLS 3008 1.6 christos u_char flags; 3009 1.7 christos #endif /* PPP_WITH_EAPTLS */ 3010 1.7 christos #ifdef PPP_WITH_CHAPMS 3011 1.6 christos u_char opcode; 3012 1.7 christos #endif /* PPP_WITH_CHAPMS */ 3013 1.1 christos 3014 1.1 christos if (inlen < EAP_HEADERLEN) 3015 1.1 christos return (0); 3016 1.1 christos pstart = inp; 3017 1.1 christos GETCHAR(code, inp); 3018 1.1 christos GETCHAR(id, inp); 3019 1.1 christos GETSHORT(len, inp); 3020 1.1 christos if (len < EAP_HEADERLEN || len > inlen) 3021 1.1 christos return (0); 3022 1.1 christos 3023 1.1 christos if (code >= 1 && code <= sizeof(eap_codenames) / sizeof(char *)) 3024 1.1 christos printer(arg, " %s", eap_codenames[code-1]); 3025 1.1 christos else 3026 1.1 christos printer(arg, " code=0x%x", code); 3027 1.1 christos printer(arg, " id=0x%x", id); 3028 1.1 christos len -= EAP_HEADERLEN; 3029 1.1 christos switch (code) { 3030 1.1 christos case EAP_REQUEST: 3031 1.1 christos if (len < 1) { 3032 1.1 christos printer(arg, " <missing type>"); 3033 1.1 christos break; 3034 1.1 christos } 3035 1.1 christos GETCHAR(rtype, inp); 3036 1.1 christos len--; 3037 1.1 christos if (rtype >= 1 && 3038 1.1 christos rtype <= sizeof (eap_typenames) / sizeof (char *)) 3039 1.1 christos printer(arg, " %s", eap_typenames[rtype-1]); 3040 1.1 christos else 3041 1.1 christos printer(arg, " type=0x%x", rtype); 3042 1.1 christos switch (rtype) { 3043 1.1 christos case EAPT_IDENTITY: 3044 1.1 christos case EAPT_NOTIFICATION: 3045 1.1 christos if (len > 0) { 3046 1.1 christos printer(arg, " <Message "); 3047 1.1 christos print_string((char *)inp, len, printer, arg); 3048 1.1 christos printer(arg, ">"); 3049 1.1 christos INCPTR(len, inp); 3050 1.1 christos len = 0; 3051 1.1 christos } else { 3052 1.1 christos printer(arg, " <No message>"); 3053 1.1 christos } 3054 1.1 christos break; 3055 1.1 christos 3056 1.1 christos case EAPT_MD5CHAP: 3057 1.1 christos if (len <= 0) 3058 1.1 christos break; 3059 1.1 christos GETCHAR(vallen, inp); 3060 1.1 christos len--; 3061 1.1 christos if (vallen > len) 3062 1.1 christos goto truncated; 3063 1.1 christos printer(arg, " <Value%.*B>", vallen, inp); 3064 1.1 christos INCPTR(vallen, inp); 3065 1.1 christos len -= vallen; 3066 1.1 christos if (len > 0) { 3067 1.1 christos printer(arg, " <Name "); 3068 1.1 christos print_string((char *)inp, len, printer, arg); 3069 1.1 christos printer(arg, ">"); 3070 1.1 christos INCPTR(len, inp); 3071 1.1 christos len = 0; 3072 1.1 christos } else { 3073 1.1 christos printer(arg, " <No name>"); 3074 1.1 christos } 3075 1.1 christos break; 3076 1.1 christos 3077 1.7 christos #ifdef PPP_WITH_CHAPMS 3078 1.6 christos case EAPT_MSCHAPV2: 3079 1.6 christos if (len <= 0) 3080 1.6 christos break; 3081 1.6 christos GETCHAR(opcode, inp); 3082 1.6 christos len--; 3083 1.6 christos switch (opcode) { 3084 1.6 christos case CHAP_CHALLENGE: 3085 1.6 christos INCPTR(3, inp); 3086 1.6 christos len -= 3; 3087 1.6 christos GETCHAR(vallen, inp); 3088 1.6 christos len--; 3089 1.6 christos if (vallen > len) 3090 1.6 christos goto truncated; 3091 1.6 christos len -= vallen; 3092 1.6 christos printer(arg, " Challenge <"); 3093 1.6 christos for (; vallen > 0; --vallen) { 3094 1.6 christos u_char val; 3095 1.6 christos GETCHAR(val, inp); 3096 1.6 christos printer(arg, "%.2x", val); 3097 1.6 christos } 3098 1.6 christos printer(arg, ">"); 3099 1.6 christos if (len > 0) { 3100 1.6 christos printer(arg, ", <Name "); 3101 1.6 christos print_string((char *)inp, len, printer, arg); 3102 1.6 christos printer(arg, ">"); 3103 1.6 christos INCPTR(len, inp); 3104 1.6 christos len = 0; 3105 1.6 christos } else { 3106 1.6 christos printer(arg, ", <No name>"); 3107 1.6 christos } 3108 1.6 christos break; 3109 1.6 christos case CHAP_SUCCESS: 3110 1.6 christos INCPTR(3, inp); 3111 1.6 christos len -= 3; 3112 1.6 christos printer(arg, " Success <Message "); 3113 1.6 christos print_string((char *)inp, len, printer, arg); 3114 1.6 christos printer(arg, ">"); 3115 1.6 christos break; 3116 1.6 christos case CHAP_FAILURE: 3117 1.6 christos INCPTR(3, inp); 3118 1.6 christos len -= 3; 3119 1.6 christos printer(arg, " Failure <Message "); 3120 1.6 christos print_string((char *)inp, len, printer, arg); 3121 1.6 christos printer(arg, ">"); 3122 1.6 christos break; 3123 1.6 christos default: 3124 1.6 christos INCPTR(3, inp); 3125 1.6 christos len -= 3; 3126 1.6 christos printer(arg, " opcode=0x%x <%.*B>", opcode, len, inp); 3127 1.6 christos break; 3128 1.6 christos } 3129 1.6 christos break; 3130 1.7 christos #endif /* PPP_WITH_CHAPMS */ 3131 1.6 christos 3132 1.7 christos #ifdef PPP_WITH_EAPTLS 3133 1.6 christos case EAPT_TLS: 3134 1.6 christos if (len < 1) 3135 1.6 christos break; 3136 1.6 christos GETCHAR(flags, inp); 3137 1.6 christos len--; 3138 1.6 christos 3139 1.6 christos if(flags == 0 && len == 0){ 3140 1.6 christos printer(arg, " Ack"); 3141 1.6 christos break; 3142 1.6 christos } 3143 1.6 christos 3144 1.6 christos printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -"); 3145 1.6 christos printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); 3146 1.6 christos printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); 3147 1.6 christos break; 3148 1.7 christos #endif /* PPP_WITH_EAPTLS */ 3149 1.6 christos 3150 1.7 christos #ifdef PPP_WITH_SRP 3151 1.1 christos case EAPT_SRP: 3152 1.1 christos if (len < 3) 3153 1.1 christos goto truncated; 3154 1.1 christos GETCHAR(vallen, inp); 3155 1.1 christos len--; 3156 1.1 christos printer(arg, "-%d", vallen); 3157 1.1 christos switch (vallen) { 3158 1.1 christos case EAPSRP_CHALLENGE: 3159 1.1 christos GETCHAR(vallen, inp); 3160 1.1 christos len--; 3161 1.1 christos if (vallen >= len) 3162 1.1 christos goto truncated; 3163 1.1 christos if (vallen > 0) { 3164 1.1 christos printer(arg, " <Name "); 3165 1.1 christos print_string((char *)inp, vallen, printer, 3166 1.1 christos arg); 3167 1.1 christos printer(arg, ">"); 3168 1.1 christos } else { 3169 1.1 christos printer(arg, " <No name>"); 3170 1.1 christos } 3171 1.1 christos INCPTR(vallen, inp); 3172 1.1 christos len -= vallen; 3173 1.1 christos GETCHAR(vallen, inp); 3174 1.1 christos len--; 3175 1.1 christos if (vallen >= len) 3176 1.1 christos goto truncated; 3177 1.1 christos printer(arg, " <s%.*B>", vallen, inp); 3178 1.1 christos INCPTR(vallen, inp); 3179 1.1 christos len -= vallen; 3180 1.1 christos GETCHAR(vallen, inp); 3181 1.1 christos len--; 3182 1.1 christos if (vallen > len) 3183 1.1 christos goto truncated; 3184 1.1 christos if (vallen == 0) { 3185 1.1 christos printer(arg, " <Default g=2>"); 3186 1.1 christos } else { 3187 1.1 christos printer(arg, " <g%.*B>", vallen, inp); 3188 1.1 christos } 3189 1.1 christos INCPTR(vallen, inp); 3190 1.1 christos len -= vallen; 3191 1.1 christos if (len == 0) { 3192 1.1 christos printer(arg, " <Default N>"); 3193 1.1 christos } else { 3194 1.1 christos printer(arg, " <N%.*B>", len, inp); 3195 1.1 christos INCPTR(len, inp); 3196 1.1 christos len = 0; 3197 1.1 christos } 3198 1.1 christos break; 3199 1.1 christos 3200 1.1 christos case EAPSRP_SKEY: 3201 1.1 christos printer(arg, " <B%.*B>", len, inp); 3202 1.1 christos INCPTR(len, inp); 3203 1.1 christos len = 0; 3204 1.1 christos break; 3205 1.1 christos 3206 1.1 christos case EAPSRP_SVALIDATOR: 3207 1.1 christos if (len < sizeof (u_int32_t)) 3208 1.1 christos break; 3209 1.1 christos GETLONG(uval, inp); 3210 1.1 christos len -= sizeof (u_int32_t); 3211 1.1 christos if (uval & SRPVAL_EBIT) { 3212 1.1 christos printer(arg, " E"); 3213 1.1 christos uval &= ~SRPVAL_EBIT; 3214 1.1 christos } 3215 1.1 christos if (uval != 0) { 3216 1.1 christos printer(arg, " f<%X>", uval); 3217 1.1 christos } 3218 1.7 christos if ((vallen = len) > SHA_DIGEST_LENGTH) 3219 1.7 christos vallen = SHA_DIGEST_LENGTH; 3220 1.1 christos printer(arg, " <M2%.*B%s>", len, inp, 3221 1.7 christos len < SHA_DIGEST_LENGTH ? "?" : ""); 3222 1.1 christos INCPTR(vallen, inp); 3223 1.1 christos len -= vallen; 3224 1.1 christos if (len > 0) { 3225 1.1 christos printer(arg, " <PN%.*B>", len, inp); 3226 1.1 christos INCPTR(len, inp); 3227 1.1 christos len = 0; 3228 1.1 christos } 3229 1.1 christos break; 3230 1.1 christos 3231 1.1 christos case EAPSRP_LWRECHALLENGE: 3232 1.1 christos printer(arg, " <Challenge%.*B>", len, inp); 3233 1.1 christos INCPTR(len, inp); 3234 1.1 christos len = 0; 3235 1.1 christos break; 3236 1.1 christos } 3237 1.1 christos break; 3238 1.7 christos #endif /* PPP_WITH_SRP */ 3239 1.1 christos } 3240 1.1 christos break; 3241 1.1 christos 3242 1.1 christos case EAP_RESPONSE: 3243 1.1 christos if (len < 1) 3244 1.1 christos break; 3245 1.1 christos GETCHAR(rtype, inp); 3246 1.1 christos len--; 3247 1.1 christos if (rtype >= 1 && 3248 1.1 christos rtype <= sizeof (eap_typenames) / sizeof (char *)) 3249 1.1 christos printer(arg, " %s", eap_typenames[rtype-1]); 3250 1.1 christos else 3251 1.1 christos printer(arg, " type=0x%x", rtype); 3252 1.1 christos switch (rtype) { 3253 1.1 christos case EAPT_IDENTITY: 3254 1.1 christos if (len > 0) { 3255 1.1 christos printer(arg, " <Name "); 3256 1.1 christos print_string((char *)inp, len, printer, arg); 3257 1.1 christos printer(arg, ">"); 3258 1.1 christos INCPTR(len, inp); 3259 1.1 christos len = 0; 3260 1.1 christos } 3261 1.1 christos break; 3262 1.1 christos 3263 1.7 christos #ifdef PPP_WITH_EAPTLS 3264 1.6 christos case EAPT_TLS: 3265 1.6 christos if (len < 1) 3266 1.6 christos break; 3267 1.6 christos GETCHAR(flags, inp); 3268 1.6 christos len--; 3269 1.6 christos 3270 1.6 christos if(flags == 0 && len == 0){ 3271 1.6 christos printer(arg, " Ack"); 3272 1.6 christos break; 3273 1.6 christos } 3274 1.6 christos 3275 1.6 christos printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -"); 3276 1.6 christos printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-"); 3277 1.6 christos printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- "); 3278 1.6 christos 3279 1.6 christos break; 3280 1.7 christos #endif /* PPP_WITH_EAPTLS */ 3281 1.6 christos 3282 1.1 christos case EAPT_NAK: 3283 1.1 christos if (len <= 0) { 3284 1.1 christos printer(arg, " <missing hint>"); 3285 1.1 christos break; 3286 1.1 christos } 3287 1.1 christos GETCHAR(rtype, inp); 3288 1.1 christos len--; 3289 1.1 christos printer(arg, " <Suggested-type %02X", rtype); 3290 1.1 christos if (rtype >= 1 && 3291 1.6 christos rtype <= sizeof (eap_typenames) / sizeof (char *)) 3292 1.1 christos printer(arg, " (%s)", eap_typenames[rtype-1]); 3293 1.1 christos printer(arg, ">"); 3294 1.1 christos break; 3295 1.1 christos 3296 1.1 christos case EAPT_MD5CHAP: 3297 1.1 christos if (len <= 0) { 3298 1.1 christos printer(arg, " <missing length>"); 3299 1.1 christos break; 3300 1.1 christos } 3301 1.1 christos GETCHAR(vallen, inp); 3302 1.1 christos len--; 3303 1.1 christos if (vallen > len) 3304 1.1 christos goto truncated; 3305 1.1 christos printer(arg, " <Value%.*B>", vallen, inp); 3306 1.1 christos INCPTR(vallen, inp); 3307 1.1 christos len -= vallen; 3308 1.1 christos if (len > 0) { 3309 1.1 christos printer(arg, " <Name "); 3310 1.1 christos print_string((char *)inp, len, printer, arg); 3311 1.1 christos printer(arg, ">"); 3312 1.1 christos INCPTR(len, inp); 3313 1.1 christos len = 0; 3314 1.1 christos } else { 3315 1.1 christos printer(arg, " <No name>"); 3316 1.1 christos } 3317 1.1 christos break; 3318 1.1 christos 3319 1.7 christos #ifdef PPP_WITH_CHAPMS 3320 1.6 christos case EAPT_MSCHAPV2: 3321 1.6 christos if (len <= 0) 3322 1.6 christos break; 3323 1.6 christos GETCHAR(opcode, inp); 3324 1.6 christos len--; 3325 1.6 christos switch (opcode) { 3326 1.6 christos case CHAP_RESPONSE: 3327 1.6 christos INCPTR(3, inp); 3328 1.6 christos len -= 3; 3329 1.6 christos GETCHAR(vallen, inp); 3330 1.6 christos len--; 3331 1.6 christos if (vallen > len) 3332 1.6 christos goto truncated; 3333 1.6 christos len -= vallen; 3334 1.6 christos printer(arg, " Response <"); 3335 1.6 christos for (; vallen > 0; --vallen) { 3336 1.6 christos u_char val; 3337 1.6 christos GETCHAR(val, inp); 3338 1.6 christos printer(arg, "%.2x", val); 3339 1.6 christos } 3340 1.6 christos printer(arg, ">"); 3341 1.6 christos if (len > 0) { 3342 1.6 christos printer(arg, ", <Name "); 3343 1.6 christos print_string((char *)inp, len, printer, arg); 3344 1.6 christos printer(arg, ">"); 3345 1.6 christos INCPTR(len, inp); 3346 1.6 christos len = 0; 3347 1.6 christos } else { 3348 1.6 christos printer(arg, ", <No name>"); 3349 1.6 christos } 3350 1.6 christos break; 3351 1.6 christos case CHAP_SUCCESS: 3352 1.6 christos printer(arg, " Success"); 3353 1.6 christos break; 3354 1.6 christos case CHAP_FAILURE: 3355 1.6 christos printer(arg, " Failure"); 3356 1.6 christos break; 3357 1.6 christos default: 3358 1.6 christos printer(arg, " opcode=0x%x <%.*B>", opcode, len, inp); 3359 1.6 christos break; 3360 1.6 christos } 3361 1.6 christos break; 3362 1.7 christos #endif /* PPP_WITH_CHAPMS */ 3363 1.6 christos 3364 1.7 christos #ifdef PPP_WITH_SRP 3365 1.1 christos case EAPT_SRP: 3366 1.1 christos if (len < 1) 3367 1.1 christos goto truncated; 3368 1.1 christos GETCHAR(vallen, inp); 3369 1.1 christos len--; 3370 1.1 christos printer(arg, "-%d", vallen); 3371 1.1 christos switch (vallen) { 3372 1.1 christos case EAPSRP_CKEY: 3373 1.1 christos printer(arg, " <A%.*B>", len, inp); 3374 1.1 christos INCPTR(len, inp); 3375 1.1 christos len = 0; 3376 1.1 christos break; 3377 1.1 christos 3378 1.1 christos case EAPSRP_CVALIDATOR: 3379 1.1 christos if (len < sizeof (u_int32_t)) 3380 1.1 christos break; 3381 1.1 christos GETLONG(uval, inp); 3382 1.1 christos len -= sizeof (u_int32_t); 3383 1.1 christos if (uval & SRPVAL_EBIT) { 3384 1.1 christos printer(arg, " E"); 3385 1.1 christos uval &= ~SRPVAL_EBIT; 3386 1.1 christos } 3387 1.1 christos if (uval != 0) { 3388 1.1 christos printer(arg, " f<%X>", uval); 3389 1.1 christos } 3390 1.1 christos printer(arg, " <M1%.*B%s>", len, inp, 3391 1.7 christos len == SHA_DIGEST_LENGTH ? "" : "?"); 3392 1.1 christos INCPTR(len, inp); 3393 1.1 christos len = 0; 3394 1.1 christos break; 3395 1.1 christos 3396 1.1 christos case EAPSRP_ACK: 3397 1.1 christos break; 3398 1.1 christos 3399 1.1 christos case EAPSRP_LWRECHALLENGE: 3400 1.1 christos printer(arg, " <Response%.*B%s>", len, inp, 3401 1.7 christos len == SHA_DIGEST_LENGTH ? "" : "?"); 3402 1.7 christos if ((vallen = len) > SHA_DIGEST_LENGTH) 3403 1.7 christos vallen = SHA_DIGEST_LENGTH; 3404 1.1 christos INCPTR(vallen, inp); 3405 1.1 christos len -= vallen; 3406 1.1 christos break; 3407 1.1 christos } 3408 1.1 christos break; 3409 1.7 christos #endif /* PPP_WITH_SRP */ 3410 1.1 christos } 3411 1.1 christos break; 3412 1.1 christos 3413 1.1 christos case EAP_SUCCESS: /* No payload expected for these! */ 3414 1.1 christos case EAP_FAILURE: 3415 1.1 christos break; 3416 1.1 christos 3417 1.1 christos truncated: 3418 1.1 christos printer(arg, " <truncated>"); 3419 1.1 christos break; 3420 1.1 christos } 3421 1.1 christos 3422 1.1 christos if (len > 8) 3423 1.1 christos printer(arg, "%8B...", inp); 3424 1.1 christos else if (len > 0) 3425 1.1 christos printer(arg, "%.*B", len, inp); 3426 1.1 christos INCPTR(len, inp); 3427 1.1 christos 3428 1.1 christos return (inp - pstart); 3429 1.1 christos } 3430