10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * chap_ms.c - Microsoft MS-CHAP compatible implementation.
30Sstevel@tonic-gate *
4*5619Sdarrenm * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
5*5619Sdarrenm * Use is subject to license terms.
60Sstevel@tonic-gate *
70Sstevel@tonic-gate * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
80Sstevel@tonic-gate * http://www.strataware.com/
90Sstevel@tonic-gate *
100Sstevel@tonic-gate * All rights reserved.
110Sstevel@tonic-gate *
120Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
130Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are
140Sstevel@tonic-gate * duplicated in all such forms and that any documentation,
150Sstevel@tonic-gate * advertising materials, and other materials related to such
160Sstevel@tonic-gate * distribution and use acknowledge that the software was developed
170Sstevel@tonic-gate * by Eric Rosenquist. The name of the author may not be used to
180Sstevel@tonic-gate * endorse or promote products derived from this software without
190Sstevel@tonic-gate * specific prior written permission.
200Sstevel@tonic-gate *
210Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
220Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
230Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * This module implements MS-CHAPv1 (RFC 2433) and MS-CHAPv2 (RFC 2759).
280Sstevel@tonic-gate *
290Sstevel@tonic-gate * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
300Sstevel@tonic-gate *
310Sstevel@tonic-gate * Implemented LANManager type password response to MS-CHAP challenges.
320Sstevel@tonic-gate * Now pppd provides both NT style and LANMan style blocks, and the
330Sstevel@tonic-gate * prefered is set by option "ms-lanman". Default is to use NT.
340Sstevel@tonic-gate * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
350Sstevel@tonic-gate *
360Sstevel@tonic-gate * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
370Sstevel@tonic-gate *
380Sstevel@tonic-gate * Modifications by James Carlson / james.d.carlson@sun.com, June 1st, 2000.
390Sstevel@tonic-gate *
400Sstevel@tonic-gate * Added MS-CHAPv2 support.
410Sstevel@tonic-gate */
420Sstevel@tonic-gate
430Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
440Sstevel@tonic-gate #define RCSID "$Id: chap_ms.c,v 1.15 1999/08/13 06:46:12 paulus Exp $"
450Sstevel@tonic-gate
460Sstevel@tonic-gate #if defined(CHAPMS) || defined(CHAPMSV2)
470Sstevel@tonic-gate
480Sstevel@tonic-gate #include <stdio.h>
490Sstevel@tonic-gate #include <stdlib.h>
500Sstevel@tonic-gate #include <string.h>
510Sstevel@tonic-gate #include <ctype.h>
520Sstevel@tonic-gate #include <sys/types.h>
530Sstevel@tonic-gate #include <sys/time.h>
540Sstevel@tonic-gate #include <unistd.h>
550Sstevel@tonic-gate #ifdef HAVE_CRYPT_H
560Sstevel@tonic-gate #include <crypt.h>
570Sstevel@tonic-gate #endif
580Sstevel@tonic-gate
590Sstevel@tonic-gate #ifdef CHAPMSV2
600Sstevel@tonic-gate #include "sha1.h"
610Sstevel@tonic-gate #endif
620Sstevel@tonic-gate
630Sstevel@tonic-gate #ifndef USE_CRYPT
640Sstevel@tonic-gate #include <des.h>
650Sstevel@tonic-gate #endif
660Sstevel@tonic-gate
670Sstevel@tonic-gate #include "pppd.h"
680Sstevel@tonic-gate #include "chap.h"
690Sstevel@tonic-gate #include "chap_ms.h"
700Sstevel@tonic-gate #include "md4.h"
710Sstevel@tonic-gate
720Sstevel@tonic-gate #if !defined(lint) && !defined(_lint)
730Sstevel@tonic-gate static const char rcsid[] = RCSID;
740Sstevel@tonic-gate #endif
750Sstevel@tonic-gate
760Sstevel@tonic-gate typedef struct {
770Sstevel@tonic-gate u_char LANManResp[24];
780Sstevel@tonic-gate u_char NTResp[24];
790Sstevel@tonic-gate u_char UseNT; /* If 1, ignore the LANMan response field */
800Sstevel@tonic-gate } MS_ChapResponse;
810Sstevel@tonic-gate /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
820Sstevel@tonic-gate in case this struct gets padded. */
830Sstevel@tonic-gate
840Sstevel@tonic-gate typedef struct {
850Sstevel@tonic-gate u_char PeerChallenge[16];
860Sstevel@tonic-gate u_char MustBeZero[8];
870Sstevel@tonic-gate u_char NTResp[24];
880Sstevel@tonic-gate u_char Flags; /* Should be zero (Win98 sends 04) */
890Sstevel@tonic-gate } MS_Chapv2Response;
900Sstevel@tonic-gate /* We use MS_CHAPV2_RESPONSE_LEN, rather than sizeof(MS_Chapv2Response),
910Sstevel@tonic-gate in case this struct gets padded. */
920Sstevel@tonic-gate
930Sstevel@tonic-gate static void ChallengeResponse __P((u_char *, u_char *, u_char *));
940Sstevel@tonic-gate static void DesEncrypt __P((u_char *, u_char *, u_char *));
950Sstevel@tonic-gate static void MakeKey __P((u_char *, u_char *));
960Sstevel@tonic-gate static u_char Get7Bits __P((u_char *, int));
970Sstevel@tonic-gate #ifdef CHAPMS
980Sstevel@tonic-gate static void ChapMS_NT __P((u_char *, char *, int, MS_ChapResponse *));
990Sstevel@tonic-gate #ifdef MSLANMAN
1000Sstevel@tonic-gate static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
1010Sstevel@tonic-gate #endif
1020Sstevel@tonic-gate #endif
1030Sstevel@tonic-gate #ifdef CHAPMSV2
1040Sstevel@tonic-gate static void ChapMSv2_NT __P((char *, u_char *, char *, int,
1050Sstevel@tonic-gate MS_Chapv2Response *));
1060Sstevel@tonic-gate #endif
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate #ifdef USE_CRYPT
1090Sstevel@tonic-gate static void Expand __P((u_char *, char *));
1100Sstevel@tonic-gate static void Collapse __P((char *, u_char *));
1110Sstevel@tonic-gate #endif
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate #if defined(MSLANMAN) && defined(CHAPMS)
1140Sstevel@tonic-gate bool ms_lanman = 0; /* Use LanMan password instead of NT */
1150Sstevel@tonic-gate /* Has meaning only with MS-CHAP challenges */
1160Sstevel@tonic-gate #endif
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate #ifdef CHAPMSV2
1190Sstevel@tonic-gate /* Specially-formatted Microsoft CHAP response message. */
1200Sstevel@tonic-gate static char status_message[256];
1210Sstevel@tonic-gate #endif
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate static void
ChallengeResponse(challenge,pwHash,response)1240Sstevel@tonic-gate ChallengeResponse(challenge, pwHash, response)
1250Sstevel@tonic-gate u_char *challenge; /* IN 8 octets */
1260Sstevel@tonic-gate u_char *pwHash; /* IN 16 octets */
1270Sstevel@tonic-gate u_char *response; /* OUT 24 octets */
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate u_char ZPasswordHash[21];
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate BZERO(ZPasswordHash, sizeof(ZPasswordHash));
1320Sstevel@tonic-gate BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate #if 0
1350Sstevel@tonic-gate dbglog("ChallengeResponse - ZPasswordHash %.*B",
1360Sstevel@tonic-gate sizeof(ZPasswordHash), ZPasswordHash);
1370Sstevel@tonic-gate #endif
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
1400Sstevel@tonic-gate DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
1410Sstevel@tonic-gate DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate #if 0
1440Sstevel@tonic-gate dbglog("ChallengeResponse - response %.24B", response);
1450Sstevel@tonic-gate #endif
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate #ifdef USE_CRYPT
1500Sstevel@tonic-gate static void
DesEncrypt(clear,key,cipher)1510Sstevel@tonic-gate DesEncrypt(clear, key, cipher)
1520Sstevel@tonic-gate u_char *clear; /* IN 8 octets */
1530Sstevel@tonic-gate u_char *key; /* IN 7 octets */
1540Sstevel@tonic-gate u_char *cipher; /* OUT 8 octets */
1550Sstevel@tonic-gate {
1560Sstevel@tonic-gate u_char des_key[8];
1570Sstevel@tonic-gate char crypt_key[66];
1580Sstevel@tonic-gate char des_input[66];
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate MakeKey(key, des_key);
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate Expand(des_key, crypt_key);
1630Sstevel@tonic-gate setkey(crypt_key);
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate #if 0
1660Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
1670Sstevel@tonic-gate #endif
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate Expand(clear, des_input);
1700Sstevel@tonic-gate encrypt(des_input, 0);
1710Sstevel@tonic-gate Collapse(des_input, cipher);
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate #if 0
1740Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
1750Sstevel@tonic-gate #endif
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate #else /* USE_CRYPT */
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate static void
DesEncrypt(clear,key,cipher)1810Sstevel@tonic-gate DesEncrypt(clear, key, cipher)
1820Sstevel@tonic-gate u_char *clear; /* IN 8 octets */
1830Sstevel@tonic-gate u_char *key; /* IN 7 octets */
1840Sstevel@tonic-gate u_char *cipher; /* OUT 8 octets */
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate des_cblock des_key;
1870Sstevel@tonic-gate des_key_schedule key_schedule;
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate MakeKey(key, des_key);
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate des_set_key(&des_key, key_schedule);
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate #if 0
1940Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
1950Sstevel@tonic-gate #endif
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate #if 0
2000Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
2010Sstevel@tonic-gate #endif
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate #endif /* USE_CRYPT */
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate
Get7Bits(input,startBit)2070Sstevel@tonic-gate static u_char Get7Bits(input, startBit)
2080Sstevel@tonic-gate u_char *input;
2090Sstevel@tonic-gate int startBit;
2100Sstevel@tonic-gate {
2110Sstevel@tonic-gate register unsigned int word;
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate word = (unsigned)input[startBit / 8] << 8;
2140Sstevel@tonic-gate word |= (unsigned)input[startBit / 8 + 1];
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate word >>= 15 - (startBit % 8 + 7);
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate return word & 0xFE;
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate #ifdef USE_CRYPT
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate /* in == 8-byte string (expanded version of the 56-bit key)
2240Sstevel@tonic-gate * out == 64-byte string where each byte is either 1 or 0
2250Sstevel@tonic-gate * Note that the low-order "bit" is always ignored by by setkey()
2260Sstevel@tonic-gate */
Expand(in,out)2270Sstevel@tonic-gate static void Expand(in, out)
2280Sstevel@tonic-gate u_char *in;
2290Sstevel@tonic-gate char *out;
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate int j, c;
2320Sstevel@tonic-gate int i;
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate for(i = 0; i < 64; in++){
2350Sstevel@tonic-gate c = *in;
2360Sstevel@tonic-gate for(j = 7; j >= 0; j--)
2370Sstevel@tonic-gate *out++ = (c >> j) & 01;
2380Sstevel@tonic-gate i += 8;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate /* The inverse of Expand
2430Sstevel@tonic-gate */
Collapse(in,out)2440Sstevel@tonic-gate static void Collapse(in, out)
2450Sstevel@tonic-gate char *in;
2460Sstevel@tonic-gate u_char *out;
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate int j;
2490Sstevel@tonic-gate int i;
2500Sstevel@tonic-gate unsigned int c;
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate for (i = 0; i < 64; i += 8, out++) {
2530Sstevel@tonic-gate c = 0;
2540Sstevel@tonic-gate for (j = 7; j >= 0; j--, in++)
2550Sstevel@tonic-gate c |= *(u_char *)in << j;
2560Sstevel@tonic-gate *out = c & 0xff;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate #endif
2600Sstevel@tonic-gate
MakeKey(key,des_key)2610Sstevel@tonic-gate static void MakeKey(key, des_key)
2620Sstevel@tonic-gate u_char *key; /* IN 56 bit DES key missing parity bits */
2630Sstevel@tonic-gate u_char *des_key; /* OUT 64 bit DES key with parity bits added */
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate des_key[0] = Get7Bits(key, 0);
2660Sstevel@tonic-gate des_key[1] = Get7Bits(key, 7);
2670Sstevel@tonic-gate des_key[2] = Get7Bits(key, 14);
2680Sstevel@tonic-gate des_key[3] = Get7Bits(key, 21);
2690Sstevel@tonic-gate des_key[4] = Get7Bits(key, 28);
2700Sstevel@tonic-gate des_key[5] = Get7Bits(key, 35);
2710Sstevel@tonic-gate des_key[6] = Get7Bits(key, 42);
2720Sstevel@tonic-gate des_key[7] = Get7Bits(key, 49);
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate #ifndef USE_CRYPT
2750Sstevel@tonic-gate des_set_odd_parity((des_cblock *)des_key);
2760Sstevel@tonic-gate #endif
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate #if 0
2790Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
2800Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
2810Sstevel@tonic-gate #endif
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate #ifdef CHAPMS
2850Sstevel@tonic-gate static void
ChapMS_NT(rchallenge,secret,secret_len,response)2860Sstevel@tonic-gate ChapMS_NT(rchallenge, secret, secret_len, response)
2870Sstevel@tonic-gate u_char *rchallenge;
2880Sstevel@tonic-gate char *secret;
2890Sstevel@tonic-gate int secret_len;
2900Sstevel@tonic-gate MS_ChapResponse *response;
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate int i;
293*5619Sdarrenm #if defined(__NetBSD__) || defined(HAVE_LIBMD)
2940Sstevel@tonic-gate /* NetBSD uses the libc md4 routines which take bytes instead of bits */
2950Sstevel@tonic-gate int mdlen = secret_len * 2;
2960Sstevel@tonic-gate #else
2970Sstevel@tonic-gate int mdlen = secret_len * 2 * 8;
2980Sstevel@tonic-gate #endif
2990Sstevel@tonic-gate MD4_CTX md4Context;
3000Sstevel@tonic-gate u_char hash[MD4_SIGNATURE_SIZE];
3010Sstevel@tonic-gate u_char unicodePassword[MAX_NT_PASSWORD * 2];
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate /* Initialize the Unicode version of the secret (== password). */
3040Sstevel@tonic-gate /* This implicitly supports 8-bit ISO8859/1 characters. */
3050Sstevel@tonic-gate BZERO(unicodePassword, sizeof(unicodePassword));
3060Sstevel@tonic-gate for (i = 0; i < secret_len; i++)
3070Sstevel@tonic-gate unicodePassword[i * 2] = (u_char)secret[i];
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate MD4Init(&md4Context);
3100Sstevel@tonic-gate MD4Update(&md4Context, unicodePassword, mdlen);
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate MD4Final(hash, &md4Context); /* Tell MD4 we're done */
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate ChallengeResponse(rchallenge, hash, response->NTResp);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate #ifdef MSLANMAN
3180Sstevel@tonic-gate static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate static void
ChapMS_LANMan(rchallenge,secret,secret_len,response)3210Sstevel@tonic-gate ChapMS_LANMan(rchallenge, secret, secret_len, response)
3220Sstevel@tonic-gate u_char *rchallenge;
3230Sstevel@tonic-gate char *secret;
3240Sstevel@tonic-gate int secret_len;
3250Sstevel@tonic-gate MS_ChapResponse *response;
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate int i;
3280Sstevel@tonic-gate u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
3290Sstevel@tonic-gate u_char PasswordHash[MD4_SIGNATURE_SIZE];
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate /* LANMan password is case insensitive */
3320Sstevel@tonic-gate BZERO(UcasePassword, sizeof(UcasePassword));
3330Sstevel@tonic-gate for (i = 0; i < secret_len; i++)
3340Sstevel@tonic-gate UcasePassword[i] = (u_char)(
3350Sstevel@tonic-gate islower(secret[i]) ? toupper(secret[i]) : secret[i]);
3360Sstevel@tonic-gate DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
3370Sstevel@tonic-gate DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
3380Sstevel@tonic-gate ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate #endif
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate void
ChapMS(cstate,rchallenge,rchallenge_len,secret,secret_len)3430Sstevel@tonic-gate ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
3440Sstevel@tonic-gate chap_state *cstate;
3450Sstevel@tonic-gate u_char *rchallenge;
3460Sstevel@tonic-gate int rchallenge_len;
3470Sstevel@tonic-gate char *secret;
3480Sstevel@tonic-gate int secret_len;
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate MS_ChapResponse response;
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate if (rchallenge_len < 8) {
3530Sstevel@tonic-gate cstate->resp_length = 0;
3540Sstevel@tonic-gate return;
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate #if 0
3580Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
3590Sstevel@tonic-gate #endif
3600Sstevel@tonic-gate BZERO(&response, sizeof(response));
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /* Calculate both always */
3630Sstevel@tonic-gate ChapMS_NT(rchallenge, secret, secret_len, &response);
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate #ifdef MSLANMAN
3660Sstevel@tonic-gate ChapMS_LANMan(rchallenge, secret, secret_len, &response);
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate /* prefered method is set by option */
3690Sstevel@tonic-gate response.UseNT = !ms_lanman;
3700Sstevel@tonic-gate #else
3710Sstevel@tonic-gate response.UseNT = 1;
3720Sstevel@tonic-gate #endif
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
3750Sstevel@tonic-gate cstate->resp_length = MS_CHAP_RESPONSE_LEN;
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate static int
ChapMSStatus(cstate,flag)3790Sstevel@tonic-gate ChapMSStatus(cstate, flag)
3800Sstevel@tonic-gate chap_state *cstate;
3810Sstevel@tonic-gate int flag;
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate if (flag != 0) {
3840Sstevel@tonic-gate cstate->stat_message = NULL;
3850Sstevel@tonic-gate cstate->stat_length = 0;
3860Sstevel@tonic-gate } else {
3870Sstevel@tonic-gate cstate->stat_message = "E=691 R=0 M=\"Authentication failed\"";
3880Sstevel@tonic-gate cstate->stat_length = strlen(cstate->stat_message);
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate return (flag);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate int
ChapMSValidate(cstate,response,response_len,secret,secret_len)3940Sstevel@tonic-gate ChapMSValidate(cstate, response, response_len, secret, secret_len)
3950Sstevel@tonic-gate chap_state *cstate;
3960Sstevel@tonic-gate u_char *response;
3970Sstevel@tonic-gate int response_len;
3980Sstevel@tonic-gate char *secret;
3990Sstevel@tonic-gate int secret_len;
4000Sstevel@tonic-gate {
4010Sstevel@tonic-gate MS_ChapResponse ckresp;
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate if (response_len < MS_CHAP_RESPONSE_LEN || cstate->chal_len < 8)
4040Sstevel@tonic-gate return (0);
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate BZERO(&ckresp, sizeof(ckresp));
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate if (response[MS_CHAP_RESPONSE_LEN-1]) {
4090Sstevel@tonic-gate ChapMS_NT(cstate->challenge, secret, secret_len, &ckresp);
4100Sstevel@tonic-gate return (ChapMSStatus(cstate, memcmp(ckresp.NTResp, response+24,
4110Sstevel@tonic-gate 24) == 0));
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate #ifdef MSLANMAN
4150Sstevel@tonic-gate ChapMS_LANMan(cstate->challenge, secret, secret_len, &ckresp);
4160Sstevel@tonic-gate return (ChapMSStatus(cstate,
4170Sstevel@tonic-gate memcmp(ckresp.LANManResp, response, 24) == 0));
4180Sstevel@tonic-gate #else
4190Sstevel@tonic-gate return (ChapMSStatus(cstate, 0));
4200Sstevel@tonic-gate #endif
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate #endif /* CHAPMS */
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate #ifdef CHAPMSV2
4250Sstevel@tonic-gate static void
ChallengeHash(peerchallenge,authenticatorchallenge,username,challenge)4260Sstevel@tonic-gate ChallengeHash(peerchallenge, authenticatorchallenge, username, challenge)
4270Sstevel@tonic-gate u_char *peerchallenge, *authenticatorchallenge, *challenge;
4280Sstevel@tonic-gate char *username;
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate uint8_t digest[20];
4310Sstevel@tonic-gate SHA1_CTX sha1Context;
4320Sstevel@tonic-gate char *cp;
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate SHA1Init(&sha1Context);
4350Sstevel@tonic-gate SHA1Update(&sha1Context, peerchallenge, 16);
4360Sstevel@tonic-gate SHA1Update(&sha1Context, authenticatorchallenge, 16);
4370Sstevel@tonic-gate
4380Sstevel@tonic-gate /*
4390Sstevel@tonic-gate * Only the user name (as presented by the peer and
4400Sstevel@tonic-gate * excluding any prepended domain name)
4410Sstevel@tonic-gate * is used as input to SHAUpdate().
4420Sstevel@tonic-gate */
4430Sstevel@tonic-gate if ((cp = strchr(username,'\\')) != NULL)
4440Sstevel@tonic-gate username = cp;
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate SHA1Update(&sha1Context, (uint8_t *)username, strlen(username));
4470Sstevel@tonic-gate SHA1Final(digest, &sha1Context);
4480Sstevel@tonic-gate BCOPY(digest, challenge, 8);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate static void
ChapMSv2_NT(username,rchallenge,secret,secret_len,response)4520Sstevel@tonic-gate ChapMSv2_NT(username, rchallenge, secret, secret_len, response)
4530Sstevel@tonic-gate char *username;
4540Sstevel@tonic-gate u_char *rchallenge;
4550Sstevel@tonic-gate char *secret;
4560Sstevel@tonic-gate int secret_len;
4570Sstevel@tonic-gate MS_Chapv2Response *response;
4580Sstevel@tonic-gate {
4590Sstevel@tonic-gate int i;
460*5619Sdarrenm #if defined(__NetBSD__) || defined(HAVE_LIBMD)
4610Sstevel@tonic-gate /* NetBSD uses the libc md4 routines that take bytes instead of bits */
4620Sstevel@tonic-gate int mdlen = secret_len * 2;
4630Sstevel@tonic-gate #else
4640Sstevel@tonic-gate int mdlen = secret_len * 2 * 8;
4650Sstevel@tonic-gate #endif
4660Sstevel@tonic-gate MD4_CTX md4Context;
4670Sstevel@tonic-gate u_char hash[MD4_SIGNATURE_SIZE];
4680Sstevel@tonic-gate u_char challenge[8];
4690Sstevel@tonic-gate u_char unicodePassword[MAX_NT_PASSWORD * 2];
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate /* Initialize the Unicode version of the secret (== password). */
4720Sstevel@tonic-gate /* This implicitly supports 8-bit ISO8859/1 characters. */
4730Sstevel@tonic-gate BZERO(unicodePassword, sizeof(unicodePassword));
4740Sstevel@tonic-gate for (i = 0; i < secret_len && i < MAX_NT_PASSWORD; i++)
4750Sstevel@tonic-gate if ((unicodePassword[i * 2] = (u_char)secret[i]) == '\0')
4760Sstevel@tonic-gate break;
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate ChallengeHash(response->PeerChallenge, rchallenge, username, challenge);
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate MD4Init(&md4Context);
4810Sstevel@tonic-gate MD4Update(&md4Context, unicodePassword, mdlen);
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate MD4Final(hash, &md4Context); /* Tell MD4 we're done */
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate ChallengeResponse(challenge, hash, response->NTResp);
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate void
ChapMSv2(cstate,rchallenge,rchallenge_len,secret,secret_len)4890Sstevel@tonic-gate ChapMSv2(cstate, rchallenge, rchallenge_len, secret, secret_len)
4900Sstevel@tonic-gate chap_state *cstate;
4910Sstevel@tonic-gate u_char *rchallenge;
4920Sstevel@tonic-gate int rchallenge_len;
4930Sstevel@tonic-gate char *secret;
4940Sstevel@tonic-gate int secret_len;
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate MS_Chapv2Response response;
4970Sstevel@tonic-gate u_char *ptr;
4980Sstevel@tonic-gate int i;
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate if (rchallenge_len < 8) {
5010Sstevel@tonic-gate cstate->resp_length = 0;
5020Sstevel@tonic-gate return;
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate BZERO(&response, sizeof(response));
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate ptr = response.PeerChallenge;
5080Sstevel@tonic-gate for (i = 0; i < 16; i++)
5090Sstevel@tonic-gate *ptr++ = (u_char) (drand48() * 0xff);
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate ChapMSv2_NT(cstate->resp_name, rchallenge, secret, secret_len, &response);
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate BCOPY(&response, cstate->response, MS_CHAPV2_RESPONSE_LEN);
5140Sstevel@tonic-gate cstate->resp_length = MS_CHAPV2_RESPONSE_LEN;
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate static void
ChapMSv2Success(cstate,msresp,authchall,rhostname,secret,secret_len)5180Sstevel@tonic-gate ChapMSv2Success(cstate, msresp, authchall, rhostname, secret, secret_len)
5190Sstevel@tonic-gate chap_state *cstate;
5200Sstevel@tonic-gate MS_Chapv2Response *msresp;
5210Sstevel@tonic-gate u_char *authchall;
5220Sstevel@tonic-gate char *rhostname, *secret;
5230Sstevel@tonic-gate int secret_len;
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate static const u_char Magic1[39] = "Magic server to client signing constant";
5260Sstevel@tonic-gate static const u_char Magic2[41] =
5270Sstevel@tonic-gate "Pad to make it do more than one iteration";
528*5619Sdarrenm #if defined(__NetBSD__) || defined(HAVE_LIBMD)
5290Sstevel@tonic-gate /* NetBSD uses the libc md4 routines that take bytes instead of bits */
5300Sstevel@tonic-gate int mdlen = 1;
5310Sstevel@tonic-gate #else
5320Sstevel@tonic-gate int mdlen = 8;
5330Sstevel@tonic-gate #endif
5340Sstevel@tonic-gate u_char unicodePassword[MAX_NT_PASSWORD * 2];
5350Sstevel@tonic-gate MD4_CTX md4Context;
5360Sstevel@tonic-gate u_char hash[MD4_SIGNATURE_SIZE];
5370Sstevel@tonic-gate u_char hashhash[MD4_SIGNATURE_SIZE];
5380Sstevel@tonic-gate SHA1_CTX sha1Context;
5390Sstevel@tonic-gate uint8_t digest[20];
5400Sstevel@tonic-gate u_char challenge[8];
5410Sstevel@tonic-gate char *cp;
5420Sstevel@tonic-gate static const char hexdig[] = "0123456789ABCDEF";
5430Sstevel@tonic-gate int i;
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate /* Initialize the Unicode version of the secret (== password). */
5460Sstevel@tonic-gate /* This implicitly supports 8-bit ISO8859/1 characters. */
5470Sstevel@tonic-gate BZERO(unicodePassword, sizeof(unicodePassword));
5480Sstevel@tonic-gate for (i = 0; i < secret_len && i < MAX_NT_PASSWORD; i++)
5490Sstevel@tonic-gate if ((unicodePassword[i * 2] = (u_char)secret[i]) == '\0')
5500Sstevel@tonic-gate break;
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate /* Hash the password with MD4 */
5530Sstevel@tonic-gate MD4Init(&md4Context);
5540Sstevel@tonic-gate MD4Update(&md4Context, unicodePassword, secret_len * 2 * mdlen);
5550Sstevel@tonic-gate MD4Final(hash, &md4Context);
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate /* Now hash the hash */
5580Sstevel@tonic-gate MD4Init(&md4Context);
5590Sstevel@tonic-gate MD4Update(&md4Context, hash, MD4_SIGNATURE_SIZE * mdlen);
5600Sstevel@tonic-gate MD4Final(hashhash, &md4Context);
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate SHA1Init(&sha1Context);
5630Sstevel@tonic-gate SHA1Update(&sha1Context, hashhash, MD4_SIGNATURE_SIZE);
5640Sstevel@tonic-gate SHA1Update(&sha1Context, msresp->NTResp, sizeof (msresp->NTResp));
5650Sstevel@tonic-gate SHA1Update(&sha1Context, Magic1, 39);
5660Sstevel@tonic-gate SHA1Final(digest, &sha1Context);
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate ChallengeHash(msresp->PeerChallenge, authchall, rhostname, challenge);
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate SHA1Init(&sha1Context);
5710Sstevel@tonic-gate SHA1Update(&sha1Context, digest, 20);
5720Sstevel@tonic-gate SHA1Update(&sha1Context, challenge, 8);
5730Sstevel@tonic-gate SHA1Update(&sha1Context, Magic2, 41);
5740Sstevel@tonic-gate SHA1Final(digest, &sha1Context);
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate cp = status_message;
5770Sstevel@tonic-gate *cp++ = 'S';
5780Sstevel@tonic-gate *cp++ = '=';
5790Sstevel@tonic-gate for (i = 0; i < 20; i++) {
5800Sstevel@tonic-gate *cp++ = hexdig[digest[i]>>4];
5810Sstevel@tonic-gate *cp++ = hexdig[digest[i]&15];
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate * RFC 2759 says that a M=<string> greeting message is possible
5850Sstevel@tonic-gate * here. It lies. Any such greeting causes Windoze-98 to give
5860Sstevel@tonic-gate * error number 742, "Dial-Up Networking was unable to complete
5870Sstevel@tonic-gate * the connection. The computer you're dialing in to does not
5880Sstevel@tonic-gate * support the data encryption requirements specified. Please
5890Sstevel@tonic-gate * check your encryption settings in the properties of the
5900Sstevel@tonic-gate * connection. If this problem persists, contact your network
5910Sstevel@tonic-gate * administrator."
5920Sstevel@tonic-gate */
5930Sstevel@tonic-gate *cp = '\0';
5940Sstevel@tonic-gate #if 0
5950Sstevel@tonic-gate slprintf(cp, sizeof (status_message) - (cp-status_message),
5960Sstevel@tonic-gate "M=\"Welcome to %s.\"", hostname);
5970Sstevel@tonic-gate #endif
5980Sstevel@tonic-gate cstate->stat_message = status_message;
5990Sstevel@tonic-gate cstate->stat_length = strlen(status_message);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate int
ChapMSv2Validate(cstate,rhostname,response,response_len,secret,secret_len)6030Sstevel@tonic-gate ChapMSv2Validate(cstate, rhostname, response, response_len, secret, secret_len)
6040Sstevel@tonic-gate chap_state *cstate;
6050Sstevel@tonic-gate char *rhostname;
6060Sstevel@tonic-gate u_char *response;
6070Sstevel@tonic-gate int response_len;
6080Sstevel@tonic-gate char *secret;
6090Sstevel@tonic-gate int secret_len;
6100Sstevel@tonic-gate {
6110Sstevel@tonic-gate MS_Chapv2Response ckresp;
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate if (response_len < MS_CHAPV2_RESPONSE_LEN ||
6140Sstevel@tonic-gate /* response[MS_CHAPV2_RESPONSE_LEN-1] != 0 || */cstate->chal_len < 8) {
6150Sstevel@tonic-gate cstate->stat_message = NULL;
6160Sstevel@tonic-gate cstate->stat_length = 0;
6170Sstevel@tonic-gate return 0;
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate BZERO(&ckresp, sizeof(ckresp));
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate BCOPY(response, ckresp.PeerChallenge, 16);
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate ChapMSv2_NT(rhostname, cstate->challenge, secret, secret_len, &ckresp);
6250Sstevel@tonic-gate if (memcmp(ckresp.NTResp, response+24, 24) != 0) {
6260Sstevel@tonic-gate cstate->stat_message = "E=691 R=0 C=11111111111111111111111111111111 V=3 M=\"Authentication failed\"";
6270Sstevel@tonic-gate cstate->stat_length = strlen(cstate->stat_message);
6280Sstevel@tonic-gate return (0);
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate ChapMSv2Success(cstate, (MS_Chapv2Response *)response, cstate->challenge,
6310Sstevel@tonic-gate rhostname, secret, secret_len);
6320Sstevel@tonic-gate return (1);
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate #endif /* CHAPMSV2 */
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate #endif /* CHAPMS or CHAPMSV2 */
637