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 "
82static 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
109static void	ascii2unicode (char[], int, u_char[]);
110static void	NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
111static void	ChallengeResponse (u_char *, u_char[MD4_SIGNATURE_SIZE],
112				u_char[24]);
113static void	ChapMS_NT (u_char *, char *, int, u_char[24]);
114static void	ChapMS2_NT (u_char *, u_char[16], char *, char *, int,
115				u_char[24]);
116static void	GenerateAuthenticatorResponsePlain
117			(char*, int, u_char[24], u_char[16], u_char *,
118			 char *, u_char[41]);
119#ifdef MSLANMAN
120static void	ChapMS_LANMan (u_char *, char *, int, u_char *);
121#endif
122
123#ifdef MPPE
124static void	Set_Start_Key (u_char *, char *, int);
125static void	SetMasterKeys (char *, int, u_char[24], int);
126#endif
127
128#ifdef MSLANMAN
129bool	ms_lanman = 0;    	/* Use LanMan password instead of NT */
130			  	/* Has meaning only with MS-CHAP challenges */
131#endif
132
133#ifdef MPPE
134u_char mppe_send_key[MPPE_MAX_KEY_LEN];
135u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
136int 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 */
141static char *mschap_challenge = NULL;
142/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
143static 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 */
154static 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 */
174static void
175chapms_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
186static void
187chapms2_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
198static int
199chapms_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
246static int
247chapms2_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
323static void
324chapms_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
333struct 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
341static struct chapms2_response_cache_entry
342    chapms2_response_cache[CHAPMS2_MAX_RESPONSE_CACHE_SIZE];
343static int chapms2_response_cache_next_index = 0;
344static int chapms2_response_cache_size = 0;
345
346static void
347chapms2_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
366static struct chapms2_response_cache_entry*
367chapms2_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
389static void
390chapms2_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
415static int
416chapms2_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
447static void
448chapms_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	}
512print_msg:
513	if (p != NULL)
514		error("MS-CHAP authentication failed: %v", p);
515	free(msg);
516}
517
518static void
519ChallengeResponse(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
545void
546ChallengeHash(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 */
576static void
577ascii2unicode(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
586static void
587NTPasswordHash(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
609static void
610ChapMS_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
623static void
624ChapMS2_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
641static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
642
643static void
644ChapMS_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
664void
665GenerateAuthenticatorResponse(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
710static void
711GenerateAuthenticatorResponsePlain
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 */
737void
738mppe_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 */
759static void
760Set_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 */
780void
781mppe_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 */
874static void
875SetMasterKeys(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
890void
891ChapMS(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 */
924void
925ChapMS2(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 */
963void
964set_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
992static 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
1001static 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
1010void
1011chapms_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