in net/ip/lwip_base/src/netif/ppp/eap.c [1725:2011]
static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) {
u_char typenum;
u_char vallen;
int secret_len;
char secret[MAXSECRETLEN];
char rhostname[MAXNAMELEN];
lwip_md5_context mdContext;
u_char hash[MD5_SIGNATURE_SIZE];
#ifdef USE_SRP
struct t_server *ts;
struct t_num A;
SHA1_CTX ctxt;
u_char dig[SHA_DIGESTSIZE];
#endif /* USE_SRP */
if (pcb->eap.es_server.ea_id != id) {
ppp_dbglog("EAP: discarding Response %d; expected ID %d", id,
pcb->eap.es_server.ea_id);
return;
}
pcb->eap.es_server.ea_responses++;
if (len <= 0) {
ppp_error("EAP: empty Response message discarded");
return;
}
GETCHAR(typenum, inp);
len--;
switch (typenum) {
case EAPT_IDENTITY:
if (pcb->eap.es_server.ea_state != eapIdentify) {
ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len,
inp);
break;
}
ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp);
if (len > MAXNAMELEN) {
len = MAXNAMELEN;
}
MEMCPY(pcb->eap.es_server.ea_peer, inp, len);
pcb->eap.es_server.ea_peer[len] = '\0';
pcb->eap.es_server.ea_peerlen = len;
eap_figure_next_state(pcb, 0);
break;
case EAPT_NOTIFICATION:
ppp_dbglog("EAP unexpected Notification; response discarded");
break;
case EAPT_NAK:
if (len < 1) {
ppp_info("EAP: Nak Response with no suggested protocol");
eap_figure_next_state(pcb, 1);
break;
}
GETCHAR(vallen, inp);
len--;
if (
#if PPP_REMOTENAME
!pcb->explicit_remote &&
#endif /* PPP_REMOTENAME */
pcb->eap.es_server.ea_state == eapIdentify){
/* Peer cannot Nak Identify Request */
eap_figure_next_state(pcb, 1);
break;
}
switch (vallen) {
case EAPT_SRP:
/* Run through SRP validator selection again. */
pcb->eap.es_server.ea_state = eapIdentify;
eap_figure_next_state(pcb, 0);
break;
case EAPT_MD5CHAP:
pcb->eap.es_server.ea_state = eapMD5Chall;
break;
default:
ppp_dbglog("EAP: peer requesting unknown Type %d", vallen);
switch (pcb->eap.es_server.ea_state) {
case eapSRP1:
case eapSRP2:
case eapSRP3:
pcb->eap.es_server.ea_state = eapMD5Chall;
break;
case eapMD5Chall:
case eapSRP4:
pcb->eap.es_server.ea_state = eapIdentify;
eap_figure_next_state(pcb, 0);
break;
default:
break;
}
break;
}
break;
case EAPT_MD5CHAP:
if (pcb->eap.es_server.ea_state != eapMD5Chall) {
ppp_error("EAP: unexpected MD5-Response");
eap_figure_next_state(pcb, 1);
break;
}
if (len < 1) {
ppp_error("EAP: received MD5-Response with no data");
eap_figure_next_state(pcb, 1);
break;
}
GETCHAR(vallen, inp);
len--;
if (vallen != 16 || vallen > len) {
ppp_error("EAP: MD5-Response with bad length %d", vallen);
eap_figure_next_state(pcb, 1);
break;
}
/* Not so likely to happen. */
if (vallen >= len + sizeof (rhostname)) {
ppp_dbglog("EAP: trimming really long peer name down");
MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1);
rhostname[sizeof (rhostname) - 1] = '\0';
} else {
MEMCPY(rhostname, inp + vallen, len - vallen);
rhostname[len - vallen] = '\0';
}
#if PPP_REMOTENAME
/* In case the remote doesn't give us his name. */
if (explicit_remote ||
(remote_name[0] != '\0' && vallen == len))
strlcpy(rhostname, remote_name, sizeof (rhostname));
#endif /* PPP_REMOTENAME */
/*
* Get the secret for authenticating the specified
* host.
*/
if (!get_secret(pcb, rhostname,
pcb->eap.es_server.ea_name, secret, &secret_len, 1)) {
ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname);
eap_send_failure(pcb);
break;
}
lwip_md5_init(&mdContext);
lwip_md5_starts(&mdContext);
lwip_md5_update(&mdContext, &pcb->eap.es_server.ea_id, 1);
lwip_md5_update(&mdContext, (u_char *)secret, secret_len);
BZERO(secret, sizeof (secret));
lwip_md5_update(&mdContext, pcb->eap.es_challenge, pcb->eap.es_challen);
lwip_md5_finish(&mdContext, hash);
lwip_md5_free(&mdContext);
if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) {
eap_send_failure(pcb);
break;
}
pcb->eap.es_server.ea_type = EAPT_MD5CHAP;
eap_send_success(pcb);
eap_figure_next_state(pcb, 0);
if (pcb->eap.es_rechallenge != 0)
TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge);
break;
#ifdef USE_SRP
case EAPT_SRP:
if (len < 1) {
ppp_error("EAP: empty SRP Response");
eap_figure_next_state(pcb, 1);
break;
}
GETCHAR(typenum, inp);
len--;
switch (typenum) {
case EAPSRP_CKEY:
if (pcb->eap.es_server.ea_state != eapSRP1) {
ppp_error("EAP: unexpected SRP Subtype 1 Response");
eap_figure_next_state(pcb, 1);
break;
}
A.data = inp;
A.len = len;
ts = (struct t_server *)pcb->eap.es_server.ea_session;
assert(ts != NULL);
pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A);
if (pcb->eap.es_server.ea_skey == NULL) {
/* Client's A value is bogus; terminate now */
ppp_error("EAP: bogus A value from client");
eap_send_failure(pcb);
} else {
eap_figure_next_state(pcb, 0);
}
break;
case EAPSRP_CVALIDATOR:
if (pcb->eap.es_server.ea_state != eapSRP2) {
ppp_error("EAP: unexpected SRP Subtype 2 Response");
eap_figure_next_state(pcb, 1);
break;
}
if (len < sizeof (u32_t) + SHA_DIGESTSIZE) {
ppp_error("EAP: M1 length %d < %d", len,
sizeof (u32_t) + SHA_DIGESTSIZE);
eap_figure_next_state(pcb, 1);
break;
}
GETLONG(pcb->eap.es_server.ea_keyflags, inp);
ts = (struct t_server *)pcb->eap.es_server.ea_session;
assert(ts != NULL);
if (t_serververify(ts, inp)) {
ppp_info("EAP: unable to validate client identity");
eap_send_failure(pcb);
break;
}
eap_figure_next_state(pcb, 0);
break;
case EAPSRP_ACK:
if (pcb->eap.es_server.ea_state != eapSRP3) {
ppp_error("EAP: unexpected SRP Subtype 3 Response");
eap_send_failure(esp);
break;
}
pcb->eap.es_server.ea_type = EAPT_SRP;
eap_send_success(pcb, esp);
eap_figure_next_state(pcb, 0);
if (pcb->eap.es_rechallenge != 0)
TIMEOUT(eap_rechallenge, pcb,
pcb->eap.es_rechallenge);
if (pcb->eap.es_lwrechallenge != 0)
TIMEOUT(srp_lwrechallenge, pcb,
pcb->eap.es_lwrechallenge);
break;
case EAPSRP_LWRECHALLENGE:
if (pcb->eap.es_server.ea_state != eapSRP4) {
ppp_info("EAP: unexpected SRP Subtype 4 Response");
return;
}
if (len != SHA_DIGESTSIZE) {
ppp_error("EAP: bad Lightweight rechallenge "
"response");
return;
}
SHA1Init(&ctxt);
vallen = id;
SHA1Update(&ctxt, &vallen, 1);
SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
SESSION_KEY_LEN);
SHA1Update(&ctxt, pcb->eap.es_challenge, pcb->eap.es_challen);
SHA1Update(&ctxt, pcb->eap.es_server.ea_peer,
pcb->eap.es_server.ea_peerlen);
SHA1Final(dig, &ctxt);
if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) {
ppp_error("EAP: failed Lightweight rechallenge");
eap_send_failure(pcb);
break;
}
pcb->eap.es_server.ea_state = eapOpen;
if (pcb->eap.es_lwrechallenge != 0)
TIMEOUT(srp_lwrechallenge, esp,
pcb->eap.es_lwrechallenge);
break;
}
break;
#endif /* USE_SRP */
default:
/* This can't happen. */
ppp_error("EAP: unknown Response type %d; ignored", typenum);
return;
}
if (pcb->settings.eap_timeout_time > 0) {
UNTIMEOUT(eap_server_timeout, pcb);
}
if (pcb->eap.es_server.ea_state != eapBadAuth &&
pcb->eap.es_server.ea_state != eapOpen) {
pcb->eap.es_server.ea_id++;
eap_send_request(pcb);
}
}