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) */
145extern 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
153static void	ascii2unicode (const char[], int, u_char[]);
154static void	NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
155static void	ChallengeResponse (const u_char *, const u_char *, u_char[24]);
156static void	ChallengeHash (const u_char[16], const u_char *, const char *, u_char[8]);
157static void	ChapMS_NT (const u_char *, const char *, int, u_char[24]);
158static void	ChapMS2_NT (const u_char *, const u_char[16], const char *, const char *, int,
159				u_char[24]);
160static 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
164static void	ChapMS_LANMan (u_char *, char *, int, u_char *);
165#endif
166
167static 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
173static void	Set_Start_Key (ppp_pcb *pcb, const u_char *, const char *, int);
174static void	SetMasterKeys (ppp_pcb *pcb, const char *, int, u_char[24], int);
175#endif /* MPPE_SUPPORT */
176
177static void ChapMS (ppp_pcb *pcb, const u_char *, const char *, int, u_char *);
178static 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
182bool	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 */
190static char *mschap_challenge = NULL;
191/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
192static 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 */
203static 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 */
225static 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
237static 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
249static 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
297static 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
374static 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
385static 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
401static 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
431static 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	}
491print_msg:
492	if (p != NULL)
493		ppp_error("MS-CHAP authentication failed: %v", p);
494}
495
496static 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
534static 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 */
564static 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
572static 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
582static 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
594static 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
610static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
611
612static 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
642static 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
690static 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 */
714static 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 */
744static 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
838static 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 */
873static 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 */
912void 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
940const 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
951const 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