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