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.33 2004/11/12 09:57:43 paulus Exp $"
85 #include <sys/types.h>
97 static const char rcsid[] = RCSID;
100 static void ascii2unicode __P((char[], int, u_char[]));
101 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
102 static void ChallengeResponse __P((u_char *, u_char *, u_char[24]));
103 static void ChapMS_NT __P((u_char *, char *, int, u_char[24]));
104 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
106 static void GenerateAuthenticatorResponsePlain
107 __P((char*, int, u_char[24], u_char[16], u_char *,
108 char *, u_char[41]));
110 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
114 static void Set_Start_Key __P((u_char *, char *, int));
115 static void SetMasterKeys __P((char *, int, u_char[24], int));
119 bool ms_lanman = 0; /* Use LanMan password instead of NT */
120 /* Has meaning only with MS-CHAP challenges */
124 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
125 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
126 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;
136 #include "fsm.h" /* Need to poke MPPE options */
138 #include <net/ppp-comp.h>
142 * Command-line options.
144 static option_t chapms_option_list[] = {
146 { "ms-lanman", o_bool, &ms_lanman,
147 "Use LanMan passwd when using MS-CHAP", 1 },
150 { "mschap-challenge", o_string, &mschap_challenge,
151 "specify CHAP challenge" },
152 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
153 "specify CHAP peer challenge" },
159 * chapms_generate_challenge - generate a challenge for MS-CHAP.
160 * For MS-CHAP the challenge length is fixed at 8 bytes.
161 * The length goes in challenge[0] and the actual challenge starts
165 chapms_generate_challenge(unsigned char *challenge)
169 if (mschap_challenge && strlen(mschap_challenge) == 8)
170 memcpy(challenge, mschap_challenge, 8);
173 random_bytes(challenge, 8);
177 chapms2_generate_challenge(unsigned char *challenge)
181 if (mschap_challenge && strlen(mschap_challenge) == 16)
182 memcpy(challenge, mschap_challenge, 16);
185 random_bytes(challenge, 16);
189 chapms_verify_response(int id, char *name,
190 unsigned char *secret, int secret_len,
191 unsigned char *challenge, unsigned char *response,
192 char *message, int message_space)
194 MS_ChapResponse *rmd;
197 int challenge_len, response_len;
199 challenge_len = *challenge++; /* skip length, is 8 */
200 response_len = *response++;
201 if (response_len != MS_CHAP_RESPONSE_LEN)
204 rmd = (MS_ChapResponse *) response;
207 if (!rmd->UseNT[0]) {
208 /* Should really propagate this into the error packet. */
209 notice("Peer request for LANMAN auth not supported");
214 /* Generate the expected response. */
215 ChapMS(challenge, (char *)secret, secret_len, &md);
218 /* Determine which part of response to verify against */
220 diff = memcmp(&rmd->LANManResp, &md.LANManResp,
221 sizeof(md.LANManResp));
224 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
227 slprintf(message, message_space, "Access granted");
232 /* See comments below for MS-CHAP V2 */
233 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
234 challenge_len, challenge);
239 chapms2_verify_response(int id, char *name,
240 unsigned char *secret, int secret_len,
241 unsigned char *challenge, unsigned char *response,
242 char *message, int message_space)
244 MS_Chap2Response *rmd;
246 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
247 int challenge_len, response_len;
249 challenge_len = *challenge++; /* skip length, is 16 */
250 response_len = *response++;
251 if (response_len != MS_CHAP2_RESPONSE_LEN)
252 goto bad; /* not even the right length */
254 rmd = (MS_Chap2Response *) response;
256 /* Generate the expected response and our mutual auth. */
257 ChapMS2(challenge, rmd->PeerChallenge, name,
258 (char *)secret, secret_len, &md,
259 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
261 /* compare MDs and send the appropriate status */
263 * Per RFC 2759, success message must be formatted as
264 * "S=<auth_string> M=<message>"
266 * <auth_string> is the Authenticator Response (mutual auth)
267 * <message> is a text message
269 * However, some versions of Windows (win98 tested) do not know
270 * about the M=<message> part (required per RFC 2759) and flag
271 * it as an error (reported incorrectly as an encryption error
272 * to the user). Since the RFC requires it, and it can be
273 * useful information, we supply it if the peer is a conforming
274 * system. Luckily (?), win98 sets the Flags field to 0x04
275 * (contrary to RFC requirements) so we can use that to
276 * distinguish between conforming and non-conforming systems.
278 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
279 * help debugging this.
281 if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
283 slprintf(message, message_space, "S=%s", saresponse);
285 slprintf(message, message_space, "S=%s M=%s",
286 saresponse, "Access granted");
292 * Failure message must be formatted as
293 * "E=e R=r C=c V=v M=m"
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
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.
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).
309 * Basically, this whole bit is useless code, even the small
310 * implementation here is only because of overspecification.
312 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
313 challenge_len, challenge, "Access denied");
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)
322 challenge++; /* skip length, should be 8 */
323 *response++ = MS_CHAP_RESPONSE_LEN;
324 ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
328 chapms2_make_response(unsigned char *response, int id, char *our_name,
329 unsigned char *challenge, char *secret, int secret_len,
330 unsigned char *private)
332 challenge++; /* skip length, should be 16 */
333 *response++ = MS_CHAP2_RESPONSE_LEN;
336 mschap2_peer_challenge,
340 our_name, secret, secret_len,
341 (MS_Chap2Response *) response, private,
342 MS_CHAP2_AUTHENTICATEE);
346 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
348 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
349 strncmp((char *)msg, "S=", 2) != 0) {
350 /* Packet does not start with "S=" */
351 error("MS-CHAPv2 Success packet is badly formed.");
356 if (len < MS_AUTH_RESPONSE_LENGTH
357 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
358 /* Authenticator Response did not match expected. */
359 error("MS-CHAPv2 mutual authentication failed.");
362 /* Authenticator Response matches. */
363 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
364 len -= MS_AUTH_RESPONSE_LENGTH;
365 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
366 msg += 3; /* Eat the delimiter */
368 /* Packet has extra text which does not begin " M=" */
369 error("MS-CHAPv2 Success packet is badly formed.");
376 chapms_handle_failure(unsigned char *inp, int len)
381 /* We want a null-terminated string for strxxx(). */
382 msg = malloc(len + 1);
384 notice("Out of memory in chapms_handle_failure");
387 BCOPY(inp, msg, len);
392 * Deal with MS-CHAP formatted failure messages; just print the
393 * M=<message> part (if any). For MS-CHAP we're not really supposed
394 * to use M=<message>, but it shouldn't hurt. See
395 * chapms[2]_verify_response.
397 if (!strncmp(p, "E=", 2))
398 err = strtol(p, NULL, 10); /* Remember the error code. */
400 goto print_msg; /* Message is badly formatted. */
402 if (len && ((p = strstr(p, " M=")) != NULL)) {
403 /* M=<message> field found. */
406 /* No M=<message>; use the error code. */
408 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
409 p = "E=646 Restricted logon hours";
412 case MS_CHAP_ERROR_ACCT_DISABLED:
413 p = "E=647 Account disabled";
416 case MS_CHAP_ERROR_PASSWD_EXPIRED:
417 p = "E=648 Password expired";
420 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
421 p = "E=649 No dialin permission";
424 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
425 p = "E=691 Authentication failure";
428 case MS_CHAP_ERROR_CHANGING_PASSWORD:
429 /* Should never see this, we don't support Change Password. */
430 p = "E=709 Error changing password";
435 error("Unknown MS-CHAP authentication failure: %.*v",
442 error("MS-CHAP authentication failed: %v", p);
447 ChallengeResponse(u_char *challenge,
448 u_char PasswordHash[MD4_SIGNATURE_SIZE],
451 u_char ZPasswordHash[21];
453 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
454 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
457 dbglog("ChallengeResponse - ZPasswordHash %.*B",
458 sizeof(ZPasswordHash), ZPasswordHash);
461 (void) DesSetkey(ZPasswordHash + 0);
462 DesEncrypt(challenge, response + 0);
463 (void) DesSetkey(ZPasswordHash + 7);
464 DesEncrypt(challenge, response + 8);
465 (void) DesSetkey(ZPasswordHash + 14);
466 DesEncrypt(challenge, response + 16);
469 dbglog("ChallengeResponse - response %.24B", response);
474 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
475 char *username, u_char Challenge[8])
478 SHA1_CTX sha1Context;
479 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
482 /* remove domain from "domain\username" */
483 if ((user = strrchr(username, '\\')) != NULL)
488 SHA1_Init(&sha1Context);
489 SHA1_Update(&sha1Context, PeerChallenge, 16);
490 SHA1_Update(&sha1Context, rchallenge, 16);
491 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
492 SHA1_Final(sha1Hash, &sha1Context);
494 BCOPY(sha1Hash, Challenge, 8);
498 * Convert the ASCII version of the password to Unicode.
499 * This implicitly supports 8-bit ISO8859/1 characters.
500 * This gives us the little-endian representation, which
501 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
502 * is machine-dependent.)
505 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
509 BZERO(unicode, ascii_len * 2);
510 for (i = 0; i < ascii_len; i++)
511 unicode[i * 2] = (u_char) ascii[i];
515 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
518 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
519 int mdlen = secret_len;
521 int mdlen = secret_len * 8;
525 MD4Init(&md4Context);
526 MD4Update(&md4Context, (unsigned char *)secret, mdlen);
527 MD4Final(hash, &md4Context);
532 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
533 u_char NTResponse[24])
535 u_char unicodePassword[MAX_NT_PASSWORD * 2];
536 u_char PasswordHash[MD4_SIGNATURE_SIZE];
538 /* Hash the Unicode version of the secret (== password). */
539 ascii2unicode(secret, secret_len, unicodePassword);
540 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
542 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
546 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
547 char *secret, int secret_len, u_char NTResponse[24])
549 u_char unicodePassword[MAX_NT_PASSWORD * 2];
550 u_char PasswordHash[MD4_SIGNATURE_SIZE];
553 ChallengeHash(PeerChallenge, (unsigned char *)rchallenge, username,
556 /* Hash the Unicode version of the secret (== password). */
557 ascii2unicode(secret, secret_len, unicodePassword);
558 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
560 ChallengeResponse(Challenge, PasswordHash, NTResponse);
564 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
567 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
568 MS_ChapResponse *response)
571 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
572 u_char PasswordHash[MD4_SIGNATURE_SIZE];
574 /* LANMan password is case insensitive */
575 BZERO(UcasePassword, sizeof(UcasePassword));
576 for (i = 0; i < secret_len; i++)
577 UcasePassword[i] = (u_char)toupper(secret[i]);
578 (void) DesSetkey(UcasePassword + 0);
579 DesEncrypt( StdText, PasswordHash + 0 );
580 (void) DesSetkey(UcasePassword + 7);
581 DesEncrypt( StdText, PasswordHash + 8 );
582 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
588 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
589 u_char NTResponse[24], u_char PeerChallenge[16],
590 u_char *rchallenge, char *username,
591 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
594 * "Magic" constants used in response generation, from RFC 2759.
596 u_char Magic1[39] = /* "Magic server to client signing constant" */
597 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
598 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
599 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
600 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
601 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
602 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
603 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
604 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
605 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
609 SHA1_CTX sha1Context;
610 u_char Digest[SHA1_SIGNATURE_SIZE];
613 SHA1_Init(&sha1Context);
614 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
615 SHA1_Update(&sha1Context, NTResponse, 24);
616 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
617 SHA1_Final(Digest, &sha1Context);
619 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
621 SHA1_Init(&sha1Context);
622 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
623 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
624 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
625 SHA1_Final(Digest, &sha1Context);
627 /* Convert to ASCII hex string. */
628 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
629 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
634 GenerateAuthenticatorResponsePlain
635 (char *secret, int secret_len,
636 u_char NTResponse[24], u_char PeerChallenge[16],
637 u_char *rchallenge, char *username,
638 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
640 u_char unicodePassword[MAX_NT_PASSWORD * 2];
641 u_char PasswordHash[MD4_SIGNATURE_SIZE];
642 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
644 /* Hash (x2) the Unicode version of the secret (== password). */
645 ascii2unicode(secret, secret_len, unicodePassword);
646 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
647 NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
650 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
651 rchallenge, username, authResponse);
657 * Set mppe_xxxx_key from the NTPasswordHashHash.
658 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
661 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
663 SHA1_CTX sha1Context;
664 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
666 SHA1_Init(&sha1Context);
667 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
668 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
669 SHA1_Update(&sha1Context, rchallenge, 8);
670 SHA1_Final(Digest, &sha1Context);
672 /* Same key in both directions. */
673 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
674 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
680 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
683 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
685 u_char unicodePassword[MAX_NT_PASSWORD * 2];
686 u_char PasswordHash[MD4_SIGNATURE_SIZE];
687 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
689 /* Hash (x2) the Unicode version of the secret (== password). */
690 ascii2unicode(secret, secret_len, unicodePassword);
691 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
692 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
694 mppe_set_keys(rchallenge, PasswordHashHash);
698 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
700 * This helper function used in the Winbind module, which gets the
701 * NTHashHash from the server.
704 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
705 u_char NTResponse[24], int IsServer)
707 SHA1_CTX sha1Context;
708 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
709 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
712 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
717 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
718 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
719 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
720 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
722 /* "This is the MPPE Master Key" */
724 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
725 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
726 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
727 /* "On the client side, this is the send key; "
728 "on the server side, it is the receive key." */
730 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
731 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
732 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
733 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
734 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
735 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
736 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
737 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
738 0x6b, 0x65, 0x79, 0x2e };
739 /* "On the client side, this is the receive key; "
740 "on the server side, it is the send key." */
742 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
743 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
744 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
745 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
746 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
747 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
748 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
749 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
750 0x6b, 0x65, 0x79, 0x2e };
753 SHA1_Init(&sha1Context);
754 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
755 SHA1_Update(&sha1Context, NTResponse, 24);
756 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
757 SHA1_Final(MasterKey, &sha1Context);
766 SHA1_Init(&sha1Context);
767 SHA1_Update(&sha1Context, MasterKey, 16);
768 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
769 SHA1_Update(&sha1Context, s, 84);
770 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
771 SHA1_Final(Digest, &sha1Context);
773 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
782 SHA1_Init(&sha1Context);
783 SHA1_Update(&sha1Context, MasterKey, 16);
784 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
785 SHA1_Update(&sha1Context, s, 84);
786 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
787 SHA1_Final(Digest, &sha1Context);
789 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
795 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
798 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
800 u_char unicodePassword[MAX_NT_PASSWORD * 2];
801 u_char PasswordHash[MD4_SIGNATURE_SIZE];
802 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
803 /* Hash (x2) the Unicode version of the secret (== password). */
804 ascii2unicode(secret, secret_len, unicodePassword);
805 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
806 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
807 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
814 ChapMS(u_char *rchallenge, char *secret, int secret_len,
815 MS_ChapResponse *response)
817 BZERO(response, sizeof(*response));
819 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
822 ChapMS_LANMan(rchallenge, secret, secret_len, response);
824 /* preferred method is set by option */
825 response->UseNT[0] = !ms_lanman;
827 response->UseNT[0] = 1;
831 Set_Start_Key(rchallenge, secret, secret_len);
837 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
838 * is filled in. Call this way when generating a response.
839 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
840 * Call this way when verifying a response (or debugging).
841 * Do not call with PeerChallenge = response->PeerChallenge.
843 * response->PeerChallenge is then used for calculation of the
844 * Authenticator Response.
847 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
848 char *user, char *secret, int secret_len, MS_Chap2Response *response,
849 u_char authResponse[], int authenticator)
852 u_char *p = response->PeerChallenge;
855 BZERO(response, sizeof(*response));
857 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
859 for (i = 0; i < sizeof(response->PeerChallenge); i++)
860 *p++ = (u_char) (drand48() * 0xff);
862 BCOPY(PeerChallenge, response->PeerChallenge,
863 sizeof(response->PeerChallenge));
865 /* Generate the NT-Response */
866 ChapMS2_NT((char *)rchallenge, response->PeerChallenge, user,
867 secret, secret_len, response->NTResp);
869 /* Generate the Authenticator Response. */
870 GenerateAuthenticatorResponsePlain(secret, secret_len, response->NTResp,
871 response->PeerChallenge, rchallenge,
875 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
881 * Set MPPE options from plugins.
884 set_mppe_enc_types(int policy, int types)
886 /* Early exit for unknown policies. */
887 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
888 policy != MPPE_ENC_POL_ENC_REQUIRED)
891 /* Don't modify MPPE if it's optional and wasn't already configured. */
892 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
896 * Disable undesirable encryption types. Note that we don't ENABLE
897 * any encryption types, to avoid overriding manual configuration.
900 case MPPE_ENC_TYPES_RC4_40:
901 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
903 case MPPE_ENC_TYPES_RC4_128:
904 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
912 static struct chap_digest_type chapms_digest = {
913 CHAP_MICROSOFT, /* code */
914 chapms_generate_challenge,
915 chapms_verify_response,
916 chapms_make_response,
917 NULL, /* check_success */
918 chapms_handle_failure,
921 static struct chap_digest_type chapms2_digest = {
922 CHAP_MICROSOFT_V2, /* code */
923 chapms2_generate_challenge,
924 chapms2_verify_response,
925 chapms2_make_response,
926 chapms2_check_success,
927 chapms_handle_failure,
933 chap_register_digest(&chapms_digest);
934 chap_register_digest(&chapms2_digest);
935 add_options(chapms_option_list);