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.30 2003/07/10 17:59:33 fcusack 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)
167 if (mschap_challenge && strlen(mschap_challenge) == 8)
168 memcpy(challenge, mschap_challenge, 8);
170 random_bytes(challenge, 8);
174 chapms2_generate_challenge(unsigned char *challenge)
177 if (mschap_challenge && strlen(mschap_challenge) == 16)
178 memcpy(challenge, mschap_challenge, 16);
180 random_bytes(challenge, 16);
184 chapms_verify_response(int id, char *name,
185 unsigned char *secret, int secret_len,
186 unsigned char *challenge, unsigned char *response,
187 char *message, int message_space)
189 MS_ChapResponse *rmd;
192 int challenge_len, response_len;
194 challenge_len = *challenge++; /* skip length, is 8 */
195 response_len = *response++;
196 if (response_len != MS_CHAP_RESPONSE_LEN)
199 rmd = (MS_ChapResponse *) response;
202 if (!rmd->UseNT[0]) {
203 /* Should really propagate this into the error packet. */
204 notice("Peer request for LANMAN auth not supported");
209 /* Generate the expected response. */
210 ChapMS(challenge, secret, secret_len, &md);
213 /* Determine which part of response to verify against */
215 diff = memcmp(&rmd->LANManResp, &md.LANManResp,
216 sizeof(md.LANManResp));
219 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
222 slprintf(message, message_space, "Access granted");
227 /* See comments below for MS-CHAP V2 */
228 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
229 challenge_len, challenge);
234 chapms2_verify_response(int id, char *name,
235 unsigned char *secret, int secret_len,
236 unsigned char *challenge, unsigned char *response,
237 char *message, int message_space)
239 MS_Chap2Response *rmd;
241 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
242 int challenge_len, response_len;
244 challenge_len = *challenge++; /* skip length, is 16 */
245 response_len = *response++;
246 if (response_len != MS_CHAP2_RESPONSE_LEN)
247 goto bad; /* not even the right length */
249 rmd = (MS_Chap2Response *) response;
251 /* Generate the expected response and our mutual auth. */
252 ChapMS2(challenge, rmd->PeerChallenge, name,
253 secret, secret_len, &md,
254 saresponse, MS_CHAP2_AUTHENTICATOR);
256 /* compare MDs and send the appropriate status */
258 * Per RFC 2759, success message must be formatted as
259 * "S=<auth_string> M=<message>"
261 * <auth_string> is the Authenticator Response (mutual auth)
262 * <message> is a text message
264 * However, some versions of Windows (win98 tested) do not know
265 * about the M=<message> part (required per RFC 2759) and flag
266 * it as an error (reported incorrectly as an encryption error
267 * to the user). Since the RFC requires it, and it can be
268 * useful information, we supply it if the peer is a conforming
269 * system. Luckily (?), win98 sets the Flags field to 0x04
270 * (contrary to RFC requirements) so we can use that to
271 * distinguish between conforming and non-conforming systems.
273 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
274 * help debugging this.
276 if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
278 slprintf(message, message_space, "S=%s", saresponse);
280 slprintf(message, message_space, "S=%s M=%s",
281 saresponse, "Access granted");
287 * Failure message must be formatted as
288 * "E=e R=r C=c V=v M=m"
290 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
291 * r = retry (we use 1, ok to retry)
292 * c = challenge to use for next response, we reuse previous
293 * v = Change Password version supported, we use 0
296 * The M=m part is only for MS-CHAPv2. Neither win2k nor
297 * win98 (others untested) display the message to the user anyway.
298 * They also both ignore the E=e code.
300 * Note that it's safe to reuse the same challenge as we don't
301 * actually accept another response based on the error message
302 * (and no clients try to resend a response anyway).
304 * Basically, this whole bit is useless code, even the small
305 * implementation here is only because of overspecification.
307 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
308 challenge_len, challenge, "Access denied");
313 chapms_make_response(unsigned char *response, int id, char *our_name,
314 unsigned char *challenge, char *secret, int secret_len,
315 unsigned char *private)
317 challenge++; /* skip length, should be 8 */
318 *response++ = MS_CHAP_RESPONSE_LEN;
319 ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
323 chapms2_make_response(unsigned char *response, int id, char *our_name,
324 unsigned char *challenge, char *secret, int secret_len,
325 unsigned char *private)
327 challenge++; /* skip length, should be 16 */
328 *response++ = MS_CHAP2_RESPONSE_LEN;
329 ChapMS2(challenge, mschap2_peer_challenge, our_name,
331 (MS_Chap2Response *) response, private,
332 MS_CHAP2_AUTHENTICATEE);
336 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
338 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || strncmp(msg, "S=", 2)) {
339 /* Packet does not start with "S=" */
340 error("MS-CHAPv2 Success packet is badly formed.");
345 if (len < MS_AUTH_RESPONSE_LENGTH
346 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
347 /* Authenticator Response did not match expected. */
348 error("MS-CHAPv2 mutual authentication failed.");
351 /* Authenticator Response matches. */
352 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
353 len -= MS_AUTH_RESPONSE_LENGTH;
354 if ((len >= 3) && !strncmp(msg, " M=", 3)) {
355 msg += 3; /* Eat the delimiter */
357 /* Packet has extra text which does not begin " M=" */
358 error("MS-CHAPv2 Success packet is badly formed.");
365 chapms_handle_failure(unsigned char *inp, int len)
370 /* We want a null-terminated string for strxxx(). */
371 msg = malloc(len + 1);
373 notice("Out of memory in chapms_handle_failure");
376 BCOPY(inp, msg, len);
381 * Deal with MS-CHAP formatted failure messages; just print the
382 * M=<message> part (if any). For MS-CHAP we're not really supposed
383 * to use M=<message>, but it shouldn't hurt. See
384 * chapms[2]_verify_response.
386 if (!strncmp(p, "E=", 2))
387 err = strtol(p, NULL, 10); /* Remember the error code. */
389 goto print_msg; /* Message is badly formatted. */
391 if (len && ((p = strstr(p, " M=")) != NULL)) {
392 /* M=<message> field found. */
395 /* No M=<message>; use the error code. */
397 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
398 p = "E=646 Restricted logon hours";
401 case MS_CHAP_ERROR_ACCT_DISABLED:
402 p = "E=647 Account disabled";
405 case MS_CHAP_ERROR_PASSWD_EXPIRED:
406 p = "E=648 Password expired";
409 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
410 p = "E=649 No dialin permission";
413 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
414 p = "E=691 Authentication failure";
417 case MS_CHAP_ERROR_CHANGING_PASSWORD:
418 /* Should never see this, we don't support Change Password. */
419 p = "E=709 Error changing password";
424 error("Unknown MS-CHAP authentication failure: %.*v",
431 error("MS-CHAP authentication failed: %v", p);
436 ChallengeResponse(u_char *challenge,
437 u_char PasswordHash[MD4_SIGNATURE_SIZE],
440 u_char ZPasswordHash[21];
442 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
443 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
446 dbglog("ChallengeResponse - ZPasswordHash %.*B",
447 sizeof(ZPasswordHash), ZPasswordHash);
450 (void) DesSetkey(ZPasswordHash + 0);
451 DesEncrypt(challenge, response + 0);
452 (void) DesSetkey(ZPasswordHash + 7);
453 DesEncrypt(challenge, response + 8);
454 (void) DesSetkey(ZPasswordHash + 14);
455 DesEncrypt(challenge, response + 16);
458 dbglog("ChallengeResponse - response %.24B", response);
463 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
464 char *username, u_char Challenge[8])
467 SHA1_CTX sha1Context;
468 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
471 /* remove domain from "domain\username" */
472 if ((user = strrchr(username, '\\')) != NULL)
477 SHA1_Init(&sha1Context);
478 SHA1_Update(&sha1Context, PeerChallenge, 16);
479 SHA1_Update(&sha1Context, rchallenge, 16);
480 SHA1_Update(&sha1Context, user, strlen(user));
481 SHA1_Final(sha1Hash, &sha1Context);
483 BCOPY(sha1Hash, Challenge, 8);
487 * Convert the ASCII version of the password to Unicode.
488 * This implicitly supports 8-bit ISO8859/1 characters.
489 * This gives us the little-endian representation, which
490 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
491 * is machine-dependent.)
494 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
498 BZERO(unicode, ascii_len * 2);
499 for (i = 0; i < ascii_len; i++)
500 unicode[i * 2] = (u_char) ascii[i];
504 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
507 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
508 int mdlen = secret_len;
510 int mdlen = secret_len * 8;
514 MD4Init(&md4Context);
515 MD4Update(&md4Context, secret, mdlen);
516 MD4Final(hash, &md4Context);
521 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
522 u_char NTResponse[24])
524 u_char unicodePassword[MAX_NT_PASSWORD * 2];
525 u_char PasswordHash[MD4_SIGNATURE_SIZE];
527 /* Hash the Unicode version of the secret (== password). */
528 ascii2unicode(secret, secret_len, unicodePassword);
529 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
531 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
535 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
536 char *secret, int secret_len, u_char NTResponse[24])
538 u_char unicodePassword[MAX_NT_PASSWORD * 2];
539 u_char PasswordHash[MD4_SIGNATURE_SIZE];
542 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
544 /* Hash the Unicode version of the secret (== password). */
545 ascii2unicode(secret, secret_len, unicodePassword);
546 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
548 ChallengeResponse(Challenge, PasswordHash, NTResponse);
552 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
555 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
556 MS_ChapResponse *response)
559 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
560 u_char PasswordHash[MD4_SIGNATURE_SIZE];
562 /* LANMan password is case insensitive */
563 BZERO(UcasePassword, sizeof(UcasePassword));
564 for (i = 0; i < secret_len; i++)
565 UcasePassword[i] = (u_char)toupper(secret[i]);
566 (void) DesSetkey(UcasePassword + 0);
567 DesEncrypt( StdText, PasswordHash + 0 );
568 (void) DesSetkey(UcasePassword + 7);
569 DesEncrypt( StdText, PasswordHash + 8 );
570 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
576 GenerateAuthenticatorResponse(char *secret, int secret_len,
577 u_char NTResponse[24], u_char PeerChallenge[16],
578 u_char *rchallenge, char *username,
579 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
582 * "Magic" constants used in response generation, from RFC 2759.
584 u_char Magic1[39] = /* "Magic server to client signing constant" */
585 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
586 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
587 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
588 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
589 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
590 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
591 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
592 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
593 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
597 SHA1_CTX sha1Context;
598 u_char unicodePassword[MAX_NT_PASSWORD * 2];
599 u_char PasswordHash[MD4_SIGNATURE_SIZE];
600 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
601 u_char Digest[SHA1_SIGNATURE_SIZE];
604 /* Hash (x2) the Unicode version of the secret (== password). */
605 ascii2unicode(secret, secret_len, unicodePassword);
606 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
607 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
609 SHA1_Init(&sha1Context);
610 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
611 SHA1_Update(&sha1Context, NTResponse, 24);
612 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
613 SHA1_Final(Digest, &sha1Context);
615 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
617 SHA1_Init(&sha1Context);
618 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
619 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
620 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
621 SHA1_Final(Digest, &sha1Context);
623 /* Convert to ASCII hex string. */
624 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
625 sprintf(&authResponse[i * 2], "%02X", Digest[i]);
631 * Set mppe_xxxx_key from the NTPasswordHashHash.
632 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
635 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
637 SHA1_CTX sha1Context;
638 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
640 SHA1_Init(&sha1Context);
641 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
642 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
643 SHA1_Update(&sha1Context, rchallenge, 8);
644 SHA1_Final(Digest, &sha1Context);
646 /* Same key in both directions. */
647 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
648 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
652 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
655 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
657 u_char unicodePassword[MAX_NT_PASSWORD * 2];
658 u_char PasswordHash[MD4_SIGNATURE_SIZE];
659 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
661 /* Hash (x2) the Unicode version of the secret (== password). */
662 ascii2unicode(secret, secret_len, unicodePassword);
663 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
664 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
666 mppe_set_keys(rchallenge, PasswordHashHash);
670 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
673 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
675 SHA1_CTX sha1Context;
676 u_char unicodePassword[MAX_NT_PASSWORD * 2];
677 u_char PasswordHash[MD4_SIGNATURE_SIZE];
678 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
679 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
680 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
683 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
688 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
689 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
690 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
691 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
693 /* "This is the MPPE Master Key" */
695 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
696 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
697 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
698 /* "On the client side, this is the send key; "
699 "on the server side, it is the receive key." */
701 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
702 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
703 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
704 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
705 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
706 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
707 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
708 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
709 0x6b, 0x65, 0x79, 0x2e };
710 /* "On the client side, this is the receive key; "
711 "on the server side, it is the send 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, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
717 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
718 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
719 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
720 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
721 0x6b, 0x65, 0x79, 0x2e };
724 /* Hash (x2) the Unicode version of the secret (== password). */
725 ascii2unicode(secret, secret_len, unicodePassword);
726 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
727 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
729 SHA1_Init(&sha1Context);
730 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
731 SHA1_Update(&sha1Context, NTResponse, 24);
732 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
733 SHA1_Final(MasterKey, &sha1Context);
742 SHA1_Init(&sha1Context);
743 SHA1_Update(&sha1Context, MasterKey, 16);
744 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
745 SHA1_Update(&sha1Context, s, 84);
746 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
747 SHA1_Final(Digest, &sha1Context);
749 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
758 SHA1_Init(&sha1Context);
759 SHA1_Update(&sha1Context, MasterKey, 16);
760 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
761 SHA1_Update(&sha1Context, s, 84);
762 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
763 SHA1_Final(Digest, &sha1Context);
765 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
772 ChapMS(u_char *rchallenge, char *secret, int secret_len,
773 MS_ChapResponse *response)
776 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
778 BZERO(response, sizeof(*response));
780 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
783 ChapMS_LANMan(rchallenge, secret, secret_len, response);
785 /* preferred method is set by option */
786 response->UseNT[0] = !ms_lanman;
788 response->UseNT[0] = 1;
792 Set_Start_Key(rchallenge, secret, secret_len);
799 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
800 * is filled in. Call this way when generating a response.
801 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
802 * Call this way when verifying a response (or debugging).
803 * Do not call with PeerChallenge = response->PeerChallenge.
805 * response->PeerChallenge is then used for calculation of the
806 * Authenticator Response.
809 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
810 char *user, char *secret, int secret_len, MS_Chap2Response *response,
811 u_char authResponse[], int authenticator)
814 u_char *p = response->PeerChallenge;
817 BZERO(response, sizeof(*response));
819 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
821 for (i = 0; i < sizeof(response->PeerChallenge); i++)
822 *p++ = (u_char) (drand48() * 0xff);
824 BCOPY(PeerChallenge, response->PeerChallenge,
825 sizeof(response->PeerChallenge));
827 /* Generate the NT-Response */
828 ChapMS2_NT(rchallenge, response->PeerChallenge, user,
829 secret, secret_len, response->NTResp);
831 /* Generate the Authenticator Response. */
832 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
833 response->PeerChallenge, rchallenge,
837 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
844 * Set MPPE options from plugins.
847 set_mppe_enc_types(int policy, int types)
849 /* Early exit for unknown policies. */
850 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
851 policy != MPPE_ENC_POL_ENC_REQUIRED)
854 /* Don't modify MPPE if it's optional and wasn't already configured. */
855 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
859 * Disable undesirable encryption types. Note that we don't ENABLE
860 * any encryption types, to avoid overriding manual configuration.
863 case MPPE_ENC_TYPES_RC4_40:
864 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
866 case MPPE_ENC_TYPES_RC4_128:
867 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
875 static struct chap_digest_type chapms_digest = {
876 CHAP_MICROSOFT, /* code */
877 chapms_generate_challenge,
878 chapms_verify_response,
879 chapms_make_response,
880 NULL, /* check_success */
881 chapms_handle_failure,
884 static struct chap_digest_type chapms2_digest = {
885 CHAP_MICROSOFT_V2, /* code */
886 chapms2_generate_challenge,
887 chapms2_verify_response,
888 chapms2_make_response,
889 chapms2_check_success,
890 chapms_handle_failure,
896 chap_register_digest(&chapms_digest);
897 chap_register_digest(&chapms2_digest);
898 add_options(chapms_option_list);