Annotation of embedaddon/mpd/src/chap.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * chap.c
4: *
5: * Written by Toshiharu OHNO <tony-o@iij.ad.jp>
6: * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
7: * See ``COPYRIGHT.iij''
8: *
9: * Rewritten by Archie Cobbs <archie@freebsd.org>
10: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
11: * See ``COPYRIGHT.whistle''
12: */
13:
14: #include "ppp.h"
15: #include "auth.h"
16: #include "msoft.h"
17: #include "util.h"
18: #include <openssl/md5.h>
19:
20: /*
21: * INTERNAL FUNCTIONS
22: */
23:
24: static int ChapHash(Link l, int alg, u_char *hash_value, u_char id,
25: const char *username, const char *secret,
26: const u_char *challenge, int clen, int local);
27: static int ChapHashAgree(int alg, const u_char *self, int slen,
28: const u_char *peer, int plen);
29: static int ChapParsePkt(const char *pref, const u_char *pkt, const int pkt_len,
30: char *peer_name, u_char *chap_value,
31: int *chap_value_size);
32: static char *ChapGetSecret(Link l, int alg, char *password);
33: static void ChapGenRandom(Link l, u_char *buf, int len);
34:
35: /*
36: * INTERNAL VARIABLES
37: */
38:
39: static const u_char gIdBytes[] = { 0x3b, 0x1e, 0x68 };
40:
41: /*
42: * ChapStart()
43: */
44:
45: void
46: ChapStart(Link l, int which)
47: {
48: Auth a = &l->lcp.auth;
49: ChapInfo chap = &l->lcp.auth.chap;
50: ChapParams cp = &l->lcp.auth.params.chap;
51:
52: chap->proto = PROTO_CHAP;
53:
54: if (l->originate == LINK_ORIGINATE_LOCAL)
55: a->params.msoft.chap_alg = a->self_to_peer_alg;
56: else
57: a->params.msoft.chap_alg = a->peer_to_self_alg;
58:
59: switch (which)
60: {
61: case AUTH_SELF_TO_PEER: /* Just wait for peer's challenge */
62: break;
63:
64: case AUTH_PEER_TO_SELF:
65:
66: /* Invalidate any old challenge data */
67: cp->chal_len = 0;
68:
69: /* Initialize retry counter and timer */
70: chap->next_id = 1;
71: chap->retry = AUTH_RETRIES;
72:
73: TimerInit(&chap->chalTimer, "ChalTimer",
74: l->conf.retry_timeout * SECONDS, ChapChalTimeout, l);
75: TimerStart(&chap->chalTimer);
76:
77: /* Send first challenge */
78: ChapSendChallenge(l);
79: break;
80:
81: default:
82: assert(0);
83: }
84: }
85:
86: /*
87: * ChapStop()
88: */
89:
90: void
91: ChapStop(ChapInfo chap)
92: {
93: TimerStop(&chap->chalTimer);
94: TimerStop(&chap->respTimer);
95: if (chap->resp) {
96: Freee(chap->resp);
97: chap->resp = NULL;
98: }
99: }
100:
101: /*
102: * ChapSendChallenge()
103: */
104:
105: void
106: ChapSendChallenge(Link l)
107: {
108: Auth const a = &l->lcp.auth;
109: ChapInfo chap = &a->chap;
110: ChapParams cp = &a->params.chap;
111: u_char *pkt;
112:
113: /* don't generate new challenges on re-transmit */
114: if (cp->chal_len)
115: goto send_pkt;
116:
117: /* Put random challenge data in buffer (only once for Microsoft CHAP) */
118: switch (a->peer_to_self_alg) {
119: case CHAP_ALG_MSOFT: {
120: cp->chal_len = CHAP_MSOFT_CHAL_LEN;
121: ChapGenRandom(l, cp->chal_data, cp->chal_len);
122: if (l->originate == LINK_ORIGINATE_REMOTE) {
123: memcpy(a->params.msoft.msChal, cp->chal_data, cp->chal_len);
124: }
125: }
126: break;
127: case CHAP_ALG_MSOFTv2:
128: cp->chal_len = CHAP_MSOFTv2_CHAL_LEN;
129: ChapGenRandom(l, cp->chal_data, cp->chal_len);
130: if (l->originate == LINK_ORIGINATE_REMOTE) {
131: memcpy(a->params.msoft.msChal, cp->chal_data, cp->chal_len);
132: }
133: break;
134: case CHAP_ALG_MD5:
135: cp->chal_len = random() % 32 + 16;
136: ChapGenRandom(l, cp->chal_data, cp->chal_len);
137: break;
138: default:
139: assert(0);
140: }
141: assert(cp->chal_len <= sizeof(cp->chal_data));
142:
143: send_pkt:
144: /* Build a challenge packet */
145: pkt = Malloc(MB_AUTH, 1 + cp->chal_len + strlen(a->conf.authname) + 1);
146: pkt[0] = cp->chal_len;
147: memcpy(pkt + 1, cp->chal_data, cp->chal_len);
148: memcpy(pkt + 1 + cp->chal_len,
149: a->conf.authname, strlen(a->conf.authname));
150:
151: /* Send it off */
152: AuthOutput(l, chap->proto,
153: chap->proto == PROTO_CHAP ? CHAP_CHALLENGE : EAP_REQUEST,
154: chap->next_id++, pkt,
155: 1 + cp->chal_len + strlen(a->conf.authname), 0,
156: EAP_TYPE_MD5CHAL);
157: Freee(pkt);
158: }
159:
160: /*
161: * ChapSendResponse()
162: */
163:
164: static void
165: ChapSendResponse(Link l)
166: {
167: ChapInfo chap = &l->lcp.auth.chap;
168:
169: /* Stop response timer */
170: TimerStop(&chap->respTimer);
171:
172: /* Send response (possibly again) */
173: assert(chap->resp);
174: AuthOutput(l, chap->proto,
175: chap->proto == PROTO_CHAP ? CHAP_RESPONSE : EAP_RESPONSE,
176: chap->resp_id, chap->resp, chap->resp_len, 0, EAP_TYPE_MD5CHAL);
177:
178: /* Start re-send timer (only during authenticate phase where the
179: authentication timer is still running) */
180: if (l->lcp.phase == PHASE_AUTHENTICATE) {
181: TimerInit(&chap->respTimer, "RespTimer",
182: l->conf.retry_timeout * SECONDS,
183: (void (*)(void *)) ChapSendResponse, (void *) l);
184: TimerStart(&chap->respTimer);
185: }
186: }
187:
188: /*
189: * ChapParsePkt()
190: *
191: */
192:
193: static int
194: ChapParsePkt(const char *pref, const u_char *pkt, const int pkt_len,
195: char *peer_name, u_char *chap_value, int *chap_value_size)
196: {
197: int val_len, name_len;
198:
199: /* Compute and check lengths */
200: if (pkt == NULL
201: || pkt_len < 1
202: || (val_len = pkt[0]) < 1
203: || val_len > CHAP_MAX_VAL
204: || (name_len = (pkt_len - val_len - 1)) < 0
205: || name_len > CHAP_MAX_NAME) {
206: Log(LG_AUTH, ("[%s] Bogus packet", pref));
207: return(-1);
208: }
209:
210: /* Extract stuff */
211: memcpy(peer_name, pkt + 1 + val_len, name_len);
212: peer_name[name_len] = 0;
213: memcpy(chap_value, pkt + 1, val_len);
214: *chap_value_size = val_len;
215: Log(LG_AUTH, ("[%s] Name: \"%s\"", pref, peer_name));
216: #if 0
217: Log(LG_AUTH, ("[%s] Value: %d bytes", pref, *chap_value_size));
218: #endif
219: return(0);
220: }
221:
222: /*
223: * ChapChalTimeout()
224: *
225: * Timer expired for reply to challenge packet
226: */
227:
228: void
229: ChapChalTimeout(void *ptr)
230: {
231: Link const l = (Link) ptr;
232: ChapInfo const chap = &l->lcp.auth.chap;
233:
234: if (--chap->retry > 0) {
235: TimerStart(&chap->chalTimer);
236: ChapSendChallenge(l);
237: }
238: }
239:
240: /*
241: * ChapInput()
242: */
243:
244: void
245: ChapInput(Link l, AuthData auth, const u_char *pkt, u_short len)
246: {
247: Auth const a = &l->lcp.auth;
248: ChapInfo const chap = &a->chap;
249: char peer_name[CHAP_MAX_NAME + 1];
250: char password[AUTH_MAX_PASSWORD];
251: u_char hash_value[CHAP_MAX_VAL];
252: int hash_value_size;
253:
254: chap->proto = auth->proto;
255:
256: switch (auth->code) {
257: case CHAP_CHALLENGE:
258: {
259: u_char value[CHAP_MAX_VAL]; /* Chap packet */
260: int value_len; /* Packet length */
261: char *name, *secret;
262: int name_len, idFail;
263:
264: auth->alg = a->self_to_peer_alg;
265:
266: /* Check packet */
267: if ((a->self_to_peer != PROTO_CHAP && a->self_to_peer != PROTO_EAP)
268: || l->lcp.phase != PHASE_AUTHENTICATE)
269: Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
270: if (ChapParsePkt(l->name, pkt, len, peer_name, value, &value_len) < 0)
271: break;
272:
273: /* Never respond to our own outstanding challenge */
274: if (value_len == auth->params.chap.chal_len
275: && !memcmp(value, auth->params.chap.chal_data, auth->params.chap.chal_len)) {
276: Log(LG_AUTH, ("[%s] CHAP: SECURITY: peer sent same challenge! Ignoring.", l->name));
277: break;
278: }
279:
280: /* Don't respond to a challenge that looks like it came from
281: us and has the wrong origination value embedded in it. This
282: avoids a security hole associated with using the same CHAP
283: password to authenticate in both directions on a link. */
284: idFail = 0;
285: do {
286: char buf[sizeof(gIdBytes)];
287: int chalOrig;
288:
289: /* Check challenge length */
290: if (value_len < sizeof(buf))
291: break;
292:
293: /* Copy challenge bits and extract origination value */
294: memcpy(buf, value, sizeof(buf));
295: chalOrig = (buf[0] >> 6) & 0x03;
296: buf[0] &= 0x3f;
297:
298: /* Check for same ID bytes in the challenge */
299: if (memcmp(buf, gIdBytes, sizeof(gIdBytes)) != 0)
300: break;
301:
302: /* ID bytes match; origination value must be opposite. Note this
303: assumes that if we can tell the origination direction of a link,
304: then so can the peer. */
305: switch (l->originate) {
306: case LINK_ORIGINATE_LOCAL:
307: idFail = (chalOrig != LINK_ORIGINATE_REMOTE);
308: break;
309: case LINK_ORIGINATE_REMOTE:
310: idFail = (chalOrig != LINK_ORIGINATE_LOCAL);
311: break;
312: case LINK_ORIGINATE_UNKNOWN:
313: default:
314: idFail = 0; /* XXX assumes leased line, etc is secure */
315: break;
316: }
317:
318: /* Log failure */
319: if (idFail) {
320: Log(LG_AUTH,
321: ("[%s] CHAP: SECURITY: origination value check failed (%s,%s). Ignoring.",
322: l->name,
323: LINK_ORIGINATION(l->originate),
324: LINK_ORIGINATION(chalOrig)));
325: break;
326: }
327: } while (0);
328: if (idFail)
329: break;
330:
331: /*
332: * Name we use to authenticate ourselves:
333: *
334: * 1. The manually configured authname ("set authname ...")
335: * 2. The peer's supplied name
336: */
337: if (*auth->conf.authname)
338: name = auth->conf.authname;
339: else
340: name = peer_name;
341: name_len = strlen(name);
342: Log(LG_AUTH, ("[%s] CHAP: Using authname \"%s\"", l->name, name));
343:
344: strlcpy(auth->params.authname, name, sizeof(auth->params.authname));
345:
346: /* Get the corresponding secret */
347: if ((strcmp(auth->conf.authname, auth->params.authname) == 0) &&
348: auth->conf.password[0] != 0) {
349: strlcpy(password, auth->conf.password, sizeof(password));
350: } else if (AuthGetData(auth->params.authname, password,
351: sizeof(password), NULL, NULL) < 0) {
352: Log(LG_AUTH, ("[%s] CHAP: Warning: no secret for \"%s\" found",
353: l->name,
354: auth->params.authname));
355: break;
356: }
357:
358: secret = ChapGetSecret(l, a->self_to_peer_alg, password);
359:
360: /* Get hash value */
361: if ((hash_value_size = ChapHash(l, a->self_to_peer_alg, hash_value,
362: auth->id, name, secret, value, value_len, 1)) < 0) {
363: Log(LG_AUTH, ("[%s] CHAP: Hash failure", l->name));
364: break;
365: }
366:
367: /* Need to remember MS-CHAP stuff for use with MPPE encryption */
368: switch (a->self_to_peer_alg) {
369: case CHAP_ALG_MSOFT:
370: if (l->originate == LINK_ORIGINATE_LOCAL)
371: memcpy(a->params.msoft.msChal, value, CHAP_MSOFT_CHAL_LEN);
372: break;
373: case CHAP_ALG_MSOFTv2:
374: if (l->originate == LINK_ORIGINATE_LOCAL) {
375: memcpy(a->params.msoft.msChal, value, CHAP_MSOFTv2_CHAL_LEN);
376: memcpy(a->params.msoft.ntResp,
377: hash_value + offsetof(struct mschapv2value, ntHash),
378: CHAP_MSOFTv2_RESP_LEN);
379: }
380: break;
381: }
382:
383: /* Build response packet */
384: if (chap->resp)
385: Freee(chap->resp);
386: chap->resp = Malloc(MB_AUTH, 1 + hash_value_size + name_len);
387: chap->resp[0] = hash_value_size;
388: memcpy(&chap->resp[1], hash_value, hash_value_size);
389: memcpy(&chap->resp[1 + hash_value_size], name, name_len);
390: chap->resp_len = 1 + hash_value_size + name_len;
391: chap->resp_id = auth->id;
392:
393: /* Send response to peer */
394: ChapSendResponse(l);
395: }
396: break;
397:
398: case CHAP_RESPONSE:
399: auth->alg = a->peer_to_self_alg;
400:
401: /* Stop challenge timer */
402: TimerStop(&chap->chalTimer);
403:
404: /* Check response */
405: if ((a->peer_to_self != PROTO_CHAP && a->peer_to_self != PROTO_EAP)
406: || l->lcp.phase != PHASE_AUTHENTICATE)
407: Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
408: if (ChapParsePkt(l->name, pkt, len,
409: peer_name, auth->params.chap.value, &auth->params.chap.value_len) < 0) {
410: auth->why_fail = AUTH_FAIL_INVALID_PACKET;
411: ChapInputFinish(l, auth);
412: return;
413: }
414:
415: /* Strip MS domain if any */
416: if (!Enabled(&l->conf.options, LINK_CONF_MSDOMAIN))
417: if (a->peer_to_self_alg == CHAP_ALG_MSOFT
418: || a->peer_to_self_alg == CHAP_ALG_MSOFTv2) {
419: char *s;
420:
421: if ((s = strrchr(peer_name, '\\')))
422: memmove(peer_name, s + 1, strlen(s) + 1);
423: }
424:
425: strlcpy(auth->params.authname, peer_name, sizeof(auth->params.authname));
426:
427: auth->finish = ChapInputFinish;
428: AuthAsyncStart(l, auth);
429: return;
430:
431: case CHAP_SUCCESS:
432: case CHAP_FAILURE:
433:
434: auth->alg = a->self_to_peer_alg;
435:
436: /* Stop response timer */
437: TimerStop(&chap->respTimer);
438: if (chap->resp) {
439: Freee(chap->resp);
440: chap->resp = NULL;
441: }
442:
443: /* Appropriate? */
444: if (a->self_to_peer != PROTO_CHAP
445: || l->lcp.phase != PHASE_AUTHENTICATE) {
446: Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
447: break;
448: }
449:
450: /* Log message */
451: ShowMesg(LG_AUTH, l->name, (char *) pkt, len);
452: AuthFinish(l, AUTH_SELF_TO_PEER, auth->code == CHAP_SUCCESS);
453: break;
454:
455: case CHAP_MS_V1_CHANGE_PW:
456: Log(LG_AUTH, ("[%s] CHAP: Sorry changing passwords using MS-CHAPv1 is not yet implemented",
457: l->name));
458: goto badResponse;
459:
460: case CHAP_MS_V2_CHANGE_PW:
461: Log(LG_AUTH, ("[%s] CHAP: Sorry changing passwords using MS-CHAPv2 is not yet implemented",
462: l->name));
463: goto badResponse;
464:
465: default:
466: Log(LG_AUTH, ("[%s] CHAP: unknown code %d", l->name, auth->code));
467: break;
468: }
469: AuthDataDestroy(auth);
470: return;
471:
472: badResponse:
473: {
474: char failMesg[64];
475:
476: auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
477: AuthFailMsg(auth, failMesg, sizeof(failMesg));
478: AuthOutput(l, auth->proto, auth->proto == PROTO_CHAP ? CHAP_FAILURE : EAP_FAILURE,
479: auth->id, (u_char *)failMesg, strlen(failMesg), 0, EAP_TYPE_MD5CHAL);
480: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
481: AuthDataDestroy(auth);
482: }
483: }
484:
485: /*
486: * ChapInputFinish()
487: *
488: * Possible return point from the asynch auth handler.
489: *
490: */
491:
492: void
493: ChapInputFinish(Link l, AuthData auth)
494: {
495: Auth a = &l->lcp.auth;
496: ChapInfo chap = &a->chap;
497: u_char hash_value[CHAP_MAX_VAL];
498: int hash_value_size;
499: char ackMesg[128], *secret;
500:
501: Log(LG_AUTH, ("[%s] CHAP: Auth return status: %s",
502: l->name, AuthStatusText(auth->status)));
503:
504: if (auth->status == AUTH_STATUS_BUSY) {
505: AuthDataDestroy(auth);
506: return;
507: }
508:
509: if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2 &&
510: auth->mschapv2resp != NULL) {
511: strlcpy(ackMesg, auth->mschapv2resp, sizeof(ackMesg));
512: } else if (auth->reply_message != NULL) {
513: strlcpy(ackMesg, auth->reply_message, sizeof(ackMesg));
514: } else {
515: strlcpy(ackMesg, AUTH_MSG_WELCOME, sizeof(ackMesg));
516: }
517:
518: if (auth->status == AUTH_STATUS_FAIL)
519: goto badResponse;
520: else if (auth->status == AUTH_STATUS_SUCCESS)
521: goto goodResponse;
522:
523: /* Copy in peer challenge for MS-CHAPv2 */
524: if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2)
525: memcpy(hash_value, a->params.chap.value, 16);
526:
527: secret = ChapGetSecret(l, a->peer_to_self_alg, a->params.password);
528:
529: /* Get expected hash value */
530: if ((hash_value_size = ChapHash(l, a->peer_to_self_alg, hash_value, auth->id,
531: a->params.authname, secret, a->params.chap.chal_data, a->params.chap.chal_len,
532: 0)) < 0) {
533: Log(LG_AUTH, ("[%s] CHAP: Hash failure", l->name));
534: auth->why_fail = AUTH_FAIL_INVALID_PACKET;
535: goto badResponse;
536: }
537:
538: /* Compare with peer's response */
539: if (a->params.chap.chal_len == 0
540: || !ChapHashAgree(a->peer_to_self_alg, hash_value, hash_value_size,
541: a->params.chap.value, a->params.chap.value_len)) {
542: Log(LG_AUTH, ("[%s] CHAP: Invalid response", l->name));
543: auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
544: goto badResponse;
545: }
546:
547: /* Response is good */
548: Log(LG_AUTH, ("[%s] CHAP: Response is valid", l->name));
549:
550: if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2) {
551: struct mschapv2value *const pv = (struct mschapv2value *)a->params.chap.value;
552: char hex[41];
553: u_char authresp[20];
554: int i;
555:
556: /* Generate MS-CHAPv2 'authenticator response' */
557: GenerateAuthenticatorResponse(a->params.msoft.nt_hash, pv->ntHash,
558: pv->peerChal, a->params.chap.chal_data, a->params.authname, authresp);
559: for (i = 0; i < 20; i++)
560: sprintf(hex + (i * 2), "%02X", authresp[i]);
561: /* If we have reply message, send it. */
562: if (auth->reply_message != NULL) {
563: snprintf(ackMesg, sizeof(ackMesg), "S=%s M=%s",
564: hex, auth->reply_message);
565: } else
566: snprintf(ackMesg, sizeof(ackMesg), "S=%s", hex);
567: }
568:
569: goodResponse:
570: #ifdef USE_OPIE
571: /* make a dummy verify to force an update of the opiekeys database */
572: if (a->params.authentic == AUTH_CONF_OPIE)
573: opieverify(&auth->opie.data, a->params.password);
574: #endif
575:
576: /* Need to remember MS-CHAP stuff for use with MPPE encryption */
577: if (l->originate == LINK_ORIGINATE_REMOTE &&
578: a->peer_to_self_alg == CHAP_ALG_MSOFTv2 &&
579: !memcmp(a->params.msoft.ntResp, gMsoftZeros, CHAP_MSOFTv2_RESP_LEN)) {
580: memcpy(a->params.msoft.ntResp,
581: a->params.chap.value + offsetof(struct mschapv2value, ntHash),
582: CHAP_MSOFTv2_RESP_LEN);
583: }
584:
585: Log(LG_AUTH, ("[%s] CHAP: Reply message: %s", l->name, ackMesg));
586: AuthOutput(l, chap->proto, chap->proto == PROTO_CHAP ? CHAP_SUCCESS : EAP_SUCCESS,
587: auth->id, (u_char *)ackMesg, strlen(ackMesg), 0, EAP_TYPE_MD5CHAL);
588: AuthFinish(l, AUTH_PEER_TO_SELF, TRUE);
589: AuthDataDestroy(auth);
590: return;
591:
592: badResponse:
593: {
594: char failMesg[64];
595:
596: AuthFailMsg(auth, failMesg, sizeof(failMesg));
597: Log(LG_AUTH, ("[%s] CHAP: Reply message: %s", l->name, failMesg));
598: AuthOutput(l, chap->proto, chap->proto == PROTO_CHAP ? CHAP_FAILURE : EAP_FAILURE,
599: auth->id, (u_char *)failMesg, strlen(failMesg), 0, EAP_TYPE_MD5CHAL);
600: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
601: AuthDataDestroy(auth);
602: }
603: }
604:
605: /*
606: * ChapGetSecret()
607: *
608: * returns either the plaintext pass for CHAP-MD5
609: * or the NT-Hash for MS-CHAP. Set's credentials for
610: * MPPE-Key derivation
611: */
612:
613: static char *
614: ChapGetSecret(Link l, int alg, char *password)
615: {
616: Auth a = &l->lcp.auth;
617: char *pw;
618:
619: if (alg == CHAP_ALG_MD5)
620: pw = password;
621: else {
622: if (!a->params.msoft.has_nt_hash)
623: {
624: NTPasswordHash(password, a->params.msoft.nt_hash);
625: NTPasswordHashHash(a->params.msoft.nt_hash, a->params.msoft.nt_hash_hash);
626: LMPasswordHash(password, a->params.msoft.lm_hash);
627: a->params.msoft.has_nt_hash = TRUE;
628: a->params.msoft.has_lm_hash = TRUE;
629: }
630:
631: pw = (char *) a->params.msoft.nt_hash;
632: }
633:
634: return pw;
635: }
636:
637: /*
638: * ChapGenRandom()
639: */
640:
641: static void
642: ChapGenRandom(Link l, u_char *buf, int len)
643: {
644: int k;
645:
646: /* Prefix with our unique ID plus origination value */
647: for (k = 0; k < sizeof(gIdBytes) && k < len; k++)
648: buf[k] = gIdBytes[k];
649: buf[0] |= (l->originate & 0x03) << 6;
650:
651: /* Fill the rest with semi-random bytes */
652: for (; k < len; k++)
653: buf[k] = random() & 0xff;
654: }
655:
656: /*
657: * ChapHash()
658: */
659:
660: static int
661: ChapHash(Link l, int alg, u_char *hash_value, u_char id, const char *username,
662: const char *secret, const u_char *challenge, int clen, int local)
663: {
664: int hash_size;
665:
666: switch (alg) {
667: case CHAP_ALG_MD5:
668: {
669: MD5_CTX md5ctx;
670:
671: MD5_Init(&md5ctx);
672: MD5_Update(&md5ctx, &id, 1);
673: MD5_Update(&md5ctx, secret, strlen(secret));
674: MD5_Update(&md5ctx, challenge, clen);
675: MD5_Final(hash_value, &md5ctx);
676: hash_size = 16;
677: }
678: break;
679:
680: case CHAP_ALG_MSOFT:
681: {
682: struct mschapvalue *const val = (struct mschapvalue *) hash_value;
683:
684: /* We don't generate the LANManager hash because it's too insecure */
685: memset(val->lmHash, 0, sizeof(val->lmHash));
686: NTChallengeResponse(challenge, secret, val->ntHash);
687: val->useNT = 1;
688: hash_size = 49;
689: }
690: break;
691: case CHAP_ALG_MSOFTv2:
692: {
693: struct mschapv2value *const val = (struct mschapv2value *) hash_value;
694: const char *s;
695:
696: if ((s = strrchr(username, '\\')) != NULL)
697: username = s + 1;
698: if (local) { /* generate reverse 'peer challenge' */
699: ChapGenRandom(l, val->peerChal, sizeof(val->peerChal));
700: memset(val->reserved, 0, sizeof(val->reserved));
701: }
702: GenerateNTResponse(challenge,
703: val->peerChal, username, secret, val->ntHash);
704:
705: hash_size = 49;
706: }
707: break;
708:
709: default:
710: return(-1);
711: }
712:
713: /* Done */
714: return(hash_size);
715: }
716:
717: /*
718: * ChapHashAgree()
719: */
720:
721: static int
722: ChapHashAgree(int alg, const u_char *self, int slen,
723: const u_char *peer, int plen)
724: {
725: switch (alg)
726: {
727: case CHAP_ALG_MD5:
728: return(slen == plen && !memcmp(self, peer, slen));
729:
730: case CHAP_ALG_MSOFT:
731: {
732: struct mschapvalue *const sv = (struct mschapvalue *) self;
733: struct mschapvalue *const pv = (struct mschapvalue *) peer;
734:
735: if (slen != 49 || plen != 49)
736: return(0);
737: if (sv->useNT != 1 || pv->useNT != 1)
738: return(0);
739: return(!memcmp(&sv->ntHash, &pv->ntHash, sizeof(sv->ntHash)));
740: }
741: case CHAP_ALG_MSOFTv2:
742: {
743: struct mschapv2value *const sv =(struct mschapv2value *) self;
744: struct mschapv2value *const pv =(struct mschapv2value *) peer;
745:
746: if (slen != 49 || plen != 49)
747: return(0);
748: return(!memcmp(&sv->ntHash, &pv->ntHash, sizeof(sv->ntHash)));
749: }
750:
751: default:
752: return(0);
753: }
754: }
755:
756: /*
757: * ChapCode()
758: */
759:
760: const char *
761: ChapCode(int code, char *buf, size_t len)
762: {
763: switch (code) {
764: case CHAP_CHALLENGE:
765: strlcpy(buf, "CHALLENGE", len);
766: break;
767: case CHAP_RESPONSE:
768: strlcpy(buf, "RESPONSE", len);
769: break;
770: case CHAP_SUCCESS:
771: strlcpy(buf, "SUCCESS", len);
772: break;
773: case CHAP_FAILURE:
774: strlcpy(buf, "FAILURE", len);
775: break;
776: default:
777: snprintf(buf, len, "code%d", code);
778: }
779: return(buf);
780: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>