ppp: mschapv2 support

This commit is contained in:
cinap_lenrek 2018-01-21 22:55:14 +01:00
parent 3004f058f6
commit 98b1f2a75b
3 changed files with 147 additions and 180 deletions

View file

@ -120,7 +120,7 @@ static void uncresetack(void*, Block*);
static int ipcheck(uchar*, int); static int ipcheck(uchar*, int);
static void hischeck(Uncstate*); static void hischeck(Uncstate*);
static void setkey(uchar *key, uchar *startkey); static void setkey(uchar *key, uchar *startkey);
Comptype cmppc = { Comptype cmppc = {
compinit, compinit,
@ -155,8 +155,8 @@ compinit(PPP *ppp)
if(ppp->sendencrypted) { if(ppp->sendencrypted) {
cs->encrypt = 1; cs->encrypt = 1;
memmove(cs->startkey, ppp->key, 16); memmove(cs->startkey, ppp->sendkey, 16);
memmove(cs->key, ppp->key, 16); memmove(cs->key, cs->startkey, 16);
setkey(cs->key, cs->startkey); setkey(cs->key, cs->startkey);
setupRC4state(&cs->rc4key, cs->key, 16); setupRC4state(&cs->rc4key, cs->key, 16);
} }
@ -467,8 +467,8 @@ uncinit(PPP *ppp)
s = mallocz(sizeof(Uncstate), 1); s = mallocz(sizeof(Uncstate), 1);
s->count = 0xfff; /* count of non existant last packet */ s->count = 0xfff; /* count of non existant last packet */
memmove(s->startkey, ppp->key, 16); memmove(s->startkey, ppp->recvkey, 16);
memmove(s->key, ppp->key, 16); memmove(s->key, s->startkey, 16);
setkey(s->key, s->startkey); setkey(s->key, s->startkey);
setupRC4state(&s->rc4key, s->key, 16); setupRC4state(&s->rc4key, s->key, 16);
@ -577,12 +577,11 @@ netlog("******* bad count - got %ux expected %ux\n", count&0xfff, ecount);
if(count & Pencrypt) { if(count & Pencrypt) {
//netlog("mppc unencrypt count = %ux\n", count); //netlog("mppc unencrypt count = %ux\n", count);
rc4(&s->rc4key, p, n); rc4(&s->rc4key, p, n);
fprint(2, "plain=%.*H\n", n, p);
} }
if(!(count & Pcompress)) { if(!(count & Pcompress))
//netlog("uncompress blen = %d\n", BLEN(b)); return b;
return b;
}
bits = 0; bits = 0;
sreg = 0; sreg = 0;
@ -729,6 +728,27 @@ uncfini(void *as)
free(s); free(s);
} }
void
getasymkey(uchar *key, uchar *masterkey, int send, int server)
{
uchar digest[SHA1dlen];
uchar pad[40];
SHAstate *s;
char *m;
s = sha1(masterkey, 16, nil, nil);
memset(pad, 0, 40);
sha1(pad, 40, nil, s);
if(send ^ server)
m = "On the client side, this is the send key; on the server side, it is the receive key.";
else
m = "On the client side, this is the receive key; on the server side, it is the send key.";
sha1((uchar*)m, 84, nil, s);
memset(pad, 0xf2, 40);
sha1(pad, 40, digest, s);
memmove(key, digest, 16);
}
static void static void
setkey(uchar *key, uchar *startkey) setkey(uchar *key, uchar *startkey)
{ {

View file

@ -114,7 +114,6 @@ static void setphase(PPP*, int);
static void terminate(PPP*, int); static void terminate(PPP*, int);
static int validv4(Ipaddr); static int validv4(Ipaddr);
static void dmppkt(char *s, uchar *a, int na); static void dmppkt(char *s, uchar *a, int na);
static void getauth(PPP*);
void void
pppopen(PPP *ppp, int mediain, int mediaout, char *net, pppopen(PPP *ppp, int mediain, int mediaout, char *net,
@ -191,7 +190,7 @@ init(PPP* ppp)
ppp->chap = mallocz(sizeof(*ppp->chap), 1); ppp->chap = mallocz(sizeof(*ppp->chap), 1);
if(ppp->chap == nil) if(ppp->chap == nil)
abort(); abort();
ppp->chap->proto = APmschap; ppp->chap->proto = APmschapv2;
ppp->chap->state = Cunauth; ppp->chap->state = Cunauth;
auth_freechal(ppp->chap->cs); auth_freechal(ppp->chap->cs);
ppp->chap->cs = nil; ppp->chap->cs = nil;
@ -252,6 +251,7 @@ setphase(PPP *ppp, int phase)
break; break;
case APmd5: case APmd5:
case APmschap: case APmschap:
case APmschapv2:
break; break;
default: default:
setphase(ppp, Pnet); setphase(ppp, Pnet);
@ -713,6 +713,7 @@ config(PPP *ppp, Pstate *p, int newid)
syslog(0, "ppp", "requesting %I", ppp->local); syslog(0, "ppp", "requesting %I", ppp->local);
putv4o(b, Oipaddr, ppp->local); putv4o(b, Oipaddr, ppp->local);
} }
primary = 1;
if(primary && (p->optmask & Fipdns)) if(primary && (p->optmask & Fipdns))
putv4o(b, Oipdns, ppp->dns[0]); putv4o(b, Oipdns, ppp->dns[0]);
if(primary && (p->optmask & Fipdns2)) if(primary && (p->optmask & Fipdns2))
@ -852,15 +853,15 @@ getopts(PPP *ppp, Pstate *p, Block *b)
} }
if(proto != Pchap) if(proto != Pchap)
break; break;
if(o->data[2] != APmd5 && o->data[2] != APmschap) if(o->data[2] != APmd5
&& o->data[2] != APmschap
&& o->data[2] != APmschapv2)
break; break;
chapproto = o->data[2]; chapproto = o->data[2];
continue; continue;
} }
break; break;
case Pccp: case Pccp:
if(nocompress)
break;
switch(o->type){ switch(o->type){
case Octhwack: case Octhwack:
break; break;
@ -880,10 +881,6 @@ getopts(PPP *ppp, Pstate *p, Block *b)
case Ocmppc: case Ocmppc:
x = nhgetl(o->data); x = nhgetl(o->data);
// hack for Mac
// if(x == 0)
// continue;
/* stop ppp loops */ /* stop ppp loops */
if((x&0x41) == 0 || ppp->ctries++ > 5) { if((x&0x41) == 0 || ppp->ctries++ > 5) {
/* /*
@ -895,7 +892,7 @@ getopts(PPP *ppp, Pstate *p, Block *b)
} }
if(rejecting) if(rejecting)
continue; continue;
if(x & 1) { if((x & 0x01000001) == 1){
ctype = &cmppc; ctype = &cmppc;
ppp->sendencrypted = (o->data[3]&0x40) == 0x40; ppp->sendencrypted = (o->data[3]&0x40) == 0x40;
continue; continue;
@ -1965,6 +1962,20 @@ putlqm(PPP *ppp)
ppp->out.reports++; ppp->out.reports++;
} }
static char*
getaproto(int proto)
{
switch(proto){
case APmd5:
return "chap";
case APmschap:
return "mschap";
case APmschapv2:
return "mschapv2";
}
return nil;
}
/* /*
* init challenge response dialog * init challenge response dialog
*/ */
@ -1975,24 +1986,14 @@ chapinit(PPP *ppp)
Lcpmsg *m; Lcpmsg *m;
Chap *c; Chap *c;
int len; int len;
char *aproto;
getauth(ppp);
c = ppp->chap; c = ppp->chap;
c->id++; c->id++;
if(c->ai != nil){
switch(c->proto){ auth_freeAI(c->ai);
default: c->ai = nil;
abort();
case APmd5:
aproto = "chap";
break;
case APmschap:
aproto = "mschap";
break;
} }
if((c->cs = auth_challenge("proto=%q role=server", aproto)) == nil) if((c->cs = auth_challenge("proto=%q role=server", getaproto(c->proto))) == nil)
sysfatal("auth_challenge: %r"); sysfatal("auth_challenge: %r");
syslog(0, LOG, ": remote=%I: sending %d byte challenge", ppp->remote, c->cs->nchal); syslog(0, LOG, ": remote=%I: sending %d byte challenge", ppp->remote, c->cs->nchal);
len = 4 + 1 + c->cs->nchal + strlen(ppp->chapname); len = 4 + 1 + c->cs->nchal + strlen(ppp->chapname);
@ -2010,73 +2011,43 @@ chapinit(PPP *ppp)
c->state = Cchalsent; c->state = Cchalsent;
} }
/*
* BUG factotum should do this
*/
enum {
MShashlen = 16,
MSresplen = 24,
MSchallen = 8,
};
void
desencrypt(uchar data[8], uchar key[7])
{
ulong ekey[32];
key_setup(key, ekey);
block_cipher(ekey, data, 0);
}
void
nthash(uchar hash[MShashlen], char *passwd)
{
uchar buf[512];
int i;
for(i=0; *passwd && i<sizeof(buf); passwd++) {
buf[i++] = *passwd;
buf[i++] = 0;
}
memset(hash, 0, 16);
md4(buf, i, hash, 0);
}
void
mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen])
{
int i;
uchar buf[21];
memset(buf, 0, sizeof(buf));
memcpy(buf, hash, MShashlen);
for(i=0; i<3; i++) {
memmove(resp+i*MSchallen, chal, MSchallen);
desencrypt(resp+i*MSchallen, buf+i*7);
}
}
/* /*
* challenge response dialog * challenge response dialog
*/ */
extern int _asrdresp(int, uchar*, int); static void
setppekey(PPP *ppp, int isserver)
{
Chap *c = ppp->chap;
switch(c->proto){
case APmschap:
if(c->ai == nil || c->ai->nsecret != 16)
sysfatal("could not get the encryption key");
memmove(ppp->sendkey, c->ai->secret, 16);
memmove(ppp->recvkey, c->ai->secret, 16);
break;
case APmschapv2:
if(c->ai == nil || c->ai->nsecret != 16+20)
sysfatal("could not get the encryption key + authenticator");
getasymkey(ppp->sendkey, c->ai->secret, 1, isserver);
getasymkey(ppp->recvkey, c->ai->secret, 0, isserver);
break;
}
auth_freeAI(c->ai);
c->ai = nil;
}
static void static void
getchap(PPP *ppp, Block *b) getchap(PPP *ppp, Block *b)
{ {
AuthInfo *ai;
Lcpmsg *m; Lcpmsg *m;
int len, vlen, i, id, n, nresp; int len, vlen, i, id, n, nresp;
char md5buf[512], code; char code;
Chap *c; Chap *c;
Chapreply cr; Chapreply cr;
MSchapreply mscr; MSchapreply mscr;
char uid[PATH]; char uid[PATH];
uchar digest[16], *p, *resp, sdigest[SHA1dlen]; uchar resp[256], *p;
uchar mshash[MShashlen], mshash2[MShashlen];
DigestState *s;
uchar msresp[2*MSresplen+1];
m = (Lcpmsg*)b->rptr; m = (Lcpmsg*)b->rptr;
len = nhgets(m->len); len = nhgets(m->len);
@ -2087,50 +2058,23 @@ getchap(PPP *ppp, Block *b)
} }
qlock(ppp); qlock(ppp);
c = ppp->chap;
vlen = m->data[0];
switch(m->code){ switch(m->code){
case Cchallenge: case Cchallenge:
getauth(ppp);
vlen = m->data[0];
if(vlen > len - 5) {
netlog("PPP: chap: bad challenge len\n");
break;
}
id = m->id; id = m->id;
switch(ppp->chap->proto){ memset(ppp->chapname, 0, sizeof(ppp->chapname));
default: nresp = auth_respondAI(m->data+1, vlen,
abort(); ppp->chapname, sizeof(ppp->chapname),
case APmd5: resp, sizeof(resp), &c->ai,
n = strlen(ppp->secret); auth_getkey,
if(n + vlen + 1 > sizeof(md5buf)) { "proto=%s role=client service=ppp %s", getaproto(c->proto), keyspec);
netlog("PPP: chap: bad challenge len\n"); if(nresp < 0)
goto end; sysfatal("auth_respond: %r");
} if(c->proto == APmschap || c->proto == APmschapv2)
md5buf[0] = m->id; while(nresp < 49) resp[nresp++] = 0;
memcpy(md5buf+1, ppp->secret, n);
memcpy(md5buf+1+n, m->data+1, vlen);
md5((uchar*)md5buf, n + vlen + 1, digest, nil);
resp = digest;
nresp = 16;
break;
case APmschap:
nthash(mshash, ppp->secret);
memset(msresp, 0, sizeof msresp);
mschalresp(msresp+MSresplen, mshash, m->data+1);
resp = msresp;
nresp = sizeof msresp;
nthash(mshash, ppp->secret);
md4(mshash, 16, mshash2, 0);
s = sha1(mshash2, 16, 0, 0);
sha1(mshash2, 16, 0, s);
sha1(m->data+1, 8, sdigest, s);
memmove(ppp->key, sdigest, 16);
break;
}
len = 4 + 1 + nresp + strlen(ppp->chapname);
freeb(b); freeb(b);
len = 4 + 1 + nresp + strlen(ppp->chapname);
b = alloclcp(Cresponse, id, len, &m); b = alloclcp(Cresponse, id, len, &m);
*b->wptr++ = nresp; *b->wptr++ = nresp;
memmove(b->wptr, resp, nresp); memmove(b->wptr, resp, nresp);
@ -2138,14 +2082,12 @@ getchap(PPP *ppp, Block *b)
memmove(b->wptr, ppp->chapname, strlen(ppp->chapname)); memmove(b->wptr, ppp->chapname, strlen(ppp->chapname));
b->wptr += strlen(ppp->chapname); b->wptr += strlen(ppp->chapname);
hnputs(m->len, len); hnputs(m->len, len);
netlog("PPP: sending response len %d\n", len); netlog("ppp: sending response len %d\n", len);
putframe(ppp, Pchap, b); putframe(ppp, Pchap, b);
break; break;
case Cresponse: case Cresponse:
c = ppp->chap; if(m->id != c->id || c->cs == nil) {
vlen = m->data[0]; netlog("ppp: chap: bad response id\n");
if(m->id != c->id) {
netlog("PPP: chap: bad response id\n");
break; break;
} }
switch(c->proto) { switch(c->proto) {
@ -2153,10 +2095,9 @@ getchap(PPP *ppp, Block *b)
sysfatal("unknown chap protocol: %d", c->proto); sysfatal("unknown chap protocol: %d", c->proto);
case APmd5: case APmd5:
if(vlen > len - 5 || vlen != 16) { if(vlen > len - 5 || vlen != 16) {
netlog("PPP: chap: bad response len\n"); netlog("ppp: chap: bad response len\n");
break; break;
} }
cr.id = m->id; cr.id = m->id;
memmove(cr.resp, m->data+1, 16); memmove(cr.resp, m->data+1, 16);
memset(uid, 0, sizeof(uid)); memset(uid, 0, sizeof(uid));
@ -2169,8 +2110,9 @@ getchap(PPP *ppp, Block *b)
c->cs->nresp = sizeof cr; c->cs->nresp = sizeof cr;
break; break;
case APmschap: case APmschap:
if(vlen > len - 5 || vlen != 49) { case APmschapv2:
netlog("PPP: chap: bad response len\n"); if(vlen > len - 5 || vlen < 48) {
netlog("ppp: chap: bad response len\n");
break; break;
} }
memset(&mscr, 0, sizeof(mscr)); memset(&mscr, 0, sizeof(mscr));
@ -2196,42 +2138,53 @@ getchap(PPP *ppp, Block *b)
break; break;
} }
syslog(0, LOG, ": remote=%I vlen %d proto %d response user %s nresp %d", ppp->remote, vlen, c->proto, c->cs->user, c->cs->nresp); syslog(0, LOG, ": remote=%I vlen %d proto %d response user %s nresp %d",
if((ai = auth_response(c->cs)) == nil || auth_chuid(ai, nil) < 0){ ppp->remote, vlen, c->proto, c->cs->user, c->cs->nresp);
if((c->ai = auth_response(c->cs)) == nil || auth_chuid(c->ai, nil) < 0){
c->state = Cunauth; c->state = Cunauth;
code = Cfailure; code = Cfailure;
syslog(0, LOG, ": remote=%I: auth failed: %r, uid=%s", ppp->remote, uid); syslog(0, LOG, ": remote=%I: auth failed: %r, uid=%s",
ppp->remote, uid);
}else{ }else{
c->state = Cauthok; c->state = Cauthok;
code = Csuccess; code = Csuccess;
syslog(0, LOG, ": remote=%I: auth ok: uid=%s nsecret=%d", ppp->remote, uid, ai->nsecret); syslog(0, LOG, ": remote=%I: auth ok: uid=%s nsecret=%d",
if(c->proto == APmschap){ ppp->remote, uid, c->ai->nsecret);
if(ai->nsecret != sizeof(ppp->key))
sysfatal("could not get the encryption key");
memmove(ppp->key, ai->secret, sizeof(ppp->key));
}
} }
auth_freeAI(ai);
auth_freechal(c->cs); auth_freechal(c->cs);
c->cs = nil; c->cs = nil;
freeb(b); freeb(b);
/* send reply */ /* send reply */
len = 4; if(code == Csuccess && c->proto == APmschapv2 && c->ai->nsecret == 16+20){
b = alloclcp(code, c->id, len, &m); b = alloclcp(code, c->id, 4+2+2*20+1, &m);
hnputs(m->len, len); b->wptr += sprint((char*)m->data, "S=%.20H", c->ai->secret+16);
} else {
b = alloclcp(code, c->id, 4, &m);
}
hnputs(m->len, BLEN(b));
putframe(ppp, Pchap, b); putframe(ppp, Pchap, b);
if(c->state == Cauthok) { if(c->state == Cauthok){
setppekey(ppp, 1);
setphase(ppp, Pnet); setphase(ppp, Pnet);
} else { } else {
/* restart chapp negotiation */ /* restart chapp negotiation */
chapinit(ppp); chapinit(ppp);
} }
break; break;
case Csuccess: case Csuccess:
if(c->proto == APmschapv2 && c->ai != nil && c->ai->nsecret == 16+20){
n = snprint((char*)resp, sizeof(resp), "S=%.20H", c->ai->secret+16);
if(len - 4 < n || tsmemcmp(m->data, resp, n) != 0){
netlog("ppp: chap: bad authenticator\n");
terminate(ppp, 0);
break;
}
}
netlog("ppp: chap succeeded\n"); netlog("ppp: chap succeeded\n");
setppekey(ppp, 0);
setphase(ppp, Pnet); setphase(ppp, Pnet);
break; break;
case Cfailure: case Cfailure:
@ -2242,7 +2195,6 @@ getchap(PPP *ppp, Block *b)
syslog(0, LOG, "chap code %d?", m->code); syslog(0, LOG, "chap code %d?", m->code);
break; break;
} }
end:
qunlock(ppp); qunlock(ppp);
freeb(b); freeb(b);
} }
@ -2253,27 +2205,32 @@ putpaprequest(PPP *ppp)
Block *b; Block *b;
Lcpmsg *m; Lcpmsg *m;
Chap *c; Chap *c;
UserPasswd *up;
int len, nlen, slen; int len, nlen, slen;
getauth(ppp); up = auth_getuserpasswd(auth_getkey, "proto=pass service=ppp %s", keyspec);
if(up == nil)
sysfatal("auth_getuserpasswd: %r");
c = ppp->chap; c = ppp->chap;
c->id++; c->id++;
netlog("PPP: pap: send authreq %d %s %s\n", c->id, ppp->chapname, "****"); netlog("ppp: pap: send authreq %d %s %s\n", c->id, up->user, "****");
nlen = strlen(ppp->chapname); nlen = strlen(up->user);
slen = strlen(ppp->secret); slen = strlen(up->passwd);
len = 4 + 1 + nlen + 1 + slen; len = 4 + 1 + nlen + 1 + slen;
b = alloclcp(Pauthreq, c->id, len, &m); b = alloclcp(Pauthreq, c->id, len, &m);
*b->wptr++ = nlen; *b->wptr++ = nlen;
memmove(b->wptr, ppp->chapname, nlen); memmove(b->wptr, up->user, nlen);
b->wptr += nlen; b->wptr += nlen;
*b->wptr++ = slen; *b->wptr++ = slen;
memmove(b->wptr, ppp->secret, slen); memmove(b->wptr, up->passwd, slen);
b->wptr += slen; b->wptr += slen;
hnputs(m->len, len); hnputs(m->len, len);
free(up);
putframe(ppp, Ppasswd, b); putframe(ppp, Ppasswd, b);
freeb(b); freeb(b);
} }
@ -2304,13 +2261,13 @@ getpap(PPP *ppp, Block *b)
qlock(ppp); qlock(ppp);
switch(m->code){ switch(m->code){
case Pauthreq: case Pauthreq:
netlog("PPP: pap auth request, not supported\n"); netlog("ppp: pap auth request, not supported\n");
break; break;
case Pauthack: case Pauthack:
if(ppp->phase == Pauth if(ppp->phase == Pauth
&& ppp->chap->proto == APpasswd && ppp->chap->proto == APpasswd
&& m->id <= ppp-> chap->id){ && m->id <= ppp-> chap->id){
netlog("PPP: pap succeeded\n"); netlog("ppp: pap succeeded\n");
setphase(ppp, Pnet); setphase(ppp, Pnet);
} }
break; break;
@ -2318,13 +2275,13 @@ getpap(PPP *ppp, Block *b)
if(ppp->phase == Pauth if(ppp->phase == Pauth
&& ppp->chap->proto == APpasswd && ppp->chap->proto == APpasswd
&& m->id <= ppp-> chap->id){ && m->id <= ppp-> chap->id){
netlog("PPP: pap failed (%d:%.*s)\n", netlog("ppp: pap failed (%d:%.*s)\n",
m->data[0], m->data[0], (char*)m->data+1); m->data[0], m->data[0], (char*)m->data+1);
terminate(ppp, 0); terminate(ppp, 0);
} }
break; break;
default: default:
netlog("PPP: unknown pap messsage %d\n", m->code); netlog("ppp: unknown pap messsage %d\n", m->code);
} }
qunlock(ppp); qunlock(ppp);
freeb(b); freeb(b);
@ -2702,6 +2659,7 @@ main(int argc, char **argv)
fmtinstall('I', eipfmt); fmtinstall('I', eipfmt);
fmtinstall('V', eipfmt); fmtinstall('V', eipfmt);
fmtinstall('E', eipfmt); fmtinstall('E', eipfmt);
fmtinstall('H', encodefmt);
dev = nil; dev = nil;
@ -2970,18 +2928,3 @@ putndb(PPP *ppp, char *net)
close(fd); close(fd);
} }
} }
static void
getauth(PPP *ppp)
{
UserPasswd *up;
if(*ppp->chapname)
return;
up = auth_getuserpasswd(auth_getkey,"proto=pass service=ppp %s", keyspec);
if(up != nil){
strcpy(ppp->chapname, up->user);
strcpy(ppp->secret, up->passwd);
}
}

