* Based on draft-ietf-pppext-eap-srp-03.txt.
*/
-#define RCSID "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $"
-
/*
- * TODO:
+ * Modification by Beniamino Galvani, Mar 2005
+ * Implemented EAP-TLS authentication
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
-#include "pppd.h"
+#include "pppd-private.h"
+#include "options.h"
#include "pathnames.h"
-#include "md5.h"
+#include "crypto.h"
+#include "crypto_ms.h"
#include "eap.h"
+#ifdef PPP_WITH_PEAP
+#include "peap.h"
+#endif /* PPP_WITH_PEAP */
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
#include <t_pwd.h>
#include <t_server.h>
#include <t_client.h>
-#include "pppcrypt.h"
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
-#ifndef SHA_DIGESTSIZE
-#define SHA_DIGESTSIZE 20
-#endif
+#ifdef PPP_WITH_EAPTLS
+#include "eap-tls.h"
+#endif /* PPP_WITH_EAPTLS */
+
+#ifdef PPP_WITH_CHAPMS
+#include "chap.h"
+#include "chap_ms.h"
+extern int chapms_strip_domain;
+#endif /* PPP_WITH_CHAPMS */
eap_state eap_states[NUM_PPP]; /* EAP state; one for each unit */
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
static char *pn_secret = NULL; /* Pseudonym generating secret */
#endif
/*
* Command-line options.
*/
-static option_t eap_option_list[] = {
+static struct option eap_option_list[] = {
{ "eap-restart", o_int, &eap_states[0].es_server.ea_timeout,
"Set retransmit timeout for EAP Requests (server)" },
{ "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests,
"Set max number of EAP Requests allows (client)" },
{ "eap-interval", o_int, &eap_states[0].es_rechallenge,
"Set interval for EAP rechallenge" },
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
{ "srp-interval", o_int, &eap_states[0].es_lwrechallenge,
"Set interval for SRP lightweight rechallenge" },
{ "srp-pn-secret", o_string, &pn_secret,
/*
* Protocol entry points.
*/
-static void eap_init __P((int unit));
-static void eap_input __P((int unit, u_char *inp, int inlen));
-static void eap_protrej __P((int unit));
-static void eap_lowerup __P((int unit));
-static void eap_lowerdown __P((int unit));
-static int eap_printpkt __P((u_char *inp, int inlen,
- void (*)(void *arg, char *fmt, ...), void *arg));
+static void eap_init (int unit);
+static void eap_input (int unit, u_char *inp, int inlen);
+static void eap_protrej (int unit);
+static void eap_lowerup (int unit);
+static void eap_lowerdown (int unit);
+static int eap_printpkt (u_char *inp, int inlen,
+ void (*)(void *arg, char *fmt, ...), void *arg);
struct protent eap_protent = {
PPP_EAP, /* protocol number */
NULL /* say whether to bring up link for this pkt */
};
+#ifdef PPP_WITH_SRP
/*
* A well-known 2048 bit modulus.
*/
0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2,
0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73
};
+#endif /* PPP_WITH_SRP */
/* Local forward declarations. */
-static void eap_server_timeout __P((void *arg));
+static void eap_server_timeout (void *arg);
/*
* Convert EAP state code to printable string for debug.
*/
static const char *
-eap_state_name(esc)
-enum eap_state_code esc;
+eap_state_name(enum eap_state_code esc)
{
static const char *state_names[] = { EAP_STATES };
* called once by main() during start-up.
*/
static void
-eap_init(unit)
-int unit;
+eap_init(int unit)
{
eap_state *esp = &eap_states[unit];
esp->es_server.ea_id = (u_char)(drand48() * 0x100);
esp->es_client.ea_timeout = EAP_DEFREQTIME;
esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ;
+#ifdef PPP_WITH_EAPTLS
+ esp->es_client.ea_using_eaptls = 0;
+#endif /* PPP_WITH_EAPTLS */
+#ifdef PPP_WITH_CHAPMS
+ esp->es_client.digest = chap_find_digest(CHAP_MICROSOFT_V2);
+ esp->es_server.digest = chap_find_digest(CHAP_MICROSOFT_V2);
+#endif
}
/*
* Request messages.
*/
static void
-eap_client_timeout(arg)
-void *arg;
+eap_client_timeout(void *arg)
{
eap_state *esp = (eap_state *) arg;
* after eap_lowerup.
*/
void
-eap_authwithpeer(unit, localname)
-int unit;
-char *localname;
+eap_authwithpeer(int unit, char *localname)
{
eap_state *esp = &eap_states[unit];
* (Server operation)
*/
static void
-eap_send_failure(esp)
-eap_state *esp;
+eap_send_failure(eap_state *esp)
{
u_char *outp;
* (Server operation)
*/
static void
-eap_send_success(esp)
-eap_state *esp;
+eap_send_success(eap_state *esp)
{
u_char *outp;
esp->es_server.ea_peer, esp->es_server.ea_peerlen);
}
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
/*
* Set DES key according to pseudonym-generating secret and current
* date.
*/
static bool
-pncrypt_setkey(int timeoffs)
+pncrypt_getkey(int timeoffs, unsigned char *key, int keylen)
{
struct tm *tp;
char tbuf[9];
- SHA1_CTX ctxt;
- u_char dig[SHA_DIGESTSIZE];
+ PPP_MD_CTX *ctxt;
time_t reftime;
if (pn_secret == NULL)
return (0);
reftime = time(NULL) + timeoffs;
tp = localtime(&reftime);
- SHA1Init(&ctxt);
- SHA1Update(&ctxt, pn_secret, strlen(pn_secret));
- strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp);
- SHA1Update(&ctxt, tbuf, strlen(tbuf));
- SHA1Final(dig, &ctxt);
- return (DesSetkey(dig));
+
+ ctxt = PPP_MD_CTX_new();
+ if (ctxt) {
+
+ strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp);
+
+ PPP_DigestInit(ctxt, PPP_sha1());
+ PPP_DigestUpdate(ctxt, pn_secret, strlen(pn_secret));
+ PPP_DigestUpdate(ctxt, tbuf, strlen(tbuf));
+ PPP_DigestFinal(ctxt, key, &keylen);
+
+ PPP_MD_CTX_free(ctxt);
+ return 1;
+ }
+
+ return (0);
}
static char base64[] =
};
static int
-b64enc(bs, inp, inlen, outp)
-struct b64state *bs;
-u_char *inp;
-int inlen;
-u_char *outp;
+b64enc(struct b64state *bs, u_char *inp, int inlen, u_char *outp)
{
int outlen = 0;
}
static int
-b64flush(bs, outp)
-struct b64state *bs;
-u_char *outp;
+b64flush(struct b64state *bs, u_char *outp)
{
int outlen = 0;
}
static int
-b64dec(bs, inp, inlen, outp)
-struct b64state *bs;
-u_char *inp;
-int inlen;
-u_char *outp;
+b64dec(struct b64state *bs, u_char *inp, int inlen, u_char *outp)
{
int outlen = 0;
char *cp;
}
return (outlen);
}
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
/*
* Assume that current waiting server state is complete and figure
* 0 for success and non-zero for failure.
*/
static void
-eap_figure_next_state(esp, status)
-eap_state *esp;
-int status;
+eap_figure_next_state(eap_state *esp, int status)
{
-#ifdef USE_SRP
- unsigned char secbuf[MAXWORDLEN], clear[8], *sp, *dp;
+#ifdef PPP_WITH_SRP
+ unsigned char secbuf[MAXWORDLEN], clear[8], *sp, *dp, key[SHA_DIGEST_LENGTH];
struct t_pw tpw;
struct t_confent *tce, mytce;
char *cp, *cp2;
struct t_server *ts;
- int id, i, plen, toffs;
+ int id, i, plen, clen, toffs, keylen;
u_char vals[2];
struct b64state bs;
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
+#ifdef PPP_WITH_EAPTLS
+ struct eaptls_session *ets;
+ int secret_len;
+ char secret[MAXWORDLEN];
+#endif /* PPP_WITH_EAPTLS */
esp->es_server.ea_timeout = esp->es_savedtime;
+#ifdef PPP_WITH_EAPTLS
+ esp->es_server.ea_prev_state = esp->es_server.ea_state;
+#endif /* PPP_WITH_EAPTLS */
switch (esp->es_server.ea_state) {
case eapBadAuth:
return;
case eapIdentify:
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
/* Discard any previous session. */
ts = (struct t_server *)esp->es_server.ea_session;
if (ts != NULL) {
esp->es_server.ea_session = NULL;
esp->es_server.ea_skey = NULL;
}
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
if (status != 0) {
esp->es_server.ea_state = eapBadAuth;
break;
}
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
/* If we've got a pseudonym, try to decode to real name. */
if (esp->es_server.ea_peerlen > SRP_PSEUDO_LEN &&
strncmp(esp->es_server.ea_peer, SRP_PSEUDO_ID,
secbuf);
toffs = 0;
for (i = 0; i < 5; i++) {
- pncrypt_setkey(toffs);
+ pncrypt_getkey(toffs, key, keylen);
toffs -= 86400;
- if (!DesDecrypt(secbuf, clear)) {
+
+ if (!DesDecrypt(secbuf, key, clear)) {
dbglog("no DES here; cannot decode "
- "pseudonym");
+ "pseudonym");
return;
}
id = *(unsigned char *)clear;
dp += i;
sp = secbuf + 8;
while (plen > 0) {
- (void) DesDecrypt(sp, dp);
+ DesDecrypt(sp, key, dp);
sp += 8;
dp += 8;
plen -= 8;
tpw.pebuf.name = esp->es_server.ea_peer;
tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf,
cp);
- tpw.pebuf.password.data = tpw.pwbuf;
+ tpw.pebuf.password.data = (char*) tpw.pwbuf;
tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf,
cp2);
tpw.pebuf.salt.data = tpw.saltbuf;
t_servergenexp(ts);
break;
}
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
+#ifdef PPP_WITH_EAPTLS
+ if (!get_secret(esp->es_unit, esp->es_server.ea_peer,
+ esp->es_server.ea_name, secret, &secret_len, 1)) {
+
+ esp->es_server.ea_state = eapTlsStart;
+ break;
+ }
+#endif /* PPP_WITH_EAPTLS */
+
esp->es_server.ea_state = eapMD5Chall;
break;
+#ifdef PPP_WITH_EAPTLS
+ case eapTlsStart:
+ /* Initialize ssl session */
+ if(!eaptls_init_ssl_server(esp)) {
+ esp->es_server.ea_state = eapBadAuth;
+ break;
+ }
+
+ esp->es_server.ea_state = eapTlsRecv;
+ break;
+
+ case eapTlsRecv:
+ ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+ if(ets->alert_sent) {
+ esp->es_server.ea_state = eapTlsSendAlert;
+ break;
+ }
+
+ if (status) {
+ esp->es_server.ea_state = eapBadAuth;
+ break;
+ }
+ ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+ if(ets->frag)
+ esp->es_server.ea_state = eapTlsSendAck;
+ else
+ esp->es_server.ea_state = eapTlsSend;
+ break;
+
+ case eapTlsSend:
+ ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+ if(ets->frag)
+ esp->es_server.ea_state = eapTlsRecvAck;
+ else
+ if(SSL_is_init_finished(ets->ssl))
+ esp->es_server.ea_state = eapTlsRecvClient;
+ else
+ /* JJK Add "TLS empty record" message here ??? */
+ esp->es_server.ea_state = eapTlsRecv;
+ break;
+
+ case eapTlsSendAck:
+ esp->es_server.ea_state = eapTlsRecv;
+ break;
+
+ case eapTlsRecvAck:
+ if (status)
+ {
+ esp->es_server.ea_state = eapBadAuth;
+ break;
+ }
+
+ esp->es_server.ea_state = eapTlsSend;
+ break;
+
+ case eapTlsSendAlert:
+ esp->es_server.ea_state = eapTlsRecvAlertAck;
+ break;
+#endif /* PPP_WITH_EAPTLS */
+
case eapSRP1:
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
ts = (struct t_server *)esp->es_server.ea_session;
if (ts != NULL && status != 0) {
t_serverclose(ts);
esp->es_server.ea_session = NULL;
esp->es_server.ea_skey = NULL;
}
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
if (status == 1) {
esp->es_server.ea_state = eapMD5Chall;
} else if (status != 0 || esp->es_server.ea_session == NULL) {
break;
case eapSRP2:
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
ts = (struct t_server *)esp->es_server.ea_session;
if (ts != NULL && status != 0) {
t_serverclose(ts);
esp->es_server.ea_session = NULL;
esp->es_server.ea_skey = NULL;
}
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
if (status != 0 || esp->es_server.ea_session == NULL) {
esp->es_server.ea_state = eapBadAuth;
} else {
case eapSRP3:
case eapSRP4:
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
ts = (struct t_server *)esp->es_server.ea_session;
if (ts != NULL && status != 0) {
t_serverclose(ts);
esp->es_server.ea_session = NULL;
esp->es_server.ea_skey = NULL;
}
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
if (status != 0 || esp->es_server.ea_session == NULL) {
esp->es_server.ea_state = eapBadAuth;
} else {
}
break;
+#ifdef PPP_WITH_CHAPMS
+ case eapMSCHAPv2Chall:
+#endif
case eapMD5Chall:
if (status != 0) {
esp->es_server.ea_state = eapBadAuth;
}
if (esp->es_server.ea_state == eapBadAuth)
eap_send_failure(esp);
+
+#ifdef PPP_WITH_EAPTLS
+ dbglog("EAP id=0x%2x '%s' -> '%s'", esp->es_server.ea_id, eap_state_name(esp->es_server.ea_prev_state), eap_state_name(esp->es_server.ea_state));
+#endif /* PPP_WITH_EAPTLS */
+}
+
+#if PPP_WITH_CHAPMS
+/*
+ * eap_chap_verify_response - check whether the peer's response matches
+ * what we think it should be. Returns 1 if it does (authentication
+ * succeeded), or 0 if it doesn't.
+ */
+static int
+eap_chap_verify_response(char *name, char *ourname, int id,
+ struct chap_digest_type *digest,
+ unsigned char *challenge, unsigned char *response,
+ char *message, int message_space)
+{
+ int ok;
+ unsigned char secret[MAXSECRETLEN];
+ int secret_len;
+
+ /* Get the secret that the peer is supposed to know */
+ if (!get_secret(0, name, ourname, (char *)secret, &secret_len, 1)) {
+ error("No CHAP secret found for authenticating %q", name);
+ return 0;
+ }
+
+ ok = digest->verify_response(id, name, secret, secret_len, challenge,
+ response, message, message_space);
+ memset(secret, 0, sizeof(secret));
+
+ return ok;
+}
+
+/*
+ * Format and send an CHAPV2-Success/Failure EAP Request message.
+ */
+static void
+eap_chapms2_send_request(eap_state *esp, u_char id,
+ u_char opcode, u_char chapid,
+ char *message, int message_len)
+{
+ u_char *outp;
+ int msglen;
+
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_EAP);
+
+ msglen = EAP_HEADERLEN + 5 * sizeof (u_char);
+ msglen += message_len;
+
+ PUTCHAR(EAP_REQUEST, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(msglen, outp);
+ PUTCHAR(EAPT_MSCHAPV2, outp);
+ PUTCHAR(opcode, outp);
+ PUTCHAR(chapid, outp);
+ /* MS len */
+ PUTSHORT(msglen - 5, outp);
+ BCOPY(message, outp, message_len);
+
+ output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
+
+ if (opcode == CHAP_SUCCESS) {
+ auth_peer_success(esp->es_unit, PPP_EAP, 0,
+ esp->es_server.ea_peer, esp->es_server.ea_peerlen);
+ }
+ else {
+ esp->es_server.ea_state = eapBadAuth;
+ auth_peer_fail(esp->es_unit, PPP_EAP);
+ }
}
+#endif /* PPP_WITH_CHAPMS */
/*
* Format an EAP Request message and send it to the peer. Message
* type depends on current state. (Server operation)
*/
static void
-eap_send_request(esp)
-eap_state *esp;
+eap_send_request(eap_state *esp)
{
u_char *outp;
u_char *lenloc;
int outlen;
int challen;
char *str;
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
struct t_server *ts;
- u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp;
- int i, j;
+ u_char clear[8], cipher[8], dig[SHA_DIGEST_LENGTH], *optr, *cp, key[SHA_DIGEST_LENGTH];
+ int i, j, diglen, clen, keylen = sizeof(key);
struct b64state b64;
- SHA1_CTX ctxt;
-#endif /* USE_SRP */
+ PPP_MD_CTX *ctxt;
+#endif /* PPP_WITH_SRP */
/* Handle both initial auth and restart */
if (esp->es_server.ea_state < eapIdentify &&
INCPTR(esp->es_server.ea_namelen, outp);
break;
-#ifdef USE_SRP
+#ifdef PPP_WITH_CHAPMS
+ case eapMSCHAPv2Chall:
+ esp->es_server.digest->generate_challenge(esp->es_challenge);
+ challen = esp->es_challenge[0];
+ esp->es_challen = challen;
+
+ PUTCHAR(EAPT_MSCHAPV2, outp);
+ PUTCHAR(CHAP_CHALLENGE, outp);
+ PUTCHAR(esp->es_server.ea_id, outp);
+ /* MS len */
+ PUTSHORT(5 + challen +
+ esp->es_server.ea_namelen,
+ outp);
+ /* challen + challenge */
+ BCOPY(esp->es_challenge, outp, challen+1);
+ INCPTR(challen+1, outp);
+ BCOPY(esp->es_server.ea_name,
+ outp,
+ esp->es_server.ea_namelen);
+ INCPTR(esp->es_server.ea_namelen, outp);
+ break;
+#endif /* PPP_WITH_CHAPMS */
+
+#ifdef PPP_WITH_EAPTLS
+ case eapTlsStart:
+ PUTCHAR(EAPT_TLS, outp);
+ PUTCHAR(EAP_TLS_FLAGS_START, outp);
+ eap_figure_next_state(esp, 0);
+ break;
+
+ case eapTlsSend:
+ eaptls_send(esp->es_server.ea_session, &outp);
+ eap_figure_next_state(esp, 0);
+ break;
+
+ case eapTlsSendAck:
+ PUTCHAR(EAPT_TLS, outp);
+ PUTCHAR(0, outp);
+ eap_figure_next_state(esp, 0);
+ break;
+
+ case eapTlsSendAlert:
+ eaptls_send(esp->es_server.ea_session, &outp);
+ eap_figure_next_state(esp, 0);
+ break;
+#endif /* PPP_WITH_EAPTLS */
+
+#ifdef PPP_WITH_SRP
case eapSRP1:
PUTCHAR(EAPT_SRP, outp);
PUTCHAR(EAPSRP_CHALLENGE, outp);
PUTLONG(SRPVAL_EBIT, outp);
ts = (struct t_server *)esp->es_server.ea_session;
assert(ts != NULL);
- BCOPY(t_serverresponse(ts), outp, SHA_DIGESTSIZE);
- INCPTR(SHA_DIGESTSIZE, outp);
+ BCOPY(t_serverresponse(ts), outp, SHA_DIGEST_LENGTH);
+ INCPTR(SHA_DIGEST_LENGTH, outp);
- if (pncrypt_setkey(0)) {
+ if (pncrypt_getkey(0, key, keylen)) {
/* Generate pseudonym */
optr = outp;
cp = (unsigned char *)esp->es_server.ea_peer;
BCOPY(cp, clear + 1, j);
i -= j;
cp += j;
- if (!DesEncrypt(clear, cipher)) {
+
+ if (!DesEncrypt(clear, key, cipher)) {
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) {
- (void) DesEncrypt(cp, cipher);
+ DesEncrypt(cp, key, cipher);
outp += b64enc(&b64, cipher, 8, outp);
cp += 8;
i -= 8;
*cp++ = drand48() * 0x100;
i++;
}
- (void) DesEncrypt(clear, cipher);
+
+ DesEncrypt(clear, key, 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;
+ i %= SHA_DIGEST_LENGTH;
if (i != 0) {
- while (i < SHA_DIGESTSIZE) {
+ while (i < SHA_DIGEST_LENGTH) {
*outp++ = drand48() * 0x100;
i++;
}
}
/* Obscure the pseudonym with SHA1 hash */
- SHA1Init(&ctxt);
- SHA1Update(&ctxt, &esp->es_server.ea_id, 1);
- SHA1Update(&ctxt, esp->es_server.ea_skey,
- SESSION_KEY_LEN);
- SHA1Update(&ctxt, esp->es_server.ea_peer,
- esp->es_server.ea_peerlen);
- while (optr < outp) {
- SHA1Final(dig, &ctxt);
- cp = dig;
- while (cp < dig + SHA_DIGESTSIZE)
- *optr++ ^= *cp++;
- SHA1Init(&ctxt);
- SHA1Update(&ctxt, &esp->es_server.ea_id, 1);
- SHA1Update(&ctxt, esp->es_server.ea_skey,
- SESSION_KEY_LEN);
- SHA1Update(&ctxt, optr - SHA_DIGESTSIZE,
- SHA_DIGESTSIZE);
+ ctxt = PPP_MD_CTX_new();
+ if (ctxt) {
+
+ PPP_DigestInit(ctxt, PPP_sha1());
+ PPP_DigestUpdate(ctxt, &esp->es_server.ea_id, 1);
+ PPP_DigestUpdate(ctxt, &esp->es_server.ea_skey,
+ SESSION_KEY_LEN);
+ PPP_DigestUpdate(ctxt, esp->es_server.ea_peer,
+ esp->es_server.ea_peerlen);
+ while (optr < outp) {
+ diglen = SHA_DIGEST_LENGTH;
+ PPP_DigestFinal(ctxt, dig, &diglen);
+ cp = dig;
+ while (cp < dig + SHA_DIGEST_LENGTH)
+ *optr++ ^= *cp++;
+
+ PPP_DigestInit(ctxt, PPP_sha1());
+ PPP_DigestUpdate(ctxt, &esp->es_server.ea_id, 1);
+ PPP_DigestUpdate(ctxt, esp->es_server.ea_skey,
+ SESSION_KEY_LEN);
+ PPP_DigestUpdate(ctxt, optr - SHA_DIGEST_LENGTH,
+ SHA_DIGEST_LENGTH);
+ }
+
+ PPP_MD_CTX_free(ctxt);
}
}
break;
BCOPY(esp->es_challenge, outp, esp->es_challen);
INCPTR(esp->es_challen, outp);
break;
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
default:
return;
* after eap_lowerup.
*/
void
-eap_authpeer(unit, localname)
-int unit;
-char *localname;
+eap_authpeer(int unit, char *localname)
{
eap_state *esp = &eap_states[unit];
* expired.
*/
static void
-eap_server_timeout(arg)
-void *arg;
+eap_server_timeout(void *arg)
{
+#ifdef PPP_WITH_EAPTLS
+ u_char *outp;
+ u_char *lenloc;
+ int outlen;
+#endif /* PPP_WITH_EAPTLS */
+
eap_state *esp = (eap_state *) arg;
if (!eap_server_active(esp))
return;
+#ifdef PPP_WITH_EAPTLS
+ switch(esp->es_server.ea_prev_state) {
+
+ /*
+ * In eap-tls the state changes after a request, so we return to
+ * previous state ...
+ */
+ case(eapTlsStart):
+ case(eapTlsSendAck):
+ esp->es_server.ea_state = esp->es_server.ea_prev_state;
+ break;
+
+ /*
+ * ... or resend the stored data
+ */
+ case(eapTlsSend):
+ case(eapTlsSendAlert):
+ outp = outpacket_buf;
+ MAKEHEADER(outp, PPP_EAP);
+ PUTCHAR(EAP_REQUEST, outp);
+ PUTCHAR(esp->es_server.ea_id, outp);
+ lenloc = outp;
+ INCPTR(2, outp);
+
+ eaptls_retransmit(esp->es_server.ea_session, &outp);
+
+ outlen = (outp - outpacket_buf) - PPP_HDRLEN;
+ PUTSHORT(outlen, lenloc);
+ output(esp->es_unit, outpacket_buf, outlen + PPP_HDRLEN);
+ esp->es_server.ea_requests++;
+
+ if (esp->es_server.ea_timeout > 0)
+ TIMEOUT(eap_server_timeout, esp, esp->es_server.ea_timeout);
+
+ return;
+ default:
+ break;
+ }
+#endif /* PPP_WITH_EAPTLS */
+
/* EAP ID number must not change on timeout. */
eap_send_request(esp);
}
* will restart the timer. If it fails, then the link is dropped.
*/
static void
-eap_rechallenge(arg)
-void *arg;
+eap_rechallenge(void *arg)
{
eap_state *esp = (eap_state *)arg;
}
static void
-srp_lwrechallenge(arg)
-void *arg;
+srp_lwrechallenge(void *arg)
{
eap_state *esp = (eap_state *)arg;
* thing.
*/
static void
-eap_lowerup(unit)
-int unit;
+eap_lowerup(int unit)
{
eap_state *esp = &eap_states[unit];
* Cancel all timeouts and return to initial state.
*/
static void
-eap_lowerdown(unit)
-int unit;
+eap_lowerdown(int unit)
{
eap_state *esp = &eap_states[unit];
* failure.
*/
static void
-eap_protrej(unit)
-int unit;
+eap_protrej(int unit)
{
eap_state *esp = &eap_states[unit];
* Format and send a regular EAP Response message.
*/
static void
-eap_send_response(esp, id, typenum, str, lenstr)
-eap_state *esp;
-u_char id;
-u_char typenum;
-u_char *str;
-int lenstr;
+eap_send_response(eap_state *esp, u_char id, u_char typenum,
+ u_char *str, int lenstr)
{
u_char *outp;
int msglen;
* Format and send an MD5-Challenge EAP Response message.
*/
static void
-eap_chap_response(esp, id, hash, name, namelen)
-eap_state *esp;
-u_char id;
-u_char *hash;
-char *name;
-int namelen;
+eap_chap_response(eap_state *esp, u_char id, u_char *hash,
+ char *name, int namelen)
{
u_char *outp;
int msglen;
outp = outpacket_buf;
-
+
MAKEHEADER(outp, PPP_EAP);
PUTCHAR(EAP_RESPONSE, outp);
PUTCHAR(id, outp);
esp->es_client.ea_id = id;
- msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE +
+ msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_DIGEST_LENGTH +
namelen;
PUTSHORT(msglen, outp);
PUTCHAR(EAPT_MD5CHAP, outp);
- PUTCHAR(MD5_SIGNATURE_SIZE, outp);
- BCOPY(hash, outp, MD5_SIGNATURE_SIZE);
- INCPTR(MD5_SIGNATURE_SIZE, outp);
+ PUTCHAR(MD5_DIGEST_LENGTH, outp);
+ BCOPY(hash, outp, MD5_DIGEST_LENGTH);
+ INCPTR(MD5_DIGEST_LENGTH, outp);
if (namelen > 0) {
BCOPY(name, outp, namelen);
}
output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
}
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
/*
* Format and send a SRP EAP Response message.
*/
static void
-eap_srp_response(esp, id, subtypenum, str, lenstr)
-eap_state *esp;
-u_char id;
-u_char subtypenum;
-u_char *str;
-int lenstr;
+eap_srp_response(eap_state *esp, u_char id, u_char subtypenum,
+ u_char *str, int lenstr)
{
u_char *outp;
int msglen;
* Format and send a SRP EAP Client Validator Response message.
*/
static void
-eap_srpval_response(esp, id, flags, str)
-eap_state *esp;
-u_char id;
-u_int32_t flags;
-u_char *str;
+eap_srpval_response(eap_state *esp, u_char id, u_int32_t flags, u_char *str)
{
u_char *outp;
int msglen;
PUTCHAR(id, outp);
esp->es_client.ea_id = id;
msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u_int32_t) +
- SHA_DIGESTSIZE;
+ SHA_DIGEST_LENGTH;
PUTSHORT(msglen, outp);
PUTCHAR(EAPT_SRP, outp);
PUTCHAR(EAPSRP_CVALIDATOR, outp);
PUTLONG(flags, outp);
- BCOPY(str, outp, SHA_DIGESTSIZE);
+ BCOPY(str, outp, SHA_DIGEST_LENGTH);
output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
}
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
+
+#ifdef PPP_WITH_EAPTLS
+/*
+ * Send an EAP-TLS response message with tls data
+ */
+static void
+eap_tls_response(eap_state *esp, u_char id)
+{
+ u_char *outp;
+ int outlen;
+ u_char *lenloc;
+
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_EAP);
+
+ PUTCHAR(EAP_RESPONSE, outp);
+ PUTCHAR(id, outp);
+
+ lenloc = outp;
+ INCPTR(2, outp);
+
+ /*
+ If the id in the request is unchanged, we must retransmit
+ the old data
+ */
+ if(id == esp->es_client.ea_id)
+ eaptls_retransmit(esp->es_client.ea_session, &outp);
+ else
+ eaptls_send(esp->es_client.ea_session, &outp);
+
+ outlen = (outp - outpacket_buf) - PPP_HDRLEN;
+ PUTSHORT(outlen, lenloc);
+
+ output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen);
+
+ esp->es_client.ea_id = id;
+}
+
+/*
+ * Send an EAP-TLS ack
+ */
+static void
+eap_tls_sendack(eap_state *esp, u_char id)
+{
+ u_char *outp;
+ int outlen;
+ u_char *lenloc;
+
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_EAP);
+
+ PUTCHAR(EAP_RESPONSE, outp);
+ PUTCHAR(id, outp);
+ esp->es_client.ea_id = id;
+
+ lenloc = outp;
+ INCPTR(2, outp);
+
+ PUTCHAR(EAPT_TLS, outp);
+ PUTCHAR(0, outp);
+
+ outlen = (outp - outpacket_buf) - PPP_HDRLEN;
+ PUTSHORT(outlen, lenloc);
+
+ output(esp->es_unit, outpacket_buf, PPP_HDRLEN + outlen);
+}
+#endif /* PPP_WITH_EAPTLS */
static void
-eap_send_nak(esp, id, type)
-eap_state *esp;
-u_char id;
-u_char type;
+eap_send_nak(eap_state *esp, u_char id, u_char type)
{
u_char *outp;
int msglen;
output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
}
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
static char *
-name_of_pn_file()
+name_of_pn_file(void)
{
char *user, *path, *file;
struct passwd *pw;
errno = EINVAL;
return (NULL);
}
- file = _PATH_PSEUDONYM;
+ file = PPP_PATH_PSEUDONYM;
pl = strlen(user) + strlen(file) + 2;
path = malloc(pl);
if (path == NULL)
}
static int
-open_pn_file(modebits)
-mode_t modebits;
+open_pn_file(mode_t modebits)
{
char *path;
int fd, err;
}
static void
-remove_pn_file()
+remove_pn_file(void)
{
char *path;
}
static void
-write_pseudonym(esp, inp, len, id)
-eap_state *esp;
-u_char *inp;
-int len, id;
+write_pseudonym(eap_state *esp, u_char *inp, int len, int id)
{
u_char val;
u_char *datp, *digp;
- SHA1_CTX ctxt;
- u_char dig[SHA_DIGESTSIZE];
- int dsize, fd, olen = len;
+ PPP_MD_CTX *ctxt;
+ u_char dig[SHA_DIGEST_LENGTH];
+ int dsize, fd, olen = len, diglen = sizeof(dig);
/*
* Do the decoding by working backwards. This eliminates the need
*/
val = id;
while (len > 0) {
- if ((dsize = len % SHA_DIGESTSIZE) == 0)
- dsize = SHA_DIGESTSIZE;
+ if ((dsize = len % SHA_DIGEST_LENGTH) == 0)
+ dsize = SHA_DIGEST_LENGTH;
len -= dsize;
datp = inp + len;
- SHA1Init(&ctxt);
- SHA1Update(&ctxt, &val, 1);
- SHA1Update(&ctxt, esp->es_client.ea_skey, SESSION_KEY_LEN);
- if (len > 0) {
- SHA1Update(&ctxt, datp, SHA_DIGESTSIZE);
- } else {
- SHA1Update(&ctxt, esp->es_client.ea_name,
- esp->es_client.ea_namelen);
+ ctxt = PPP_MD_CTX_new();
+ if (ctxt) {
+
+ PPP_DigestInit(ctxt, PPP_sha1());
+ PPP_DigestUpdate(ctxt, &val, 1);
+ PPP_DigestUpdate(ctxt, esp->es_client.ea_skey,
+ SESSION_KEY_LEN);
+ if (len > 0) {
+ PPP_DigestUpdate(ctxt, datp, SHA_DIGEST_LENGTH);
+ } else {
+ PPP_DigestUpdate(ctxt, esp->es_client.ea_name,
+ esp->es_client.ea_namelen);
+ }
+ PPP_DigestFinal(ctxt, dig, &diglen);
+
+ for (digp = dig; digp < dig + SHA_DIGEST_LENGTH; digp++)
+ *datp++ ^= *digp;
+
+ PPP_MD_CTX_free(ctxt);
}
- SHA1Final(dig, &ctxt);
- for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++)
- *datp++ ^= *digp;
}
/* Now check that the result is sane */
remove_pn_file();
}
}
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
+
+#if PPP_WITH_CHAPMS
+/*
+ * Format and send an CHAPV2-Challenge EAP Response message.
+ */
+static void
+eap_chapv2_response(eap_state *esp, u_char id, u_char chapid, u_char *response, char *user, int user_len)
+{
+ u_char *outp;
+ int msglen;
+
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_EAP);
+
+ PUTCHAR(EAP_RESPONSE, outp);
+ PUTCHAR(id, outp);
+ esp->es_client.ea_id = id;
+ msglen = EAP_HEADERLEN + 6 * sizeof (u_char) + MS_CHAP2_RESPONSE_LEN + user_len;
+ PUTSHORT(msglen, outp);
+ PUTCHAR(EAPT_MSCHAPV2, outp);
+ PUTCHAR(CHAP_RESPONSE, outp);
+ PUTCHAR(chapid, outp);
+ PUTCHAR(0, outp);
+ /* len */
+ PUTCHAR(5 + user_len + MS_CHAP2_RESPONSE_LEN, outp);
+ BCOPY(response, outp, MS_CHAP2_RESPONSE_LEN+1); // VLEN + VALUE
+ INCPTR(MS_CHAP2_RESPONSE_LEN+1, outp);
+ BCOPY(user, outp, user_len);
+
+ output(esp->es_unit, outpacket_buf, PPP_HDRLEN + msglen);
+}
+#endif
/*
* eap_request - Receive EAP Request message (client mode).
*/
static void
-eap_request(esp, inp, id, len)
-eap_state *esp;
-u_char *inp;
-int id;
-int len;
+eap_request(eap_state *esp, u_char *inp, int id, int len)
{
u_char typenum;
u_char vallen;
int secret_len;
char secret[MAXWORDLEN];
char rhostname[256];
- MD5_CTX mdContext;
- u_char hash[MD5_SIGNATURE_SIZE];
-#ifdef USE_SRP
+ PPP_MD_CTX *mdctx;
+ u_char hash[MD5_DIGEST_LENGTH];
+ int hashlen = MD5_DIGEST_LENGTH;
+#ifdef PPP_WITH_EAPTLS
+ u_char flags;
+ struct eaptls_session *ets = esp->es_client.ea_session;
+#endif /* PPP_WITH_EAPTLS */
+
+#ifdef PPP_WITH_SRP
struct t_client *tc;
struct t_num sval, gval, Nval, *Ap, Bval;
u_char vals[2];
- SHA1_CTX ctxt;
- u_char dig[SHA_DIGESTSIZE];
+ PPP_MD_CTX *ctxt;
+ u_char dig[SHA_DIGEST_LENGTH];
+ int diglen = sizeof(dig);
int fd;
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
+
+ /*
+ * Ignore requests if we're not open
+ */
+ if (esp->es_client.ea_state <= eapClosed)
+ return;
/*
* Note: we update es_client.ea_id *only if* a Response
case EAPT_IDENTITY:
if (len > 0)
info("EAP: Identity prompt \"%.*q\"", len, inp);
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
if (esp->es_usepseudo &&
(esp->es_usedpseudo == 0 ||
(esp->es_usedpseudo == 1 &&
remove_pn_file();
esp->es_usedpseudo = 2;
}
-#endif /* USE_SRP */
- eap_send_response(esp, id, typenum, esp->es_client.ea_name,
+#endif /* PPP_WITH_SRP */
+ eap_send_response(esp, id, typenum, (u_char *)esp->es_client.ea_name,
esp->es_client.ea_namelen);
break;
eap_send_nak(esp, id, EAPT_SRP);
break;
}
- MD5_Init(&mdContext);
- typenum = id;
- MD5_Update(&mdContext, &typenum, 1);
- MD5_Update(&mdContext, (u_char *)secret, secret_len);
- BZERO(secret, sizeof (secret));
- MD5_Update(&mdContext, inp, vallen);
- MD5_Final(hash, &mdContext);
- eap_chap_response(esp, id, hash, esp->es_client.ea_name,
- esp->es_client.ea_namelen);
+
+ mdctx = PPP_MD_CTX_new();
+ if (mdctx != NULL) {
+ if (PPP_DigestInit(mdctx, PPP_md5())) {
+ typenum = id;
+ if (PPP_DigestUpdate(mdctx, &typenum, 1)) {
+ if (PPP_DigestUpdate(mdctx, secret, secret_len)) {
+ BZERO(secret, sizeof(secret));
+ if (PPP_DigestUpdate(mdctx, inp, vallen)) {
+ if (PPP_DigestFinal(mdctx, hash, &hashlen)) {
+ eap_chap_response(esp, id, hash, esp->es_client.ea_name,
+ esp->es_client.ea_namelen);
+ PPP_MD_CTX_free(mdctx);
+ break;
+ }
+ }
+ }
+ }
+ }
+ PPP_MD_CTX_free(mdctx);
+ }
+ dbglog("EAP: Invalid MD5 checksum");
+ eap_send_nak(esp, id, EAPT_SRP);
break;
-#ifdef USE_SRP
+#ifdef PPP_WITH_EAPTLS
+ case EAPT_TLS:
+
+ switch(esp->es_client.ea_state) {
+
+ case eapListen:
+
+ if (len < 1) {
+ error("EAP: received EAP-TLS Listen packet with no data");
+ /* Bogus request; wait for something real. */
+ return;
+ }
+ GETCHAR(flags, inp);
+ if(flags & EAP_TLS_FLAGS_START){
+
+ esp->es_client.ea_using_eaptls = 1;
+
+ if (explicit_remote){
+ esp->es_client.ea_peer = strdup(remote_name);
+ esp->es_client.ea_peerlen = strlen(remote_name);
+ } else
+ esp->es_client.ea_peer = NULL;
+
+ /* Init ssl session */
+ if(!eaptls_init_ssl_client(esp)) {
+ dbglog("cannot init ssl");
+ eap_send_nak(esp, id, EAPT_MSCHAPV2);
+ esp->es_client.ea_using_eaptls = 0;
+ break;
+ }
+
+ ets = esp->es_client.ea_session;
+ eap_tls_response(esp, id);
+ esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv);
+ break;
+ }
+
+ /* The server has sent a bad start packet. */
+ eap_send_nak(esp, id, EAPT_MSCHAPV2);
+ break;
+
+ case eapTlsRecvAck:
+ eap_tls_response(esp, id);
+ esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv);
+ break;
+
+ case eapTlsRecv:
+ if (len < 1) {
+ error("EAP: discarding EAP-TLS Receive packet with no data");
+ /* Bogus request; wait for something real. */
+ return;
+ }
+ eaptls_receive(ets, inp, len);
+
+ if(ets->frag) {
+ eap_tls_sendack(esp, id);
+ esp->es_client.ea_state = eapTlsRecv;
+ break;
+ }
+
+ if(ets->alert_recv) {
+ eap_tls_sendack(esp, id);
+ esp->es_client.ea_state = eapTlsRecvFailure;
+ break;
+ }
+
+ /* Check if TLS handshake is finished */
+ if(eaptls_is_init_finished(ets)) {
+#ifdef PPP_WITH_MPPE
+ eaptls_gen_mppe_keys(ets, 1);
+#endif
+ eaptls_free_session(ets);
+ eap_tls_sendack(esp, id);
+ esp->es_client.ea_state = eapTlsRecvSuccess;
+ break;
+ }
+
+ eap_tls_response(esp,id);
+ esp->es_client.ea_state = (ets->frag ? eapTlsRecvAck : eapTlsRecv);
+ break;
+
+ default:
+ eap_send_nak(esp, id, EAPT_MSCHAPV2);
+ esp->es_client.ea_using_eaptls = 0;
+ break;
+ }
+
+ break;
+#endif /* PPP_WITH_EAPTLS */
+
+#ifdef PPP_WITH_SRP
case EAPT_SRP:
if (len < 1) {
error("EAP: received empty SRP Request");
esp->es_client.ea_id, id);
}
} else {
- len -= sizeof (u_int32_t) + SHA_DIGESTSIZE;
+ len -= sizeof (u_int32_t) + SHA_DIGEST_LENGTH;
if (len < 0 || t_clientverify(tc, inp +
sizeof (u_int32_t)) != 0) {
error("EAP: SRP server verification "
GETLONG(esp->es_client.ea_keyflags, inp);
/* Save pseudonym if user wants it. */
if (len > 0 && esp->es_usepseudo) {
- INCPTR(SHA_DIGESTSIZE, inp);
+ INCPTR(SHA_DIGEST_LENGTH, inp);
write_pseudonym(esp, inp, len, id);
}
}
warn("EAP: malformed Lightweight rechallenge");
return;
}
- SHA1Init(&ctxt);
- vals[0] = id;
- SHA1Update(&ctxt, vals, 1);
- SHA1Update(&ctxt, esp->es_client.ea_skey,
- SESSION_KEY_LEN);
- SHA1Update(&ctxt, inp, len);
- SHA1Update(&ctxt, esp->es_client.ea_name,
- esp->es_client.ea_namelen);
- SHA1Final(dig, &ctxt);
- eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig,
- SHA_DIGESTSIZE);
+ ctxt = PPP_MD_CTX_new();
+ if (ctxt) {
+
+ vals[0] = id;
+ PPP_DigestInit(ctxt, PPP_sha1());
+ PPP_DigestUpdate(ctxt, vals, 1);
+ PPP_DigestUpdate(ctxt, esp->es_client.ea_skey,
+ SESSION_KEY_LEN);
+ PPP_DigestUpdate(ctxt, inp, len);
+ PPP_DigestUpdate(ctxt, esp->es_client.ea_name,
+ esp->es_client.ea_namelen);
+ PPP_DigestFinal(ctxt, dig, &diglen);
+
+ PPP_MD_CTX_free(ctxt);
+
+ eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig,
+ SHA_DIGEST_LENGTH);
+ }
break;
default:
break;
}
break;
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
+
+#ifdef PPP_WITH_CHAPMS
+ case EAPT_MSCHAPV2:
+ if (len < 4) {
+ error("EAP: received invalid MSCHAPv2 packet, too short");
+ return;
+ }
+ unsigned char opcode;
+ GETCHAR(opcode, inp);
+ unsigned char chapid; /* Chapv2-ID */
+ GETCHAR(chapid, inp);
+ short mssize;
+ GETSHORT(mssize, inp);
+
+ /* Validate the mssize field */
+ if (len != mssize) {
+ error("EAP: received invalid MSCHAPv2 packet, invalid length");
+ return;
+ }
+ len -= 4;
+
+ /* If MSCHAPv2 digest was not found, NAK the packet */
+ if (!esp->es_client.digest) {
+ error("EAP MSCHAPv2 not supported");
+ eap_send_nak(esp, id, EAPT_SRP);
+ return;
+ }
+
+ switch (opcode) {
+ case CHAP_CHALLENGE: {
+
+ /* make_response() expects: VLEN + VALUE */
+ u_char *challenge = inp;
+
+ unsigned char vsize;
+ GETCHAR(vsize, inp);
+ len -= 1;
+
+ /* Validate the VALUE field */
+ if (vsize != MS_CHAP2_PEER_CHAL_LEN || len < MS_CHAP2_PEER_CHAL_LEN) {
+ error("EAP: received invalid MSCHAPv2 packet, invalid value-length: %d", vsize);
+ return;
+ }
+
+ /* Increment past the VALUE field */
+ INCPTR(MS_CHAP2_PEER_CHAL_LEN, inp);
+ len -= MS_CHAP2_PEER_CHAL_LEN;
+
+ /* Extract the hostname */
+ rhostname[0] = '\0';
+ if (len > 0) {
+ if (len >= sizeof (rhostname)) {
+ dbglog("EAP: trimming really long peer name down");
+ len = sizeof(rhostname) - 1;
+ }
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\0';
+ }
+
+ /* In case the remote doesn't give us his name. */
+ if (explicit_remote || (remote_name[0] != '\0' && len == 0))
+ strlcpy(rhostname, remote_name, sizeof(rhostname));
+
+ /* Get the secret for authenticating ourselves with the specified host. */
+ if (!get_secret(esp->es_unit, esp->es_client.ea_name,
+ rhostname, secret, &secret_len, 0)) {
+ dbglog("EAP: no CHAP secret for auth to %q", rhostname);
+ eap_send_nak(esp, id, EAPT_SRP);
+ break;
+ }
+ esp->es_client.ea_namelen = strlen(esp->es_client.ea_name);
+
+ /* Create the MSCHAPv2 response (and add to cache) */
+ unsigned char response[MS_CHAP2_RESPONSE_LEN+1]; // VLEN + VALUE
+ esp->es_client.digest->make_response(response, chapid, esp->es_client.ea_name,
+ challenge, secret, secret_len, NULL);
+
+ eap_chapv2_response(esp, id, chapid, response, esp->es_client.ea_name, esp->es_client.ea_namelen);
+ break;
+ }
+ case CHAP_SUCCESS: {
+
+ /* Check response for mutual authentication */
+ u_char status = CHAP_FAILURE;
+ if (esp->es_client.digest->check_success(chapid, inp, len) == 1) {
+ info("Chap authentication succeeded! %.*v", len, inp);
+ status = CHAP_SUCCESS;
+ }
+ eap_send_response(esp, id, EAPT_MSCHAPV2, &status, sizeof(status));
+ break;
+ }
+ case CHAP_FAILURE: {
+
+ /* Process the failure string, and log appropriate information */
+ esp->es_client.digest->handle_failure(inp, len);
+
+ u_char status = CHAP_FAILURE;
+ eap_send_response(esp, id, EAPT_MSCHAPV2, &status, sizeof(status));
+ goto client_failure; /* force termination */
+ }
+ default:
+
+ error("EAP: received invalid MSCHAPv2 packet, invalid or unsupported opcode: %d", opcode);
+ eap_send_nak(esp, id, EAPT_SRP);
+ }
+
+ break;
+#endif /* PPP_WITH_CHAPMS */
+#ifdef PPP_WITH_PEAP
+ case EAPT_PEAP:
+
+ /* Initialize the PEAP context (if not already initialized) */
+ if (!esp->ea_peap) {
+ rhostname[0] = '\0';
+ if (explicit_remote || (remote_name[0] != '\0')) {
+ strlcpy(rhostname, remote_name, sizeof (rhostname));
+ }
+ if (peap_init(&esp->ea_peap, rhostname)) {
+ eap_send_nak(esp, id, EAPT_TLS);
+ break;
+ }
+ }
+
+ /* Process the PEAP packet */
+ if (peap_process(esp, id, inp, len)) {
+ eap_send_nak(esp, id, EAPT_TLS);
+ }
+
+ break;
+#endif // PPP_WITH_PEAP
default:
info("EAP: unknown authentication type %d; Naking", typenum);
}
return;
-#ifdef USE_SRP
client_failure:
esp->es_client.ea_state = eapBadAuth;
if (esp->es_client.ea_timeout > 0) {
UNTIMEOUT(eap_client_timeout, (void *)esp);
}
esp->es_client.ea_session = NULL;
+#ifdef PPP_WITH_SRP
t_clientclose(tc);
auth_withpeer_fail(esp->es_unit, PPP_EAP);
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
}
/*
* eap_response - Receive EAP Response message (server mode).
*/
static void
-eap_response(esp, inp, id, len)
-eap_state *esp;
-u_char *inp;
-int id;
-int len;
+eap_response(eap_state *esp, u_char *inp, int id, int len)
{
u_char typenum;
u_char vallen;
int secret_len;
char secret[MAXSECRETLEN];
char rhostname[256];
- MD5_CTX mdContext;
- u_char hash[MD5_SIGNATURE_SIZE];
-#ifdef USE_SRP
+ PPP_MD_CTX *mdctx;
+ u_char hash[MD5_DIGEST_LENGTH];
+ int hashlen = MD5_DIGEST_LENGTH;
+#ifdef PPP_WITH_SRP
struct t_server *ts;
struct t_num A;
- SHA1_CTX ctxt;
- u_char dig[SHA_DIGESTSIZE];
-#endif /* USE_SRP */
+ PPP_MD_CTX *ctxt;
+ u_char dig[SHA_DIGEST_LENGTH];
+ int diglen = sizeof(dig);
+#endif /* PPP_WITH_SRP */
+
+#ifdef PPP_WITH_EAPTLS
+ struct eaptls_session *ets;
+ u_char flags;
+#endif /* PPP_WITH_EAPTLS */
+#ifdef PPP_WITH_CHAPMS
+ u_char opcode;
+ chap_verify_hook_fn *chap_verifier;
+ char response_message[256];
+#endif /* PPP_WITH_CHAPMS */
+
+ /*
+ * Ignore responses if we're not open
+ */
+ if (esp->es_server.ea_state <= eapClosed)
+ return;
if (esp->es_server.ea_id != id) {
dbglog("EAP: discarding Response %d; expected ID %d", id,
eap_figure_next_state(esp, 0);
break;
+#ifdef PPP_WITH_EAPTLS
+ case EAPT_TLS:
+ switch(esp->es_server.ea_state) {
+
+ case eapTlsRecv:
+
+ ets = (struct eaptls_session *) esp->es_server.ea_session;
+
+ eap_figure_next_state(esp,
+ eaptls_receive(esp->es_server.ea_session, inp, len));
+
+ if(ets->alert_recv) {
+ eap_send_failure(esp);
+ break;
+ }
+ break;
+
+ case eapTlsRecvAck:
+ if(len > 1) {
+ dbglog("EAP-TLS ACK with extra data");
+ }
+ eap_figure_next_state(esp, 0);
+ break;
+
+ case eapTlsRecvClient:
+ /* Receive authentication response from client */
+ if (len > 0) {
+ GETCHAR(flags, inp);
+
+ if(len == 1 && !flags) { /* Ack = ok */
+#ifdef PPP_WITH_MPPE
+ eaptls_gen_mppe_keys( esp->es_server.ea_session, 0 );
+#endif
+ eap_send_success(esp);
+ }
+ else { /* failure */
+ warn("Server authentication failed");
+ eap_send_failure(esp);
+ }
+ }
+ else
+ warn("Bogus EAP-TLS packet received from client");
+
+ eaptls_free_session(esp->es_server.ea_session);
+
+ break;
+
+ case eapTlsRecvAlertAck:
+ eap_send_failure(esp);
+ break;
+
+ default:
+ eap_figure_next_state(esp, 1);
+ break;
+ }
+ break;
+#endif /* PPP_WITH_EAPTLS */
+
case EAPT_NOTIFICATION:
dbglog("EAP unexpected Notification; response discarded");
break;
esp->es_server.ea_state = eapMD5Chall;
break;
+#ifdef PPP_WITH_EAPTLS
+ /* Send EAP-TLS start packet */
+ case EAPT_TLS:
+ esp->es_server.ea_state = eapTlsStart;
+ break;
+#endif /* PPP_WITH_EAPTLS */
+
+#ifdef PPP_WITH_CHAPMS
+ case EAPT_MSCHAPV2:
+ info("EAP: peer proposes MSCHAPv2");
+ /* If MSCHAPv2 digest was not found, NAK the packet */
+ if (!esp->es_server.digest) {
+ error("EAP MSCHAPv2 not supported");
+ eap_send_nak(esp, id, EAPT_SRP);
+ break;
+ }
+ esp->es_server.ea_state = eapMSCHAPv2Chall;
+ break;
+#endif /* PPP_WITH_CHAPMS */
+
default:
dbglog("EAP: peer requesting unknown Type %d", vallen);
switch (esp->es_server.ea_state) {
eap_send_failure(esp);
break;
}
- MD5_Init(&mdContext);
- MD5_Update(&mdContext, &esp->es_server.ea_id, 1);
- MD5_Update(&mdContext, (u_char *)secret, secret_len);
- BZERO(secret, sizeof (secret));
- MD5_Update(&mdContext, esp->es_challenge, esp->es_challen);
- MD5_Final(hash, &mdContext);
- if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) {
- eap_send_failure(esp);
+
+ mdctx = PPP_MD_CTX_new();
+ if (mdctx != NULL) {
+
+ if (PPP_DigestInit(mdctx, PPP_md5())) {
+
+ if (PPP_DigestUpdate(mdctx, &esp->es_server.ea_id, 1)) {
+
+ if (PPP_DigestUpdate(mdctx, &secret, secret_len)) {
+
+ BZERO(secret, sizeof(secret));
+ if (PPP_DigestUpdate(mdctx, esp->es_challenge, esp->es_challen)) {
+
+ if (PPP_DigestFinal(mdctx, hash, &hashlen)) {
+
+ if (BCMP(hash, inp, MD5_DIGEST_LENGTH) == 0) {
+ esp->es_server.ea_type = EAPT_MD5CHAP;
+ eap_send_success(esp);
+ eap_figure_next_state(esp, 0);
+
+ if (esp->es_rechallenge != 0) {
+ TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge);
+ }
+ PPP_MD_CTX_free(mdctx);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ PPP_MD_CTX_free(mdctx);
+ }
+
+ eap_send_failure(esp);
+ break;
+
+#ifdef PPP_WITH_CHAPMS
+ case EAPT_MSCHAPV2:
+ if (len < 1) {
+ error("EAP: received MSCHAPv2 with no data");
+ eap_figure_next_state(esp, 1);
break;
}
- esp->es_server.ea_type = EAPT_MD5CHAP;
- eap_send_success(esp);
- eap_figure_next_state(esp, 0);
- if (esp->es_rechallenge != 0)
- TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge);
+ GETCHAR(opcode, inp);
+ len--;
+
+ switch (opcode) {
+ case CHAP_RESPONSE:
+ if (esp->es_server.ea_state != eapMSCHAPv2Chall) {
+ error("EAP: unexpected MSCHAPv2-Response");
+ eap_figure_next_state(esp, 1);
+ break;
+ }
+ /* skip MS ID + len */
+ INCPTR(3, inp);
+ GETCHAR(vallen, inp);
+ len -= 4;
+
+ if (vallen != MS_CHAP2_RESPONSE_LEN || vallen > len) {
+ error("EAP: Invalid MSCHAPv2-Response "
+ "length %d", vallen);
+ eap_figure_next_state(esp, 1);
+ break;
+ }
+
+ /* Not so likely to happen. */
+ if (len - vallen >= sizeof (rhostname)) {
+ dbglog("EAP: trimming really long peer name down");
+ BCOPY(inp + vallen, rhostname, sizeof (rhostname) - 1);
+ rhostname[sizeof (rhostname) - 1] = '\0';
+ } else {
+ BCOPY(inp + vallen, rhostname, len - vallen);
+ rhostname[len - vallen] = '\0';
+ }
+
+ /* 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));
+
+ /* strip the MS domain name */
+ if (chapms_strip_domain && strrchr(rhostname, '\\')) {
+ char tmp[MAXNAMELEN+1];
+
+ strcpy(tmp, strrchr(rhostname, '\\') + 1);
+ strlcpy(rhostname, tmp, sizeof(rhostname));
+ }
+
+ if (chap_verify_hook)
+ chap_verifier = chap_verify_hook;
+ else
+ chap_verifier = eap_chap_verify_response;
+
+ esp->es_server.ea_id += 1;
+ if ((*chap_verifier)(rhostname,
+ esp->es_server.ea_name,
+ id,
+ esp->es_server.digest,
+ esp->es_challenge,
+ inp - 1,
+ response_message,
+ sizeof(response_message)))
+ {
+ info("EAP: MSCHAPv2 success for peer %q",
+ rhostname);
+ esp->es_server.ea_type = EAPT_MSCHAPV2;
+ eap_chapms2_send_request(esp,
+ esp->es_server.ea_id,
+ CHAP_SUCCESS,
+ esp->es_server.ea_id,
+ response_message,
+ strlen(response_message));
+ eap_figure_next_state(esp, 0);
+ if (esp->es_rechallenge != 0)
+ TIMEOUT(eap_rechallenge, esp, esp->es_rechallenge);
+ }
+ else {
+ warn("EAP: MSCHAPv2 failure for peer %q",
+ rhostname);
+ eap_chapms2_send_request(esp,
+ esp->es_server.ea_id,
+ CHAP_FAILURE,
+ esp->es_server.ea_id,
+ response_message,
+ strlen(response_message));
+ }
+ break;
+ case CHAP_SUCCESS:
+ info("EAP: MSCHAPv2 success confirmed");
+ break;
+ case CHAP_FAILURE:
+ info("EAP: MSCHAPv2 failure confirmed");
+ break;
+ default:
+ error("EAP: Unhandled MSCHAPv2 opcode %d", opcode);
+ eap_send_nak(esp, id, EAPT_SRP);
+ }
+
break;
+#endif /* PPP_WITH_CHAPMS */
-#ifdef USE_SRP
+#ifdef PPP_WITH_SRP
case EAPT_SRP:
if (len < 1) {
error("EAP: empty SRP Response");
eap_figure_next_state(esp, 1);
break;
}
- if (len < sizeof (u_int32_t) + SHA_DIGESTSIZE) {
+ if (len < sizeof (u_int32_t) + SHA_DIGEST_LENGTH) {
error("EAP: M1 length %d < %d", len,
- sizeof (u_int32_t) + SHA_DIGESTSIZE);
+ sizeof (u_int32_t) + SHA_DIGEST_LENGTH);
eap_figure_next_state(esp, 1);
break;
}
info("EAP: unexpected SRP Subtype 4 Response");
return;
}
- if (len != SHA_DIGESTSIZE) {
+ if (len != SHA_DIGEST_LENGTH) {
error("EAP: bad Lightweight rechallenge "
"response");
return;
}
- SHA1Init(&ctxt);
- vallen = id;
- SHA1Update(&ctxt, &vallen, 1);
- SHA1Update(&ctxt, esp->es_server.ea_skey,
- SESSION_KEY_LEN);
- SHA1Update(&ctxt, esp->es_challenge, esp->es_challen);
- SHA1Update(&ctxt, esp->es_server.ea_peer,
- esp->es_server.ea_peerlen);
- SHA1Final(dig, &ctxt);
- if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) {
- error("EAP: failed Lightweight rechallenge");
- eap_send_failure(esp);
- break;
+ ctxt = PPP_MD_CTX_new();
+ if (ctxt) {
+ vallen = id;
+
+ PPP_DigestInit(ctxt, PPP_sha1());
+ PPP_DigestUpdate(ctxt, &vallen, 1);
+ PPP_DigestUpdate(ctxt, esp->es_server.ea_skey,
+ SESSION_KEY_LEN);
+ PPP_DigestUpdate(ctxt, esp->es_challenge, esp->es_challen);
+ PPP_DigestUpdate(ctxt, esp->es_server.ea_peer,
+ esp->es_server.ea_peerlen);
+ PPP_DigestFinal(ctxt, dig, &diglen);
+
+ PPP_MD_CTX_free(ctxt);
+
+ if (BCMP(dig, inp, SHA_DIGEST_LENGTH) != 0) {
+ error("EAP: failed Lightweight rechallenge");
+ eap_send_failure(esp);
+ break;
+ }
+
+ esp->es_server.ea_state = eapOpen;
+ if (esp->es_lwrechallenge != 0)
+ TIMEOUT(srp_lwrechallenge, esp,
+ esp->es_lwrechallenge);
}
- esp->es_server.ea_state = eapOpen;
- if (esp->es_lwrechallenge != 0)
- TIMEOUT(srp_lwrechallenge, esp,
- esp->es_lwrechallenge);
break;
}
break;
-#endif /* USE_SRP */
+#endif /* PPP_WITH_SRP */
default:
/* This can't happen. */
* eap_success - Receive EAP Success message (client mode).
*/
static void
-eap_success(esp, inp, id, len)
-eap_state *esp;
-u_char *inp;
-int id;
-int len;
+eap_success(eap_state *esp, u_char *inp, int id, int len)
{
- if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)) {
+ if (esp->es_client.ea_state != eapOpen && !eap_client_active(esp)
+#ifdef PPP_WITH_EAPTLS
+ && esp->es_client.ea_state != eapTlsRecvSuccess
+#endif /* PPP_WITH_EAPTLS */
+ ) {
dbglog("EAP unexpected success message in state %s (%d)",
eap_state_name(esp->es_client.ea_state),
esp->es_client.ea_state);
return;
}
+#ifdef PPP_WITH_EAPTLS
+ if(esp->es_client.ea_using_eaptls && esp->es_client.ea_state !=
+ eapTlsRecvSuccess) {
+ dbglog("EAP-TLS unexpected success message in state %s (%d)",
+ eap_state_name(esp->es_client.ea_state),
+ esp->es_client.ea_state);
+ return;
+ }
+#endif /* PPP_WITH_EAPTLS */
+
if (esp->es_client.ea_timeout > 0) {
UNTIMEOUT(eap_client_timeout, (void *)esp);
}
PRINTMSG(inp, len);
}
+#ifdef PPP_WITH_PEAP
+ peap_finish(&esp->ea_peap);
+#endif
+
esp->es_client.ea_state = eapOpen;
auth_withpeer_success(esp->es_unit, PPP_EAP, 0);
}
* eap_failure - Receive EAP Failure message (client mode).
*/
static void
-eap_failure(esp, inp, id, len)
-eap_state *esp;
-u_char *inp;
-int id;
-int len;
+eap_failure(eap_state *esp, u_char *inp, int id, int len)
{
+ /*
+ * Ignore failure messages if we're not open
+ */
+ if (esp->es_client.ea_state <= eapClosed)
+ return;
+
if (!eap_client_active(esp)) {
dbglog("EAP unexpected failure message in state %s (%d)",
eap_state_name(esp->es_client.ea_state),
esp->es_client.ea_state = eapBadAuth;
error("EAP: peer reports authentication failure");
+
+#ifdef PPP_WITH_PEAP
+ peap_finish(&esp->ea_peap);
+#endif
+
auth_withpeer_fail(esp->es_unit, PPP_EAP);
}
* eap_input - Handle received EAP message.
*/
static void
-eap_input(unit, inp, inlen)
-int unit;
-u_char *inp;
-int inlen;
+eap_input(int unit, u_char *inp, int inlen)
{
eap_state *esp = &eap_states[unit];
u_char code, id;
"OTP", "Generic-Token", NULL, NULL,
"RSA", "DSS", "KEA", "KEA-Validate",
"TLS", "Defender", "Windows 2000", "Arcot",
- "Cisco", "Nokia", "SRP"
+ "Cisco", "Nokia", "SRP", NULL,
+ "TTLS", "RAS", "AKA", "3COM", "PEAP",
+ "MSCHAPv2"
};
static int
-eap_printpkt(inp, inlen, printer, arg)
-u_char *inp;
-int inlen;
-void (*printer) __P((void *, char *, ...));
-void *arg;
+eap_printpkt(u_char *inp, int inlen,
+ void (*printer) (void *, char *, ...), void *arg)
{
int code, id, len, rtype, vallen;
u_char *pstart;
u_int32_t uval;
+#ifdef PPP_WITH_EAPTLS
+ u_char flags;
+#endif /* PPP_WITH_EAPTLS */
+#ifdef PPP_WITH_CHAPMS
+ u_char opcode;
+#endif /* PPP_WITH_CHAPMS */
if (inlen < EAP_HEADERLEN)
return (0);
}
break;
+#ifdef PPP_WITH_CHAPMS
+ case EAPT_MSCHAPV2:
+ if (len <= 0)
+ break;
+ GETCHAR(opcode, inp);
+ len--;
+ switch (opcode) {
+ case CHAP_CHALLENGE:
+ INCPTR(3, inp);
+ len -= 3;
+ GETCHAR(vallen, inp);
+ len--;
+ if (vallen > len)
+ goto truncated;
+ len -= vallen;
+ printer(arg, " Challenge <");
+ for (; vallen > 0; --vallen) {
+ u_char val;
+ GETCHAR(val, inp);
+ printer(arg, "%.2x", val);
+ }
+ printer(arg, ">");
+ if (len > 0) {
+ printer(arg, ", <Name ");
+ print_string((char *)inp, len, printer, arg);
+ printer(arg, ">");
+ INCPTR(len, inp);
+ len = 0;
+ } else {
+ printer(arg, ", <No name>");
+ }
+ break;
+ case CHAP_SUCCESS:
+ INCPTR(3, inp);
+ len -= 3;
+ printer(arg, " Success <Message ");
+ print_string((char *)inp, len, printer, arg);
+ printer(arg, ">");
+ break;
+ case CHAP_FAILURE:
+ INCPTR(3, inp);
+ len -= 3;
+ printer(arg, " Failure <Message ");
+ print_string((char *)inp, len, printer, arg);
+ printer(arg, ">");
+ break;
+ default:
+ INCPTR(3, inp);
+ len -= 3;
+ printer(arg, " opcode=0x%x <%.*B>", opcode, len, inp);
+ break;
+ }
+ break;
+#endif /* PPP_WITH_CHAPMS */
+
+#ifdef PPP_WITH_EAPTLS
+ case EAPT_TLS:
+ if (len < 1)
+ break;
+ GETCHAR(flags, inp);
+ len--;
+
+ if(flags == 0 && len == 0){
+ printer(arg, " Ack");
+ break;
+ }
+
+ printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -");
+ printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-");
+ printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- ");
+ break;
+#endif /* PPP_WITH_EAPTLS */
+
+#ifdef PPP_WITH_SRP
case EAPT_SRP:
if (len < 3)
goto truncated;
if (uval != 0) {
printer(arg, " f<%X>", uval);
}
- if ((vallen = len) > SHA_DIGESTSIZE)
- vallen = SHA_DIGESTSIZE;
+ if ((vallen = len) > SHA_DIGEST_LENGTH)
+ vallen = SHA_DIGEST_LENGTH;
printer(arg, " <M2%.*B%s>", len, inp,
- len < SHA_DIGESTSIZE ? "?" : "");
+ len < SHA_DIGEST_LENGTH ? "?" : "");
INCPTR(vallen, inp);
len -= vallen;
if (len > 0) {
break;
}
break;
+#endif /* PPP_WITH_SRP */
}
break;
}
break;
+#ifdef PPP_WITH_EAPTLS
+ case EAPT_TLS:
+ if (len < 1)
+ break;
+ GETCHAR(flags, inp);
+ len--;
+
+ if(flags == 0 && len == 0){
+ printer(arg, " Ack");
+ break;
+ }
+
+ printer(arg, flags & EAP_TLS_FLAGS_LI ? " L":" -");
+ printer(arg, flags & EAP_TLS_FLAGS_MF ? "M":"-");
+ printer(arg, flags & EAP_TLS_FLAGS_START ? "S":"- ");
+
+ break;
+#endif /* PPP_WITH_EAPTLS */
+
case EAPT_NAK:
if (len <= 0) {
printer(arg, " <missing hint>");
len--;
printer(arg, " <Suggested-type %02X", rtype);
if (rtype >= 1 &&
- rtype < sizeof (eap_typenames) / sizeof (char *))
+ rtype <= sizeof (eap_typenames) / sizeof (char *))
printer(arg, " (%s)", eap_typenames[rtype-1]);
printer(arg, ">");
break;
}
break;
+#ifdef PPP_WITH_CHAPMS
+ case EAPT_MSCHAPV2:
+ if (len <= 0)
+ break;
+ GETCHAR(opcode, inp);
+ len--;
+ switch (opcode) {
+ case CHAP_RESPONSE:
+ INCPTR(3, inp);
+ len -= 3;
+ GETCHAR(vallen, inp);
+ len--;
+ if (vallen > len)
+ goto truncated;
+ len -= vallen;
+ printer(arg, " Response <");
+ for (; vallen > 0; --vallen) {
+ u_char val;
+ GETCHAR(val, inp);
+ printer(arg, "%.2x", val);
+ }
+ printer(arg, ">");
+ if (len > 0) {
+ printer(arg, ", <Name ");
+ print_string((char *)inp, len, printer, arg);
+ printer(arg, ">");
+ INCPTR(len, inp);
+ len = 0;
+ } else {
+ printer(arg, ", <No name>");
+ }
+ break;
+ case CHAP_SUCCESS:
+ printer(arg, " Success");
+ break;
+ case CHAP_FAILURE:
+ printer(arg, " Failure");
+ break;
+ default:
+ printer(arg, " opcode=0x%x <%.*B>", opcode, len, inp);
+ break;
+ }
+ break;
+#endif /* PPP_WITH_CHAPMS */
+
+#ifdef PPP_WITH_SRP
case EAPT_SRP:
if (len < 1)
goto truncated;
printer(arg, " f<%X>", uval);
}
printer(arg, " <M1%.*B%s>", len, inp,
- len == SHA_DIGESTSIZE ? "" : "?");
+ len == SHA_DIGEST_LENGTH ? "" : "?");
INCPTR(len, inp);
len = 0;
break;
case EAPSRP_LWRECHALLENGE:
printer(arg, " <Response%.*B%s>", len, inp,
- len == SHA_DIGESTSIZE ? "" : "?");
- if ((vallen = len) > SHA_DIGESTSIZE)
- vallen = SHA_DIGESTSIZE;
+ len == SHA_DIGEST_LENGTH ? "" : "?");
+ if ((vallen = len) > SHA_DIGEST_LENGTH)
+ vallen = SHA_DIGEST_LENGTH;
INCPTR(vallen, inp);
len -= vallen;
break;
}
break;
+#endif /* PPP_WITH_SRP */
}
break;