chap.c revision 6059
131921Sbrian/*
231921Sbrian *			PPP CHAP Module
331921Sbrian *
431921Sbrian *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
531921Sbrian *
631921Sbrian *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
731921Sbrian *
831921Sbrian * Redistribution and use in source and binary forms are permitted
931921Sbrian * provided that the above copyright notice and this paragraph are
1031921Sbrian * duplicated in all such forms and that any documentation,
1131921Sbrian * advertising materials, and other materials related to such
1231921Sbrian * distribution and use acknowledge that the software was developed
1331921Sbrian * by the Internet Initiative Japan, Inc.  The name of the
1431921Sbrian * IIJ may not be used to endorse or promote products derived
1531921Sbrian * from this software without specific prior written permission.
1631921Sbrian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1731921Sbrian * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1831921Sbrian * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1931921Sbrian *
2031921Sbrian * $Id:$
2131921Sbrian *
2231921Sbrian *	TODO:
2331921Sbrian *		o Imprement retransmission timer.
2431921Sbrian */
2531921Sbrian#include "fsm.h"
2650479Speter#include "chap.h"
2730715Sbrian#include "lcpproto.h"
2830715Sbrian#include "lcp.h"
2936285Sbrian#include "hdlc.h"
3026940Sbrian#include "phase.h"
3136285Sbrian#include "vars.h"
3258028Sbrian
3336285Sbrianstatic int chapid;
3436285Sbrian
3571657Sbrianstatic char *chapcodes[] = {
3671657Sbrian  "???", "CHALLENGE", "RESPONCE", "SUCCESS", "FAILURE"
3736285Sbrian};
3874001Sbrian
3971657Sbrianextern char *AuthGetSecret();
4071657Sbrian
4171657Sbrianvoid
4271657SbrianChapOutput(code, id, ptr, count)
4336285Sbrianu_int code, id;
4436285Sbrianu_char *ptr;
4571657Sbrianint count;
4671657Sbrian{
4771657Sbrian  int plen;
4871657Sbrian  struct fsmheader lh;
4971657Sbrian  struct mbuf *bp;
5071657Sbrian
5171657Sbrian  plen =  sizeof(struct fsmheader) + count;
5236285Sbrian  lh.code = code;
5336285Sbrian  lh.id = id;
5436285Sbrian  lh.length = htons(plen);
5536285Sbrian  bp = mballoc(plen, MB_FSM);
5636285Sbrian  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
5771657Sbrian  if (count)
5871657Sbrian    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
5971657Sbrian#ifdef DEBUG
6036285Sbrian  DumpBp(bp);
6171657Sbrian#endif
62  LogPrintf(LOG_LCP, "ChapOutput: %s\n", chapcodes[code]);
63  HdlcOutput(PRI_NORMAL, PROTO_CHAP, bp);
64}
65
66
67static char challenge_data[80];
68static int  challenge_len;
69
70void
71SendChapChallenge()
72{
73  int keylen, len, i;
74  char *cp;
75
76  srandom(time(NULL));
77  ++chapid;
78
79  cp = challenge_data;
80  *cp++ = challenge_len = random() % 32 + 16;
81  for (i = 0; i < challenge_len; i++)
82    *cp++ = random() & 0xff;
83  len = strlen(VarAuthName);
84  bcopy(VarAuthName, cp, len);
85  cp += len;
86  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
87}
88
89#ifdef DEBUG
90void
91DumpDigest(mes, cp, len)
92char *mes;
93char *cp;
94{
95  int i;
96
97  logprintf("%s: ", mes);
98  for (i = 0; i < len; i++) {
99    logprintf(" %02x", *cp++ & 0xff);
100  }
101  logprintf("\n");
102}
103#endif
104
105void
106RecvChapTalk(chp, bp)
107struct fsmheader *chp;
108struct mbuf *bp;
109{
110  int valsize, len;
111  int arglen, keylen, namelen;
112  char *cp, *argp, *ap, *name, *digest;
113  char *keyp;
114  MD5_CTX context;                            /* context */
115  char answer[100];
116  char cdigest[16];
117
118  len = ntohs(chp->length);
119#ifdef DEBUG
120  logprintf("length: %d\n", len);
121#endif
122  arglen = len - sizeof(struct fsmheader);
123  cp = (char *)MBUF_CTOP(bp);
124  valsize = *cp++ & 255;
125  name = cp + valsize;
126  namelen = arglen - valsize - 1;
127  name[namelen] = 0;
128  LogPrintf(LOG_PHASE, " Valsize = %d, Name = %s\n", valsize, name);
129
130  /*
131   * Get a secret key corresponds to the peer
132   */
133  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
134
135  switch (chp->code) {
136  case CHAP_CHALLENGE:
137    if (keyp) {
138      keylen = strlen(keyp);
139    } else {
140      keylen = strlen(VarAuthKey);
141      keyp = VarAuthKey;
142    }
143    name = VarAuthName;
144    namelen = strlen(VarAuthName);
145    argp = malloc(1 + valsize + namelen);
146    digest = argp;
147    *digest++ = 16;		/* value size */
148    ap = answer;
149    *ap++ = chp->id;
150    bcopy(keyp, ap, keylen);
151    ap += keylen;
152    bcopy(cp, ap, valsize);
153#ifdef DEBUG
154    DumpDigest("recv", ap, valsize);
155#endif
156    ap += valsize;
157    MD5Init(&context);
158    MD5Update(&context, answer, ap - answer);
159    MD5Final(digest, &context);
160#ifdef DEBUG
161    DumpDigest("answer", digest, 16);
162#endif
163    bcopy(name, digest + 16, namelen);
164    ap += namelen;
165    /* Send answer to the peer */
166    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
167    break;
168  case CHAP_RESPONSE:
169    if (keyp) {
170      /*
171       * Compute correct digest value
172       */
173      keylen = strlen(keyp);
174      ap = answer;
175      *ap++ = chp->id;
176      bcopy(keyp, ap, keylen);
177      ap += keylen;
178      MD5Init(&context);
179      MD5Update(&context, answer, ap - answer);
180      MD5Update(&context, challenge_data+1, challenge_len);
181      MD5Final(cdigest, &context);
182#ifdef DEBUG
183      DumpDigest("got", cp, 16);
184      DumpDigest("expect", cdigest, 16);
185#endif
186      /*
187       * Compare with the response
188       */
189      if (bcmp(cp, cdigest, 16) == 0) {
190	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
191	NewPhase(PHASE_NETWORK);
192	break;
193      }
194    }
195    /*
196     * Peer is not registerd, or response digest is wrong.
197     */
198    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
199    LcpClose();
200    break;
201  }
202}
203
204void
205RecvChapResult(chp, bp)
206struct fsmheader *chp;
207struct mbuf *bp;
208{
209  int len;
210  struct lcpstate *lcp = &LcpInfo;
211
212  len = ntohs(chp->length);
213#ifdef DEBUG
214  logprintf("length: %d\n", len);
215#endif
216  if (chp->code == CHAP_SUCCESS) {
217    if (lcp->auth_iwait == PROTO_CHAP) {
218      lcp->auth_iwait = 0;
219      if (lcp->auth_ineed == 0)
220	NewPhase(PHASE_NETWORK);
221    }
222  } else {
223    /*
224     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
225     */
226    ;
227  }
228}
229
230void
231ChapInput(struct mbuf *bp)
232{
233  int len = plength(bp);
234  struct fsmheader *chp;
235
236  if (len >= sizeof(struct fsmheader)) {
237    chp = (struct fsmheader *)MBUF_CTOP(bp);
238    if (len >= ntohs(chp->length)) {
239      if (chp->code < 1 || chp->code > 4)
240	chp->code = 0;
241      LogPrintf(LOG_LCP, "ChapInput: %s\n", chapcodes[chp->code]);
242
243      bp->offset += sizeof(struct fsmheader);
244      bp->cnt -= sizeof(struct fsmheader);
245
246      switch (chp->code) {
247      case CHAP_CHALLENGE:
248      case CHAP_RESPONSE:
249	RecvChapTalk(chp, bp);
250	break;
251      case CHAP_SUCCESS:
252      case CHAP_FAILURE:
253	RecvChapResult(chp, bp);
254	break;
255      }
256    }
257  }
258  pfree(bp);
259}
260