View file

@ -113,6 +113,7 @@ enum {
/* authentication protocols */ /* authentication protocols */
APmd5= 5, APmd5= 5,
APmschap= 128, APmschap= 128,
APmschapv2= 129,
APpasswd= Ppasswd, /* use Pap, not Chap */ APpasswd= Ppasswd, /* use Pap, not Chap */
/* lcp flags */ /* lcp flags */
@ -221,7 +222,8 @@ struct Chap
int state; /* chap state */ int state; /* chap state */
uchar id; /* id of current message */ uchar id; /* id of current message */
int timeout; /* for current state */ int timeout; /* for current state */
Chalstate *cs; AuthInfo *ai;
Chalstate *cs;
}; };
struct Qualstats struct Qualstats
@ -292,11 +294,11 @@ struct PPP
void *uncstate; /* uncompression state */ void *uncstate; /* uncompression state */
/* encryption key */ /* encryption key */
uchar key[16]; uchar sendkey[16];
uchar recvkey[16];
int sendencrypted; int sendencrypted;
/* authentication */ /* authentication */
char secret[256]; /* md5 key */
char chapname[256]; /* chap system name */ char chapname[256]; /* chap system name */
/* link quality monitoring */ /* link quality monitoring */
@ -374,6 +376,8 @@ extern ushort ptclcsum(Block*, int, int);
extern ushort ptclbsum(uchar*, int); extern ushort ptclbsum(uchar*, int);
extern ushort ipcsum(uchar*); extern ushort ipcsum(uchar*);
void getasymkey(uchar *key, uchar *masterkey, int send, int server);
extern Comptype cmppc; extern Comptype cmppc;
extern Uncomptype uncmppc; extern Uncomptype uncmppc;