ref: fd1e50d653c32a85086f6bd14f7e261c2683224c
parent: 9840c50a3e0d2392a9102484e0caf970d3153790
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jan 21 17:32:34 EST 2018
authsrv: implement mschapv2 authentication, include MPPE secret in the ticket this adds new rpc for mschapv2 authentication (21) deliver the MPPE secret not after the ticket/authenticator response as cheartext, but include it in the first 128 bit of the ticket key. and the authenticator in the first 160 bit of the authenticator random field.
--- a/sys/include/authsrv.h
+++ b/sys/include/authsrv.h
@@ -61,6 +61,7 @@
AuthHttp=13, /* http domain login */
AuthVNC=14, /* VNC server login (deprecated) */
AuthPAK=19, /* authenticated diffie hellman key agreement */
+ AuthMSchapv2=21,/* MS chap v2 authentication for ppp */
AuthTs=64, /* ticket encrypted with server's key */
AuthTc, /* ticket encrypted with client's key */
AuthAs, /* server generated authenticator */
--- a/sys/src/cmd/auth/authsrv.c
+++ b/sys/src/cmd/auth/authsrv.c
@@ -27,6 +27,7 @@
MShashlen = 16,
MSchallen = 8,
MSresplen = 24,
+ MSchallenv2 = 16,
};
void pak(Ticketreq*);
@@ -35,7 +36,7 @@
void changepasswd(Ticketreq*);
void apop(Ticketreq*, int);
void chap(Ticketreq*);
-void mschap(Ticketreq*);
+void mschap(Ticketreq*, int);
void vnc(Ticketreq*);
int speaksfor(char*, char*);
void replyerror(char*, ...);
@@ -49,6 +50,7 @@
void mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]);
void desencrypt(uchar data[8], uchar key[7]);
void tickauthreply(Ticketreq*, Authkey*);
+void tickauthreply2(Ticketreq*, Authkey*, uchar *, int, uchar *, int);
void safecpy(char*, char*, int);
void
@@ -98,8 +100,11 @@
chap(&tr);
break;
case AuthMSchap:
- mschap(&tr);
+ mschap(&tr, MSchallen);
break;
+ case AuthMSchapv2:
+ mschap(&tr, MSchallenv2);
+ break;
case AuthCram:
apop(&tr, AuthCram);
break;
@@ -674,24 +679,23 @@
static uchar ntblobsig[] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void
-mschap(Ticketreq *tr)
+mschap(Ticketreq *tr, int nchal)
{
char *secret;
char sbuf[SECRETLEN], windom[128];
- uchar chal[CHALLEN], ntblob[1024];
+ uchar chal[16], ntblob[1024];
uchar hash[MShashlen];
- uchar hash2[MShashlen];
uchar resp[MSresplen];
OMSchapreply reply;
int dupe, lmok, ntok, ntbloblen;
+ uchar phash[SHA1dlen], chash[SHA1dlen], ahash[SHA1dlen];
DigestState *s;
- uchar digest[SHA1dlen];
/*
* Create a challenge and send it.
*/
genrandom(chal, sizeof(chal));
- if(write(1, chal, sizeof(chal)) != sizeof(chal))
+ if(write(1, chal, nchal) != nchal)
exits(0);
/*
@@ -704,7 +708,7 @@
* CIFS/NTLMv2 uses variable length NT response.
*/
ntbloblen = 0;
- if(memcmp(reply.NTresp+16, ntblobsig, sizeof(ntblobsig)) == 0){
+ if(nchal == MSchallen && memcmp(reply.NTresp+16, ntblobsig, sizeof(ntblobsig)) == 0){
/* Version[1], HiVision[1], Z[6] */
ntbloblen += 1+1+6;
memmove(ntblob, reply.NTresp+16, ntbloblen);
@@ -784,13 +788,24 @@
windom[0] = '\0'; /* try NIL domain */
}
dupe = 0;
+ } else if(nchal == MSchallenv2){
+ s = sha1((uchar*)reply.LMresp, MSchallenv2, nil, nil);
+ s = sha1(chal, MSchallenv2, nil, s);
+ sha1((uchar*)tr->uid, strlen(tr->uid), chash, s);
+
+ nthash(hash, secret);
+ mschalresp(resp, hash, chash);
+ ntok = lmok = tsmemcmp(resp, reply.NTresp, MSresplen) == 0;
+ dupe = 0;
} else {
lmhash(hash, secret);
mschalresp(resp, hash, chal);
lmok = tsmemcmp(resp, reply.LMresp, MSresplen) == 0;
+
nthash(hash, secret);
mschalresp(resp, hash, chal);
ntok = tsmemcmp(resp, reply.NTresp, MSresplen) == 0;
+
dupe = tsmemcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
}
@@ -815,21 +830,37 @@
succeed(tr->uid);
+ nthash(hash, secret);
+ md4(hash, 16, hash, nil);
+
/*
* reply with ticket & authenticator
*/
- tickauthreply(tr, &hkey);
+ if(nchal == MSchallenv2){
+ s = sha1(hash, 16, nil, nil);
+ sha1((uchar*)reply.NTresp, MSresplen, nil, s);
+ sha1((uchar*)"This is the MPPE Master Key", 27, phash, s);
- syslog(0, AUTHLOG, "mschap-ok %s/%s(%s)", tr->uid, tr->hostid, raddr);
+ s = sha1(hash, 16, nil, nil);
+ sha1((uchar*)reply.NTresp, MSresplen, nil, s);
+ sha1((uchar*)"Magic server to client signing constant", 39, ahash, s);
- nthash(hash, secret);
- md4(hash, 16, hash2, 0);
- s = sha1(hash2, 16, 0, 0);
- sha1(hash2, 16, 0, s);
- sha1(chal, 8, digest, s);
+ s = sha1(ahash, 20, nil, nil);
+ sha1(chash, 8, nil, s);
+ sha1((uchar*)"Pad to make it do more than one iteration", 41, ahash, s);
- if(write(1, digest, 16) != 16)
- exits(0);
+ tickauthreply2(tr, &hkey, phash, 16, ahash, 20);
+ } else {
+ s = sha1(hash, 16, nil, nil);
+ sha1(hash, 16, nil, s);
+ sha1(chal, 8, phash, s);
+
+ tickauthreply2(tr, &hkey, phash, 16, nil, 0);
+ }
+
+ syslog(0, AUTHLOG, "mschap-ok %s/%s(%s)", tr->uid, tr->hostid, raddr);
+
+ exits(0);
}
void
@@ -1059,9 +1090,22 @@
/*
* reply with ticket and authenticator
*/
+/*
+ * reply with ticket and authenticator
+ */
void
tickauthreply(Ticketreq *tr, Authkey *key)
{
+ tickauthreply2(tr, key, nil, 0, nil, 0);
+}
+
+/*
+ * reply with ticket and authenticator with
+ * secret s[ns] and authenticator data a[na].
+ */
+void
+tickauthreply2(Ticketreq *tr, Authkey *key, uchar *ps, int ns, uchar *pa, int na)
+{
Ticket t;
Authenticator a;
char buf[MAXTICKETLEN+MAXAUTHENTLEN+1];
@@ -1068,6 +1112,10 @@
int n;
mkticket(tr, &t);
+ if(t.form != 0 && ns > 0){
+ assert(ns <= NONCELEN);
+ memmove(t.key, ps, ns);
+ }
t.num = AuthTs;
n = 0;
buf[n++] = AuthOK;
@@ -1075,11 +1123,16 @@
memset(&a, 0, sizeof(a));
memmove(a.chal, t.chal, CHALLEN);
genrandom(a.rand, NONCELEN);
+ if(t.form != 0 && na > 0){
+ assert(na <= NONCELEN);
+ memmove(a.rand, pa, na);
+ }
a.num = AuthAc;
n += convA2M(&a, buf+n, sizeof(buf)-n, &t);
if(write(1, buf, n) != n)
exits(0);
}
+
void
safecpy(char *to, char *from, int len)