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