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