ref: 98b1f2a75b99f1af3c7c7cecf3735bab1793e2a2
parent: 3004f058f69a16f09c07c58d0e60a1732190f0d3
author: cinap_lenrek <[email protected]>
date: Sun Jan 21 17:55:14 EST 2018
ppp: mschapv2 support
--- a/sys/src/cmd/ip/ppp/mppc.c
+++ b/sys/src/cmd/ip/ppp/mppc.c
@@ -120,7 +120,7 @@
static int ipcheck(uchar*, int);
static void hischeck(Uncstate*);
-static void setkey(uchar *key, uchar *startkey);
+static void setkey(uchar *key, uchar *startkey);
Comptype cmppc = {
compinit,
@@ -155,8 +155,8 @@
if(ppp->sendencrypted) {
cs->encrypt = 1;
- memmove(cs->startkey, ppp->key, 16);
- memmove(cs->key, ppp->key, 16);
+ memmove(cs->startkey, ppp->sendkey, 16);
+ memmove(cs->key, cs->startkey, 16);
setkey(cs->key, cs->startkey);
setupRC4state(&cs->rc4key, cs->key, 16);
}
@@ -467,8 +467,8 @@
s = mallocz(sizeof(Uncstate), 1);
s->count = 0xfff; /* count of non existant last packet */
- memmove(s->startkey, ppp->key, 16);
- memmove(s->key, ppp->key, 16);
+ memmove(s->startkey, ppp->recvkey, 16);
+ memmove(s->key, s->startkey, 16);
setkey(s->key, s->startkey);
setupRC4state(&s->rc4key, s->key, 16);
@@ -577,12 +577,11 @@
if(count & Pencrypt) {
//netlog("mppc unencrypt count = %ux\n", count);
rc4(&s->rc4key, p, n);
+fprint(2, "plain=%.*H\n", n, p);
}
- if(!(count & Pcompress)) {
-//netlog("uncompress blen = %d\n", BLEN(b));
- return b;
- }
+ if(!(count & Pcompress))
+ return b;
bits = 0;
sreg = 0;
@@ -727,6 +726,27 @@
s = as;
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
--- a/sys/src/cmd/ip/ppp/ppp.c
+++ b/sys/src/cmd/ip/ppp/ppp.c
@@ -114,7 +114,6 @@
static void terminate(PPP*, int);
static int validv4(Ipaddr);
static void dmppkt(char *s, uchar *a, int na);
-static void getauth(PPP*);
void
pppopen(PPP *ppp, int mediain, int mediaout, char *net,
@@ -191,7 +190,7 @@
ppp->chap = mallocz(sizeof(*ppp->chap), 1);
if(ppp->chap == nil)
abort();
- ppp->chap->proto = APmschap;
+ ppp->chap->proto = APmschapv2;
ppp->chap->state = Cunauth;
auth_freechal(ppp->chap->cs);
ppp->chap->cs = nil;
@@ -252,6 +251,7 @@
break;
case APmd5:
case APmschap:
+ case APmschapv2:
break;
default:
setphase(ppp, Pnet);
@@ -713,6 +713,7 @@
syslog(0, "ppp", "requesting %I", ppp->local);
putv4o(b, Oipaddr, ppp->local);
}
+ primary = 1;
if(primary && (p->optmask & Fipdns))
putv4o(b, Oipdns, ppp->dns[0]);
if(primary && (p->optmask & Fipdns2))
@@ -852,7 +853,9 @@
}
if(proto != Pchap)
break;
- if(o->data[2] != APmd5 && o->data[2] != APmschap)
+ if(o->data[2] != APmd5
+ && o->data[2] != APmschap
+ && o->data[2] != APmschapv2)
break;
chapproto = o->data[2];
continue;
@@ -859,8 +862,6 @@
}
break;
case Pccp:
- if(nocompress)
- break;
switch(o->type){
case Octhwack:
break;
@@ -880,10 +881,6 @@
case Ocmppc:
x = nhgetl(o->data);
- // hack for Mac
- // if(x == 0)
- // continue;
-
/* stop ppp loops */
if((x&0x41) == 0 || ppp->ctries++ > 5) {
/*
@@ -895,7 +892,7 @@
}
if(rejecting)
continue;
- if(x & 1) {
+ if((x & 0x01000001) == 1){
ctype = &cmppc;
ppp->sendencrypted = (o->data[3]&0x40) == 0x40;
continue;
@@ -1965,6 +1962,20 @@
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
*/
@@ -1975,24 +1986,14 @@
Lcpmsg *m;
Chap *c;
int len;
- char *aproto;
- getauth(ppp);
-
c = ppp->chap;
c->id++;
-
- switch(c->proto){
- default:
- abort();
- case APmd5:
- aproto = "chap";
- break;
- case APmschap:
- aproto = "mschap";
- break;
+ if(c->ai != nil){
+ auth_freeAI(c->ai);
+ c->ai = nil;
}
- 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");
syslog(0, LOG, ": remote=%I: sending %d byte challenge", ppp->remote, c->cs->nchal);
len = 4 + 1 + c->cs->nchal + strlen(ppp->chapname);
@@ -2011,72 +2012,42 @@
}
/*
- * BUG factotum should do this
+ * challenge response dialog
*/
-enum {
- MShashlen = 16,
- MSresplen = 24,
- MSchallen = 8,
-};
-
-void
-desencrypt(uchar data[8], uchar key[7])
+static void
+setppekey(PPP *ppp, int isserver)
{
- ulong ekey[32];
+ Chap *c = ppp->chap;
- 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;
+ 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;
}
- memset(hash, 0, 16);
- md4(buf, i, hash, 0);
+ auth_freeAI(c->ai);
+ c->ai = nil;
}
-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
- */
-extern int _asrdresp(int, uchar*, int);
-
static void
getchap(PPP *ppp, Block *b)
{
- AuthInfo *ai;
Lcpmsg *m;
int len, vlen, i, id, n, nresp;
- char md5buf[512], code;
+ char code;
Chap *c;
Chapreply cr;
MSchapreply mscr;
char uid[PATH];
- uchar digest[16], *p, *resp, sdigest[SHA1dlen];
- uchar mshash[MShashlen], mshash2[MShashlen];
- DigestState *s;
- uchar msresp[2*MSresplen+1];
+ uchar resp[256], *p;
m = (Lcpmsg*)b->rptr;
len = nhgets(m->len);
@@ -2087,50 +2058,23 @@
}
qlock(ppp);
-
+ c = ppp->chap;
+ vlen = m->data[0];
switch(m->code){
case Cchallenge:
- getauth(ppp);
-
- vlen = m->data[0];
- if(vlen > len - 5) {
- netlog("PPP: chap: bad challenge len\n");
- break;
- }
-
id = m->id;
- switch(ppp->chap->proto){
- default:
- abort();
- case APmd5:
- n = strlen(ppp->secret);
- if(n + vlen + 1 > sizeof(md5buf)) {
- netlog("PPP: chap: bad challenge len\n");
- goto end;
- }
- md5buf[0] = m->id;
- 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);
+ memset(ppp->chapname, 0, sizeof(ppp->chapname));
+ nresp = auth_respondAI(m->data+1, vlen,
+ ppp->chapname, sizeof(ppp->chapname),
+ resp, sizeof(resp), &c->ai,
+ auth_getkey,
+ "proto=%s role=client service=ppp %s", getaproto(c->proto), keyspec);
+ if(nresp < 0)
+ sysfatal("auth_respond: %r");
+ if(c->proto == APmschap || c->proto == APmschapv2)
+ while(nresp < 49) resp[nresp++] = 0;
freeb(b);
+ len = 4 + 1 + nresp + strlen(ppp->chapname);
b = alloclcp(Cresponse, id, len, &m);
*b->wptr++ = nresp;
memmove(b->wptr, resp, nresp);
@@ -2138,14 +2082,12 @@
memmove(b->wptr, ppp->chapname, strlen(ppp->chapname));
b->wptr += strlen(ppp->chapname);
hnputs(m->len, len);
- netlog("PPP: sending response len %d\n", len);
+ netlog("ppp: sending response len %d\n", len);
putframe(ppp, Pchap, b);
break;
case Cresponse:
- c = ppp->chap;
- vlen = m->data[0];
- if(m->id != c->id) {
- netlog("PPP: chap: bad response id\n");
+ if(m->id != c->id || c->cs == nil) {
+ netlog("ppp: chap: bad response id\n");
break;
}
switch(c->proto) {
@@ -2153,10 +2095,9 @@
sysfatal("unknown chap protocol: %d", c->proto);
case APmd5:
if(vlen > len - 5 || vlen != 16) {
- netlog("PPP: chap: bad response len\n");
+ netlog("ppp: chap: bad response len\n");
break;
}
-
cr.id = m->id;
memmove(cr.resp, m->data+1, 16);
memset(uid, 0, sizeof(uid));
@@ -2169,8 +2110,9 @@
c->cs->nresp = sizeof cr;
break;
case APmschap:
- if(vlen > len - 5 || vlen != 49) {
- netlog("PPP: chap: bad response len\n");
+ case APmschapv2:
+ if(vlen > len - 5 || vlen < 48) {
+ netlog("ppp: chap: bad response len\n");
break;
}
memset(&mscr, 0, sizeof(mscr));
@@ -2196,42 +2138,53 @@
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);
- if((ai = auth_response(c->cs)) == nil || auth_chuid(ai, nil) < 0){
+ 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);
+
+ if((c->ai = auth_response(c->cs)) == nil || auth_chuid(c->ai, nil) < 0){
c->state = Cunauth;
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{
c->state = Cauthok;
code = Csuccess;
- syslog(0, LOG, ": remote=%I: auth ok: uid=%s nsecret=%d", ppp->remote, uid, ai->nsecret);
- if(c->proto == APmschap){
- if(ai->nsecret != sizeof(ppp->key))
- sysfatal("could not get the encryption key");
- memmove(ppp->key, ai->secret, sizeof(ppp->key));
- }
+ syslog(0, LOG, ": remote=%I: auth ok: uid=%s nsecret=%d",
+ ppp->remote, uid, c->ai->nsecret);
}
- auth_freeAI(ai);
auth_freechal(c->cs);
c->cs = nil;
freeb(b);
/* send reply */
- len = 4;
- b = alloclcp(code, c->id, len, &m);
- hnputs(m->len, len);
+ if(code == Csuccess && c->proto == APmschapv2 && c->ai->nsecret == 16+20){
+ b = alloclcp(code, c->id, 4+2+2*20+1, &m);
+ 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);
- if(c->state == Cauthok) {
+ if(c->state == Cauthok){
+ setppekey(ppp, 1);
setphase(ppp, Pnet);
} else {
/* restart chapp negotiation */
chapinit(ppp);
}
-
break;
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");
+ setppekey(ppp, 0);
setphase(ppp, Pnet);
break;
case Cfailure:
@@ -2242,7 +2195,6 @@
syslog(0, LOG, "chap code %d?", m->code);
break;
}
-end:
qunlock(ppp);
freeb(b);
}
@@ -2253,27 +2205,32 @@
Block *b;
Lcpmsg *m;
Chap *c;
+ UserPasswd *up;
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->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);
- slen = strlen(ppp->secret);
+ nlen = strlen(up->user);
+ slen = strlen(up->passwd);
len = 4 + 1 + nlen + 1 + slen;
b = alloclcp(Pauthreq, c->id, len, &m);
*b->wptr++ = nlen;
- memmove(b->wptr, ppp->chapname, nlen);
+ memmove(b->wptr, up->user, nlen);
b->wptr += nlen;
*b->wptr++ = slen;
- memmove(b->wptr, ppp->secret, slen);
+ memmove(b->wptr, up->passwd, slen);
b->wptr += slen;
hnputs(m->len, len);
+ free(up);
+
putframe(ppp, Ppasswd, b);
freeb(b);
}
@@ -2304,13 +2261,13 @@
qlock(ppp);
switch(m->code){
case Pauthreq:
- netlog("PPP: pap auth request, not supported\n");
+ netlog("ppp: pap auth request, not supported\n");
break;
case Pauthack:
if(ppp->phase == Pauth
&& ppp->chap->proto == APpasswd
&& m->id <= ppp-> chap->id){
- netlog("PPP: pap succeeded\n");
+ netlog("ppp: pap succeeded\n");
setphase(ppp, Pnet);
}
break;
@@ -2318,13 +2275,13 @@
if(ppp->phase == Pauth
&& ppp->chap->proto == APpasswd
&& 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);
terminate(ppp, 0);
}
break;
default:
- netlog("PPP: unknown pap messsage %d\n", m->code);
+ netlog("ppp: unknown pap messsage %d\n", m->code);
}
qunlock(ppp);
freeb(b);
@@ -2702,6 +2659,7 @@
fmtinstall('I', eipfmt);
fmtinstall('V', eipfmt);
fmtinstall('E', eipfmt);
+ fmtinstall('H', encodefmt);
dev = nil;
@@ -2969,19 +2927,4 @@
write(fd, "refresh", 7);
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);
- }
}
--- a/sys/src/cmd/ip/ppp/ppp.h
+++ b/sys/src/cmd/ip/ppp/ppp.h
@@ -113,6 +113,7 @@
/* authentication protocols */
APmd5= 5,
APmschap= 128,
+ APmschapv2= 129,
APpasswd= Ppasswd, /* use Pap, not Chap */
/* lcp flags */
@@ -221,7 +222,8 @@
int state; /* chap state */
uchar id; /* id of current message */
int timeout; /* for current state */
- Chalstate *cs;
+ AuthInfo *ai;
+ Chalstate *cs;
};
struct Qualstats
@@ -292,11 +294,11 @@
void *uncstate; /* uncompression state */
/* encryption key */
- uchar key[16];
+ uchar sendkey[16];
+ uchar recvkey[16];
int sendencrypted;
/* authentication */
- char secret[256]; /* md5 key */
char chapname[256]; /* chap system name */
/* link quality monitoring */
@@ -373,6 +375,8 @@
extern ushort ptclcsum(Block*, int, int);
extern ushort ptclbsum(uchar*, int);
extern ushort ipcsum(uchar*);
+
+void getasymkey(uchar *key, uchar *masterkey, int send, int server);
extern Comptype cmppc;
extern Uncomptype uncmppc;