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