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