in net/ip/lwip_base/src/netif/ppp/eap.c [638:868]
static void eap_send_request(ppp_pcb *pcb) {
struct pbuf *p;
u_char *outp;
u_char *lenloc;
int outlen;
int len;
const char *str;
#ifdef USE_SRP
struct t_server *ts;
u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp;
int i, j;
struct b64state b64;
SHA1_CTX ctxt;
#endif /* USE_SRP */
/* Handle both initial auth and restart */
if (pcb->eap.es_server.ea_state < eapIdentify &&
pcb->eap.es_server.ea_state != eapInitial) {
pcb->eap.es_server.ea_state = eapIdentify;
#if PPP_REMOTENAME
if (pcb->settings.explicit_remote && pcb->remote_name) {
/*
* If we already know the peer's
* unauthenticated name, then there's no
* reason to ask. Go to next state instead.
*/
int len = (int)strlen(pcb->remote_name);
if (len > MAXNAMELEN) {
len = MAXNAMELEN;
}
MEMCPY(pcb->eap.es_server.ea_peer, pcb->remote_name, len);
pcb->eap.es_server.ea_peer[len] = '\0';
pcb->eap.es_server.ea_peerlen = len;
eap_figure_next_state(pcb, 0);
}
#endif /* PPP_REMOTENAME */
}
if (pcb->settings.eap_max_transmits > 0 &&
pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) {
if (pcb->eap.es_server.ea_responses > 0)
ppp_error("EAP: too many Requests sent");
else
ppp_error("EAP: no response to Requests");
eap_send_failure(pcb);
return;
}
p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
outp = (u_char*)p->payload;
MAKEHEADER(outp, PPP_EAP);
PUTCHAR(EAP_REQUEST, outp);
PUTCHAR(pcb->eap.es_server.ea_id, outp);
lenloc = outp;
INCPTR(2, outp);
switch (pcb->eap.es_server.ea_state) {
case eapIdentify:
PUTCHAR(EAPT_IDENTITY, outp);
str = "Name";
len = strlen(str);
MEMCPY(outp, str, len);
INCPTR(len, outp);
break;
case eapMD5Chall:
PUTCHAR(EAPT_MD5CHAP, outp);
/*
* pick a random challenge length between
* EAP_MIN_CHALLENGE_LENGTH and EAP_MAX_CHALLENGE_LENGTH
*/
pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH +
magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH);
PUTCHAR(pcb->eap.es_challen, outp);
magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen);
MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen);
INCPTR(pcb->eap.es_challen, outp);
MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen);
INCPTR(pcb->eap.es_server.ea_namelen, outp);
break;
#ifdef USE_SRP
case eapSRP1:
PUTCHAR(EAPT_SRP, outp);
PUTCHAR(EAPSRP_CHALLENGE, outp);
PUTCHAR(pcb->eap.es_server.ea_namelen, outp);
MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen);
INCPTR(pcb->eap.es_server.ea_namelen, outp);
ts = (struct t_server *)pcb->eap.es_server.ea_session;
assert(ts != NULL);
PUTCHAR(ts->s.len, outp);
MEMCPY(outp, ts->s.data, ts->s.len);
INCPTR(ts->s.len, outp);
if (ts->g.len == 1 && ts->g.data[0] == 2) {
PUTCHAR(0, outp);
} else {
PUTCHAR(ts->g.len, outp);
MEMCPY(outp, ts->g.data, ts->g.len);
INCPTR(ts->g.len, outp);
}
if (ts->n.len != sizeof (wkmodulus) ||
BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) {
MEMCPY(outp, ts->n.data, ts->n.len);
INCPTR(ts->n.len, outp);
}
break;
case eapSRP2:
PUTCHAR(EAPT_SRP, outp);
PUTCHAR(EAPSRP_SKEY, outp);
ts = (struct t_server *)pcb->eap.es_server.ea_session;
assert(ts != NULL);
MEMCPY(outp, ts->B.data, ts->B.len);
INCPTR(ts->B.len, outp);
break;
case eapSRP3:
PUTCHAR(EAPT_SRP, outp);
PUTCHAR(EAPSRP_SVALIDATOR, outp);
PUTLONG(SRPVAL_EBIT, outp);
ts = (struct t_server *)pcb->eap.es_server.ea_session;
assert(ts != NULL);
MEMCPY(outp, t_serverresponse(ts), SHA_DIGESTSIZE);
INCPTR(SHA_DIGESTSIZE, outp);
if (pncrypt_setkey(0)) {
/* Generate pseudonym */
optr = outp;
cp = (unsigned char *)pcb->eap.es_server.ea_peer;
if ((j = i = pcb->eap.es_server.ea_peerlen) > 7)
j = 7;
clear[0] = i;
MEMCPY(clear + 1, cp, j);
i -= j;
cp += j;
/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
if (!DesEncrypt(clear, cipher)) {
ppp_dbglog("no DES here; not generating pseudonym");
break;
}
BZERO(&b64, sizeof (b64));
outp++; /* space for pseudonym length */
outp += b64enc(&b64, cipher, 8, outp);
while (i >= 8) {
/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
(void) DesEncrypt(cp, cipher);
outp += b64enc(&b64, cipher, 8, outp);
cp += 8;
i -= 8;
}
if (i > 0) {
MEMCPY(clear, cp, i);
cp += i;
magic_random_bytes(cp, 8-i);
/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
(void) DesEncrypt(clear, cipher);
outp += b64enc(&b64, cipher, 8, outp);
}
outp += b64flush(&b64, outp);
/* Set length and pad out to next 20 octet boundary */
i = outp - optr - 1;
*optr = i;
i %= SHA_DIGESTSIZE;
if (i != 0) {
magic_random_bytes(outp, SHA_DIGESTSIZE-i);
INCPTR(SHA_DIGESTSIZE-i, outp);
}
/* Obscure the pseudonym with SHA1 hash */
SHA1Init(&ctxt);
SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1);
SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
SESSION_KEY_LEN);
SHA1Update(&ctxt, pcb->eap.es_server.ea_peer,
pcb->eap.es_server.ea_peerlen);
while (optr < outp) {
SHA1Final(dig, &ctxt);
cp = dig;
while (cp < dig + SHA_DIGESTSIZE)
*optr++ ^= *cp++;
SHA1Init(&ctxt);
SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1);
SHA1Update(&ctxt, pcb->eap.es_server.ea_skey,
SESSION_KEY_LEN);
SHA1Update(&ctxt, optr - SHA_DIGESTSIZE,
SHA_DIGESTSIZE);
}
}
break;
case eapSRP4:
PUTCHAR(EAPT_SRP, outp);
PUTCHAR(EAPSRP_LWRECHALLENGE, outp);
pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH +
magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH);
magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen);
MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen);
INCPTR(pcb->eap.es_challen, outp);
break;
#endif /* USE_SRP */
default:
return;
}
outlen = (outp - (unsigned char*)p->payload) - PPP_HDRLEN;
PUTSHORT(outlen, lenloc);
pbuf_realloc(p, outlen + PPP_HDRLEN);
ppp_write(pcb, p);
pcb->eap.es_server.ea_requests++;
if (pcb->settings.eap_timeout_time > 0)
TIMEOUT(eap_server_timeout, pcb, pcb->settings.eap_timeout_time);
}