summaryrefslogtreecommitdiff
path: root/sys/src/cmd
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2018-01-21 22:35:01 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2018-01-21 22:35:01 +0100
commita7974d96b7e510cba9ae4ef87fed8b0ded109f98 (patch)
treef681a17845a34759fa6a083a9bc0e8e847b27614 /sys/src/cmd
parentfd1e50d653c32a85086f6bd14f7e261c2683224c (diff)
factotum: implement mschapv2 role=server authentication (for ppp)
this implements the server part of mschapv2 with the new authserver changes. we also provide AuthInfo for the client now with the MPPE secret and the authenticator.
Diffstat (limited to 'sys/src/cmd')
-rw-r--r--sys/src/cmd/auth/factotum/chap.c149
1 files changed, 96 insertions, 53 deletions
diff --git a/sys/src/cmd/auth/factotum/chap.c b/sys/src/cmd/auth/factotum/chap.c
index 67e817ae0..03e1d3047 100644
--- a/sys/src/cmd/auth/factotum/chap.c
+++ b/sys/src/cmd/auth/factotum/chap.c
@@ -1,14 +1,14 @@
/*
* CHAP, MSCHAP
*
- * The client does not authenticate the server, hence no CAI
+ * The client does not authenticate the server
*
* Client protocol:
* write Chapchal
* read response Chapreply or MSchaprely structure
*
* Server protocol:
- * read challenge: 8 bytes binary
+ * read challenge: 8 bytes binary (or 16 bytes for mschapv2)
* write user: utf8
* write response: Chapreply or MSchapreply structure
*/
@@ -24,6 +24,7 @@ enum {
MShashlen = 16,
MSchallen = 8,
MSresplen = 24,
+
MSchallenv2 = 16,
Chapreplylen = MD5LEN+1,
@@ -35,6 +36,7 @@ static int doreply(State *s, uchar *reply, int nreply);
static int dochap(char *passwd, int id, char chal[ChapChallen], uchar *resp, int resplen);
static int domschap(char *passwd, uchar chal[MSchallen], uchar *resp, int resplen);
static int domschap2(char *passwd, char *user, char *dom, uchar chal[MSchallen], uchar *resp, int resplen);
+static void nthash(uchar hash[MShashlen], char *passwd);
struct State
{
@@ -44,12 +46,13 @@ struct State
Authkey k;
Ticket t;
Ticketreq tr;
- char chal[ChapChallen];
+ int nchal;
+ char chal[16];
int nresp;
uchar resp[4096];
char err[ERRMAX];
char user[64];
- uchar secret[16]; /* for mschap */
+ uchar secret[16+20]; /* for mschap: MPPE Master secret + authenticator (v2) */
int nsecret;
};
@@ -61,8 +64,6 @@ enum
SHaveChal,
SNeedUser,
SNeedResp,
- SHaveZero,
- SHaveCAI,
Maxphase
};
@@ -75,8 +76,6 @@ static char *phasenames[Maxphase] =
[SHaveChal] "SHaveChal",
[SNeedUser] "SNeedUser",
[SNeedResp] "SNeedResp",
-[SHaveZero] "SHaveZero",
-[SHaveCAI] "SHaveCAI",
};
static int
@@ -88,19 +87,24 @@ chapinit(Proto *p, Fsstate *fss)
if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
return failure(fss, nil);
- if(!iscli && p == &mschapv2)
- return failure(fss, "role must be client");
-
s = emalloc(sizeof *s);
s->nresp = 0;
s->nsecret = 0;
+ strcpy(s->user, "none");
fss->phasename = phasenames;
fss->maxphase = Maxphase;
s->asfd = -1;
- if(p == &mschap || p == &mschapv2 || p == &mschap2){
- s->astype = AuthMSchap;
- }else {
- s->astype = AuthChap;
+ if(p == &mschapv2) {
+ s->nchal = MSchallenv2;
+ s->astype = AuthMSchapv2;
+ } else {
+ if(p == &mschap || p == &mschap2){
+ s->nchal = MSchallen;
+ s->astype = AuthMSchap;
+ }else {
+ s->nchal = ChapChallen;
+ s->astype = AuthChap;
+ }
}
if(iscli)
fss->phase = CNeedChal;
@@ -137,7 +141,7 @@ static int
chapwrite(Fsstate *fss, void *va, uint n)
{
int ret, nreply;
- char *a, *v;
+ char *a, *pass;
Key *k;
Keyinfo ki;
State *s;
@@ -145,8 +149,11 @@ chapwrite(Fsstate *fss, void *va, uint n)
MSchapreply *mcr;
OChapreply *ocr;
OMSchapreply *omcr;
+ uchar pchal[MSchallenv2];
+ uchar digest[SHA1dlen];
uchar reply[4096];
char *user, *dom;
+ DigestState *ds;
s = fss->ps;
a = va;
@@ -158,11 +165,13 @@ chapwrite(Fsstate *fss, void *va, uint n)
ret = findkey(&k, mkkeyinfo(&ki, fss, nil), "%s", fss->proto->keyprompt);
if(ret != RpcOk)
return ret;
- v = _strfindattr(k->privattr, "!password");
- if(v == nil){
+ user = nil;
+ pass = _strfindattr(k->privattr, "!password");
+ if(pass == nil){
closekey(k);
return failure(fss, "key has no password");
}
+ s->nsecret = 0;
s->nresp = 0;
memset(s->resp, 0, sizeof(s->resp));
setattrs(fss->attr, k->attr);
@@ -177,46 +186,64 @@ chapwrite(Fsstate *fss, void *va, uint n)
dom = _strfindattr(fss->attr, "windom");
if(dom == nil)
dom = "";
- s->nresp = domschap2(v, user, dom, (uchar*)a, s->resp, sizeof(s->resp));
+ s->nresp = domschap2(pass, user, dom, (uchar*)a, s->resp, sizeof(s->resp));
+ } else {
+ s->nresp = domschap(pass, (uchar*)a, s->resp, sizeof(s->resp));
}
- else if(fss->proto == &mschapv2 || n == MSchallenv2){
- uchar pchal[MSchallenv2];
- DigestState *ds;
+ nthash(digest, pass);
+ md4(digest, 16, digest, nil);
+ ds = sha1(digest, 16, nil, nil);
+ sha1(digest, 16, nil, ds);
+ sha1((uchar*)a, 8, s->secret, ds);
+ s->nsecret = 16;
+ break;
+ case AuthMSchapv2:
+ if(n < MSchallenv2)
+ break;
+ user = _strfindattr(fss->attr, "user");
+ if(user == nil)
+ break;
+ genrandom((uchar*)pchal, MSchallenv2);
- if(n < MSchallenv2)
- break;
- user = _strfindattr(fss->attr, "user");
- if(user == nil)
- break;
+ /* ChallengeHash() */
+ ds = sha1(pchal, MSchallenv2, nil, nil);
+ ds = sha1((uchar*)a, MSchallenv2, nil, ds);
+ sha1((uchar*)user, strlen(user), reply, ds);
- genrandom((uchar*)pchal, MSchallenv2);
+ s->nresp = domschap(pass, reply, s->resp, sizeof(s->resp));
+ if(s->nresp <= 0)
+ break;
- /* ChallengeHash() */
- ds = sha1(pchal, MSchallenv2, nil, nil);
- ds = sha1((uchar*)a, MSchallenv2, nil, ds);
- sha1((uchar*)user, strlen(user), reply, ds);
+ mcr = (MSchapreply*)s->resp;
+ memset(mcr->LMresp, 0, sizeof(mcr->LMresp));
+ memmove(mcr->LMresp, pchal, MSchallenv2);
- s->nresp = domschap(v, reply, s->resp, sizeof(s->resp));
- if(s->nresp <= 0)
- break;
+ nthash(digest, pass);
+ md4(digest, 16, digest, nil);
+ ds = sha1(digest, 16, nil, nil);
+ sha1((uchar*)mcr->NTresp, MSresplen, nil, ds);
+ sha1((uchar*)"This is the MPPE Master Key", 27, s->secret, ds);
- mcr = (MSchapreply*)s->resp;
- memset(mcr->LMresp, 0, sizeof(mcr->LMresp));
- memmove(mcr->LMresp, pchal, MSchallenv2);
- }
- else {
- s->nresp = domschap(v, (uchar*)a, s->resp, sizeof(s->resp));
- }
+ ds = sha1(digest, 16, nil, nil);
+ sha1((uchar*)mcr->NTresp, MSresplen, nil, ds);
+ sha1((uchar*)"Magic server to client signing constant", 39, digest, ds);
+
+ ds = sha1(digest, 20, nil, nil);
+ sha1(reply, 8, nil, ds); /* ChallngeHash */
+ sha1((uchar*)"Pad to make it do more than one iteration", 41, s->secret+16, ds);
+ s->nsecret = 16+20;
break;
case AuthChap:
if(n < ChapChallen+1)
break;
- s->nresp = dochap(v, *a, a+1, s->resp, sizeof(s->resp));
+ s->nresp = dochap(pass, *a, a+1, s->resp, sizeof(s->resp));
break;
}
closekey(k);
if(s->nresp <= 0)
return failure(fss, "chap botch");
+ if(user != nil)
+ safecpy(s->user, user, sizeof s->user);
fss->phase = CHaveResp;
return RpcOk;
@@ -244,6 +271,7 @@ chapwrite(Fsstate *fss, void *va, uint n)
memmove(ocr->resp, cr->resp, sizeof(ocr->resp));
break;
case AuthMSchap:
+ case AuthMSchapv2:
if(n < MSchapreplylen)
return failure(fss, "did not get MSchapreply");
if(n > sizeof(reply)+MSchapreplylen-OMSCHAPREPLYLEN)
@@ -284,12 +312,20 @@ chapread(Fsstate *fss, void *va, uint *n)
*n = s->nresp;
memmove(va, s->resp, *n);
fss->phase = Established;
- fss->haveai = 0;
+ if(s->nsecret == 0){
+ fss->haveai = 0;
+ return RpcOk;
+ }
+ fss->ai.cuid = s->user;
+ fss->ai.suid = "none"; /* server not authenticated */
+ fss->ai.secret = s->secret;
+ fss->ai.nsecret = s->nsecret;
+ fss->haveai = 1;
return RpcOk;
case SHaveChal:
- if(*n > sizeof s->chal)
- *n = sizeof s->chal;
+ if(*n > s->nchal)
+ *n = s->nchal;
memmove(va, s->chal, *n);
fss->phase = SNeedUser;
return RpcOk;
@@ -322,9 +358,9 @@ dochal(State *s)
goto err;
alarm(30*1000);
- n = readn(s->asfd, s->chal, sizeof s->chal);
+ n = readn(s->asfd, s->chal, s->nchal);
alarm(0);
- if(n != sizeof s->chal)
+ if(n != s->nchal)
goto err;
return 0;
@@ -348,15 +384,11 @@ doreply(State *s, uchar *reply, int nreply)
goto err;
}
n = _asgetresp(s->asfd, &s->t, &a, &s->k);
+ alarm(0);
if(n < 0){
- alarm(0);
/* leave connection open so we can try again */
return -1;
}
- s->nsecret = readn(s->asfd, s->secret, sizeof s->secret);
- alarm(0);
- if(s->nsecret < 0)
- s->nsecret = 0;
close(s->asfd);
s->asfd = -1;
@@ -373,6 +405,17 @@ doreply(State *s, uchar *reply, int nreply)
werrstr(Easproto);
return -1;
}
+ s->nsecret = 0;
+ if(s->t.form != 0){
+ if(s->astype == AuthMSchap || s->astype == AuthMSchapv2){
+ memmove(s->secret, s->t.key, 16);
+ if(s->astype == AuthMSchapv2){
+ memmove(s->secret+16, a.rand, 20);
+ s->nsecret = 16+20;
+ } else
+ s->nsecret = 16;
+ }
+ }
return 0;
err:
if(s->asfd >= 0)