2 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
4 * Copyright (c) 1995 Eric Rosenquist. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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
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.
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.
32 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
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.
39 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
43 * Modifications by Frank Cusack, frank@google.com, March 2002.
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.
49 * Copyright (c) 2002 Google, Inc. All rights reserved.
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
55 * 1. Redistributions of source code must retain the above copyright
56 * notice, this list of conditions and the following disclaimer.
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
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.
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.
77 #define RCSID "$Id: chap_ms.c,v 1.31 2004/04/14 02:39:39 carlsonj Exp $"
85 #include <sys/types.h>
97 static const char rcsid[] = RCSID;
100 static void ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
101 static void ascii2unicode __P((char[], int, u_char[]));
102 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
103 static void ChallengeResponse __P((u_char *, u_char *, u_char[24]));
104 static void ChapMS_NT __P((u_char *, char *, int, u_char[24]));
105 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
107 static void GenerateAuthenticatorResponse __P((char*, int, u_char[24],
108 u_char[16], u_char *,
109 char *, u_char[41]));
111 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
115 static void Set_Start_Key __P((u_char *, char *, int));
116 static void SetMasterKeys __P((char *, int, u_char[24], int));
120 bool ms_lanman = 0; /* Use LanMan password instead of NT */
121 /* Has meaning only with MS-CHAP challenges */
125 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
126 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
127 int mppe_keys_set = 0; /* Have the MPPE keys been set? */
130 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
131 static char *mschap_challenge = NULL;
132 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
133 static char *mschap2_peer_challenge = NULL;
135 #include "fsm.h" /* Need to poke MPPE options */
137 #include <net/ppp-comp.h>
141 * Command-line options.
143 static option_t chapms_option_list[] = {
145 { "ms-lanman", o_bool, &ms_lanman,
146 "Use LanMan passwd when using MS-CHAP", 1 },
149 { "mschap-challenge", o_string, &mschap_challenge,
150 "specify CHAP challenge" },
151 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
152 "specify CHAP peer challenge" },
158 * chapms_generate_challenge - generate a challenge for MS-CHAP.
159 * For MS-CHAP the challenge length is fixed at 8 bytes.
160 * The length goes in challenge[0] and the actual challenge starts
164 chapms_generate_challenge(unsigned char *challenge)
168 if (mschap_challenge && strlen(mschap_challenge) == 8)
169 memcpy(challenge, mschap_challenge, 8);
172 random_bytes(challenge, 8);
176 chapms2_generate_challenge(unsigned char *challenge)
180 if (mschap_challenge && strlen(mschap_challenge) == 16)
181 memcpy(challenge, mschap_challenge, 16);
184 random_bytes(challenge, 16);
188 chapms_verify_response(int id, char *name,
189 unsigned char *secret, int secret_len,
190 unsigned char *challenge, unsigned char *response,
191 char *message, int message_space)
193 MS_ChapResponse *rmd;
196 int challenge_len, response_len;
198 challenge_len = *challenge++; /* skip length, is 8 */
199 response_len = *response++;
200 if (response_len != MS_CHAP_RESPONSE_LEN)
203 rmd = (MS_ChapResponse *) response;
206 if (!rmd->UseNT[0]) {
207 /* Should really propagate this into the error packet. */
208 notice("Peer request for LANMAN auth not supported");
213 /* Generate the expected response. */
214 ChapMS(challenge, (char *)secret, secret_len, &md);
217 /* Determine which part of response to verify against */
219 diff = memcmp(&rmd->LANManResp, &md.LANManResp,
220 sizeof(md.LANManResp));
223 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
226 slprintf(message, message_space, "Access granted");
231 /* See comments below for MS-CHAP V2 */
232 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
233 challenge_len, challenge);
238 chapms2_verify_response(int id, char *name,
239 unsigned char *secret, int secret_len,
240 unsigned char *challenge, unsigned char *response,
241 char *message, int message_space)
243 MS_Chap2Response *rmd;
245 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
246 int challenge_len, response_len;
248 challenge_len = *challenge++; /* skip length, is 16 */
249 response_len = *response++;
250 if (response_len != MS_CHAP2_RESPONSE_LEN)
251 goto bad; /* not even the right length */
253 rmd = (MS_Chap2Response *) response;
255 /* Generate the expected response and our mutual auth. */
256 ChapMS2(challenge, rmd->PeerChallenge, name,
257 (char *)secret, secret_len, &md,
258 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
260 /* compare MDs and send the appropriate status */
262 * Per RFC 2759, success message must be formatted as
263 * "S=<auth_string> M=<message>"
265 * <auth_string> is the Authenticator Response (mutual auth)
266 * <message> is a text message
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.
277 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
278 * help debugging this.
280 if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
282 slprintf(message, message_space, "S=%s", saresponse);
284 slprintf(message, message_space, "S=%s M=%s",
285 saresponse, "Access granted");
291 * Failure message must be formatted as
292 * "E=e R=r C=c V=v M=m"
294 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
295 * r = retry (we use 1, ok to retry)
296 * c = challenge to use for next response, we reuse previous
297 * v = Change Password version supported, we use 0
300 * The M=m part is only for MS-CHAPv2. Neither win2k nor
301 * win98 (others untested) display the message to the user anyway.
302 * They also both ignore the E=e code.
304 * Note that it's safe to reuse the same challenge as we don't
305 * actually accept another response based on the error message
306 * (and no clients try to resend a response anyway).
308 * Basically, this whole bit is useless code, even the small
309 * implementation here is only because of overspecification.
311 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
312 challenge_len, challenge, "Access denied");
317 chapms_make_response(unsigned char *response, int id, char *our_name,
318 unsigned char *challenge, char *secret, int secret_len,
319 unsigned char *private)
321 challenge++; /* skip length, should be 8 */
322 *response++ = MS_CHAP_RESPONSE_LEN;
323 ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
327 chapms2_make_response(unsigned char *response, int id, char *our_name,
328 unsigned char *challenge, char *secret, int secret_len,
329 unsigned char *private)
331 challenge++; /* skip length, should be 16 */
332 *response++ = MS_CHAP2_RESPONSE_LEN;
335 mschap2_peer_challenge,
339 our_name, secret, secret_len,
340 (MS_Chap2Response *) response, private,
341 MS_CHAP2_AUTHENTICATEE);
345 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
347 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
348 strncmp((char *)msg, "S=", 2) != 0) {
349 /* Packet does not start with "S=" */
350 error("MS-CHAPv2 Success packet is badly formed.");
355 if (len < MS_AUTH_RESPONSE_LENGTH
356 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
357 /* Authenticator Response did not match expected. */
358 error("MS-CHAPv2 mutual authentication failed.");
361 /* Authenticator Response matches. */
362 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
363 len -= MS_AUTH_RESPONSE_LENGTH;
364 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
365 msg += 3; /* Eat the delimiter */
367 /* Packet has extra text which does not begin " M=" */
368 error("MS-CHAPv2 Success packet is badly formed.");
375 chapms_handle_failure(unsigned char *inp, int len)
380 /* We want a null-terminated string for strxxx(). */
381 msg = malloc(len + 1);
383 notice("Out of memory in chapms_handle_failure");
386 BCOPY(inp, msg, len);
391 * Deal with MS-CHAP formatted failure messages; just print the
392 * M=<message> part (if any). For MS-CHAP we're not really supposed
393 * to use M=<message>, but it shouldn't hurt. See
394 * chapms[2]_verify_response.
396 if (!strncmp(p, "E=", 2))
397 err = strtol(p, NULL, 10); /* Remember the error code. */
399 goto print_msg; /* Message is badly formatted. */
401 if (len && ((p = strstr(p, " M=")) != NULL)) {
402 /* M=<message> field found. */
405 /* No M=<message>; use the error code. */
407 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
408 p = "E=646 Restricted logon hours";
411 case MS_CHAP_ERROR_ACCT_DISABLED:
412 p = "E=647 Account disabled";
415 case MS_CHAP_ERROR_PASSWD_EXPIRED:
416 p = "E=648 Password expired";
419 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
420 p = "E=649 No dialin permission";
423 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
424 p = "E=691 Authentication failure";
427 case MS_CHAP_ERROR_CHANGING_PASSWORD:
428 /* Should never see this, we don't support Change Password. */
429 p = "E=709 Error changing password";
434 error("Unknown MS-CHAP authentication failure: %.*v",
441 error("MS-CHAP authentication failed: %v", p);
446 ChallengeResponse(u_char *challenge,
447 u_char PasswordHash[MD4_SIGNATURE_SIZE],
450 u_char ZPasswordHash[21];
452 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
453 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
456 dbglog("ChallengeResponse - ZPasswordHash %.*B",
457 sizeof(ZPasswordHash), ZPasswordHash);
460 (void) DesSetkey(ZPasswordHash + 0);
461 DesEncrypt(challenge, response + 0);
462 (void) DesSetkey(ZPasswordHash + 7);
463 DesEncrypt(challenge, response + 8);
464 (void) DesSetkey(ZPasswordHash + 14);
465 DesEncrypt(challenge, response + 16);
468 dbglog("ChallengeResponse - response %.24B", response);
473 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
474 char *username, u_char Challenge[8])
477 SHA1_CTX sha1Context;
478 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
481 /* remove domain from "domain\username" */
482 if ((user = strrchr(username, '\\')) != NULL)
487 SHA1_Init(&sha1Context);
488 SHA1_Update(&sha1Context, PeerChallenge, 16);
489 SHA1_Update(&sha1Context, rchallenge, 16);
490 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
491 SHA1_Final(sha1Hash, &sha1Context);
493 BCOPY(sha1Hash, Challenge, 8);
497 * Convert the ASCII version of the password to Unicode.
498 * This implicitly supports 8-bit ISO8859/1 characters.
499 * This gives us the little-endian representation, which
500 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
501 * is machine-dependent.)
504 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
508 BZERO(unicode, ascii_len * 2);
509 for (i = 0; i < ascii_len; i++)
510 unicode[i * 2] = (u_char) ascii[i];
514 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
517 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
518 int mdlen = secret_len;
520 int mdlen = secret_len * 8;
524 MD4Init(&md4Context);
525 MD4Update(&md4Context, (unsigned char *)secret, mdlen);
526 MD4Final(hash, &md4Context);
531 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
532 u_char NTResponse[24])
534 u_char unicodePassword[MAX_NT_PASSWORD * 2];
535 u_char PasswordHash[MD4_SIGNATURE_SIZE];
537 /* Hash the Unicode version of the secret (== password). */
538 ascii2unicode(secret, secret_len, unicodePassword);
539 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
541 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
545 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
546 char *secret, int secret_len, u_char NTResponse[24])
548 u_char unicodePassword[MAX_NT_PASSWORD * 2];
549 u_char PasswordHash[MD4_SIGNATURE_SIZE];
552 ChallengeHash(PeerChallenge, (unsigned char *)rchallenge, username,
555 /* Hash the Unicode version of the secret (== password). */
556 ascii2unicode(secret, secret_len, unicodePassword);
557 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
559 ChallengeResponse(Challenge, PasswordHash, NTResponse);
563 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
566 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
567 MS_ChapResponse *response)
570 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
571 u_char PasswordHash[MD4_SIGNATURE_SIZE];
573 /* LANMan password is case insensitive */
574 BZERO(UcasePassword, sizeof(UcasePassword));
575 for (i = 0; i < secret_len; i++)
576 UcasePassword[i] = (u_char)toupper(secret[i]);
577 (void) DesSetkey(UcasePassword + 0);
578 DesEncrypt( StdText, PasswordHash + 0 );
579 (void) DesSetkey(UcasePassword + 7);
580 DesEncrypt( StdText, PasswordHash + 8 );
581 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
587 GenerateAuthenticatorResponse(char *secret, int secret_len,
588 u_char NTResponse[24], u_char PeerChallenge[16],
589 u_char *rchallenge, char *username,
590 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
593 * "Magic" constants used in response generation, from RFC 2759.
595 u_char Magic1[39] = /* "Magic server to client signing constant" */
596 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
597 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
598 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
599 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
600 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
601 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
602 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
603 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
604 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
608 SHA1_CTX sha1Context;
609 u_char unicodePassword[MAX_NT_PASSWORD * 2];
610 u_char PasswordHash[MD4_SIGNATURE_SIZE];
611 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
612 u_char Digest[SHA1_SIGNATURE_SIZE];
615 /* Hash (x2) the Unicode version of the secret (== password). */
616 ascii2unicode(secret, secret_len, unicodePassword);
617 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
618 NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
621 SHA1_Init(&sha1Context);
622 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
623 SHA1_Update(&sha1Context, NTResponse, 24);
624 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
625 SHA1_Final(Digest, &sha1Context);
627 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
629 SHA1_Init(&sha1Context);
630 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
631 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
632 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
633 SHA1_Final(Digest, &sha1Context);
635 /* Convert to ASCII hex string. */
636 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
637 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
643 * Set mppe_xxxx_key from the NTPasswordHashHash.
644 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
647 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
649 SHA1_CTX sha1Context;
650 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
652 SHA1_Init(&sha1Context);
653 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
654 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
655 SHA1_Update(&sha1Context, rchallenge, 8);
656 SHA1_Final(Digest, &sha1Context);
658 /* Same key in both directions. */
659 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
660 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
664 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
667 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
669 u_char unicodePassword[MAX_NT_PASSWORD * 2];
670 u_char PasswordHash[MD4_SIGNATURE_SIZE];
671 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
673 /* Hash (x2) the Unicode version of the secret (== password). */
674 ascii2unicode(secret, secret_len, unicodePassword);
675 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
676 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
678 mppe_set_keys(rchallenge, PasswordHashHash);
682 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
685 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
687 SHA1_CTX sha1Context;
688 u_char unicodePassword[MAX_NT_PASSWORD * 2];
689 u_char PasswordHash[MD4_SIGNATURE_SIZE];
690 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
691 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
692 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
695 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
696 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
697 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
700 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
701 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
702 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
703 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
705 /* "This is the MPPE Master Key" */
707 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
708 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
709 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
710 /* "On the client side, this is the send key; "
711 "on the server side, it is the receive key." */
713 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
714 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
715 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
716 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
717 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
718 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
719 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
720 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
721 0x6b, 0x65, 0x79, 0x2e };
722 /* "On the client side, this is the receive key; "
723 "on the server side, it is the send key." */
725 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
726 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
727 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
728 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
729 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
730 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
731 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
732 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
733 0x6b, 0x65, 0x79, 0x2e };
736 /* Hash (x2) the Unicode version of the secret (== password). */
737 ascii2unicode(secret, secret_len, unicodePassword);
738 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
739 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
741 SHA1_Init(&sha1Context);
742 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
743 SHA1_Update(&sha1Context, NTResponse, 24);
744 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
745 SHA1_Final(MasterKey, &sha1Context);
754 SHA1_Init(&sha1Context);
755 SHA1_Update(&sha1Context, MasterKey, 16);
756 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
757 SHA1_Update(&sha1Context, s, 84);
758 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
759 SHA1_Final(Digest, &sha1Context);
761 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
770 SHA1_Init(&sha1Context);
771 SHA1_Update(&sha1Context, MasterKey, 16);
772 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
773 SHA1_Update(&sha1Context, s, 84);
774 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
775 SHA1_Final(Digest, &sha1Context);
777 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
784 ChapMS(u_char *rchallenge, char *secret, int secret_len,
785 MS_ChapResponse *response)
788 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
790 BZERO(response, sizeof(*response));
792 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
795 ChapMS_LANMan(rchallenge, secret, secret_len, response);
797 /* preferred method is set by option */
798 response->UseNT[0] = !ms_lanman;
800 response->UseNT[0] = 1;
804 Set_Start_Key(rchallenge, secret, secret_len);
811 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
812 * is filled in. Call this way when generating a response.
813 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
814 * Call this way when verifying a response (or debugging).
815 * Do not call with PeerChallenge = response->PeerChallenge.
817 * response->PeerChallenge is then used for calculation of the
818 * Authenticator Response.
821 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
822 char *user, char *secret, int secret_len, MS_Chap2Response *response,
823 u_char authResponse[], int authenticator)
826 u_char *p = response->PeerChallenge;
829 BZERO(response, sizeof(*response));
831 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
833 for (i = 0; i < sizeof(response->PeerChallenge); i++)
834 *p++ = (u_char) (drand48() * 0xff);
836 BCOPY(PeerChallenge, response->PeerChallenge,
837 sizeof(response->PeerChallenge));
839 /* Generate the NT-Response */
840 ChapMS2_NT((char *)rchallenge, response->PeerChallenge, user,
841 secret, secret_len, response->NTResp);
843 /* Generate the Authenticator Response. */
844 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
845 response->PeerChallenge, rchallenge,
849 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
856 * Set MPPE options from plugins.
859 set_mppe_enc_types(int policy, int types)
861 /* Early exit for unknown policies. */
862 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
863 policy != MPPE_ENC_POL_ENC_REQUIRED)
866 /* Don't modify MPPE if it's optional and wasn't already configured. */
867 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
871 * Disable undesirable encryption types. Note that we don't ENABLE
872 * any encryption types, to avoid overriding manual configuration.
875 case MPPE_ENC_TYPES_RC4_40:
876 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
878 case MPPE_ENC_TYPES_RC4_128:
879 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
887 static struct chap_digest_type chapms_digest = {
888 CHAP_MICROSOFT, /* code */
889 chapms_generate_challenge,
890 chapms_verify_response,
891 chapms_make_response,
892 NULL, /* check_success */
893 chapms_handle_failure,
896 static struct chap_digest_type chapms2_digest = {
897 CHAP_MICROSOFT_V2, /* code */
898 chapms2_generate_challenge,
899 chapms2_verify_response,
900 chapms2_make_response,
901 chapms2_check_success,
902 chapms_handle_failure,
908 chap_register_digest(&chapms_digest);
909 chap_register_digest(&chapms2_digest);
910 add_options(chapms_option_list);