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