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