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