Home | History | Annotate | Download | only in pppd
      1 /*
      2  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
      3  *
      4  * Copyright (c) 1995 Eric Rosenquist.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  *
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in
     15  *    the documentation and/or other materials provided with the
     16  *    distribution.
     17  *
     18  * 3. The name(s) of the authors of this software must not be used to
     19  *    endorse or promote products derived from this software without
     20  *    prior written permission.
     21  *
     22  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
     23  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     24  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
     25  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     26  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     27  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     28  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     29  */
     30 
     31 /*
     32  * Modifications by Lauri Pesonen / lpesonen (at) clinet.fi, april 1997
     33  *
     34  *   Implemented LANManager type password response to MS-CHAP challenges.
     35  *   Now pppd provides both NT style and LANMan style blocks, and the
     36  *   prefered is set by option "ms-lanman". Default is to use NT.
     37  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
     38  *
     39  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
     40  */
     41 
     42 /*
     43  * Modifications by Frank Cusack, frank (at) google.com, March 2002.
     44  *
     45  *   Implemented MS-CHAPv2 functionality, heavily based on sample
     46  *   implementation in RFC 2759.  Implemented MPPE functionality,
     47  *   heavily based on sample implementation in RFC 3079.
     48  *
     49  * Copyright (c) 2002 The Android Open Source Project
     50  *
     51  * Redistribution and use in source and binary forms, with or without
     52  * modification, are permitted provided that the following conditions
     53  * are met:
     54  *
     55  * 1. Redistributions of source code must retain the above copyright
     56  *    notice, this list of conditions and the following disclaimer.
     57  *
     58  * 2. Redistributions in binary form must reproduce the above copyright
     59  *    notice, this list of conditions and the following disclaimer in
     60  *    the documentation and/or other materials provided with the
     61  *    distribution.
     62  *
     63  * 3. The name(s) of the authors of this software must not be used to
     64  *    endorse or promote products derived from this software without
     65  *    prior written permission.
     66  *
     67  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
     68  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     69  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
     70  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     71  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     72  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     73  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     74  *
     75  */
     76 
     77 #define RCSID	"$Id: chap_ms.c,v 1.33 2004/11/12 09:57:43 paulus Exp $"
     78 
     79 #ifdef CHAPMS
     80 
     81 #include <stdio.h>
     82 #include <stdlib.h>
     83 #include <string.h>
     84 #include <ctype.h>
     85 #include <sys/types.h>
     86 #include <sys/time.h>
     87 #include <unistd.h>
     88 
     89 #include "pppd.h"
     90 #include "chap-new.h"
     91 #include "chap_ms.h"
     92 #ifdef ANDROID_CHANGES
     93 #include "openssl-hash.h"
     94 #else
     95 #include "md4.h"
     96 #include "sha1.h"
     97 #endif
     98 #include "pppcrypt.h"
     99 #include "magic.h"
    100 
    101 static const char rcsid[] = RCSID;
    102 
    103 
    104 static void	ascii2unicode __P((char[], int, u_char[]));
    105 static void	NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
    106 static void	ChallengeResponse __P((u_char *, u_char *, u_char[24]));
    107 static void	ChapMS_NT __P((u_char *, char *, int, u_char[24]));
    108 static void	ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
    109 				u_char[24]));
    110 static void	GenerateAuthenticatorResponsePlain
    111 			__P((char*, int, u_char[24], u_char[16], u_char *,
    112 			     char *, u_char[41]));
    113 #ifdef MSLANMAN
    114 static void	ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
    115 #endif
    116 
    117 #ifdef MPPE
    118 static void	Set_Start_Key __P((u_char *, char *, int));
    119 static void	SetMasterKeys __P((char *, int, u_char[24], int));
    120 #endif
    121 
    122 #ifdef MSLANMAN
    123 bool	ms_lanman = 0;    	/* Use LanMan password instead of NT */
    124 			  	/* Has meaning only with MS-CHAP challenges */
    125 #endif
    126 
    127 #ifdef MPPE
    128 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
    129 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
    130 int mppe_keys_set = 0;		/* Have the MPPE keys been set? */
    131 
    132 #ifdef DEBUGMPPEKEY
    133 /* For MPPE debug */
    134 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
    135 static char *mschap_challenge = NULL;
    136 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
    137 static char *mschap2_peer_challenge = NULL;
    138 #endif
    139 
    140 #include "fsm.h"		/* Need to poke MPPE options */
    141 #include "ccp.h"
    142 #include <net/ppp-comp.h>
    143 #endif
    144 
    145 /*
    146  * Command-line options.
    147  */
    148 static option_t chapms_option_list[] = {
    149 #ifdef MSLANMAN
    150 	{ "ms-lanman", o_bool, &ms_lanman,
    151 	  "Use LanMan passwd when using MS-CHAP", 1 },
    152 #endif
    153 #ifdef DEBUGMPPEKEY
    154 	{ "mschap-challenge", o_string, &mschap_challenge,
    155 	  "specify CHAP challenge" },
    156 	{ "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
    157 	  "specify CHAP peer challenge" },
    158 #endif
    159 	{ NULL }
    160 };
    161 
    162 /*
    163  * chapms_generate_challenge - generate a challenge for MS-CHAP.
    164  * For MS-CHAP the challenge length is fixed at 8 bytes.
    165  * The length goes in challenge[0] and the actual challenge starts
    166  * at challenge[1].
    167  */
    168 static void
    169 chapms_generate_challenge(unsigned char *challenge)
    170 {
    171 	*challenge++ = 8;
    172 #ifdef DEBUGMPPEKEY
    173 	if (mschap_challenge && strlen(mschap_challenge) == 8)
    174 		memcpy(challenge, mschap_challenge, 8);
    175 	else
    176 #endif
    177 		random_bytes(challenge, 8);
    178 }
    179 
    180 static void
    181 chapms2_generate_challenge(unsigned char *challenge)
    182 {
    183 	*challenge++ = 16;
    184 #ifdef DEBUGMPPEKEY
    185 	if (mschap_challenge && strlen(mschap_challenge) == 16)
    186 		memcpy(challenge, mschap_challenge, 16);
    187 	else
    188 #endif
    189 		random_bytes(challenge, 16);
    190 }
    191 
    192 static int
    193 chapms_verify_response(int id, char *name,
    194 		       unsigned char *secret, int secret_len,
    195 		       unsigned char *challenge, unsigned char *response,
    196 		       char *message, int message_space)
    197 {
    198 	MS_ChapResponse *rmd;
    199 	MS_ChapResponse md;
    200 	int diff;
    201 	int challenge_len, response_len;
    202 
    203 	challenge_len = *challenge++;	/* skip length, is 8 */
    204 	response_len = *response++;
    205 	if (response_len != MS_CHAP_RESPONSE_LEN)
    206 		goto bad;
    207 
    208 	rmd = (MS_ChapResponse *) response;
    209 
    210 #ifndef MSLANMAN
    211 	if (!rmd->UseNT[0]) {
    212 		/* Should really propagate this into the error packet. */
    213 		notice("Peer request for LANMAN auth not supported");
    214 		goto bad;
    215 	}
    216 #endif
    217 
    218 	/* Generate the expected response. */
    219 	ChapMS(challenge, (char *)secret, secret_len, &md);
    220 
    221 #ifdef MSLANMAN
    222 	/* Determine which part of response to verify against */
    223 	if (!rmd->UseNT[0])
    224 		diff = memcmp(&rmd->LANManResp, &md.LANManResp,
    225 			      sizeof(md.LANManResp));
    226 	else
    227 #endif
    228 		diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
    229 
    230 	if (diff == 0) {
    231 		slprintf(message, message_space, "Access granted");
    232 		return 1;
    233 	}
    234 
    235  bad:
    236 	/* See comments below for MS-CHAP V2 */
    237 	slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
    238 		 challenge_len, challenge);
    239 	return 0;
    240 }
    241 
    242 static int
    243 chapms2_verify_response(int id, char *name,
    244 			unsigned char *secret, int secret_len,
    245 			unsigned char *challenge, unsigned char *response,
    246 			char *message, int message_space)
    247 {
    248 	MS_Chap2Response *rmd;
    249 	MS_Chap2Response md;
    250 	char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
    251 	int challenge_len, response_len;
    252 
    253 	challenge_len = *challenge++;	/* skip length, is 16 */
    254 	response_len = *response++;
    255 	if (response_len != MS_CHAP2_RESPONSE_LEN)
    256 		goto bad;	/* not even the right length */
    257 
    258 	rmd = (MS_Chap2Response *) response;
    259 
    260 	/* Generate the expected response and our mutual auth. */
    261 	ChapMS2(challenge, rmd->PeerChallenge, name,
    262 		(char *)secret, secret_len, &md,
    263 		(unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
    264 
    265 	/* compare MDs and send the appropriate status */
    266 	/*
    267 	 * Per RFC 2759, success message must be formatted as
    268 	 *     "S=<auth_string> M=<message>"
    269 	 * where
    270 	 *     <auth_string> is the Authenticator Response (mutual auth)
    271 	 *     <message> is a text message
    272 	 *
    273 	 * However, some versions of Windows (win98 tested) do not know
    274 	 * about the M=<message> part (required per RFC 2759) and flag
    275 	 * it as an error (reported incorrectly as an encryption error
    276 	 * to the user).  Since the RFC requires it, and it can be
    277 	 * useful information, we supply it if the peer is a conforming
    278 	 * system.  Luckily (?), win98 sets the Flags field to 0x04
    279 	 * (contrary to RFC requirements) so we can use that to
    280 	 * distinguish between conforming and non-conforming systems.
    281 	 *
    282 	 * Special thanks to Alex Swiridov <say (at) real.kharkov.ua> for
    283 	 * help debugging this.
    284 	 */
    285 	if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
    286 		if (rmd->Flags[0])
    287 			slprintf(message, message_space, "S=%s", saresponse);
    288 		else
    289 			slprintf(message, message_space, "S=%s M=%s",
    290 				 saresponse, "Access granted");
    291 		return 1;
    292 	}
    293 
    294  bad:
    295 	/*
    296 	 * Failure message must be formatted as
    297 	 *     "E=e R=r C=c V=v M=m"
    298 	 * where
    299 	 *     e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
    300 	 *     r = retry (we use 1, ok to retry)
    301 	 *     c = challenge to use for next response, we reuse previous
    302 	 *     v = Change Password version supported, we use 0
    303 	 *     m = text message
    304 	 *
    305 	 * The M=m part is only for MS-CHAPv2.  Neither win2k nor
    306 	 * win98 (others untested) display the message to the user anyway.
    307 	 * They also both ignore the E=e code.
    308 	 *
    309 	 * Note that it's safe to reuse the same challenge as we don't
    310 	 * actually accept another response based on the error message
    311 	 * (and no clients try to resend a response anyway).
    312 	 *
    313 	 * Basically, this whole bit is useless code, even the small
    314 	 * implementation here is only because of overspecification.
    315 	 */
    316 	slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
    317 		 challenge_len, challenge, "Access denied");
    318 	return 0;
    319 }
    320 
    321 static void
    322 chapms_make_response(unsigned char *response, int id, char *our_name,
    323 		     unsigned char *challenge, char *secret, int secret_len,
    324 		     unsigned char *private)
    325 {
    326 	challenge++;	/* skip length, should be 8 */
    327 	*response++ = MS_CHAP_RESPONSE_LEN;
    328 	ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
    329 }
    330 
    331 static void
    332 chapms2_make_response(unsigned char *response, int id, char *our_name,
    333 		      unsigned char *challenge, char *secret, int secret_len,
    334 		      unsigned char *private)
    335 {
    336 	challenge++;	/* skip length, should be 16 */
    337 	*response++ = MS_CHAP2_RESPONSE_LEN;
    338 	ChapMS2(challenge,
    339 #ifdef DEBUGMPPEKEY
    340 		mschap2_peer_challenge,
    341 #else
    342 		NULL,
    343 #endif
    344 		our_name, secret, secret_len,
    345 		(MS_Chap2Response *) response, private,
    346 		MS_CHAP2_AUTHENTICATEE);
    347 }
    348 
    349 static int
    350 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
    351 {
    352 	if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
    353 	    strncmp((char *)msg, "S=", 2) != 0) {
    354 		/* Packet does not start with "S=" */
    355 		error("MS-CHAPv2 Success packet is badly formed.");
    356 		return 0;
    357 	}
    358 	msg += 2;
    359 	len -= 2;
    360 	if (len < MS_AUTH_RESPONSE_LENGTH
    361 	    || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
    362 		/* Authenticator Response did not match expected. */
    363 		error("MS-CHAPv2 mutual authentication failed.");
    364 		return 0;
    365 	}
    366 	/* Authenticator Response matches. */
    367 	msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
    368 	len -= MS_AUTH_RESPONSE_LENGTH;
    369 	if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
    370 		msg += 3; /* Eat the delimiter */
    371 	} else if (len) {
    372 		/* Packet has extra text which does not begin " M=" */
    373 		error("MS-CHAPv2 Success packet is badly formed.");
    374 		return 0;
    375 	}
    376 	return 1;
    377 }
    378 
    379 static void
    380 chapms_handle_failure(unsigned char *inp, int len)
    381 {
    382 	int err;
    383 	char *p, *msg;
    384 
    385 	/* We want a null-terminated string for strxxx(). */
    386 	msg = malloc(len + 1);
    387 	if (!msg) {
    388 		notice("Out of memory in chapms_handle_failure");
    389 		return;
    390 	}
    391 	BCOPY(inp, msg, len);
    392 	msg[len] = 0;
    393 	p = msg;
    394 
    395 	/*
    396 	 * Deal with MS-CHAP formatted failure messages; just print the
    397 	 * M=<message> part (if any).  For MS-CHAP we're not really supposed
    398 	 * to use M=<message>, but it shouldn't hurt.  See
    399 	 * chapms[2]_verify_response.
    400 	 */
    401 	if (!strncmp(p, "E=", 2))
    402 		err = strtol(p, NULL, 10); /* Remember the error code. */
    403 	else
    404 		goto print_msg; /* Message is badly formatted. */
    405 
    406 	if (len && ((p = strstr(p, " M=")) != NULL)) {
    407 		/* M=<message> field found. */
    408 		p += 3;
    409 	} else {
    410 		/* No M=<message>; use the error code. */
    411 		switch (err) {
    412 		case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
    413 			p = "E=646 Restricted logon hours";
    414 			break;
    415 
    416 		case MS_CHAP_ERROR_ACCT_DISABLED:
    417 			p = "E=647 Account disabled";
    418 			break;
    419 
    420 		case MS_CHAP_ERROR_PASSWD_EXPIRED:
    421 			p = "E=648 Password expired";
    422 			break;
    423 
    424 		case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
    425 			p = "E=649 No dialin permission";
    426 			break;
    427 
    428 		case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
    429 			p = "E=691 Authentication failure";
    430 			break;
    431 
    432 		case MS_CHAP_ERROR_CHANGING_PASSWORD:
    433 			/* Should never see this, we don't support Change Password. */
    434 			p = "E=709 Error changing password";
    435 			break;
    436 
    437 		default:
    438 			free(msg);
    439 			error("Unknown MS-CHAP authentication failure: %.*v",
    440 			      len, inp);
    441 			return;
    442 		}
    443 	}
    444 print_msg:
    445 	if (p != NULL)
    446 		error("MS-CHAP authentication failed: %v", p);
    447 	free(msg);
    448 }
    449 
    450 static void
    451 ChallengeResponse(u_char *challenge,
    452 		  u_char PasswordHash[MD4_SIGNATURE_SIZE],
    453 		  u_char response[24])
    454 {
    455     u_char    ZPasswordHash[21];
    456 
    457     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
    458     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
    459 
    460 #if 0
    461     dbglog("ChallengeResponse - ZPasswordHash %.*B",
    462 	   sizeof(ZPasswordHash), ZPasswordHash);
    463 #endif
    464 
    465     (void) DesSetkey(ZPasswordHash + 0);
    466     DesEncrypt(challenge, response + 0);
    467     (void) DesSetkey(ZPasswordHash + 7);
    468     DesEncrypt(challenge, response + 8);
    469     (void) DesSetkey(ZPasswordHash + 14);
    470     DesEncrypt(challenge, response + 16);
    471 
    472 #if 0
    473     dbglog("ChallengeResponse - response %.24B", response);
    474 #endif
    475 }
    476 
    477 void
    478 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
    479 	      char *username, u_char Challenge[8])
    480 
    481 {
    482     SHA1_CTX	sha1Context;
    483     u_char	sha1Hash[SHA1_SIGNATURE_SIZE];
    484     char	*user;
    485 
    486     /* remove domain from "domain\username" */
    487     if ((user = strrchr(username, '\\')) != NULL)
    488 	++user;
    489     else
    490 	user = username;
    491 
    492     SHA1_Init(&sha1Context);
    493     SHA1_Update(&sha1Context, PeerChallenge, 16);
    494     SHA1_Update(&sha1Context, rchallenge, 16);
    495     SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
    496     SHA1_Final(sha1Hash, &sha1Context);
    497 
    498     BCOPY(sha1Hash, Challenge, 8);
    499 }
    500 
    501 /*
    502  * Convert the ASCII version of the password to Unicode.
    503  * This implicitly supports 8-bit ISO8859/1 characters.
    504  * This gives us the little-endian representation, which
    505  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
    506  * is machine-dependent.)
    507  */
    508 static void
    509 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
    510 {
    511     int i;
    512 
    513     BZERO(unicode, ascii_len * 2);
    514     for (i = 0; i < ascii_len; i++)
    515 	unicode[i * 2] = (u_char) ascii[i];
    516 }
    517 
    518 static void
    519 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
    520 {
    521 #ifdef ANDROID_CHANGES
    522     /* We link with MD4 routines in openssl, we have to take bytes instead */
    523     int			mdlen = secret_len;
    524 #else
    525 #ifdef __NetBSD__
    526     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
    527     int			mdlen = secret_len;
    528 #else
    529     int			mdlen = secret_len * 8;
    530 #endif
    531 #endif
    532     MD4_CTX		md4Context;
    533 
    534     MD4Init(&md4Context);
    535     MD4Update(&md4Context, (unsigned char *)secret, mdlen);
    536     MD4Final(hash, &md4Context);
    537 
    538 }
    539 
    540 static void
    541 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
    542 	  u_char NTResponse[24])
    543 {
    544     u_char	unicodePassword[MAX_NT_PASSWORD * 2];
    545     u_char	PasswordHash[MD4_SIGNATURE_SIZE];
    546 
    547     /* Hash the Unicode version of the secret (== password). */
    548     ascii2unicode(secret, secret_len, unicodePassword);
    549     NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
    550 
    551     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
    552 }
    553 
    554 static void
    555 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
    556 	   char *secret, int secret_len, u_char NTResponse[24])
    557 {
    558     u_char	unicodePassword[MAX_NT_PASSWORD * 2];
    559     u_char	PasswordHash[MD4_SIGNATURE_SIZE];
    560     u_char	Challenge[8];
    561 
    562     ChallengeHash(PeerChallenge, (unsigned char *)rchallenge, username,
    563 		  Challenge);
    564 
    565     /* Hash the Unicode version of the secret (== password). */
    566     ascii2unicode(secret, secret_len, unicodePassword);
    567     NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
    568 
    569     ChallengeResponse(Challenge, PasswordHash, NTResponse);
    570 }
    571 
    572 #ifdef MSLANMAN
    573 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
    574 
    575 static void
    576 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
    577 	      MS_ChapResponse *response)
    578 {
    579     int			i;
    580     u_char		UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
    581     u_char		PasswordHash[MD4_SIGNATURE_SIZE];
    582 
    583     /* LANMan password is case insensitive */
    584     BZERO(UcasePassword, sizeof(UcasePassword));
    585     for (i = 0; i < secret_len; i++)
    586        UcasePassword[i] = (u_char)toupper(secret[i]);
    587     (void) DesSetkey(UcasePassword + 0);
    588     DesEncrypt( StdText, PasswordHash + 0 );
    589     (void) DesSetkey(UcasePassword + 7);
    590     DesEncrypt( StdText, PasswordHash + 8 );
    591     ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
    592 }
    593 #endif
    594 
    595 
    596 void
    597 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
    598 			      u_char NTResponse[24], u_char PeerChallenge[16],
    599 			      u_char *rchallenge, char *username,
    600 			      u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
    601 {
    602     /*
    603      * "Magic" constants used in response generation, from RFC 2759.
    604      */
    605     u_char Magic1[39] = /* "Magic server to client signing constant" */
    606 	{ 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
    607 	  0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
    608 	  0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
    609 	  0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
    610     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
    611 	{ 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
    612 	  0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
    613 	  0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
    614 	  0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
    615 	  0x6E };
    616 
    617     int		i;
    618     SHA1_CTX	sha1Context;
    619     u_char	Digest[SHA1_SIGNATURE_SIZE];
    620     u_char	Challenge[8];
    621 
    622     SHA1_Init(&sha1Context);
    623     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
    624     SHA1_Update(&sha1Context, NTResponse, 24);
    625     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
    626     SHA1_Final(Digest, &sha1Context);
    627 
    628     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
    629 
    630     SHA1_Init(&sha1Context);
    631     SHA1_Update(&sha1Context, Digest, sizeof(Digest));
    632     SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
    633     SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
    634     SHA1_Final(Digest, &sha1Context);
    635 
    636     /* Convert to ASCII hex string. */
    637     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
    638 	sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
    639 }
    640 
    641 
    642 static void
    643 GenerateAuthenticatorResponsePlain
    644 		(char *secret, int secret_len,
    645 		 u_char NTResponse[24], u_char PeerChallenge[16],
    646 		 u_char *rchallenge, char *username,
    647 		 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
    648 {
    649     u_char	unicodePassword[MAX_NT_PASSWORD * 2];
    650     u_char	PasswordHash[MD4_SIGNATURE_SIZE];
    651     u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
    652 
    653     /* Hash (x2) the Unicode version of the secret (== password). */
    654     ascii2unicode(secret, secret_len, unicodePassword);
    655     NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
    656     NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
    657 		   PasswordHashHash);
    658 
    659     GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
    660 				  rchallenge, username, authResponse);
    661 }
    662 
    663 
    664 #ifdef MPPE
    665 /*
    666  * Set mppe_xxxx_key from the NTPasswordHashHash.
    667  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
    668  */
    669 void
    670 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
    671 {
    672     SHA1_CTX	sha1Context;
    673     u_char	Digest[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
    674 
    675     SHA1_Init(&sha1Context);
    676     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
    677     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
    678     SHA1_Update(&sha1Context, rchallenge, 8);
    679     SHA1_Final(Digest, &sha1Context);
    680 
    681     /* Same key in both directions. */
    682     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
    683     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
    684 
    685     mppe_keys_set = 1;
    686 }
    687 
    688 /*
    689  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
    690  */
    691 static void
    692 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
    693 {
    694     u_char	unicodePassword[MAX_NT_PASSWORD * 2];
    695     u_char	PasswordHash[MD4_SIGNATURE_SIZE];
    696     u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
    697 
    698     /* Hash (x2) the Unicode version of the secret (== password). */
    699     ascii2unicode(secret, secret_len, unicodePassword);
    700     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
    701     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
    702 
    703     mppe_set_keys(rchallenge, PasswordHashHash);
    704 }
    705 
    706 /*
    707  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
    708  *
    709  * This helper function used in the Winbind module, which gets the
    710  * NTHashHash from the server.
    711  */
    712 void
    713 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
    714 	       u_char NTResponse[24], int IsServer)
    715 {
    716     SHA1_CTX	sha1Context;
    717     u_char	MasterKey[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
    718     u_char	Digest[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
    719 
    720     u_char SHApad1[40] =
    721 	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    722 	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    723 	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    724 	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    725     u_char SHApad2[40] =
    726 	{ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
    727 	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
    728 	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
    729 	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
    730 
    731     /* "This is the MPPE Master Key" */
    732     u_char Magic1[27] =
    733 	{ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
    734 	  0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
    735 	  0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
    736     /* "On the client side, this is the send key; "
    737        "on the server side, it is the receive key." */
    738     u_char Magic2[84] =
    739 	{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
    740 	  0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
    741 	  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
    742 	  0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
    743 	  0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
    744 	  0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
    745 	  0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
    746 	  0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
    747 	  0x6b, 0x65, 0x79, 0x2e };
    748     /* "On the client side, this is the receive key; "
    749        "on the server side, it is the send key." */
    750     u_char Magic3[84] =
    751 	{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
    752 	  0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
    753 	  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
    754 	  0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
    755 	  0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
    756 	  0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
    757 	  0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
    758 	  0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
    759 	  0x6b, 0x65, 0x79, 0x2e };
    760     u_char *s;
    761 
    762     SHA1_Init(&sha1Context);
    763     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
    764     SHA1_Update(&sha1Context, NTResponse, 24);
    765     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
    766     SHA1_Final(MasterKey, &sha1Context);
    767 
    768     /*
    769      * generate send key
    770      */
    771     if (IsServer)
    772 	s = Magic3;
    773     else
    774 	s = Magic2;
    775     SHA1_Init(&sha1Context);
    776     SHA1_Update(&sha1Context, MasterKey, 16);
    777     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
    778     SHA1_Update(&sha1Context, s, 84);
    779     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
    780     SHA1_Final(Digest, &sha1Context);
    781 
    782     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
    783 
    784     /*
    785      * generate recv key
    786      */
    787     if (IsServer)
    788 	s = Magic2;
    789     else
    790 	s = Magic3;
    791     SHA1_Init(&sha1Context);
    792     SHA1_Update(&sha1Context, MasterKey, 16);
    793     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
    794     SHA1_Update(&sha1Context, s, 84);
    795     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
    796     SHA1_Final(Digest, &sha1Context);
    797 
    798     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
    799 
    800     mppe_keys_set = 1;
    801 }
    802 
    803 /*
    804  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
    805  */
    806 static void
    807 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
    808 {
    809     u_char	unicodePassword[MAX_NT_PASSWORD * 2];
    810     u_char	PasswordHash[MD4_SIGNATURE_SIZE];
    811     u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
    812     /* Hash (x2) the Unicode version of the secret (== password). */
    813     ascii2unicode(secret, secret_len, unicodePassword);
    814     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
    815     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
    816     mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
    817 }
    818 
    819 #endif /* MPPE */
    820 
    821 
    822 void
    823 ChapMS(u_char *rchallenge, char *secret, int secret_len,
    824        MS_ChapResponse *response)
    825 {
    826     BZERO(response, sizeof(*response));
    827 
    828     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
    829 
    830 #ifdef MSLANMAN
    831     ChapMS_LANMan(rchallenge, secret, secret_len, response);
    832 
    833     /* preferred method is set by option  */
    834     response->UseNT[0] = !ms_lanman;
    835 #else
    836     response->UseNT[0] = 1;
    837 #endif
    838 
    839 #ifdef MPPE
    840     Set_Start_Key(rchallenge, secret, secret_len);
    841 #endif
    842 }
    843 
    844 
    845 /*
    846  * If PeerChallenge is NULL, one is generated and response->PeerChallenge
    847  * is filled in.  Call this way when generating a response.
    848  * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
    849  * Call this way when verifying a response (or debugging).
    850  * Do not call with PeerChallenge = response->PeerChallenge.
    851  *
    852  * response->PeerChallenge is then used for calculation of the
    853  * Authenticator Response.
    854  */
    855 void
    856 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
    857 	char *user, char *secret, int secret_len, MS_Chap2Response *response,
    858 	u_char authResponse[], int authenticator)
    859 {
    860     /* ARGSUSED */
    861     u_char *p = response->PeerChallenge;
    862     int i;
    863 
    864     BZERO(response, sizeof(*response));
    865 
    866     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
    867     if (!PeerChallenge)
    868 	for (i = 0; i < sizeof(response->PeerChallenge); i++)
    869 	    *p++ = (u_char) (drand48() * 0xff);
    870     else
    871 	BCOPY(PeerChallenge, response->PeerChallenge,
    872 	      sizeof(response->PeerChallenge));
    873 
    874     /* Generate the NT-Response */
    875     ChapMS2_NT((char *)rchallenge, response->PeerChallenge, user,
    876 	       secret, secret_len, response->NTResp);
    877 
    878     /* Generate the Authenticator Response. */
    879     GenerateAuthenticatorResponsePlain(secret, secret_len, response->NTResp,
    880 				       response->PeerChallenge, rchallenge,
    881 				       user, authResponse);
    882 
    883 #ifdef MPPE
    884     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
    885 #endif
    886 }
    887 
    888 #ifdef MPPE
    889 /*
    890  * Set MPPE options from plugins.
    891  */
    892 void
    893 set_mppe_enc_types(int policy, int types)
    894 {
    895     /* Early exit for unknown policies. */
    896     if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
    897 	policy != MPPE_ENC_POL_ENC_REQUIRED)
    898 	return;
    899 
    900     /* Don't modify MPPE if it's optional and wasn't already configured. */
    901     if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
    902 	return;
    903 
    904     /*
    905      * Disable undesirable encryption types.  Note that we don't ENABLE
    906      * any encryption types, to avoid overriding manual configuration.
    907      */
    908     switch(types) {
    909 	case MPPE_ENC_TYPES_RC4_40:
    910 	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;	/* disable 128-bit */
    911 	    break;
    912 	case MPPE_ENC_TYPES_RC4_128:
    913 	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;	/* disable 40-bit */
    914 	    break;
    915 	default:
    916 	    break;
    917     }
    918 }
    919 #endif /* MPPE */
    920 
    921 static struct chap_digest_type chapms_digest = {
    922 	CHAP_MICROSOFT,		/* code */
    923 	chapms_generate_challenge,
    924 	chapms_verify_response,
    925 	chapms_make_response,
    926 	NULL,			/* check_success */
    927 	chapms_handle_failure,
    928 };
    929 
    930 static struct chap_digest_type chapms2_digest = {
    931 	CHAP_MICROSOFT_V2,	/* code */
    932 	chapms2_generate_challenge,
    933 	chapms2_verify_response,
    934 	chapms2_make_response,
    935 	chapms2_check_success,
    936 	chapms_handle_failure,
    937 };
    938 
    939 void
    940 chapms_init(void)
    941 {
    942 	chap_register_digest(&chapms_digest);
    943 	chap_register_digest(&chapms2_digest);
    944 	add_options(chapms_option_list);
    945 }
    946 
    947 #endif /* CHAPMS */
    948