summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)