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.36 2006/05/21 11:56:40 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#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		     unsigned char *private)
317{
318	challenge++;	/* skip length, should be 8 */
319	*response++ = MS_CHAP_RESPONSE_LEN;
320	ChapMS(challenge, secret, secret_len, response);
321}
322
323static void
324chapms2_make_response(unsigned char *response, int id, char *our_name,
325		      unsigned char *challenge, char *secret, int secret_len,
326		      unsigned char *private)
327{
328	challenge++;	/* skip length, should be 16 */
329	*response++ = MS_CHAP2_RESPONSE_LEN;
330	ChapMS2(challenge,
331#ifdef DEBUGMPPEKEY
332		mschap2_peer_challenge,
333#else
334		NULL,
335#endif
336		our_name, secret, secret_len, response, private,
337		MS_CHAP2_AUTHENTICATEE);
338}
339
340static int
341chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
342{
343	if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
344	    strncmp((char *)msg, "S=", 2) != 0) {
345		/* Packet does not start with "S=" */
346		error("MS-CHAPv2 Success packet is badly formed.");
347		return 0;
348	}
349	msg += 2;
350	len -= 2;
351	if (len < MS_AUTH_RESPONSE_LENGTH
352	    || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
353		/* Authenticator Response did not match expected. */
354		error("MS-CHAPv2 mutual authentication failed.");
355		return 0;
356	}
357	/* Authenticator Response matches. */
358	msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
359	len -= MS_AUTH_RESPONSE_LENGTH;
360	if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
361		msg += 3; /* Eat the delimiter */
362	} else if (len) {
363		/* Packet has extra text which does not begin " M=" */
364		error("MS-CHAPv2 Success packet is badly formed.");
365		return 0;
366	}
367	return 1;
368}
369
370static void
371chapms_handle_failure(unsigned char *inp, int len)
372{
373	int err;
374	char *p, *msg;
375
376	/* We want a null-terminated string for strxxx(). */
377	msg = malloc(len + 1);
378	if (!msg) {
379		notice("Out of memory in chapms_handle_failure");
380		return;
381	}
382	BCOPY(inp, msg, len);
383	msg[len] = 0;
384	p = msg;
385
386	/*
387	 * Deal with MS-CHAP formatted failure messages; just print the
388	 * M=<message> part (if any).  For MS-CHAP we're not really supposed
389	 * to use M=<message>, but it shouldn't hurt.  See
390	 * chapms[2]_verify_response.
391	 */
392	if (!strncmp(p, "E=", 2))
393		err = strtol(p+2, NULL, 10); /* Remember the error code. */
394	else
395		goto print_msg; /* Message is badly formatted. */
396
397	if (len && ((p = strstr(p, " M=")) != NULL)) {
398		/* M=<message> field found. */
399		p += 3;
400	} else {
401		/* No M=<message>; use the error code. */
402		switch (err) {
403		case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
404			p = "E=646 Restricted logon hours";
405			break;
406
407		case MS_CHAP_ERROR_ACCT_DISABLED:
408			p = "E=647 Account disabled";
409			break;
410
411		case MS_CHAP_ERROR_PASSWD_EXPIRED:
412			p = "E=648 Password expired";
413			break;
414
415		case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
416			p = "E=649 No dialin permission";
417			break;
418
419		case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
420			p = "E=691 Authentication failure";
421			break;
422
423		case MS_CHAP_ERROR_CHANGING_PASSWORD:
424			/* Should never see this, we don't support Change Password. */
425			p = "E=709 Error changing password";
426			break;
427
428		default:
429			free(msg);
430			error("Unknown MS-CHAP authentication failure: %.*v",
431			      len, inp);
432			return;
433		}
434	}
435print_msg:
436	if (p != NULL)
437		error("MS-CHAP authentication failed: %v", p);
438	free(msg);
439}
440
441static void
442ChallengeResponse(u_char *challenge,
443		  u_char PasswordHash[MD4_SIGNATURE_SIZE],
444		  u_char response[24])
445{
446    u_char    ZPasswordHash[21];
447
448    BZERO(ZPasswordHash, sizeof(ZPasswordHash));
449    BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
450
451#if 0
452    dbglog("ChallengeResponse - ZPasswordHash %.*B",
453	   sizeof(ZPasswordHash), ZPasswordHash);
454#endif
455
456    (void) DesSetkey(ZPasswordHash + 0);
457    DesEncrypt(challenge, response + 0);
458    (void) DesSetkey(ZPasswordHash + 7);
459    DesEncrypt(challenge, response + 8);
460    (void) DesSetkey(ZPasswordHash + 14);
461    DesEncrypt(challenge, response + 16);
462
463#if 0
464    dbglog("ChallengeResponse - response %.24B", response);
465#endif
466}
467
468void
469ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
470	      char *username, u_char Challenge[8])
471
472{
473    SHA1_CTX	sha1Context;
474    u_char	sha1Hash[SHA1_SIGNATURE_SIZE];
475    char	*user;
476
477    /* remove domain from "domain\username" */
478    if ((user = strrchr(username, '\\')) != NULL)
479	++user;
480    else
481	user = username;
482
483    SHA1_Init(&sha1Context);
484    SHA1_Update(&sha1Context, PeerChallenge, 16);
485    SHA1_Update(&sha1Context, rchallenge, 16);
486    SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
487    SHA1_Final(sha1Hash, &sha1Context);
488
489    BCOPY(sha1Hash, Challenge, 8);
490}
491
492/*
493 * Convert the ASCII version of the password to Unicode.
494 * This implicitly supports 8-bit ISO8859/1 characters.
495 * This gives us the little-endian representation, which
496 * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
497 * is machine-dependent.)
498 */
499static void
500ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
501{
502    int i;
503
504    BZERO(unicode, ascii_len * 2);
505    for (i = 0; i < ascii_len; i++)
506	unicode[i * 2] = (u_char) ascii[i];
507}
508
509static void
510NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
511{
512#ifdef __NetBSD__
513    /* NetBSD uses the libc md4 routines which take bytes instead of bits */
514    int			mdlen = secret_len;
515#else
516    int			mdlen = secret_len * 8;
517#endif
518    MD4_CTX		md4Context;
519
520    MD4Init(&md4Context);
521    /* MD4Update can take at most 64 bytes at a time */
522    while (mdlen > 512) {
523	MD4Update(&md4Context, secret, 512);
524	secret += 64;
525	mdlen -= 512;
526    }
527    MD4Update(&md4Context, secret, mdlen);
528    MD4Final(hash, &md4Context);
529
530}
531
532static void
533ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
534	  u_char NTResponse[24])
535{
536    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
537    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
538
539    /* Hash the Unicode version of the secret (== password). */
540    ascii2unicode(secret, secret_len, unicodePassword);
541    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
542
543    ChallengeResponse(rchallenge, PasswordHash, NTResponse);
544}
545
546static void
547ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
548	   char *secret, int secret_len, u_char NTResponse[24])
549{
550    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
551    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
552    u_char	Challenge[8];
553
554    ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
555
556    /* Hash the Unicode version of the secret (== password). */
557    ascii2unicode(secret, secret_len, unicodePassword);
558    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
559
560    ChallengeResponse(Challenge, PasswordHash, NTResponse);
561}
562
563#ifdef MSLANMAN
564static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
565
566static void
567ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
568	      unsigned char *response)
569{
570    int			i;
571    u_char		UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
572    u_char		PasswordHash[MD4_SIGNATURE_SIZE];
573
574    /* LANMan password is case insensitive */
575    BZERO(UcasePassword, sizeof(UcasePassword));
576    for (i = 0; i < secret_len; i++)
577       UcasePassword[i] = (u_char)toupper(secret[i]);
578    (void) DesSetkey(UcasePassword + 0);
579    DesEncrypt( StdText, PasswordHash + 0 );
580    (void) DesSetkey(UcasePassword + 7);
581    DesEncrypt( StdText, PasswordHash + 8 );
582    ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
583}
584#endif
585
586
587void
588GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
589			      u_char NTResponse[24], u_char PeerChallenge[16],
590			      u_char *rchallenge, char *username,
591			      u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
592{
593    /*
594     * "Magic" constants used in response generation, from RFC 2759.
595     */
596    u_char Magic1[39] = /* "Magic server to client signing constant" */
597	{ 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
598	  0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
599	  0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
600	  0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
601    u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
602	{ 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
603	  0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
604	  0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
605	  0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
606	  0x6E };
607
608    int		i;
609    SHA1_CTX	sha1Context;
610    u_char	Digest[SHA1_SIGNATURE_SIZE];
611    u_char	Challenge[8];
612
613    SHA1_Init(&sha1Context);
614    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
615    SHA1_Update(&sha1Context, NTResponse, 24);
616    SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
617    SHA1_Final(Digest, &sha1Context);
618
619    ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
620
621    SHA1_Init(&sha1Context);
622    SHA1_Update(&sha1Context, Digest, sizeof(Digest));
623    SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
624    SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
625    SHA1_Final(Digest, &sha1Context);
626
627    /* Convert to ASCII hex string. */
628    for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
629	sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
630}
631
632
633static void
634GenerateAuthenticatorResponsePlain
635		(char *secret, int secret_len,
636		 u_char NTResponse[24], u_char PeerChallenge[16],
637		 u_char *rchallenge, char *username,
638		 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
639{
640    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
641    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
642    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
643
644    /* Hash (x2) the Unicode version of the secret (== password). */
645    ascii2unicode(secret, secret_len, unicodePassword);
646    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
647    NTPasswordHash(PasswordHash, sizeof(PasswordHash),
648		   PasswordHashHash);
649
650    GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
651				  rchallenge, username, authResponse);
652}
653
654
655#ifdef MPPE
656/*
657 * Set mppe_xxxx_key from the NTPasswordHashHash.
658 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
659 */
660void
661mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
662{
663    SHA1_CTX	sha1Context;
664    u_char	Digest[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
665
666    SHA1_Init(&sha1Context);
667    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
668    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
669    SHA1_Update(&sha1Context, rchallenge, 8);
670    SHA1_Final(Digest, &sha1Context);
671
672    /* Same key in both directions. */
673    BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
674    BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
675
676    mppe_keys_set = 1;
677}
678
679/*
680 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
681 */
682static void
683Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
684{
685    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
686    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
687    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
688
689    /* Hash (x2) the Unicode version of the secret (== password). */
690    ascii2unicode(secret, secret_len, unicodePassword);
691    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
692    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
693
694    mppe_set_keys(rchallenge, PasswordHashHash);
695}
696
697/*
698 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
699 *
700 * This helper function used in the Winbind module, which gets the
701 * NTHashHash from the server.
702 */
703void
704mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
705	       u_char NTResponse[24], int IsServer)
706{
707    SHA1_CTX	sha1Context;
708    u_char	MasterKey[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
709    u_char	Digest[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
710
711    u_char SHApad1[40] =
712	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
716    u_char SHApad2[40] =
717	{ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
718	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
719	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
720	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
721
722    /* "This is the MPPE Master Key" */
723    u_char Magic1[27] =
724	{ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
725	  0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
726	  0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
727    /* "On the client side, this is the send key; "
728       "on the server side, it is the receive key." */
729    u_char Magic2[84] =
730	{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
731	  0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
732	  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
733	  0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
734	  0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
735	  0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
736	  0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
737	  0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
738	  0x6b, 0x65, 0x79, 0x2e };
739    /* "On the client side, this is the receive key; "
740       "on the server side, it is the send key." */
741    u_char Magic3[84] =
742	{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
743	  0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
744	  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
745	  0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
746	  0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
747	  0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
748	  0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
749	  0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
750	  0x6b, 0x65, 0x79, 0x2e };
751    u_char *s;
752
753    SHA1_Init(&sha1Context);
754    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
755    SHA1_Update(&sha1Context, NTResponse, 24);
756    SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
757    SHA1_Final(MasterKey, &sha1Context);
758
759    /*
760     * generate send key
761     */
762    if (IsServer)
763	s = Magic3;
764    else
765	s = Magic2;
766    SHA1_Init(&sha1Context);
767    SHA1_Update(&sha1Context, MasterKey, 16);
768    SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
769    SHA1_Update(&sha1Context, s, 84);
770    SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
771    SHA1_Final(Digest, &sha1Context);
772
773    BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
774
775    /*
776     * generate recv key
777     */
778    if (IsServer)
779	s = Magic2;
780    else
781	s = Magic3;
782    SHA1_Init(&sha1Context);
783    SHA1_Update(&sha1Context, MasterKey, 16);
784    SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
785    SHA1_Update(&sha1Context, s, 84);
786    SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
787    SHA1_Final(Digest, &sha1Context);
788
789    BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
790
791    mppe_keys_set = 1;
792}
793
794/*
795 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
796 */
797static void
798SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
799{
800    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
801    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
802    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
803    /* Hash (x2) the Unicode version of the secret (== password). */
804    ascii2unicode(secret, secret_len, unicodePassword);
805    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
806    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
807    mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
808}
809
810#endif /* MPPE */
811
812
813void
814ChapMS(u_char *rchallenge, char *secret, int secret_len,
815       unsigned char *response)
816{
817    BZERO(response, MS_CHAP_RESPONSE_LEN);
818
819    ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
820
821#ifdef MSLANMAN
822    ChapMS_LANMan(rchallenge, secret, secret_len, &response);
823
824    /* preferred method is set by option  */
825    response[MS_CHAP_USENT] = !ms_lanman;
826#else
827    response[MS_CHAP_USENT] = 1;
828#endif
829
830#ifdef MPPE
831    Set_Start_Key(rchallenge, secret, secret_len);
832#endif
833}
834
835
836/*
837 * If PeerChallenge is NULL, one is generated and the PeerChallenge
838 * field of response is filled in.  Call this way when generating a response.
839 * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
840 * Call this way when verifying a response (or debugging).
841 * Do not call with PeerChallenge = response.
842 *
843 * The PeerChallenge field of response is then used for calculation of the
844 * Authenticator Response.
845 */
846void
847ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
848	char *user, char *secret, int secret_len, unsigned char *response,
849	u_char authResponse[], int authenticator)
850{
851    /* ARGSUSED */
852    u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
853    int i;
854
855    BZERO(response, sizeof(*response));
856
857    /* Generate the Peer-Challenge if requested, or copy it if supplied. */
858    if (!PeerChallenge)
859	for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
860	    *p++ = (u_char) (drand48() * 0xff);
861    else
862	BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
863	      MS_CHAP2_PEER_CHAL_LEN);
864
865    /* Generate the NT-Response */
866    ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
867	       secret, secret_len, &response[MS_CHAP2_NTRESP]);
868
869    /* Generate the Authenticator Response. */
870    GenerateAuthenticatorResponsePlain(secret, secret_len,
871				       &response[MS_CHAP2_NTRESP],
872				       &response[MS_CHAP2_PEER_CHALLENGE],
873				       rchallenge, user, authResponse);
874
875#ifdef MPPE
876    SetMasterKeys(secret, secret_len,
877		  &response[MS_CHAP2_NTRESP], authenticator);
878#endif
879}
880
881#ifdef MPPE
882/*
883 * Set MPPE options from plugins.
884 */
885void
886set_mppe_enc_types(int policy, int types)
887{
888    /* Early exit for unknown policies. */
889    if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
890	policy != MPPE_ENC_POL_ENC_REQUIRED)
891	return;
892
893    /* Don't modify MPPE if it's optional and wasn't already configured. */
894    if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
895	return;
896
897    /*
898     * Disable undesirable encryption types.  Note that we don't ENABLE
899     * any encryption types, to avoid overriding manual configuration.
900     */
901    switch(types) {
902	case MPPE_ENC_TYPES_RC4_40:
903	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;	/* disable 128-bit */
904	    break;
905	case MPPE_ENC_TYPES_RC4_128:
906	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;	/* disable 40-bit */
907	    break;
908	default:
909	    break;
910    }
911}
912#endif /* MPPE */
913
914static struct chap_digest_type chapms_digest = {
915	CHAP_MICROSOFT,		/* code */
916	chapms_generate_challenge,
917	chapms_verify_response,
918	chapms_make_response,
919	NULL,			/* check_success */
920	chapms_handle_failure,
921};
922
923static struct chap_digest_type chapms2_digest = {
924	CHAP_MICROSOFT_V2,	/* code */
925	chapms2_generate_challenge,
926	chapms2_verify_response,
927	chapms2_make_response,
928	chapms2_check_success,
929	chapms_handle_failure,
930};
931
932void
933chapms_init(void)
934{
935	chap_register_digest(&chapms_digest);
936	chap_register_digest(&chapms2_digest);
937	add_options(chapms_option_list);
938}
939
940#endif /* CHAPMS */
941