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 The Android Open Source Project
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.33 2004/11/12 09:57:43 paulus 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 #ifdef ANDROID_CHANGES
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((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((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, MS_ChapResponse *));
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 MS_ChapResponse *rmd;
199 MS_ChapResponse md;
200 int diff;
201 int challenge_len, response_len;
202
203 challenge_len = *challenge++; /* skip length, is 8 */
204 response_len = *response++;
205 if (response_len != MS_CHAP_RESPONSE_LEN)
206 goto bad;
207
208 rmd = (MS_ChapResponse *) response;
209
210 #ifndef MSLANMAN
211 if (!rmd->UseNT[0]) {
212 /* Should really propagate this into the error packet. */
213 notice("Peer request for LANMAN auth not supported");
214 goto bad;
215 }
216 #endif
217
218 /* Generate the expected response. */
219 ChapMS(challenge, (char *)secret, secret_len, &md);
220
221 #ifdef MSLANMAN
222 /* Determine which part of response to verify against */
223 if (!rmd->UseNT[0])
224 diff = memcmp(&rmd->LANManResp, &md.LANManResp,
225 sizeof(md.LANManResp));
226 else
227 #endif
228 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
229
230 if (diff == 0) {
231 slprintf(message, message_space, "Access granted");
232 return 1;
233 }
234
235 bad:
236 /* See comments below for MS-CHAP V2 */
237 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
238 challenge_len, challenge);
239 return 0;
240 }
241
242 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)243 chapms2_verify_response(int id, char *name,
244 unsigned char *secret, int secret_len,
245 unsigned char *challenge, unsigned char *response,
246 char *message, int message_space)
247 {
248 MS_Chap2Response *rmd;
249 MS_Chap2Response md;
250 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
251 int challenge_len, response_len;
252
253 challenge_len = *challenge++; /* skip length, is 16 */
254 response_len = *response++;
255 if (response_len != MS_CHAP2_RESPONSE_LEN)
256 goto bad; /* not even the right length */
257
258 rmd = (MS_Chap2Response *) response;
259
260 /* Generate the expected response and our mutual auth. */
261 ChapMS2(challenge, rmd->PeerChallenge, 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.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
286 if (rmd->Flags[0])
287 slprintf(message, message_space, "S=%s", saresponse);
288 else
289 slprintf(message, message_space, "S=%s M=%s",
290 saresponse, "Access granted");
291 return 1;
292 }
293
294 bad:
295 /*
296 * Failure message must be formatted as
297 * "E=e R=r C=c V=v M=m"
298 * where
299 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
300 * r = retry (we use 1, ok to retry)
301 * c = challenge to use for next response, we reuse previous
302 * v = Change Password version supported, we use 0
303 * m = text message
304 *
305 * The M=m part is only for MS-CHAPv2. Neither win2k nor
306 * win98 (others untested) display the message to the user anyway.
307 * They also both ignore the E=e code.
308 *
309 * Note that it's safe to reuse the same challenge as we don't
310 * actually accept another response based on the error message
311 * (and no clients try to resend a response anyway).
312 *
313 * Basically, this whole bit is useless code, even the small
314 * implementation here is only because of overspecification.
315 */
316 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
317 challenge_len, challenge, "Access denied");
318 return 0;
319 }
320
321 static void
chapms_make_response(unsigned char * response,int id,char * our_name,unsigned char * challenge,char * secret,int secret_len,unsigned char * private)322 chapms_make_response(unsigned char *response, int id, char *our_name,
323 unsigned char *challenge, char *secret, int secret_len,
324 unsigned char *private)
325 {
326 challenge++; /* skip length, should be 8 */
327 *response++ = MS_CHAP_RESPONSE_LEN;
328 ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
329 }
330
331 static void
chapms2_make_response(unsigned char * response,int id,char * our_name,unsigned char * challenge,char * secret,int secret_len,unsigned char * private)332 chapms2_make_response(unsigned char *response, int id, char *our_name,
333 unsigned char *challenge, char *secret, int secret_len,
334 unsigned char *private)
335 {
336 challenge++; /* skip length, should be 16 */
337 *response++ = MS_CHAP2_RESPONSE_LEN;
338 ChapMS2(challenge,
339 #ifdef DEBUGMPPEKEY
340 mschap2_peer_challenge,
341 #else
342 NULL,
343 #endif
344 our_name, secret, secret_len,
345 (MS_Chap2Response *) response, private,
346 MS_CHAP2_AUTHENTICATEE);
347 }
348
349 static int
chapms2_check_success(unsigned char * msg,int len,unsigned char * private)350 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
351 {
352 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
353 strncmp((char *)msg, "S=", 2) != 0) {
354 /* Packet does not start with "S=" */
355 error("MS-CHAPv2 Success packet is badly formed.");
356 return 0;
357 }
358 msg += 2;
359 len -= 2;
360 if (len < MS_AUTH_RESPONSE_LENGTH
361 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
362 /* Authenticator Response did not match expected. */
363 error("MS-CHAPv2 mutual authentication failed.");
364 return 0;
365 }
366 /* Authenticator Response matches. */
367 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
368 len -= MS_AUTH_RESPONSE_LENGTH;
369 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
370 msg += 3; /* Eat the delimiter */
371 } else if (len) {
372 /* Packet has extra text which does not begin " M=" */
373 error("MS-CHAPv2 Success packet is badly formed.");
374 return 0;
375 }
376 return 1;
377 }
378
379 static void
chapms_handle_failure(unsigned char * inp,int len)380 chapms_handle_failure(unsigned char *inp, int len)
381 {
382 int err;
383 char *p, *msg;
384
385 /* We want a null-terminated string for strxxx(). */
386 msg = malloc(len + 1);
387 if (!msg) {
388 notice("Out of memory in chapms_handle_failure");
389 return;
390 }
391 BCOPY(inp, msg, len);
392 msg[len] = 0;
393 p = msg;
394
395 /*
396 * Deal with MS-CHAP formatted failure messages; just print the
397 * M=<message> part (if any). For MS-CHAP we're not really supposed
398 * to use M=<message>, but it shouldn't hurt. See
399 * chapms[2]_verify_response.
400 */
401 if (!strncmp(p, "E=", 2))
402 err = strtol(p, NULL, 10); /* Remember the error code. */
403 else
404 goto print_msg; /* Message is badly formatted. */
405
406 if (len && ((p = strstr(p, " M=")) != NULL)) {
407 /* M=<message> field found. */
408 p += 3;
409 } else {
410 /* No M=<message>; use the error code. */
411 switch (err) {
412 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
413 p = "E=646 Restricted logon hours";
414 break;
415
416 case MS_CHAP_ERROR_ACCT_DISABLED:
417 p = "E=647 Account disabled";
418 break;
419
420 case MS_CHAP_ERROR_PASSWD_EXPIRED:
421 p = "E=648 Password expired";
422 break;
423
424 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
425 p = "E=649 No dialin permission";
426 break;
427
428 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
429 p = "E=691 Authentication failure";
430 break;
431
432 case MS_CHAP_ERROR_CHANGING_PASSWORD:
433 /* Should never see this, we don't support Change Password. */
434 p = "E=709 Error changing password";
435 break;
436
437 default:
438 free(msg);
439 error("Unknown MS-CHAP authentication failure: %.*v",
440 len, inp);
441 return;
442 }
443 }
444 print_msg:
445 if (p != NULL)
446 error("MS-CHAP authentication failed: %v", p);
447 free(msg);
448 }
449
450 static void
ChallengeResponse(u_char * challenge,u_char PasswordHash[MD4_SIGNATURE_SIZE],u_char response[24])451 ChallengeResponse(u_char *challenge,
452 u_char PasswordHash[MD4_SIGNATURE_SIZE],
453 u_char response[24])
454 {
455 u_char ZPasswordHash[21];
456
457 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
458 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
459
460 #if 0
461 dbglog("ChallengeResponse - ZPasswordHash %.*B",
462 sizeof(ZPasswordHash), ZPasswordHash);
463 #endif
464
465 (void) DesSetkey(ZPasswordHash + 0);
466 DesEncrypt(challenge, response + 0);
467 (void) DesSetkey(ZPasswordHash + 7);
468 DesEncrypt(challenge, response + 8);
469 (void) DesSetkey(ZPasswordHash + 14);
470 DesEncrypt(challenge, response + 16);
471
472 #if 0
473 dbglog("ChallengeResponse - response %.24B", response);
474 #endif
475 }
476
477 void
ChallengeHash(u_char PeerChallenge[16],u_char * rchallenge,char * username,u_char Challenge[8])478 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
479 char *username, u_char Challenge[8])
480
481 {
482 SHA1_CTX sha1Context;
483 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
484 char *user;
485
486 /* remove domain from "domain\username" */
487 if ((user = strrchr(username, '\\')) != NULL)
488 ++user;
489 else
490 user = username;
491
492 SHA1_Init(&sha1Context);
493 SHA1_Update(&sha1Context, PeerChallenge, 16);
494 SHA1_Update(&sha1Context, rchallenge, 16);
495 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
496 SHA1_Final(sha1Hash, &sha1Context);
497
498 BCOPY(sha1Hash, Challenge, 8);
499 }
500
501 /*
502 * Convert the ASCII version of the password to Unicode.
503 * This implicitly supports 8-bit ISO8859/1 characters.
504 * This gives us the little-endian representation, which
505 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
506 * is machine-dependent.)
507 */
508 static void
ascii2unicode(char ascii[],int ascii_len,u_char unicode[])509 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
510 {
511 int i;
512
513 BZERO(unicode, ascii_len * 2);
514 for (i = 0; i < ascii_len; i++)
515 unicode[i * 2] = (u_char) ascii[i];
516 }
517
518 static void
NTPasswordHash(char * secret,int secret_len,u_char hash[MD4_SIGNATURE_SIZE])519 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
520 {
521 #ifdef ANDROID_CHANGES
522 /* We link with MD4 routines in openssl, we have to take bytes instead */
523 int mdlen = secret_len;
524 #else
525 #ifdef __NetBSD__
526 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
527 int mdlen = secret_len;
528 #else
529 int mdlen = secret_len * 8;
530 #endif
531 #endif
532 MD4_CTX md4Context;
533
534 MD4Init(&md4Context);
535 MD4Update(&md4Context, (unsigned char *)secret, mdlen);
536 MD4Final(hash, &md4Context);
537
538 }
539
540 static void
ChapMS_NT(u_char * rchallenge,char * secret,int secret_len,u_char NTResponse[24])541 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
542 u_char NTResponse[24])
543 {
544 u_char unicodePassword[MAX_NT_PASSWORD * 2];
545 u_char PasswordHash[MD4_SIGNATURE_SIZE];
546
547 /* Hash the Unicode version of the secret (== password). */
548 ascii2unicode(secret, secret_len, unicodePassword);
549 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
550
551 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
552 }
553
554 static void
ChapMS2_NT(char * rchallenge,u_char PeerChallenge[16],char * username,char * secret,int secret_len,u_char NTResponse[24])555 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
556 char *secret, int secret_len, u_char NTResponse[24])
557 {
558 u_char unicodePassword[MAX_NT_PASSWORD * 2];
559 u_char PasswordHash[MD4_SIGNATURE_SIZE];
560 u_char Challenge[8];
561
562 ChallengeHash(PeerChallenge, (unsigned char *)rchallenge, username,
563 Challenge);
564
565 /* Hash the Unicode version of the secret (== password). */
566 ascii2unicode(secret, secret_len, unicodePassword);
567 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
568
569 ChallengeResponse(Challenge, PasswordHash, NTResponse);
570 }
571
572 #ifdef MSLANMAN
573 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
574
575 static void
ChapMS_LANMan(u_char * rchallenge,char * secret,int secret_len,MS_ChapResponse * response)576 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
577 MS_ChapResponse *response)
578 {
579 int i;
580 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
581 u_char PasswordHash[MD4_SIGNATURE_SIZE];
582
583 /* LANMan password is case insensitive */
584 BZERO(UcasePassword, sizeof(UcasePassword));
585 for (i = 0; i < secret_len; i++)
586 UcasePassword[i] = (u_char)toupper(secret[i]);
587 (void) DesSetkey(UcasePassword + 0);
588 DesEncrypt( StdText, PasswordHash + 0 );
589 (void) DesSetkey(UcasePassword + 7);
590 DesEncrypt( StdText, PasswordHash + 8 );
591 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
592 }
593 #endif
594
595
596 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])597 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
598 u_char NTResponse[24], u_char PeerChallenge[16],
599 u_char *rchallenge, char *username,
600 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
601 {
602 /*
603 * "Magic" constants used in response generation, from RFC 2759.
604 */
605 u_char Magic1[39] = /* "Magic server to client signing constant" */
606 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
607 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
608 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
609 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
610 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
611 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
612 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
613 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
614 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
615 0x6E };
616
617 int i;
618 SHA1_CTX sha1Context;
619 u_char Digest[SHA1_SIGNATURE_SIZE];
620 u_char Challenge[8];
621
622 SHA1_Init(&sha1Context);
623 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
624 SHA1_Update(&sha1Context, NTResponse, 24);
625 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
626 SHA1_Final(Digest, &sha1Context);
627
628 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
629
630 SHA1_Init(&sha1Context);
631 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
632 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
633 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
634 SHA1_Final(Digest, &sha1Context);
635
636 /* Convert to ASCII hex string. */
637 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
638 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
639 }
640
641
642 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])643 GenerateAuthenticatorResponsePlain
644 (char *secret, int secret_len,
645 u_char NTResponse[24], u_char PeerChallenge[16],
646 u_char *rchallenge, char *username,
647 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
648 {
649 u_char unicodePassword[MAX_NT_PASSWORD * 2];
650 u_char PasswordHash[MD4_SIGNATURE_SIZE];
651 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
652
653 /* Hash (x2) the Unicode version of the secret (== password). */
654 ascii2unicode(secret, secret_len, unicodePassword);
655 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
656 NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
657 PasswordHashHash);
658
659 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
660 rchallenge, username, authResponse);
661 }
662
663
664 #ifdef MPPE
665 /*
666 * Set mppe_xxxx_key from the NTPasswordHashHash.
667 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
668 */
669 void
mppe_set_keys(u_char * rchallenge,u_char PasswordHashHash[MD4_SIGNATURE_SIZE])670 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
671 {
672 SHA1_CTX sha1Context;
673 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
674
675 SHA1_Init(&sha1Context);
676 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
677 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
678 SHA1_Update(&sha1Context, rchallenge, 8);
679 SHA1_Final(Digest, &sha1Context);
680
681 /* Same key in both directions. */
682 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
683 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
684
685 mppe_keys_set = 1;
686 }
687
688 /*
689 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
690 */
691 static void
Set_Start_Key(u_char * rchallenge,char * secret,int secret_len)692 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
693 {
694 u_char unicodePassword[MAX_NT_PASSWORD * 2];
695 u_char PasswordHash[MD4_SIGNATURE_SIZE];
696 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
697
698 /* Hash (x2) the Unicode version of the secret (== password). */
699 ascii2unicode(secret, secret_len, unicodePassword);
700 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
701 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
702
703 mppe_set_keys(rchallenge, PasswordHashHash);
704 }
705
706 /*
707 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
708 *
709 * This helper function used in the Winbind module, which gets the
710 * NTHashHash from the server.
711 */
712 void
mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],u_char NTResponse[24],int IsServer)713 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
714 u_char NTResponse[24], int IsServer)
715 {
716 SHA1_CTX sha1Context;
717 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
718 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
719
720 u_char SHApad1[40] =
721 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
722 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
725 u_char SHApad2[40] =
726 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
727 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
728 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
729 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
730
731 /* "This is the MPPE Master Key" */
732 u_char Magic1[27] =
733 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
734 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
735 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
736 /* "On the client side, this is the send key; "
737 "on the server side, it is the receive key." */
738 u_char Magic2[84] =
739 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
740 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
741 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
742 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
743 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
744 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
745 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
746 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
747 0x6b, 0x65, 0x79, 0x2e };
748 /* "On the client side, this is the receive key; "
749 "on the server side, it is the send key." */
750 u_char Magic3[84] =
751 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
752 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
753 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
754 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
755 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
756 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
757 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
758 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
759 0x6b, 0x65, 0x79, 0x2e };
760 u_char *s;
761
762 SHA1_Init(&sha1Context);
763 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
764 SHA1_Update(&sha1Context, NTResponse, 24);
765 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
766 SHA1_Final(MasterKey, &sha1Context);
767
768 /*
769 * generate send key
770 */
771 if (IsServer)
772 s = Magic3;
773 else
774 s = Magic2;
775 SHA1_Init(&sha1Context);
776 SHA1_Update(&sha1Context, MasterKey, 16);
777 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
778 SHA1_Update(&sha1Context, s, 84);
779 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
780 SHA1_Final(Digest, &sha1Context);
781
782 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
783
784 /*
785 * generate recv key
786 */
787 if (IsServer)
788 s = Magic2;
789 else
790 s = Magic3;
791 SHA1_Init(&sha1Context);
792 SHA1_Update(&sha1Context, MasterKey, 16);
793 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
794 SHA1_Update(&sha1Context, s, 84);
795 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
796 SHA1_Final(Digest, &sha1Context);
797
798 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
799
800 mppe_keys_set = 1;
801 }
802
803 /*
804 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
805 */
806 static void
SetMasterKeys(char * secret,int secret_len,u_char NTResponse[24],int IsServer)807 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
808 {
809 u_char unicodePassword[MAX_NT_PASSWORD * 2];
810 u_char PasswordHash[MD4_SIGNATURE_SIZE];
811 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
812 /* Hash (x2) the Unicode version of the secret (== password). */
813 ascii2unicode(secret, secret_len, unicodePassword);
814 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
815 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
816 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
817 }
818
819 #endif /* MPPE */
820
821
822 void
ChapMS(u_char * rchallenge,char * secret,int secret_len,MS_ChapResponse * response)823 ChapMS(u_char *rchallenge, char *secret, int secret_len,
824 MS_ChapResponse *response)
825 {
826 BZERO(response, sizeof(*response));
827
828 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
829
830 #ifdef MSLANMAN
831 ChapMS_LANMan(rchallenge, secret, secret_len, response);
832
833 /* preferred method is set by option */
834 response->UseNT[0] = !ms_lanman;
835 #else
836 response->UseNT[0] = 1;
837 #endif
838
839 #ifdef MPPE
840 Set_Start_Key(rchallenge, secret, secret_len);
841 #endif
842 }
843
844
845 /*
846 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
847 * is filled in. Call this way when generating a response.
848 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
849 * Call this way when verifying a response (or debugging).
850 * Do not call with PeerChallenge = response->PeerChallenge.
851 *
852 * response->PeerChallenge is then used for calculation of the
853 * Authenticator Response.
854 */
855 void
ChapMS2(u_char * rchallenge,u_char * PeerChallenge,char * user,char * secret,int secret_len,MS_Chap2Response * response,u_char authResponse[],int authenticator)856 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
857 char *user, char *secret, int secret_len, MS_Chap2Response *response,
858 u_char authResponse[], int authenticator)
859 {
860 /* ARGSUSED */
861 u_char *p = response->PeerChallenge;
862 int i;
863
864 BZERO(response, sizeof(*response));
865
866 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
867 if (!PeerChallenge)
868 for (i = 0; i < sizeof(response->PeerChallenge); i++)
869 *p++ = (u_char) (drand48() * 0xff);
870 else
871 BCOPY(PeerChallenge, response->PeerChallenge,
872 sizeof(response->PeerChallenge));
873
874 /* Generate the NT-Response */
875 ChapMS2_NT((char *)rchallenge, response->PeerChallenge, user,
876 secret, secret_len, response->NTResp);
877
878 /* Generate the Authenticator Response. */
879 GenerateAuthenticatorResponsePlain(secret, secret_len, response->NTResp,
880 response->PeerChallenge, rchallenge,
881 user, authResponse);
882
883 #ifdef MPPE
884 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
885 #endif
886 }
887
888 #ifdef MPPE
889 /*
890 * Set MPPE options from plugins.
891 */
892 void
set_mppe_enc_types(int policy,int types)893 set_mppe_enc_types(int policy, int types)
894 {
895 /* Early exit for unknown policies. */
896 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
897 policy != MPPE_ENC_POL_ENC_REQUIRED)
898 return;
899
900 /* Don't modify MPPE if it's optional and wasn't already configured. */
901 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
902 return;
903
904 /*
905 * Disable undesirable encryption types. Note that we don't ENABLE
906 * any encryption types, to avoid overriding manual configuration.
907 */
908 switch(types) {
909 case MPPE_ENC_TYPES_RC4_40:
910 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
911 break;
912 case MPPE_ENC_TYPES_RC4_128:
913 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
914 break;
915 default:
916 break;
917 }
918 }
919 #endif /* MPPE */
920
921 static struct chap_digest_type chapms_digest = {
922 CHAP_MICROSOFT, /* code */
923 chapms_generate_challenge,
924 chapms_verify_response,
925 chapms_make_response,
926 NULL, /* check_success */
927 chapms_handle_failure,
928 };
929
930 static struct chap_digest_type chapms2_digest = {
931 CHAP_MICROSOFT_V2, /* code */
932 chapms2_generate_challenge,
933 chapms2_verify_response,
934 chapms2_make_response,
935 chapms2_check_success,
936 chapms_handle_failure,
937 };
938
939 void
chapms_init(void)940 chapms_init(void)
941 {
942 chap_register_digest(&chapms_digest);
943 chap_register_digest(&chapms2_digest);
944 add_options(chapms_option_list);
945 }
946
947 #endif /* CHAPMS */
948