1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
25 *
26 * Copyright (c) 1995 Eric Rosenquist.  All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 *
32 * 1. Redistributions of source code must retain the above copyright
33 *    notice, this list of conditions and the following disclaimer.
34 *
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in
37 *    the documentation and/or other materials provided with the
38 *    distribution.
39 *
40 * 3. The name(s) of the authors of this software must not be used to
41 *    endorse or promote products derived from this software without
42 *    prior written permission.
43 *
44 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
45 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
47 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
49 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
50 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51 */
52
53/*
54 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
55 *
56 *   Implemented LANManager type password response to MS-CHAP challenges.
57 *   Now pppd provides both NT style and LANMan style blocks, and the
58 *   prefered is set by option "ms-lanman". Default is to use NT.
59 *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
60 *
61 *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
62 */
63
64/*
65 * Modifications by Frank Cusack, frank@google.com, March 2002.
66 *
67 *   Implemented MS-CHAPv2 functionality, heavily based on sample
68 *   implementation in RFC 2759.  Implemented MPPE functionality,
69 *   heavily based on sample implementation in RFC 3079.
70 *
71 * Copyright (c) 2002 Google, Inc.  All rights reserved.
72 *
73 * Redistribution and use in source and binary forms, with or without
74 * modification, are permitted provided that the following conditions
75 * are met:
76 *
77 * 1. Redistributions of source code must retain the above copyright
78 *    notice, this list of conditions and the following disclaimer.
79 *
80 * 2. Redistributions in binary form must reproduce the above copyright
81 *    notice, this list of conditions and the following disclaimer in
82 *    the documentation and/or other materials provided with the
83 *    distribution.
84 *
85 * 3. The name(s) of the authors of this software must not be used to
86 *    endorse or promote products derived from this software without
87 *    prior written permission.
88 *
89 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
90 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
91 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
92 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
93 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
94 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
95 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
96 *
97 */
98
99#define RCSID	"$Id: chap_ms.c,v 1.9 2005/08/30 22:53:50 lindak Exp $"
100
101#ifdef CHAPMS
102
103#include <stdio.h>
104#include <stdlib.h>
105#include <string.h>
106#include <ctype.h>
107#include <sys/types.h>
108#include <sys/time.h>
109#include <unistd.h>
110#include <pthread.h>
111
112#include "pppd.h"
113#include "chap-new.h"
114#include "chap_ms.h"
115#ifdef __APPLE__
116#define SHA1_CTX SHA_CTX
117#define SHA1_SIGNATURE_SIZE SHA_DIGEST_LENGTH
118#include "CommonCrypto/CommonDigest.h"
119#else
120#include "sha1.h"
121#include "md4.h"
122#endif
123#include "pppcrypt.h"
124#include "magic.h"
125
126#ifndef lint
127static const char rcsid[] = RCSID;
128#endif
129
130
131static void	ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
132static void	ascii2unicode __P((u_char[], int, u_char[]));
133static void	NTPasswordHash __P((u_char *, int, u_char[MD4_SIGNATURE_SIZE]));
134static void	ChallengeResponse __P((u_char *, u_char *, u_char[24]));
135static void	ChapMS_NT __P((u_char *, u_char *, int, u_char[24]));
136static void	ChapMS2_NT __P((u_char *, u_char[16], char *, u_char *, int,
137				u_char[24]));
138static void	GenerateAuthenticatorResponse __P((u_char*, int, u_char[24],
139						   u_char[16], u_char *,
140						   char *, u_char[41]));
141#ifdef MSLANMAN
142static void	ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
143#endif
144
145#ifdef MPPE
146static void	Set_Start_Key __P((u_char *, u_char *, int));
147static void	SetMasterKeys __P((u_char *, int, u_char[24], int));
148#endif
149
150#ifdef MSLANMAN
151bool	ms_lanman = 0;    	/* Use LanMan password instead of NT */
152			  	/* Has meaning only with MS-CHAP challenges */
153#endif
154
155#ifdef MPPE
156u_char mppe_send_key[MPPE_MAX_KEY_LEN];
157u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
158int mppe_keys_set = 0;		/* Have the MPPE keys been set? */
159
160/* For MPPE debug */
161/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
162static char *mschap_challenge = NULL;
163/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
164static u_char *mschap2_peer_challenge = NULL;
165
166#ifdef __APPLE__
167static u_char last_challenge_id = 0;
168static u_char last_challenge_response[16] = "";
169#endif
170
171#include "fsm.h"		/* Need to poke MPPE options */
172#include "ccp.h"
173//#include <net/ppp-comp.h>
174#include <ppp_comp.h>
175#endif
176
177/*
178 * Command-line options.
179 */
180static option_t chapms_option_list[] = {
181#ifdef MSLANMAN
182	{ "ms-lanman", o_bool, &ms_lanman,
183	  "Use LanMan passwd when using MS-CHAP", 1 },
184#endif
185#ifdef DEBUGMPPEKEY
186	{ "mschap-challenge", o_string, &mschap_challenge,
187	  "specify CHAP challenge" },
188	{ "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
189	  "specify CHAP peer challenge" },
190#endif
191	{ NULL }
192};
193
194/*
195 * chapms_generate_challenge - generate a challenge for MS-CHAP.
196 * For MS-CHAP the challenge length is fixed at 8 bytes.
197 * The length goes in challenge[0] and the actual challenge starts
198 * at challenge[1].
199 */
200static void
201chapms_generate_challenge(unsigned char *challenge)
202{
203	*challenge++ = 8;
204	if (mschap_challenge && strlen(mschap_challenge) == 8)
205		memcpy(challenge, mschap_challenge, 8);
206	else
207		random_bytes(challenge, 8);
208}
209
210static void
211chapms2_generate_challenge(unsigned char *challenge)
212{
213	*challenge++ = 16;
214	if (mschap_challenge && strlen(mschap_challenge) == 16)
215		memcpy(challenge, mschap_challenge, 16);
216	else
217		random_bytes(challenge, 16);
218}
219
220static int
221chapms_verify_response(int id, char *name,
222		       unsigned char *secret, int secret_len,
223		       unsigned char *challenge, unsigned char *response,
224		       char *message, int message_space)
225{
226	MS_ChapResponse *rmd;
227	MS_ChapResponse md;
228	int diff;
229	int challenge_len, response_len;
230
231	challenge_len = *challenge++;	/* skip length, is 8 */
232	response_len = *response++;
233	if (response_len != MS_CHAP_RESPONSE_LEN)
234		goto bad;
235
236	rmd = (MS_ChapResponse *) response;
237
238#ifndef MSLANMAN
239	if (!rmd->UseNT[0]) {
240		/* Should really propagate this into the error packet. */
241		notice("Peer request for LANMAN auth not supported");
242		goto bad;
243	}
244#endif
245
246	/* Generate the expected response. */
247	ChapMS(challenge, secret, secret_len, &md);
248
249#ifdef MSLANMAN
250	/* Determine which part of response to verify against */
251	if (!rmd->UseNT[0])
252		diff = memcmp(&rmd->LANManResp, &md.LANManResp,
253			      sizeof(md.LANManResp));
254	else
255#endif
256		diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
257
258	if (diff == 0) {
259		slprintf(message, message_space, "Access granted");
260		return 1;
261	}
262
263 bad:
264	/* See comments below for MS-CHAP V2 */
265	slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
266		 challenge_len, challenge);
267	return 0;
268}
269
270static int
271chapms2_verify_response(int id, char *name,
272			unsigned char *secret, int secret_len,
273			unsigned char *challenge, unsigned char *response,
274			char *message, int message_space)
275{
276	MS_Chap2Response *rmd;
277	MS_Chap2Response md;
278	u_char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
279	int challenge_len, response_len;
280
281	challenge_len = *challenge++;	/* skip length, is 16 */
282	response_len = *response++;
283	if (response_len != MS_CHAP2_RESPONSE_LEN)
284		goto bad;	/* not even the right length */
285
286	rmd = (MS_Chap2Response *) response;
287
288	/* Generate the expected response and our mutual auth. */
289	ChapMS2(challenge, rmd->PeerChallenge, name,
290		secret, secret_len, &md,
291		saresponse, MS_CHAP2_AUTHENTICATOR);
292
293	/* compare MDs and send the appropriate status */
294	/*
295	 * Per RFC 2759, success message must be formatted as
296	 *     "S=<auth_string> M=<message>"
297	 * where
298	 *     <auth_string> is the Authenticator Response (mutual auth)
299	 *     <message> is a text message
300	 *
301	 * However, some versions of Windows (win98 tested) do not know
302	 * about the M=<message> part (required per RFC 2759) and flag
303	 * it as an error (reported incorrectly as an encryption error
304	 * to the user).  Since the RFC requires it, and it can be
305	 * useful information, we supply it if the peer is a conforming
306	 * system.  Luckily (?), win98 sets the Flags field to 0x04
307	 * (contrary to RFC requirements) so we can use that to
308	 * distinguish between conforming and non-conforming systems.
309	 *
310	 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
311	 * help debugging this.
312	 */
313	if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
314		if (rmd->Flags[0])
315			slprintf(message, message_space, "S=%s", saresponse);
316		else
317			slprintf(message, message_space, "S=%s M=%s",
318				 saresponse, "Access granted");
319		return 1;
320	}
321
322 bad:
323	/*
324	 * Failure message must be formatted as
325	 *     "E=e R=r C=c V=v M=m"
326	 * where
327	 *     e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
328	 *     r = retry (we use 1, ok to retry)
329	 *     c = challenge to use for next response, we reuse previous
330	 *     v = Change Password version supported, we use 0
331	 *     m = text message
332	 *
333	 * The M=m part is only for MS-CHAPv2.  Neither win2k nor
334	 * win98 (others untested) display the message to the user anyway.
335	 * They also both ignore the E=e code.
336	 *
337	 * Note that it's safe to reuse the same challenge as we don't
338	 * actually accept another response based on the error message
339	 * (and no clients try to resend a response anyway).
340	 *
341	 * Basically, this whole bit is useless code, even the small
342	 * implementation here is only because of overspecification.
343	 */
344	slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
345		 challenge_len, challenge, "Access denied");
346	return 0;
347}
348
349static void
350chapms_make_response(unsigned char *response, int id, char *our_name,
351		     unsigned char *challenge, u_char *secret, int secret_len,
352		     unsigned char *private)
353{
354	challenge++;	/* skip length, should be 8 */
355	*response++ = MS_CHAP_RESPONSE_LEN;
356	ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
357}
358
359static void
360chapms2_make_response(unsigned char *response, int id, char *our_name,
361		      unsigned char *challenge, u_char *secret, int secret_len,
362		      unsigned char *private)
363{
364	u_char *challenge_resp;
365
366	challenge++;	/* skip length, should be 16 */
367	*response++ = MS_CHAP2_RESPONSE_LEN;
368
369	challenge_resp = mschap2_peer_challenge;
370
371#ifdef __APPLE__
372	if(!challenge_resp) {
373		/* use the the last challenge response known if the peer
374		 * hasn't supplied one
375		 */
376		if(id == last_challenge_id && last_challenge_response[0])
377			challenge_resp = last_challenge_response;
378		else {
379			challenge_resp = NULL;
380		}
381	}
382#endif
383
384	ChapMS2(challenge,  challenge_resp,
385//#ifdef __APPLE__
386#if 0
387			? mschap2_peer_challenge :
388				(id == last_challenge_id && last_challenge_response[0] ? last_challenge_response : NULL),
389#endif
390		our_name,
391		secret, secret_len,
392		(MS_Chap2Response *) response, private,
393		MS_CHAP2_AUTHENTICATEE);
394#ifdef __APPLE__
395	last_challenge_id = id;
396#endif
397}
398
399struct rc4_state {
400        u_char  perm[256];
401        u_char  index1;
402        u_char  index2;
403};
404
405static __inline void
406swap_bytes(u_char *a, u_char *b)
407{
408        u_char temp;
409
410        temp = *a;
411        *a = *b;
412        *b = temp;
413}
414
415/*
416 * Initialize an RC4 state buffer using the supplied key,
417 * which can have arbitrary length.
418 */
419static void
420rc4_init(struct rc4_state *const state, const u_char *key, int keylen)
421{
422        u_char j;
423        int i;
424
425        /* Initialize state with identity permutation */
426        for (i = 0; i < 256; i++)
427                state->perm[i] = (u_char)i;
428        state->index1 = 0;
429        state->index2 = 0;
430
431        /* Randomize the permutation using key data */
432        for (j = i = 0; i < 256; i++) {
433                j += state->perm[i] + key[i % keylen];
434                swap_bytes(&state->perm[i], &state->perm[j]);
435        }
436}
437
438/*
439 * Encrypt some data using the supplied RC4 state buffer.
440 * The input and output buffers may be the same buffer.
441 * Since RC4 is a stream cypher, this function is used
442 * for both encryption and decryption.
443 */
444static void
445rc4_crypt(struct rc4_state *const state,
446        const u_char *inbuf, u_char *outbuf, int buflen)
447{
448        int i;
449        u_char j;
450
451        for (i = 0; i < buflen; i++) {
452
453                /* Update modification indicies */
454                state->index1++;
455                state->index2 += state->perm[state->index1];
456
457                /* Modify permutation */
458                swap_bytes(&state->perm[state->index1],
459                    &state->perm[state->index2]);
460
461                /* Encrypt/decrypt next byte */
462                j = state->perm[state->index1] + state->perm[state->index2];
463                outbuf[i] = inbuf[i] ^ state->perm[j];
464        }
465}
466
467
468static void
469EncryptPwBlockWithPasswordHash(
470   u_char	*UnicodePassword,
471   int		UnicodePasswordLen,
472   u_char	*PasswordHash,
473   u_char *EncryptedPwBlock)
474{
475	struct rc4_state rcs;
476
477	u_char ClearPwBlock[MAX_NT_PASSWORD * 2 + 4];
478	int offset = MAX_NT_PASSWORD * 2 - UnicodePasswordLen;
479
480	/* Fill ClearPwBlock with random octet values */
481	random_bytes(ClearPwBlock, sizeof(ClearPwBlock));
482
483	memcpy(ClearPwBlock + offset, UnicodePassword, UnicodePasswordLen);
484
485	// Fix Me: This needs to be little endian
486	//*(u_int32_t*)&ClearPwBlock[MAX_NT_PASSWORD * 2] = UnicodePasswordLen;
487	ClearPwBlock[MAX_NT_PASSWORD*2 + 0] = UnicodePasswordLen;
488	ClearPwBlock[MAX_NT_PASSWORD*2 + 1] = UnicodePasswordLen >> 8;
489	ClearPwBlock[MAX_NT_PASSWORD*2 + 2] = UnicodePasswordLen >> 16;
490	ClearPwBlock[MAX_NT_PASSWORD*2 + 3] = UnicodePasswordLen >> 24;
491
492	rc4_init(&rcs, PasswordHash, MD4_SIGNATURE_SIZE);
493	rc4_crypt(&rcs, ClearPwBlock, EncryptedPwBlock, sizeof(ClearPwBlock));
494}
495
496static void
497NewPasswordEncryptedWithOldNtPasswordHash(u_char *NewPassword, int NewPasswordLen,
498	u_char *OldPassword, int OldPasswordLen,
499	u_char *EncryptedPwBlock)
500{
501    u_char	unicodeOldPassword[MAX_NT_PASSWORD * 2];
502    u_char	OldPasswordHash[MD4_SIGNATURE_SIZE];
503    u_char	unicodeNewPassword[MAX_NT_PASSWORD * 2];
504
505    /* Hash the Unicode version of the old password */
506    ascii2unicode(OldPassword, OldPasswordLen, unicodeOldPassword);
507    NTPasswordHash(unicodeOldPassword, OldPasswordLen * 2, OldPasswordHash);
508
509    /* Unicode version of the new password */
510    ascii2unicode(NewPassword, NewPasswordLen, unicodeNewPassword);
511
512	EncryptPwBlockWithPasswordHash(unicodeNewPassword, NewPasswordLen * 2,
513					OldPasswordHash, EncryptedPwBlock);
514}
515
516static void
517NtPasswordHashEncryptedWithBlock(u_char *PasswordHash, u_char *Block, u_char *Cypher)
518{
519    (void) DesSetkey(Block + 0);
520    DesEncrypt(PasswordHash, Cypher + 0);
521
522    (void) DesSetkey(Block + 7);
523    DesEncrypt(PasswordHash + 8, Cypher + 8);
524}
525
526static void
527OldNtPasswordHashEncryptedWithNewNtPasswordHash(u_char *NewPassword, int NewPasswordLen,
528	u_char *OldPassword, int OldPasswordLen,
529	u_char *EncryptedPasswordHash)
530{
531    u_char	unicodeOldPassword[MAX_NT_PASSWORD * 2];
532    u_char	OldPasswordHash[MD4_SIGNATURE_SIZE];
533    u_char	unicodeNewPassword[MAX_NT_PASSWORD * 2];
534	u_char	NewPasswordHash[MD4_SIGNATURE_SIZE];
535
536    /* Hash the Unicode version of the old password */
537    ascii2unicode(OldPassword, OldPasswordLen, unicodeOldPassword);
538    NTPasswordHash(unicodeOldPassword, OldPasswordLen * 2, OldPasswordHash);
539
540    /* Hash the Unicode version of the new password */
541    ascii2unicode(NewPassword, NewPasswordLen, unicodeNewPassword);
542    NTPasswordHash(unicodeNewPassword, NewPasswordLen * 2, NewPasswordHash);
543
544	NtPasswordHashEncryptedWithBlock(OldPasswordHash, NewPasswordHash,
545									EncryptedPasswordHash);
546}
547
548static void
549ascii2hex(u_char *text, int len, u_char *hex)
550{
551	int i;
552	for (i = 0; i < len; i++) {
553		if (text[0] >= '0' && text[0] <= '9')
554			hex[i] = text[0] - '0';
555		else if (text[0] >= 'a' && text[0] <= 'f')
556			hex[i] = text[0] - 'a' + 10;
557		else if (text[0] >= 'A' && text[0] <= 'F')
558			hex[i] = text[0] - 'A' + 10;
559
560		hex[i] <<= 4;
561
562		if (text[1] >= '0' && text[1] <= '9')
563			hex[i] |= text[1] - '0';
564		else if (text[1] >= 'a' && text[1] <= 'f')
565			hex[i] |= text[1] - 'a' + 10;
566		else if (text[1] >= 'A' && text[1] <= 'F')
567			hex[i] |= text[1] - 'A' + 10;
568
569		text += 2;
570	}
571}
572
573static int
574chapms2_change_password(unsigned char *response, char *our_name,
575		      unsigned char *status_pkt,
576			  u_char *secret, int secret_len,
577			  u_char *new_secret, int new_secret_len,
578		      unsigned char *private)
579{
580	int pktlen;
581	unsigned char *p = response;
582
583	/* status_pkt and response point to the beginning of the CHAP payload */
584	pktlen = status_pkt[2];
585	pktlen <<= 8;
586	pktlen += status_pkt[3];
587
588	p[0] = MS_CHAP2_CHANGE_PASSWORD;
589	p[1] = status_pkt[1] + 1; // id of failure + 1
590	p[2] = (MS_CHAP2_CHANGE_PASSWORD_LEN + CHAP_HDRLEN) >> 8;
591	p[3] = (unsigned char)(MS_CHAP2_CHANGE_PASSWORD_LEN + CHAP_HDRLEN);
592	p += CHAP_HDRLEN;
593
594	/* first copy encrypted password */
595	NewPasswordEncryptedWithOldNtPasswordHash(new_secret, new_secret_len,
596		secret, secret_len, p);
597	p += 516;
598
599	/* then copy encrypted hash */
600	OldNtPasswordHashEncryptedWithNewNtPasswordHash(new_secret, new_secret_len,
601		secret, secret_len, p);
602	p += MD4_SIGNATURE_SIZE;
603
604	status_pkt += CHAP_HDRLEN;
605	pktlen -= CHAP_HDRLEN;
606	/* then the response */
607	for (; pktlen; pktlen--, status_pkt++) {
608		if (!strncmp((char*)status_pkt, " C=", 3)) {
609
610			unsigned char challenge[MAX_CHALLENGE_LEN];
611
612			ascii2hex(status_pkt + 3, sizeof(challenge), challenge);
613
614			ChapMS2(challenge,  mschap2_peer_challenge,
615				our_name,
616				new_secret, new_secret_len,
617				(MS_Chap2Response *) p, private,
618				MS_CHAP2_AUTHENTICATEE);
619			break;
620		}
621	}
622
623	/* then add one zero value flag, not in regular response */
624	p += sizeof(MS_Chap2Response);
625	*p = 0;
626
627	return 0;
628}
629
630static int
631chapms2_retry_password(unsigned char *response, char *our_name,
632		      unsigned char *status_pkt,
633			  u_char *secret, int secret_len,
634		      unsigned char *private)
635{
636	int pktlen, namelen = strlen(our_name);
637	unsigned char *p = response;
638
639	/* status_pkt and response point to the beginning of the CHAP payload */
640	pktlen = status_pkt[2];
641	pktlen <<= 8;
642	pktlen += status_pkt[3];
643
644	p[0] = CHAP_RESPONSE;
645	p[1] = status_pkt[1] + 1; // id of failure + 1
646	p[2] = (MS_CHAP2_RESPONSE_LEN + 1 + namelen + CHAP_HDRLEN) >> 8;
647	p[3] = (unsigned char)(MS_CHAP2_RESPONSE_LEN + 1 + namelen + CHAP_HDRLEN);
648	p += CHAP_HDRLEN;
649
650	status_pkt += CHAP_HDRLEN;
651	pktlen -= CHAP_HDRLEN;
652	/* then the response */
653	for (; pktlen; pktlen--, status_pkt++) {
654		if (!strncmp((char*)status_pkt, " C=", 3)) {
655			unsigned char challenge[MAX_CHALLENGE_LEN];
656
657			ascii2hex(status_pkt + 3, sizeof(challenge), challenge);
658
659			*p++ = MS_CHAP2_RESPONSE_LEN;
660			ChapMS2(challenge,  mschap2_peer_challenge,
661				our_name,
662				secret, secret_len,
663				(MS_Chap2Response *) p, private,
664				MS_CHAP2_AUTHENTICATEE);
665
666			p += MS_CHAP2_RESPONSE_LEN;
667			memcpy(p, our_name, namelen);
668			break;
669		}
670	}
671
672	return 0;
673}
674
675static int
676chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
677{
678	if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || strncmp((char*)msg, "S=", 2)) {
679		/* Packet does not start with "S=" */
680		error("MS-CHAPv2 Success packet is badly formed.");
681		return 0;
682	}
683	msg += 2;
684	len -= 2;
685	if (len < MS_AUTH_RESPONSE_LENGTH
686	    || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
687		/* Authenticator Response did not match expected. */
688		error("MS-CHAPv2 mutual authentication failed.");
689		return 0;
690	}
691	/* Authenticator Response matches. */
692	msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
693	len -= MS_AUTH_RESPONSE_LENGTH;
694	if ((len >= 3) && !strncmp((char*)msg, " M=", 3))
695	{
696		//spec-conformant
697		msg += 3; /* Eat the delimiter */
698	} else if (len) {
699		/* Packet has extra text which does not begin " M=" */
700
701		//we'll allow the missing-space case from the server, even though
702		//it's non-conforming to spec!
703		dbglog("Rcvd non-conforming MSCHAPv2 Success packet, len=%d", len);
704		if(len >= 2 && !strncmp((char*)msg, "M=", 2))
705			msg += 2;
706		else
707		{
708			error("MS-CHAPv2 Success packet is badly formed.");
709			return 0;
710		}
711	}
712	return 1;
713}
714
715static int
716chapms_handle_failure(unsigned char *inp, int len, char *message, int message_max_len)
717{
718	int err, ret = 0;
719	char *p, *p1, *msg;
720
721	/* We want a null-terminated string for strxxx(). */
722	msg = malloc(len + 1);
723	if (!msg) {
724		notice("Out of memory in chapms_handle_failure");
725		return 0;
726	}
727	BCOPY(inp, msg, len);
728	msg[len] = 0;
729	p = msg;
730
731	/*
732	 * Deal with MS-CHAP formatted failure messages; just print the
733	 * M=<message> part (if any).  For MS-CHAP we're not really supposed
734	 * to use M=<message>, but it shouldn't hurt.  See
735	 * chapms[2]_verify_response.
736	 */
737	if (!strncmp(p, "E=", 2))
738		err = strtol(p + 2, NULL, 10); /* Remember the error code. */
739	else {
740#ifdef __APPLE__
741		p += len;
742#endif
743		goto print_msg; /* Message is badly formatted. */
744	}
745
746	if (len && ((p1 = strstr(p, " R=")) != NULL)) {
747		/* R=x field found. */
748		p1 += 3;
749		if (*p1 == '1' && retry_password_hook)
750			ret = 2;
751	}
752
753#ifdef __APPLE__
754	if (err == MS_CHAP_ERROR_PASSWD_EXPIRED && change_password_hook)
755		ret = 1;
756#endif
757
758	if (len && ((p = strstr(p, " M=")) != NULL)) {
759		/* M=<message> field found. */
760		p += 3;
761#ifdef __APPLE__
762		strncpy(message, p, message_max_len-1);
763		message[message_max_len] = 0;
764#endif
765	} else {
766		/* No M=<message>; use the error code. */
767		switch (err) {
768		case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
769			p = "E=646 Restricted logon hours";
770			break;
771
772		case MS_CHAP_ERROR_ACCT_DISABLED:
773			p = "E=647 Account disabled";
774			break;
775
776		case MS_CHAP_ERROR_PASSWD_EXPIRED:
777			p = "E=648 Password expired";
778			break;
779
780		case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
781			p = "E=649 No dialin permission";
782			break;
783
784		case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
785			p = "E=691 Authentication failure";
786			break;
787
788		case MS_CHAP_ERROR_CHANGING_PASSWORD:
789#ifndef __APPLE__
790			/* Should never see this, we don't support Change Password. */
791#endif
792			p = "E=709 Error changing password";
793			break;
794
795		default:
796			free(msg);
797			error("error %d", err);
798			error("Unknown MS-CHAP authentication failure: %.*v",
799			      len, inp);
800			return 0;
801		}
802	}
803print_msg:
804	if (p != NULL)
805		error("MS-CHAP authentication failed: %v", p);
806	free(msg);
807	return ret;
808}
809
810
811static void
812ChallengeResponse(u_char *challenge,
813		  u_char PasswordHash[MD4_SIGNATURE_SIZE],
814		  u_char response[24])
815{
816    u_char    ZPasswordHash[21];
817
818    BZERO(ZPasswordHash, sizeof(ZPasswordHash));
819    BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
820
821#if 0
822    dbglog("ChallengeResponse - ZPasswordHash %.*B",
823	   sizeof(ZPasswordHash), ZPasswordHash);
824#endif
825
826    (void) DesSetkey(ZPasswordHash + 0);
827    DesEncrypt(challenge, response + 0);
828    (void) DesSetkey(ZPasswordHash + 7);
829    DesEncrypt(challenge, response + 8);
830    (void) DesSetkey(ZPasswordHash + 14);
831    DesEncrypt(challenge, response + 16);
832
833#if 0
834    dbglog("ChallengeResponse - response %.24B", response);
835#endif
836}
837
838static void
839ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
840	      char *username, u_char Challenge[8])
841
842{
843    SHA1_CTX	sha1Context;
844    u_char	sha1Hash[SHA1_SIGNATURE_SIZE];
845    char	*user;
846
847    /* remove domain from "domain\username" */
848    if ((user = strrchr(username, '\\')) != NULL)
849	++user;
850    else
851	user = username;
852
853    SHA1_Init(&sha1Context);
854    SHA1_Update(&sha1Context, PeerChallenge, 16);
855    SHA1_Update(&sha1Context, rchallenge, 16);
856    SHA1_Update(&sha1Context, user, strlen(user));
857    SHA1_Final(sha1Hash, &sha1Context);
858
859    BCOPY(sha1Hash, Challenge, 8);
860}
861
862/*
863 * Convert the ASCII version of the password to Unicode.
864 * This implicitly supports 8-bit ISO8859/1 characters.
865 * This gives us the little-endian representation, which
866 * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
867 * is machine-dependent.)
868 */
869static void
870ascii2unicode(u_char ascii[], int ascii_len, u_char unicode[])
871{
872    int i;
873
874    BZERO(unicode, ascii_len * 2);
875    for (i = 0; i < ascii_len; i++)
876	unicode[i * 2] = (u_char) ascii[i];
877}
878
879static void
880NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
881{
882#ifdef __APPLE__
883	CC_MD4(secret, secret_len, hash);
884
885#else
886#ifdef __NetBSD__
887    /* NetBSD uses the libc md4 routines which take bytes instead of bits */
888    int			mdlen = secret_len;
889#else
890    int			mdlen = secret_len * 8;
891#endif
892    MD4_CTX		md4Context;
893
894    MD4Init(&md4Context);
895    /* MD4Update can take at most 64 bytes at a time */
896    while (mdlen > 512) {
897	MD4Update(&md4Context, secret, 512);
898	secret += 64;
899	mdlen -= 512;
900    }
901    MD4Update(&md4Context, secret, mdlen);
902    MD4Final(hash, &md4Context);
903#endif
904
905}
906
907static void
908ChapMS_NT(u_char *rchallenge, u_char *secret, int secret_len,
909	  u_char NTResponse[24])
910{
911    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
912    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
913
914    /* Hash the Unicode version of the secret (== password). */
915    ascii2unicode(secret, secret_len, unicodePassword);
916    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
917
918    ChallengeResponse(rchallenge, PasswordHash, NTResponse);
919}
920
921static void
922ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
923	   u_char *secret, int secret_len, u_char NTResponse[24])
924{
925    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
926    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
927    u_char	Challenge[8];
928
929    ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
930
931    /* Hash the Unicode version of the secret (== password). */
932    ascii2unicode(secret, secret_len, unicodePassword);
933    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
934
935    ChallengeResponse(Challenge, PasswordHash, NTResponse);
936}
937
938#ifdef MSLANMAN
939static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
940
941static void
942ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
943	      MS_ChapResponse *response)
944{
945    int			i;
946    u_char		UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
947    u_char		PasswordHash[MD4_SIGNATURE_SIZE];
948
949    /* LANMan password is case insensitive */
950    BZERO(UcasePassword, sizeof(UcasePassword));
951    for (i = 0; i < secret_len; i++)
952       UcasePassword[i] = (u_char)toupper(secret[i]);
953    (void) DesSetkey(UcasePassword + 0);
954    DesEncrypt( StdText, PasswordHash + 0 );
955    (void) DesSetkey(UcasePassword + 7);
956    DesEncrypt( StdText, PasswordHash + 8 );
957    ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
958}
959#endif
960
961
962static void
963GenerateAuthenticatorResponse(u_char *secret, int secret_len,
964			      u_char NTResponse[24], u_char PeerChallenge[16],
965			      u_char *rchallenge, char *username,
966			      u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
967{
968    /*
969     * "Magic" constants used in response generation, from RFC 2759.
970     */
971    u_char Magic1[39] = /* "Magic server to client signing constant" */
972	{ 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
973	  0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
974	  0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
975	  0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
976    u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
977	{ 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
978	  0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
979	  0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
980	  0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
981	  0x6E };
982
983    int		i;
984    SHA1_CTX	sha1Context;
985    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
986    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
987    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
988    u_char	Digest[SHA1_SIGNATURE_SIZE];
989    u_char	Challenge[8];
990
991    /* Hash (x2) the Unicode version of the secret (== password). */
992    ascii2unicode(secret, secret_len, unicodePassword);
993    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
994    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
995
996    SHA1_Init(&sha1Context);
997    SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
998    SHA1_Update(&sha1Context, NTResponse, 24);
999    SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
1000    SHA1_Final(Digest, &sha1Context);
1001
1002    ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
1003
1004    SHA1_Init(&sha1Context);
1005    SHA1_Update(&sha1Context, Digest, sizeof(Digest));
1006    SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
1007    SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
1008    SHA1_Final(Digest, &sha1Context);
1009
1010    /* Convert to ASCII hex string. */
1011    for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
1012	snprintf((char*)&authResponse[i * 2], MS_AUTH_RESPONSE_LENGTH+1 - i * 2, "%02X", Digest[i]);
1013}
1014
1015
1016#ifdef MPPE
1017/*
1018 * Set mppe_xxxx_key from the NTPasswordHashHash.
1019 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
1020 */
1021void
1022mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
1023{
1024    SHA1_CTX	sha1Context;
1025    u_char	Digest[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
1026
1027    SHA1_Init(&sha1Context);
1028    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
1029    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
1030    SHA1_Update(&sha1Context, rchallenge, 8);
1031    SHA1_Final(Digest, &sha1Context);
1032
1033    /* Same key in both directions. */
1034    BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
1035    BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
1036}
1037
1038/*
1039 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
1040 */
1041static void
1042Set_Start_Key(u_char *rchallenge, u_char *secret, int secret_len)
1043{
1044    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
1045    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
1046    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
1047
1048    /* Hash (x2) the Unicode version of the secret (== password). */
1049    ascii2unicode(secret, secret_len, unicodePassword);
1050    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
1051    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
1052
1053    mppe_set_keys(rchallenge, PasswordHashHash);
1054}
1055
1056/*
1057 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
1058 */
1059static void
1060SetMasterKeys(u_char *secret, int secret_len, u_char NTResponse[24], int IsServer)
1061{
1062    SHA1_CTX	sha1Context;
1063    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
1064    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
1065    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
1066    u_char	MasterKey[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
1067    u_char	Digest[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
1068
1069    u_char SHApad1[40] =
1070	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1071	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1072	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1073	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1074    u_char SHApad2[40] =
1075	{ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
1076	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
1077	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
1078	  0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
1079
1080    /* "This is the MPPE Master Key" */
1081    u_char Magic1[27] =
1082	{ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
1083	  0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
1084	  0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
1085    /* "On the client side, this is the send key; "
1086       "on the server side, it is the receive key." */
1087    u_char Magic2[84] =
1088	{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
1089	  0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
1090	  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
1091	  0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
1092	  0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
1093	  0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
1094	  0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
1095	  0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
1096	  0x6b, 0x65, 0x79, 0x2e };
1097    /* "On the client side, this is the receive key; "
1098       "on the server side, it is the send key." */
1099    u_char Magic3[84] =
1100	{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
1101	  0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
1102	  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
1103	  0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
1104	  0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
1105	  0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
1106	  0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
1107	  0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
1108	  0x6b, 0x65, 0x79, 0x2e };
1109    u_char *s;
1110
1111    /* Hash (x2) the Unicode version of the secret (== password). */
1112    ascii2unicode(secret, secret_len, unicodePassword);
1113    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
1114    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
1115
1116    SHA1_Init(&sha1Context);
1117    SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
1118    SHA1_Update(&sha1Context, NTResponse, 24);
1119    SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
1120    SHA1_Final(MasterKey, &sha1Context);
1121
1122    /*
1123     * generate send key
1124     */
1125    if (IsServer)
1126	s = Magic3;
1127    else
1128	s = Magic2;
1129    SHA1_Init(&sha1Context);
1130    SHA1_Update(&sha1Context, MasterKey, 16);
1131    SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
1132    SHA1_Update(&sha1Context, s, 84);
1133    SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
1134    SHA1_Final(Digest, &sha1Context);
1135
1136    BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
1137
1138    /*
1139     * generate recv key
1140     */
1141    if (IsServer)
1142	s = Magic2;
1143    else
1144	s = Magic3;
1145    SHA1_Init(&sha1Context);
1146    SHA1_Update(&sha1Context, MasterKey, 16);
1147    SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
1148    SHA1_Update(&sha1Context, s, 84);
1149    SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
1150    SHA1_Final(Digest, &sha1Context);
1151
1152    BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
1153}
1154
1155#endif /* MPPE */
1156
1157
1158void
1159ChapMS(u_char *rchallenge, u_char *secret, int secret_len,
1160       MS_ChapResponse *response)
1161{
1162#if 0
1163    CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
1164#endif
1165    BZERO(response, sizeof(*response));
1166
1167    ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
1168
1169#ifdef MSLANMAN
1170    ChapMS_LANMan(rchallenge, secret, secret_len, response);
1171
1172    /* preferred method is set by option  */
1173    response->UseNT[0] = !ms_lanman;
1174#else
1175    response->UseNT[0] = 1;
1176#endif
1177
1178#ifdef MPPE
1179    Set_Start_Key(rchallenge, secret, secret_len);
1180    mppe_keys_set = 1;
1181#endif
1182}
1183
1184
1185/*
1186 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
1187 * is filled in.  Call this way when generating a response.
1188 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
1189 * Call this way when verifying a response (or debugging).
1190 * Do not call with PeerChallenge = response->PeerChallenge.
1191 *
1192 * response->PeerChallenge is then used for calculation of the
1193 * Authenticator Response.
1194 */
1195void
1196ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
1197	char *user, u_char *secret, int secret_len, MS_Chap2Response *response,
1198	u_char authResponse[], int authenticator)
1199{
1200    /* ARGSUSED */
1201    u_char *p = response->PeerChallenge;
1202    int i;
1203
1204    BZERO(response, sizeof(*response));
1205
1206    /* Generate the Peer-Challenge if requested, or copy it if supplied. */
1207    if (!PeerChallenge)
1208	for (i = 0; i < sizeof(response->PeerChallenge); i++) {
1209#ifdef __APPLE__
1210		last_challenge_response[i] = *p++ = (u_char) (drand48() * 0xff);
1211#else
1212	    *p++ = (u_char) (drand48() * 0xff);
1213#endif
1214	}
1215    else
1216	BCOPY(PeerChallenge, response->PeerChallenge,
1217	      sizeof(response->PeerChallenge));
1218
1219    /* Generate the NT-Response */
1220    ChapMS2_NT(rchallenge, response->PeerChallenge, user,
1221	       secret, secret_len, response->NTResp);
1222
1223    /* Generate the Authenticator Response. */
1224    GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
1225				  response->PeerChallenge, rchallenge,
1226				  user, authResponse);
1227
1228#ifdef MPPE
1229    SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
1230    mppe_keys_set = 1;
1231#endif
1232}
1233
1234#ifdef MPPE
1235/*
1236 * Set MPPE options from plugins.
1237 */
1238void
1239set_mppe_enc_types(int policy, int types)
1240{
1241    /* Early exit for unknown policies. */
1242    if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
1243	policy != MPPE_ENC_POL_ENC_REQUIRED)
1244	return;
1245
1246    /* Don't modify MPPE if it's optional and wasn't already configured. */
1247    if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
1248	return;
1249
1250    /*
1251     * Disable undesirable encryption types.  Note that we don't ENABLE
1252     * any encryption types, to avoid overriding manual configuration.
1253     */
1254    switch(types) {
1255	case MPPE_ENC_TYPES_RC4_40:
1256	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;	/* disable 128-bit */
1257	    break;
1258	case MPPE_ENC_TYPES_RC4_128:
1259	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;	/* disable 40-bit */
1260	    break;
1261	default:
1262	    break;
1263    }
1264}
1265#endif /* MPPE */
1266
1267static struct chap_digest_type chapms_digest = {
1268	CHAP_MICROSOFT,		/* code */
1269	chapms_generate_challenge,
1270	chapms_verify_response,
1271	chapms_make_response,
1272	NULL,			/* check_success */
1273	chapms_handle_failure,
1274#ifdef __APPLE__
1275	0,
1276	0
1277#endif
1278};
1279
1280static struct chap_digest_type chapms2_digest = {
1281	CHAP_MICROSOFT_V2,	/* code */
1282	chapms2_generate_challenge,
1283	chapms2_verify_response,
1284	chapms2_make_response,
1285	chapms2_check_success,
1286	chapms_handle_failure,
1287#ifdef __APPLE__
1288	chapms2_change_password,
1289	chapms2_retry_password
1290#endif
1291};
1292
1293void
1294chapms_init(void)
1295{
1296	chap_register_digest(&chapms_digest);
1297	chap_register_digest(&chapms2_digest);
1298	add_options(chapms_option_list);
1299}
1300
1301#ifdef __APPLE__
1302void
1303chapms_reinit(void)
1304{
1305	last_challenge_id = 0;
1306	last_challenge_response[0] = 0;
1307}
1308#endif
1309
1310#endif /* CHAPMS */
1311