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