17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * chap_ms.c - Microsoft MS-CHAP compatible implementation. 37c478bd9Sstevel@tonic-gate * 4*eedefb95Sdarrenm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 5*eedefb95Sdarrenm * Use is subject to license terms. 67c478bd9Sstevel@tonic-gate * 77c478bd9Sstevel@tonic-gate * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. 87c478bd9Sstevel@tonic-gate * http://www.strataware.com/ 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * All rights reserved. 117c478bd9Sstevel@tonic-gate * 127c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 137c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 147c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 157c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 167c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 177c478bd9Sstevel@tonic-gate * by Eric Rosenquist. The name of the author may not be used to 187c478bd9Sstevel@tonic-gate * endorse or promote products derived from this software without 197c478bd9Sstevel@tonic-gate * specific prior written permission. 207c478bd9Sstevel@tonic-gate * 217c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 227c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 237c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * This module implements MS-CHAPv1 (RFC 2433) and MS-CHAPv2 (RFC 2759). 287c478bd9Sstevel@tonic-gate * 297c478bd9Sstevel@tonic-gate * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * Implemented LANManager type password response to MS-CHAP challenges. 327c478bd9Sstevel@tonic-gate * Now pppd provides both NT style and LANMan style blocks, and the 337c478bd9Sstevel@tonic-gate * prefered is set by option "ms-lanman". Default is to use NT. 347c478bd9Sstevel@tonic-gate * The hash text (StdText) was taken from Win95 RASAPI32.DLL. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * Modifications by James Carlson / james.d.carlson@sun.com, June 1st, 2000. 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * Added MS-CHAPv2 support. 417c478bd9Sstevel@tonic-gate */ 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 447c478bd9Sstevel@tonic-gate #define RCSID "$Id: chap_ms.c,v 1.15 1999/08/13 06:46:12 paulus Exp $" 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #if defined(CHAPMS) || defined(CHAPMSV2) 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include <stdio.h> 497c478bd9Sstevel@tonic-gate #include <stdlib.h> 507c478bd9Sstevel@tonic-gate #include <string.h> 517c478bd9Sstevel@tonic-gate #include <ctype.h> 527c478bd9Sstevel@tonic-gate #include <sys/types.h> 537c478bd9Sstevel@tonic-gate #include <sys/time.h> 547c478bd9Sstevel@tonic-gate #include <unistd.h> 557c478bd9Sstevel@tonic-gate #ifdef HAVE_CRYPT_H 567c478bd9Sstevel@tonic-gate #include <crypt.h> 577c478bd9Sstevel@tonic-gate #endif 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #ifdef CHAPMSV2 607c478bd9Sstevel@tonic-gate #include "sha1.h" 617c478bd9Sstevel@tonic-gate #endif 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #ifndef USE_CRYPT 647c478bd9Sstevel@tonic-gate #include <des.h> 657c478bd9Sstevel@tonic-gate #endif 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #include "pppd.h" 687c478bd9Sstevel@tonic-gate #include "chap.h" 697c478bd9Sstevel@tonic-gate #include "chap_ms.h" 707c478bd9Sstevel@tonic-gate #include "md4.h" 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(_lint) 737c478bd9Sstevel@tonic-gate static const char rcsid[] = RCSID; 747c478bd9Sstevel@tonic-gate #endif 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate typedef struct { 777c478bd9Sstevel@tonic-gate u_char LANManResp[24]; 787c478bd9Sstevel@tonic-gate u_char NTResp[24]; 797c478bd9Sstevel@tonic-gate u_char UseNT; /* If 1, ignore the LANMan response field */ 807c478bd9Sstevel@tonic-gate } MS_ChapResponse; 817c478bd9Sstevel@tonic-gate /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse), 827c478bd9Sstevel@tonic-gate in case this struct gets padded. */ 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate typedef struct { 857c478bd9Sstevel@tonic-gate u_char PeerChallenge[16]; 867c478bd9Sstevel@tonic-gate u_char MustBeZero[8]; 877c478bd9Sstevel@tonic-gate u_char NTResp[24]; 887c478bd9Sstevel@tonic-gate u_char Flags; /* Should be zero (Win98 sends 04) */ 897c478bd9Sstevel@tonic-gate } MS_Chapv2Response; 907c478bd9Sstevel@tonic-gate /* We use MS_CHAPV2_RESPONSE_LEN, rather than sizeof(MS_Chapv2Response), 917c478bd9Sstevel@tonic-gate in case this struct gets padded. */ 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate static void ChallengeResponse __P((u_char *, u_char *, u_char *)); 947c478bd9Sstevel@tonic-gate static void DesEncrypt __P((u_char *, u_char *, u_char *)); 957c478bd9Sstevel@tonic-gate static void MakeKey __P((u_char *, u_char *)); 967c478bd9Sstevel@tonic-gate static u_char Get7Bits __P((u_char *, int)); 977c478bd9Sstevel@tonic-gate #ifdef CHAPMS 987c478bd9Sstevel@tonic-gate static void ChapMS_NT __P((u_char *, char *, int, MS_ChapResponse *)); 997c478bd9Sstevel@tonic-gate #ifdef MSLANMAN 1007c478bd9Sstevel@tonic-gate static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *)); 1017c478bd9Sstevel@tonic-gate #endif 1027c478bd9Sstevel@tonic-gate #endif 1037c478bd9Sstevel@tonic-gate #ifdef CHAPMSV2 1047c478bd9Sstevel@tonic-gate static void ChapMSv2_NT __P((char *, u_char *, char *, int, 1057c478bd9Sstevel@tonic-gate MS_Chapv2Response *)); 1067c478bd9Sstevel@tonic-gate #endif 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate #ifdef USE_CRYPT 1097c478bd9Sstevel@tonic-gate static void Expand __P((u_char *, char *)); 1107c478bd9Sstevel@tonic-gate static void Collapse __P((char *, u_char *)); 1117c478bd9Sstevel@tonic-gate #endif 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate #if defined(MSLANMAN) && defined(CHAPMS) 1147c478bd9Sstevel@tonic-gate bool ms_lanman = 0; /* Use LanMan password instead of NT */ 1157c478bd9Sstevel@tonic-gate /* Has meaning only with MS-CHAP challenges */ 1167c478bd9Sstevel@tonic-gate #endif 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate #ifdef CHAPMSV2 1197c478bd9Sstevel@tonic-gate /* Specially-formatted Microsoft CHAP response message. */ 1207c478bd9Sstevel@tonic-gate static char status_message[256]; 1217c478bd9Sstevel@tonic-gate #endif 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate static void 1247c478bd9Sstevel@tonic-gate ChallengeResponse(challenge, pwHash, response) 1257c478bd9Sstevel@tonic-gate u_char *challenge; /* IN 8 octets */ 1267c478bd9Sstevel@tonic-gate u_char *pwHash; /* IN 16 octets */ 1277c478bd9Sstevel@tonic-gate u_char *response; /* OUT 24 octets */ 1287c478bd9Sstevel@tonic-gate { 1297c478bd9Sstevel@tonic-gate u_char ZPasswordHash[21]; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate BZERO(ZPasswordHash, sizeof(ZPasswordHash)); 1327c478bd9Sstevel@tonic-gate BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate #if 0 1357c478bd9Sstevel@tonic-gate dbglog("ChallengeResponse - ZPasswordHash %.*B", 1367c478bd9Sstevel@tonic-gate sizeof(ZPasswordHash), ZPasswordHash); 1377c478bd9Sstevel@tonic-gate #endif 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate DesEncrypt(challenge, ZPasswordHash + 0, response + 0); 1407c478bd9Sstevel@tonic-gate DesEncrypt(challenge, ZPasswordHash + 7, response + 8); 1417c478bd9Sstevel@tonic-gate DesEncrypt(challenge, ZPasswordHash + 14, response + 16); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate #if 0 1447c478bd9Sstevel@tonic-gate dbglog("ChallengeResponse - response %.24B", response); 1457c478bd9Sstevel@tonic-gate #endif 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate #ifdef USE_CRYPT 1507c478bd9Sstevel@tonic-gate static void 1517c478bd9Sstevel@tonic-gate DesEncrypt(clear, key, cipher) 1527c478bd9Sstevel@tonic-gate u_char *clear; /* IN 8 octets */ 1537c478bd9Sstevel@tonic-gate u_char *key; /* IN 7 octets */ 1547c478bd9Sstevel@tonic-gate u_char *cipher; /* OUT 8 octets */ 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate u_char des_key[8]; 1577c478bd9Sstevel@tonic-gate char crypt_key[66]; 1587c478bd9Sstevel@tonic-gate char des_input[66]; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate MakeKey(key, des_key); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate Expand(des_key, crypt_key); 1637c478bd9Sstevel@tonic-gate setkey(crypt_key); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate #if 0 1667c478bd9Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear)); 1677c478bd9Sstevel@tonic-gate #endif 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate Expand(clear, des_input); 1707c478bd9Sstevel@tonic-gate encrypt(des_input, 0); 1717c478bd9Sstevel@tonic-gate Collapse(des_input, cipher); 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate #if 0 1747c478bd9Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher)); 1757c478bd9Sstevel@tonic-gate #endif 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate #else /* USE_CRYPT */ 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate static void 1817c478bd9Sstevel@tonic-gate DesEncrypt(clear, key, cipher) 1827c478bd9Sstevel@tonic-gate u_char *clear; /* IN 8 octets */ 1837c478bd9Sstevel@tonic-gate u_char *key; /* IN 7 octets */ 1847c478bd9Sstevel@tonic-gate u_char *cipher; /* OUT 8 octets */ 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate des_cblock des_key; 1877c478bd9Sstevel@tonic-gate des_key_schedule key_schedule; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate MakeKey(key, des_key); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate des_set_key(&des_key, key_schedule); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate #if 0 1947c478bd9Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear)); 1957c478bd9Sstevel@tonic-gate #endif 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate #if 0 2007c478bd9Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher)); 2017c478bd9Sstevel@tonic-gate #endif 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate #endif /* USE_CRYPT */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate static u_char Get7Bits(input, startBit) 2087c478bd9Sstevel@tonic-gate u_char *input; 2097c478bd9Sstevel@tonic-gate int startBit; 2107c478bd9Sstevel@tonic-gate { 2117c478bd9Sstevel@tonic-gate register unsigned int word; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate word = (unsigned)input[startBit / 8] << 8; 2147c478bd9Sstevel@tonic-gate word |= (unsigned)input[startBit / 8 + 1]; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate word >>= 15 - (startBit % 8 + 7); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate return word & 0xFE; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate #ifdef USE_CRYPT 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate /* in == 8-byte string (expanded version of the 56-bit key) 2247c478bd9Sstevel@tonic-gate * out == 64-byte string where each byte is either 1 or 0 2257c478bd9Sstevel@tonic-gate * Note that the low-order "bit" is always ignored by by setkey() 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate static void Expand(in, out) 2287c478bd9Sstevel@tonic-gate u_char *in; 2297c478bd9Sstevel@tonic-gate char *out; 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate int j, c; 2327c478bd9Sstevel@tonic-gate int i; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate for(i = 0; i < 64; in++){ 2357c478bd9Sstevel@tonic-gate c = *in; 2367c478bd9Sstevel@tonic-gate for(j = 7; j >= 0; j--) 2377c478bd9Sstevel@tonic-gate *out++ = (c >> j) & 01; 2387c478bd9Sstevel@tonic-gate i += 8; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* The inverse of Expand 2437c478bd9Sstevel@tonic-gate */ 2447c478bd9Sstevel@tonic-gate static void Collapse(in, out) 2457c478bd9Sstevel@tonic-gate char *in; 2467c478bd9Sstevel@tonic-gate u_char *out; 2477c478bd9Sstevel@tonic-gate { 2487c478bd9Sstevel@tonic-gate int j; 2497c478bd9Sstevel@tonic-gate int i; 2507c478bd9Sstevel@tonic-gate unsigned int c; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate for (i = 0; i < 64; i += 8, out++) { 2537c478bd9Sstevel@tonic-gate c = 0; 2547c478bd9Sstevel@tonic-gate for (j = 7; j >= 0; j--, in++) 2557c478bd9Sstevel@tonic-gate c |= *(u_char *)in << j; 2567c478bd9Sstevel@tonic-gate *out = c & 0xff; 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate #endif 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate static void MakeKey(key, des_key) 2627c478bd9Sstevel@tonic-gate u_char *key; /* IN 56 bit DES key missing parity bits */ 2637c478bd9Sstevel@tonic-gate u_char *des_key; /* OUT 64 bit DES key with parity bits added */ 2647c478bd9Sstevel@tonic-gate { 2657c478bd9Sstevel@tonic-gate des_key[0] = Get7Bits(key, 0); 2667c478bd9Sstevel@tonic-gate des_key[1] = Get7Bits(key, 7); 2677c478bd9Sstevel@tonic-gate des_key[2] = Get7Bits(key, 14); 2687c478bd9Sstevel@tonic-gate des_key[3] = Get7Bits(key, 21); 2697c478bd9Sstevel@tonic-gate des_key[4] = Get7Bits(key, 28); 2707c478bd9Sstevel@tonic-gate des_key[5] = Get7Bits(key, 35); 2717c478bd9Sstevel@tonic-gate des_key[6] = Get7Bits(key, 42); 2727c478bd9Sstevel@tonic-gate des_key[7] = Get7Bits(key, 49); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate #ifndef USE_CRYPT 2757c478bd9Sstevel@tonic-gate des_set_odd_parity((des_cblock *)des_key); 2767c478bd9Sstevel@tonic-gate #endif 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate #if 0 2797c478bd9Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key)); 2807c478bd9Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key)); 2817c478bd9Sstevel@tonic-gate #endif 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate #ifdef CHAPMS 2857c478bd9Sstevel@tonic-gate static void 2867c478bd9Sstevel@tonic-gate ChapMS_NT(rchallenge, secret, secret_len, response) 2877c478bd9Sstevel@tonic-gate u_char *rchallenge; 2887c478bd9Sstevel@tonic-gate char *secret; 2897c478bd9Sstevel@tonic-gate int secret_len; 2907c478bd9Sstevel@tonic-gate MS_ChapResponse *response; 2917c478bd9Sstevel@tonic-gate { 2927c478bd9Sstevel@tonic-gate int i; 293*eedefb95Sdarrenm #if defined(__NetBSD__) || defined(HAVE_LIBMD) 2947c478bd9Sstevel@tonic-gate /* NetBSD uses the libc md4 routines which take bytes instead of bits */ 2957c478bd9Sstevel@tonic-gate int mdlen = secret_len * 2; 2967c478bd9Sstevel@tonic-gate #else 2977c478bd9Sstevel@tonic-gate int mdlen = secret_len * 2 * 8; 2987c478bd9Sstevel@tonic-gate #endif 2997c478bd9Sstevel@tonic-gate MD4_CTX md4Context; 3007c478bd9Sstevel@tonic-gate u_char hash[MD4_SIGNATURE_SIZE]; 3017c478bd9Sstevel@tonic-gate u_char unicodePassword[MAX_NT_PASSWORD * 2]; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* Initialize the Unicode version of the secret (== password). */ 3047c478bd9Sstevel@tonic-gate /* This implicitly supports 8-bit ISO8859/1 characters. */ 3057c478bd9Sstevel@tonic-gate BZERO(unicodePassword, sizeof(unicodePassword)); 3067c478bd9Sstevel@tonic-gate for (i = 0; i < secret_len; i++) 3077c478bd9Sstevel@tonic-gate unicodePassword[i * 2] = (u_char)secret[i]; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate MD4Init(&md4Context); 3107c478bd9Sstevel@tonic-gate MD4Update(&md4Context, unicodePassword, mdlen); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate MD4Final(hash, &md4Context); /* Tell MD4 we're done */ 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate ChallengeResponse(rchallenge, hash, response->NTResp); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate #ifdef MSLANMAN 3187c478bd9Sstevel@tonic-gate static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate static void 3217c478bd9Sstevel@tonic-gate ChapMS_LANMan(rchallenge, secret, secret_len, response) 3227c478bd9Sstevel@tonic-gate u_char *rchallenge; 3237c478bd9Sstevel@tonic-gate char *secret; 3247c478bd9Sstevel@tonic-gate int secret_len; 3257c478bd9Sstevel@tonic-gate MS_ChapResponse *response; 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate int i; 3287c478bd9Sstevel@tonic-gate u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ 3297c478bd9Sstevel@tonic-gate u_char PasswordHash[MD4_SIGNATURE_SIZE]; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* LANMan password is case insensitive */ 3327c478bd9Sstevel@tonic-gate BZERO(UcasePassword, sizeof(UcasePassword)); 3337c478bd9Sstevel@tonic-gate for (i = 0; i < secret_len; i++) 3347c478bd9Sstevel@tonic-gate UcasePassword[i] = (u_char)( 3357c478bd9Sstevel@tonic-gate islower(secret[i]) ? toupper(secret[i]) : secret[i]); 3367c478bd9Sstevel@tonic-gate DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 ); 3377c478bd9Sstevel@tonic-gate DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 ); 3387c478bd9Sstevel@tonic-gate ChallengeResponse(rchallenge, PasswordHash, response->LANManResp); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate #endif 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate void 3437c478bd9Sstevel@tonic-gate ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len) 3447c478bd9Sstevel@tonic-gate chap_state *cstate; 3457c478bd9Sstevel@tonic-gate u_char *rchallenge; 3467c478bd9Sstevel@tonic-gate int rchallenge_len; 3477c478bd9Sstevel@tonic-gate char *secret; 3487c478bd9Sstevel@tonic-gate int secret_len; 3497c478bd9Sstevel@tonic-gate { 3507c478bd9Sstevel@tonic-gate MS_ChapResponse response; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate if (rchallenge_len < 8) { 3537c478bd9Sstevel@tonic-gate cstate->resp_length = 0; 3547c478bd9Sstevel@tonic-gate return; 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate #if 0 3587c478bd9Sstevel@tonic-gate CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret)); 3597c478bd9Sstevel@tonic-gate #endif 3607c478bd9Sstevel@tonic-gate BZERO(&response, sizeof(response)); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* Calculate both always */ 3637c478bd9Sstevel@tonic-gate ChapMS_NT(rchallenge, secret, secret_len, &response); 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate #ifdef MSLANMAN 3667c478bd9Sstevel@tonic-gate ChapMS_LANMan(rchallenge, secret, secret_len, &response); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* prefered method is set by option */ 3697c478bd9Sstevel@tonic-gate response.UseNT = !ms_lanman; 3707c478bd9Sstevel@tonic-gate #else 3717c478bd9Sstevel@tonic-gate response.UseNT = 1; 3727c478bd9Sstevel@tonic-gate #endif 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); 3757c478bd9Sstevel@tonic-gate cstate->resp_length = MS_CHAP_RESPONSE_LEN; 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate static int 3797c478bd9Sstevel@tonic-gate ChapMSStatus(cstate, flag) 3807c478bd9Sstevel@tonic-gate chap_state *cstate; 3817c478bd9Sstevel@tonic-gate int flag; 3827c478bd9Sstevel@tonic-gate { 3837c478bd9Sstevel@tonic-gate if (flag != 0) { 3847c478bd9Sstevel@tonic-gate cstate->stat_message = NULL; 3857c478bd9Sstevel@tonic-gate cstate->stat_length = 0; 3867c478bd9Sstevel@tonic-gate } else { 3877c478bd9Sstevel@tonic-gate cstate->stat_message = "E=691 R=0 M=\"Authentication failed\""; 3887c478bd9Sstevel@tonic-gate cstate->stat_length = strlen(cstate->stat_message); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate return (flag); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate int 3947c478bd9Sstevel@tonic-gate ChapMSValidate(cstate, response, response_len, secret, secret_len) 3957c478bd9Sstevel@tonic-gate chap_state *cstate; 3967c478bd9Sstevel@tonic-gate u_char *response; 3977c478bd9Sstevel@tonic-gate int response_len; 3987c478bd9Sstevel@tonic-gate char *secret; 3997c478bd9Sstevel@tonic-gate int secret_len; 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate MS_ChapResponse ckresp; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if (response_len < MS_CHAP_RESPONSE_LEN || cstate->chal_len < 8) 4047c478bd9Sstevel@tonic-gate return (0); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate BZERO(&ckresp, sizeof(ckresp)); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate if (response[MS_CHAP_RESPONSE_LEN-1]) { 4097c478bd9Sstevel@tonic-gate ChapMS_NT(cstate->challenge, secret, secret_len, &ckresp); 4107c478bd9Sstevel@tonic-gate return (ChapMSStatus(cstate, memcmp(ckresp.NTResp, response+24, 4117c478bd9Sstevel@tonic-gate 24) == 0)); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate #ifdef MSLANMAN 4157c478bd9Sstevel@tonic-gate ChapMS_LANMan(cstate->challenge, secret, secret_len, &ckresp); 4167c478bd9Sstevel@tonic-gate return (ChapMSStatus(cstate, 4177c478bd9Sstevel@tonic-gate memcmp(ckresp.LANManResp, response, 24) == 0)); 4187c478bd9Sstevel@tonic-gate #else 4197c478bd9Sstevel@tonic-gate return (ChapMSStatus(cstate, 0)); 4207c478bd9Sstevel@tonic-gate #endif 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate #endif /* CHAPMS */ 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate #ifdef CHAPMSV2 4257c478bd9Sstevel@tonic-gate static void 4267c478bd9Sstevel@tonic-gate ChallengeHash(peerchallenge, authenticatorchallenge, username, challenge) 4277c478bd9Sstevel@tonic-gate u_char *peerchallenge, *authenticatorchallenge, *challenge; 4287c478bd9Sstevel@tonic-gate char *username; 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate uint8_t digest[20]; 4317c478bd9Sstevel@tonic-gate SHA1_CTX sha1Context; 4327c478bd9Sstevel@tonic-gate char *cp; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate SHA1Init(&sha1Context); 4357c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, peerchallenge, 16); 4367c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, authenticatorchallenge, 16); 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * Only the user name (as presented by the peer and 4407c478bd9Sstevel@tonic-gate * excluding any prepended domain name) 4417c478bd9Sstevel@tonic-gate * is used as input to SHAUpdate(). 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate if ((cp = strchr(username,'\\')) != NULL) 4447c478bd9Sstevel@tonic-gate username = cp; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, (uint8_t *)username, strlen(username)); 4477c478bd9Sstevel@tonic-gate SHA1Final(digest, &sha1Context); 4487c478bd9Sstevel@tonic-gate BCOPY(digest, challenge, 8); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate static void 4527c478bd9Sstevel@tonic-gate ChapMSv2_NT(username, rchallenge, secret, secret_len, response) 4537c478bd9Sstevel@tonic-gate char *username; 4547c478bd9Sstevel@tonic-gate u_char *rchallenge; 4557c478bd9Sstevel@tonic-gate char *secret; 4567c478bd9Sstevel@tonic-gate int secret_len; 4577c478bd9Sstevel@tonic-gate MS_Chapv2Response *response; 4587c478bd9Sstevel@tonic-gate { 4597c478bd9Sstevel@tonic-gate int i; 460*eedefb95Sdarrenm #if defined(__NetBSD__) || defined(HAVE_LIBMD) 4617c478bd9Sstevel@tonic-gate /* NetBSD uses the libc md4 routines that take bytes instead of bits */ 4627c478bd9Sstevel@tonic-gate int mdlen = secret_len * 2; 4637c478bd9Sstevel@tonic-gate #else 4647c478bd9Sstevel@tonic-gate int mdlen = secret_len * 2 * 8; 4657c478bd9Sstevel@tonic-gate #endif 4667c478bd9Sstevel@tonic-gate MD4_CTX md4Context; 4677c478bd9Sstevel@tonic-gate u_char hash[MD4_SIGNATURE_SIZE]; 4687c478bd9Sstevel@tonic-gate u_char challenge[8]; 4697c478bd9Sstevel@tonic-gate u_char unicodePassword[MAX_NT_PASSWORD * 2]; 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* Initialize the Unicode version of the secret (== password). */ 4727c478bd9Sstevel@tonic-gate /* This implicitly supports 8-bit ISO8859/1 characters. */ 4737c478bd9Sstevel@tonic-gate BZERO(unicodePassword, sizeof(unicodePassword)); 4747c478bd9Sstevel@tonic-gate for (i = 0; i < secret_len && i < MAX_NT_PASSWORD; i++) 4757c478bd9Sstevel@tonic-gate if ((unicodePassword[i * 2] = (u_char)secret[i]) == '\0') 4767c478bd9Sstevel@tonic-gate break; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate ChallengeHash(response->PeerChallenge, rchallenge, username, challenge); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate MD4Init(&md4Context); 4817c478bd9Sstevel@tonic-gate MD4Update(&md4Context, unicodePassword, mdlen); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate MD4Final(hash, &md4Context); /* Tell MD4 we're done */ 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate ChallengeResponse(challenge, hash, response->NTResp); 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate void 4897c478bd9Sstevel@tonic-gate ChapMSv2(cstate, rchallenge, rchallenge_len, secret, secret_len) 4907c478bd9Sstevel@tonic-gate chap_state *cstate; 4917c478bd9Sstevel@tonic-gate u_char *rchallenge; 4927c478bd9Sstevel@tonic-gate int rchallenge_len; 4937c478bd9Sstevel@tonic-gate char *secret; 4947c478bd9Sstevel@tonic-gate int secret_len; 4957c478bd9Sstevel@tonic-gate { 4967c478bd9Sstevel@tonic-gate MS_Chapv2Response response; 4977c478bd9Sstevel@tonic-gate u_char *ptr; 4987c478bd9Sstevel@tonic-gate int i; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate if (rchallenge_len < 8) { 5017c478bd9Sstevel@tonic-gate cstate->resp_length = 0; 5027c478bd9Sstevel@tonic-gate return; 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate BZERO(&response, sizeof(response)); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate ptr = response.PeerChallenge; 5087c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) 5097c478bd9Sstevel@tonic-gate *ptr++ = (u_char) (drand48() * 0xff); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate ChapMSv2_NT(cstate->resp_name, rchallenge, secret, secret_len, &response); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate BCOPY(&response, cstate->response, MS_CHAPV2_RESPONSE_LEN); 5147c478bd9Sstevel@tonic-gate cstate->resp_length = MS_CHAPV2_RESPONSE_LEN; 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate static void 5187c478bd9Sstevel@tonic-gate ChapMSv2Success(cstate, msresp, authchall, rhostname, secret, secret_len) 5197c478bd9Sstevel@tonic-gate chap_state *cstate; 5207c478bd9Sstevel@tonic-gate MS_Chapv2Response *msresp; 5217c478bd9Sstevel@tonic-gate u_char *authchall; 5227c478bd9Sstevel@tonic-gate char *rhostname, *secret; 5237c478bd9Sstevel@tonic-gate int secret_len; 5247c478bd9Sstevel@tonic-gate { 5257c478bd9Sstevel@tonic-gate static const u_char Magic1[39] = "Magic server to client signing constant"; 5267c478bd9Sstevel@tonic-gate static const u_char Magic2[41] = 5277c478bd9Sstevel@tonic-gate "Pad to make it do more than one iteration"; 528*eedefb95Sdarrenm #if defined(__NetBSD__) || defined(HAVE_LIBMD) 5297c478bd9Sstevel@tonic-gate /* NetBSD uses the libc md4 routines that take bytes instead of bits */ 5307c478bd9Sstevel@tonic-gate int mdlen = 1; 5317c478bd9Sstevel@tonic-gate #else 5327c478bd9Sstevel@tonic-gate int mdlen = 8; 5337c478bd9Sstevel@tonic-gate #endif 5347c478bd9Sstevel@tonic-gate u_char unicodePassword[MAX_NT_PASSWORD * 2]; 5357c478bd9Sstevel@tonic-gate MD4_CTX md4Context; 5367c478bd9Sstevel@tonic-gate u_char hash[MD4_SIGNATURE_SIZE]; 5377c478bd9Sstevel@tonic-gate u_char hashhash[MD4_SIGNATURE_SIZE]; 5387c478bd9Sstevel@tonic-gate SHA1_CTX sha1Context; 5397c478bd9Sstevel@tonic-gate uint8_t digest[20]; 5407c478bd9Sstevel@tonic-gate u_char challenge[8]; 5417c478bd9Sstevel@tonic-gate char *cp; 5427c478bd9Sstevel@tonic-gate static const char hexdig[] = "0123456789ABCDEF"; 5437c478bd9Sstevel@tonic-gate int i; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* Initialize the Unicode version of the secret (== password). */ 5467c478bd9Sstevel@tonic-gate /* This implicitly supports 8-bit ISO8859/1 characters. */ 5477c478bd9Sstevel@tonic-gate BZERO(unicodePassword, sizeof(unicodePassword)); 5487c478bd9Sstevel@tonic-gate for (i = 0; i < secret_len && i < MAX_NT_PASSWORD; i++) 5497c478bd9Sstevel@tonic-gate if ((unicodePassword[i * 2] = (u_char)secret[i]) == '\0') 5507c478bd9Sstevel@tonic-gate break; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate /* Hash the password with MD4 */ 5537c478bd9Sstevel@tonic-gate MD4Init(&md4Context); 5547c478bd9Sstevel@tonic-gate MD4Update(&md4Context, unicodePassword, secret_len * 2 * mdlen); 5557c478bd9Sstevel@tonic-gate MD4Final(hash, &md4Context); 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* Now hash the hash */ 5587c478bd9Sstevel@tonic-gate MD4Init(&md4Context); 5597c478bd9Sstevel@tonic-gate MD4Update(&md4Context, hash, MD4_SIGNATURE_SIZE * mdlen); 5607c478bd9Sstevel@tonic-gate MD4Final(hashhash, &md4Context); 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate SHA1Init(&sha1Context); 5637c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, hashhash, MD4_SIGNATURE_SIZE); 5647c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, msresp->NTResp, sizeof (msresp->NTResp)); 5657c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, Magic1, 39); 5667c478bd9Sstevel@tonic-gate SHA1Final(digest, &sha1Context); 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate ChallengeHash(msresp->PeerChallenge, authchall, rhostname, challenge); 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate SHA1Init(&sha1Context); 5717c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, digest, 20); 5727c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, challenge, 8); 5737c478bd9Sstevel@tonic-gate SHA1Update(&sha1Context, Magic2, 41); 5747c478bd9Sstevel@tonic-gate SHA1Final(digest, &sha1Context); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate cp = status_message; 5777c478bd9Sstevel@tonic-gate *cp++ = 'S'; 5787c478bd9Sstevel@tonic-gate *cp++ = '='; 5797c478bd9Sstevel@tonic-gate for (i = 0; i < 20; i++) { 5807c478bd9Sstevel@tonic-gate *cp++ = hexdig[digest[i]>>4]; 5817c478bd9Sstevel@tonic-gate *cp++ = hexdig[digest[i]&15]; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate /* 5847c478bd9Sstevel@tonic-gate * RFC 2759 says that a M=<string> greeting message is possible 5857c478bd9Sstevel@tonic-gate * here. It lies. Any such greeting causes Windoze-98 to give 5867c478bd9Sstevel@tonic-gate * error number 742, "Dial-Up Networking was unable to complete 5877c478bd9Sstevel@tonic-gate * the connection. The computer you're dialing in to does not 5887c478bd9Sstevel@tonic-gate * support the data encryption requirements specified. Please 5897c478bd9Sstevel@tonic-gate * check your encryption settings in the properties of the 5907c478bd9Sstevel@tonic-gate * connection. If this problem persists, contact your network 5917c478bd9Sstevel@tonic-gate * administrator." 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate *cp = '\0'; 5947c478bd9Sstevel@tonic-gate #if 0 5957c478bd9Sstevel@tonic-gate slprintf(cp, sizeof (status_message) - (cp-status_message), 5967c478bd9Sstevel@tonic-gate "M=\"Welcome to %s.\"", hostname); 5977c478bd9Sstevel@tonic-gate #endif 5987c478bd9Sstevel@tonic-gate cstate->stat_message = status_message; 5997c478bd9Sstevel@tonic-gate cstate->stat_length = strlen(status_message); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate int 6037c478bd9Sstevel@tonic-gate ChapMSv2Validate(cstate, rhostname, response, response_len, secret, secret_len) 6047c478bd9Sstevel@tonic-gate chap_state *cstate; 6057c478bd9Sstevel@tonic-gate char *rhostname; 6067c478bd9Sstevel@tonic-gate u_char *response; 6077c478bd9Sstevel@tonic-gate int response_len; 6087c478bd9Sstevel@tonic-gate char *secret; 6097c478bd9Sstevel@tonic-gate int secret_len; 6107c478bd9Sstevel@tonic-gate { 6117c478bd9Sstevel@tonic-gate MS_Chapv2Response ckresp; 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate if (response_len < MS_CHAPV2_RESPONSE_LEN || 6147c478bd9Sstevel@tonic-gate /* response[MS_CHAPV2_RESPONSE_LEN-1] != 0 || */cstate->chal_len < 8) { 6157c478bd9Sstevel@tonic-gate cstate->stat_message = NULL; 6167c478bd9Sstevel@tonic-gate cstate->stat_length = 0; 6177c478bd9Sstevel@tonic-gate return 0; 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate BZERO(&ckresp, sizeof(ckresp)); 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate BCOPY(response, ckresp.PeerChallenge, 16); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate ChapMSv2_NT(rhostname, cstate->challenge, secret, secret_len, &ckresp); 6257c478bd9Sstevel@tonic-gate if (memcmp(ckresp.NTResp, response+24, 24) != 0) { 6267c478bd9Sstevel@tonic-gate cstate->stat_message = "E=691 R=0 C=11111111111111111111111111111111 V=3 M=\"Authentication failed\""; 6277c478bd9Sstevel@tonic-gate cstate->stat_length = strlen(cstate->stat_message); 6287c478bd9Sstevel@tonic-gate return (0); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate ChapMSv2Success(cstate, (MS_Chapv2Response *)response, cstate->challenge, 6317c478bd9Sstevel@tonic-gate rhostname, secret, secret_len); 6327c478bd9Sstevel@tonic-gate return (1); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate #endif /* CHAPMSV2 */ 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate #endif /* CHAPMS or CHAPMSV2 */ 637