chap.c revision 6735
1229198Sed/*
2229198Sed *			PPP CHAP Module
3229198Sed *
4229198Sed *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5229198Sed *
6229198Sed *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7229198Sed *
8229198Sed * Redistribution and use in source and binary forms are permitted
9229198Sed * provided that the above copyright notice and this paragraph are
10229198Sed * duplicated in all such forms and that any documentation,
11229198Sed * advertising materials, and other materials related to such
12229198Sed * distribution and use acknowledge that the software was developed
13229198Sed * by the Internet Initiative Japan, Inc.  The name of the
14229198Sed * IIJ may not be used to endorse or promote products derived
15229198Sed * from this software without specific prior written permission.
16229198Sed * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17229198Sed * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18229198Sed * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19229198Sed *
20229198Sed * $Id:$
21229198Sed *
22229198Sed *	TODO:
23229198Sed */
24229198Sed#include "fsm.h"
25229198Sed#include "chap.h"
26229198Sed#include "lcpproto.h"
27229198Sed#include "lcp.h"
28229198Sed#include "hdlc.h"
29229198Sed#include "phase.h"
30229198Sed#include "vars.h"
31229198Sed#include "auth.h"
32229198Sed
33229198Sedstatic char *chapcodes[] = {
34229198Sed  "???", "CHALLENGE", "RESPONCE", "SUCCESS", "FAILURE"
35229198Sed};
36229198Sed
37229198Sedstruct authinfo AuthChapInfo  = {
38229198Sed  SendChapChallenge,
39229198Sed};
40229198Sed
41229198Sedextern char *AuthGetSecret();
42229198Sed
43229198Sedvoid
44229198SedChapOutput(code, id, ptr, count)
45229198Sedu_int code, id;
46229198Sedu_char *ptr;
47229198Sedint count;
48229198Sed{
49229198Sed  int plen;
50229198Sed  struct fsmheader lh;
51229198Sed  struct mbuf *bp;
52229198Sed
53229198Sed  plen =  sizeof(struct fsmheader) + count;
54229198Sed  lh.code = code;
55229198Sed  lh.id = id;
56229198Sed  lh.length = htons(plen);
57229198Sed  bp = mballoc(plen, MB_FSM);
58229198Sed  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
59229198Sed  if (count)
60229198Sed    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
61229198Sed#ifdef DEBUG
62229198Sed  DumpBp(bp);
63229198Sed#endif
64229198Sed  LogPrintf(LOG_LCP, "ChapOutput: %s\n", chapcodes[code]);
65229198Sed  HdlcOutput(PRI_NORMAL, PROTO_CHAP, bp);
66229198Sed}
67229198Sed
68229198Sed
69229198Sedstatic char challenge_data[80];
70229198Sedstatic int  challenge_len;
71229198Sed
72229198Sedvoid
73229198SedSendChapChallenge(chapid)
74229198Sedint chapid;
75229198Sed{
76229198Sed  int keylen, len, i;
77229198Sed  char *cp;
78229198Sed
79229198Sed  srandom(time(NULL));
80229198Sed
81229198Sed  cp = challenge_data;
82229198Sed  *cp++ = challenge_len = random() % 32 + 16;
83229198Sed  for (i = 0; i < challenge_len; i++)
84229198Sed    *cp++ = random() & 0xff;
85229198Sed  len = strlen(VarAuthName);
86229198Sed  bcopy(VarAuthName, cp, len);
87229198Sed  cp += len;
88229198Sed  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
89229198Sed}
90229198Sed
91229198Sed#ifdef DEBUG
92229198Sedvoid
93229198SedDumpDigest(mes, cp, len)
94229198Sedchar *mes;
95229198Sedchar *cp;
96229198Sedint len;
97229198Sed{
98229198Sed  int i;
99229198Sed
100229198Sed  logprintf("%s: ", mes);
101229198Sed  for (i = 0; i < len; i++) {
102229198Sed    logprintf(" %02x", *cp++ & 0xff);
103229198Sed  }
104229198Sed  logprintf("\n");
105229198Sed}
106229198Sed#endif
107229198Sed
108229198Sedvoid
109229198SedRecvChapTalk(chp, bp)
110229198Sedstruct fsmheader *chp;
111229198Sedstruct mbuf *bp;
112229198Sed{
113229198Sed  int valsize, len;
114229198Sed  int arglen, keylen, namelen;
115229198Sed  char *cp, *argp, *ap, *name, *digest;
116  char *keyp;
117  MD5_CTX context;                            /* context */
118  char answer[100];
119  char cdigest[16];
120
121  len = ntohs(chp->length);
122#ifdef DEBUG
123  logprintf("length: %d\n", len);
124#endif
125  arglen = len - sizeof(struct fsmheader);
126  cp = (char *)MBUF_CTOP(bp);
127  valsize = *cp++ & 255;
128  name = cp + valsize;
129  namelen = arglen - valsize - 1;
130  name[namelen] = 0;
131  LogPrintf(LOG_PHASE, " Valsize = %d, Name = %s\n", valsize, name);
132
133  /*
134   * Get a secret key corresponds to the peer
135   */
136  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
137
138  switch (chp->code) {
139  case CHAP_CHALLENGE:
140    if (keyp) {
141      keylen = strlen(keyp);
142    } else {
143      keylen = strlen(VarAuthKey);
144      keyp = VarAuthKey;
145    }
146    name = VarAuthName;
147    namelen = strlen(VarAuthName);
148    argp = malloc(1 + valsize + namelen);
149    digest = argp;
150    *digest++ = 16;		/* value size */
151    ap = answer;
152    *ap++ = chp->id;
153    bcopy(keyp, ap, keylen);
154    ap += keylen;
155    bcopy(cp, ap, valsize);
156#ifdef DEBUG
157    DumpDigest("recv", ap, valsize);
158#endif
159    ap += valsize;
160    MD5Init(&context);
161    MD5Update(&context, answer, ap - answer);
162    MD5Final(digest, &context);
163#ifdef DEBUG
164    DumpDigest("answer", digest, 16);
165#endif
166    bcopy(name, digest + 16, namelen);
167    ap += namelen;
168    /* Send answer to the peer */
169    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
170    break;
171  case CHAP_RESPONSE:
172    if (keyp) {
173      /*
174       * Compute correct digest value
175       */
176      keylen = strlen(keyp);
177      ap = answer;
178      *ap++ = chp->id;
179      bcopy(keyp, ap, keylen);
180      ap += keylen;
181      MD5Init(&context);
182      MD5Update(&context, answer, ap - answer);
183      MD5Update(&context, challenge_data+1, challenge_len);
184      MD5Final(cdigest, &context);
185#ifdef DEBUG
186      DumpDigest("got", cp, 16);
187      DumpDigest("expect", cdigest, 16);
188#endif
189      /*
190       * Compare with the response
191       */
192      if (bcmp(cp, cdigest, 16) == 0) {
193	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
194	NewPhase(PHASE_NETWORK);
195	break;
196      }
197    }
198    /*
199     * Peer is not registerd, or response digest is wrong.
200     */
201    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
202    LcpClose();
203    break;
204  }
205}
206
207void
208RecvChapResult(chp, bp)
209struct fsmheader *chp;
210struct mbuf *bp;
211{
212  int len;
213  struct lcpstate *lcp = &LcpInfo;
214
215  len = ntohs(chp->length);
216#ifdef DEBUG
217  logprintf("length: %d\n", len);
218#endif
219  if (chp->code == CHAP_SUCCESS) {
220    if (lcp->auth_iwait == PROTO_CHAP) {
221      lcp->auth_iwait = 0;
222      if (lcp->auth_ineed == 0)
223	NewPhase(PHASE_NETWORK);
224    }
225  } else {
226    /*
227     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
228     */
229    ;
230  }
231}
232
233void
234ChapInput(struct mbuf *bp)
235{
236  int len = plength(bp);
237  struct fsmheader *chp;
238
239  if (len >= sizeof(struct fsmheader)) {
240    chp = (struct fsmheader *)MBUF_CTOP(bp);
241    if (len >= ntohs(chp->length)) {
242      if (chp->code < 1 || chp->code > 4)
243	chp->code = 0;
244      LogPrintf(LOG_LCP, "ChapInput: %s\n", chapcodes[chp->code]);
245
246      bp->offset += sizeof(struct fsmheader);
247      bp->cnt -= sizeof(struct fsmheader);
248
249      switch (chp->code) {
250      case CHAP_RESPONSE:
251	StopAuthTimer(&AuthChapInfo);
252	/* Fall into.. */
253      case CHAP_CHALLENGE:
254	RecvChapTalk(chp, bp);
255	break;
256      case CHAP_SUCCESS:
257      case CHAP_FAILURE:
258	RecvChapResult(chp, bp);
259	break;
260      }
261    }
262  }
263  pfree(bp);
264}
265