shithub: riscv

Download patch

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;