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