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