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.38 2007/12/01 20:10:51 carlsonj Exp $"
89 #include <sys/types.h>
102 static void ascii2unicode (char[], int, u_char[]);
103 static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
104 static void ChallengeResponse (u_char *, u_char *, u_char[24]);
105 static void ChapMS_NT (u_char *, char *, int, u_char[24]);
106 static void ChapMS2_NT (u_char *, u_char[16], char *, char *, int,
108 static void GenerateAuthenticatorResponsePlain
109 (char*, int, u_char[24], u_char[16], u_char *,
112 static void ChapMS_LANMan (u_char *, char *, int, u_char *);
116 bool ms_lanman = 0; /* Use LanMan password instead of NT */
117 /* Has meaning only with MS-CHAP challenges */
123 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
124 static char *mschap_challenge = NULL;
125 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
126 static char *mschap2_peer_challenge = NULL;
129 #include "fsm.h" /* Need to poke MPPE options */
131 #include <net/ppp-comp.h>
135 * Command-line options.
137 static option_t chapms_option_list[] = {
139 { "ms-lanman", o_bool, &ms_lanman,
140 "Use LanMan passwd when using MS-CHAP", 1 },
143 { "mschap-challenge", o_string, &mschap_challenge,
144 "specify CHAP challenge" },
145 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
146 "specify CHAP peer challenge" },
152 * chapms_generate_challenge - generate a challenge for MS-CHAP.
153 * For MS-CHAP the challenge length is fixed at 8 bytes.
154 * The length goes in challenge[0] and the actual challenge starts
158 chapms_generate_challenge(unsigned char *challenge)
162 if (mschap_challenge && strlen(mschap_challenge) == 8)
163 memcpy(challenge, mschap_challenge, 8);
166 random_bytes(challenge, 8);
170 chapms2_generate_challenge(unsigned char *challenge)
174 if (mschap_challenge && strlen(mschap_challenge) == 16)
175 memcpy(challenge, mschap_challenge, 16);
178 random_bytes(challenge, 16);
182 chapms_verify_response(int id, char *name,
183 unsigned char *secret, int secret_len,
184 unsigned char *challenge, unsigned char *response,
185 char *message, int message_space)
187 unsigned char md[MS_CHAP_RESPONSE_LEN];
189 int challenge_len, response_len;
191 challenge_len = *challenge++; /* skip length, is 8 */
192 response_len = *response++;
193 if (response_len != MS_CHAP_RESPONSE_LEN)
197 if (!response[MS_CHAP_USENT]) {
198 /* Should really propagate this into the error packet. */
199 notice("Peer request for LANMAN auth not supported");
204 /* Generate the expected response. */
205 ChapMS(challenge, (char *)secret, secret_len, md);
208 /* Determine which part of response to verify against */
209 if (!response[MS_CHAP_USENT])
210 diff = memcmp(&response[MS_CHAP_LANMANRESP],
211 &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
214 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
218 slprintf(message, message_space, "Access granted");
223 /* See comments below for MS-CHAP V2 */
224 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
225 challenge_len, challenge);
230 chapms2_verify_response(int id, char *name,
231 unsigned char *secret, int secret_len,
232 unsigned char *challenge, unsigned char *response,
233 char *message, int message_space)
235 unsigned char md[MS_CHAP2_RESPONSE_LEN];
236 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
237 int challenge_len, response_len;
239 challenge_len = *challenge++; /* skip length, is 16 */
240 response_len = *response++;
241 if (response_len != MS_CHAP2_RESPONSE_LEN)
242 goto bad; /* not even the right length */
244 /* Generate the expected response and our mutual auth. */
245 ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,
246 (char *)secret, secret_len, md,
247 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
249 /* compare MDs and send the appropriate status */
251 * Per RFC 2759, success message must be formatted as
252 * "S=<auth_string> M=<message>"
254 * <auth_string> is the Authenticator Response (mutual auth)
255 * <message> is a text message
257 * However, some versions of Windows (win98 tested) do not know
258 * about the M=<message> part (required per RFC 2759) and flag
259 * it as an error (reported incorrectly as an encryption error
260 * to the user). Since the RFC requires it, and it can be
261 * useful information, we supply it if the peer is a conforming
262 * system. Luckily (?), win98 sets the Flags field to 0x04
263 * (contrary to RFC requirements) so we can use that to
264 * distinguish between conforming and non-conforming systems.
266 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
267 * help debugging this.
269 if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
270 MS_CHAP2_NTRESP_LEN) == 0) {
271 if (response[MS_CHAP2_FLAGS])
272 slprintf(message, message_space, "S=%s", saresponse);
274 slprintf(message, message_space, "S=%s M=%s",
275 saresponse, "Access granted");
281 * Failure message must be formatted as
282 * "E=e R=r C=c V=v M=m"
284 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
285 * r = retry (we use 1, ok to retry)
286 * c = challenge to use for next response, we reuse previous
287 * v = Change Password version supported, we use 0
290 * The M=m part is only for MS-CHAPv2. Neither win2k nor
291 * win98 (others untested) display the message to the user anyway.
292 * They also both ignore the E=e code.
294 * Note that it's safe to reuse the same challenge as we don't
295 * actually accept another response based on the error message
296 * (and no clients try to resend a response anyway).
298 * Basically, this whole bit is useless code, even the small
299 * implementation here is only because of overspecification.
301 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
302 challenge_len, challenge, "Access denied");
307 chapms_make_response(unsigned char *response, int id, char *our_name,
308 unsigned char *challenge, char *secret, int secret_len,
309 unsigned char *private)
311 challenge++; /* skip length, should be 8 */
312 *response++ = MS_CHAP_RESPONSE_LEN;
313 ChapMS(challenge, secret, secret_len, response);
316 struct chapms2_response_cache_entry {
318 unsigned char challenge[16];
319 unsigned char response[MS_CHAP2_RESPONSE_LEN];
320 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
323 #define CHAPMS2_MAX_RESPONSE_CACHE_SIZE 10
324 static struct chapms2_response_cache_entry
325 chapms2_response_cache[CHAPMS2_MAX_RESPONSE_CACHE_SIZE];
326 static int chapms2_response_cache_next_index = 0;
327 static int chapms2_response_cache_size = 0;
330 chapms2_add_to_response_cache(int id, unsigned char *challenge,
331 unsigned char *response,
332 unsigned char *auth_response)
334 int i = chapms2_response_cache_next_index;
336 chapms2_response_cache[i].id = id;
337 memcpy(chapms2_response_cache[i].challenge, challenge, 16);
338 memcpy(chapms2_response_cache[i].response, response,
339 MS_CHAP2_RESPONSE_LEN);
340 memcpy(chapms2_response_cache[i].auth_response,
341 auth_response, MS_AUTH_RESPONSE_LENGTH);
342 chapms2_response_cache_next_index =
343 (i + 1) % CHAPMS2_MAX_RESPONSE_CACHE_SIZE;
344 if (chapms2_response_cache_next_index > chapms2_response_cache_size)
345 chapms2_response_cache_size = chapms2_response_cache_next_index;
346 dbglog("added response cache entry %d", i);
349 static struct chapms2_response_cache_entry*
350 chapms2_find_in_response_cache(int id, unsigned char *challenge,
351 unsigned char *auth_response)
355 for (i = 0; i < chapms2_response_cache_size; i++) {
356 if (id == chapms2_response_cache[i].id
359 chapms2_response_cache[i].challenge,
362 || memcmp(auth_response,
363 chapms2_response_cache[i].auth_response,
364 MS_AUTH_RESPONSE_LENGTH) == 0)) {
365 dbglog("response found in cache (entry %d)", i);
366 return &chapms2_response_cache[i];
369 return NULL; /* not found */
373 chapms2_make_response(unsigned char *response, int id, char *our_name,
374 unsigned char *challenge, char *secret, int secret_len,
375 unsigned char *private)
377 const struct chapms2_response_cache_entry *cache_entry;
378 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH+1];
380 challenge++; /* skip length, should be 16 */
381 *response++ = MS_CHAP2_RESPONSE_LEN;
382 cache_entry = chapms2_find_in_response_cache(id, challenge, NULL);
384 memcpy(response, cache_entry->response, MS_CHAP2_RESPONSE_LEN);
389 mschap2_peer_challenge,
393 our_name, secret, secret_len, response, auth_response,
394 MS_CHAP2_AUTHENTICATEE);
395 chapms2_add_to_response_cache(id, challenge, response, auth_response);
399 chapms2_check_success(int id, unsigned char *msg, int len)
401 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
402 strncmp((char *)msg, "S=", 2) != 0) {
403 /* Packet does not start with "S=" */
404 error("MS-CHAPv2 Success packet is badly formed.");
409 if (len < MS_AUTH_RESPONSE_LENGTH
410 || !chapms2_find_in_response_cache(id, NULL /* challenge */, msg)) {
411 /* Authenticator Response did not match expected. */
412 error("MS-CHAPv2 mutual authentication failed.");
415 /* Authenticator Response matches. */
416 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
417 len -= MS_AUTH_RESPONSE_LENGTH;
418 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
419 msg += 3; /* Eat the delimiter */
420 } else if ((len >= 2) && !strncmp((char *)msg, "M=", 2)) {
421 msg += 2; /* Eat the delimiter */
423 /* Packet has extra text which does not begin " M=" */
424 error("MS-CHAPv2 Success packet is badly formed.");
431 chapms_handle_failure(unsigned char *inp, int len)
436 /* We want a null-terminated string for strxxx(). */
437 msg = malloc(len + 1);
439 notice("Out of memory in chapms_handle_failure");
442 BCOPY(inp, msg, len);
447 * Deal with MS-CHAP formatted failure messages; just print the
448 * M=<message> part (if any). For MS-CHAP we're not really supposed
449 * to use M=<message>, but it shouldn't hurt. See
450 * chapms[2]_verify_response.
452 if (!strncmp(p, "E=", 2))
453 err = strtol(p+2, NULL, 10); /* Remember the error code. */
455 goto print_msg; /* Message is badly formatted. */
457 if (len && ((p = strstr(p, " M=")) != NULL)) {
458 /* M=<message> field found. */
461 /* No M=<message>; use the error code. */
463 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
464 p = "E=646 Restricted logon hours";
467 case MS_CHAP_ERROR_ACCT_DISABLED:
468 p = "E=647 Account disabled";
471 case MS_CHAP_ERROR_PASSWD_EXPIRED:
472 p = "E=648 Password expired";
475 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
476 p = "E=649 No dialin permission";
479 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
480 p = "E=691 Authentication failure";
483 case MS_CHAP_ERROR_CHANGING_PASSWORD:
484 /* Should never see this, we don't support Change Password. */
485 p = "E=709 Error changing password";
490 error("Unknown MS-CHAP authentication failure: %.*v",
497 error("MS-CHAP authentication failed: %v", p);
502 ChallengeResponse(u_char *challenge,
503 u_char PasswordHash[MD4_SIGNATURE_SIZE],
506 u_char ZPasswordHash[21];
508 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
509 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
512 dbglog("ChallengeResponse - ZPasswordHash %.*B",
513 sizeof(ZPasswordHash), ZPasswordHash);
516 (void) DesSetkey(ZPasswordHash + 0);
517 DesEncrypt(challenge, response + 0);
518 (void) DesSetkey(ZPasswordHash + 7);
519 DesEncrypt(challenge, response + 8);
520 (void) DesSetkey(ZPasswordHash + 14);
521 DesEncrypt(challenge, response + 16);
524 dbglog("ChallengeResponse - response %.24B", response);
529 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
530 char *username, u_char Challenge[8])
533 SHA1_CTX sha1Context;
534 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
537 /* remove domain from "domain\username" */
538 if ((user = strrchr(username, '\\')) != NULL)
543 SHA1_Init(&sha1Context);
544 SHA1_Update(&sha1Context, PeerChallenge, 16);
545 SHA1_Update(&sha1Context, rchallenge, 16);
546 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
547 SHA1_Final(sha1Hash, &sha1Context);
549 BCOPY(sha1Hash, Challenge, 8);
553 * Convert the ASCII version of the password to Unicode.
554 * This implicitly supports 8-bit ISO8859/1 characters.
555 * This gives us the little-endian representation, which
556 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
557 * is machine-dependent.)
560 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
564 BZERO(unicode, ascii_len * 2);
565 for (i = 0; i < ascii_len; i++)
566 unicode[i * 2] = (u_char) ascii[i];
570 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
572 #if defined(__NetBSD__) || !defined(USE_MD4)
573 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
574 int mdlen = secret_len;
576 int mdlen = secret_len * 8;
580 MD4Init(&md4Context);
581 #if !defined(USE_MD4)
582 /* Internal MD4Update can take at most 64 bytes at a time */
583 while (mdlen > 512) {
584 MD4Update(&md4Context, secret, 512);
589 MD4Update(&md4Context, secret, mdlen);
590 MD4Final(hash, &md4Context);
595 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
596 u_char NTResponse[24])
598 u_char unicodePassword[MAX_NT_PASSWORD * 2];
599 u_char PasswordHash[MD4_SIGNATURE_SIZE];
601 /* Hash the Unicode version of the secret (== password). */
602 ascii2unicode(secret, secret_len, unicodePassword);
603 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
605 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
609 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
610 char *secret, int secret_len, u_char NTResponse[24])
612 u_char unicodePassword[MAX_NT_PASSWORD * 2];
613 u_char PasswordHash[MD4_SIGNATURE_SIZE];
616 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
618 /* Hash the Unicode version of the secret (== password). */
619 ascii2unicode(secret, secret_len, unicodePassword);
620 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
622 ChallengeResponse(Challenge, PasswordHash, NTResponse);
626 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
629 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
630 unsigned char *response)
633 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
634 u_char PasswordHash[MD4_SIGNATURE_SIZE];
636 /* LANMan password is case insensitive */
637 BZERO(UcasePassword, sizeof(UcasePassword));
638 for (i = 0; i < secret_len; i++)
639 UcasePassword[i] = (u_char)toupper(secret[i]);
640 (void) DesSetkey(UcasePassword + 0);
641 DesEncrypt( StdText, PasswordHash + 0 );
642 (void) DesSetkey(UcasePassword + 7);
643 DesEncrypt( StdText, PasswordHash + 8 );
644 ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
650 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
651 u_char NTResponse[24], u_char PeerChallenge[16],
652 u_char *rchallenge, char *username,
653 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
656 * "Magic" constants used in response generation, from RFC 2759.
658 u_char Magic1[39] = /* "Magic server to client signing constant" */
659 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
660 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
661 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
662 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
663 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
664 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
665 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
666 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
667 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
671 SHA1_CTX sha1Context;
672 u_char Digest[SHA1_SIGNATURE_SIZE];
675 SHA1_Init(&sha1Context);
676 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
677 SHA1_Update(&sha1Context, NTResponse, 24);
678 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
679 SHA1_Final(Digest, &sha1Context);
681 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
683 SHA1_Init(&sha1Context);
684 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
685 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
686 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
687 SHA1_Final(Digest, &sha1Context);
689 /* Convert to ASCII hex string. */
690 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
691 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
696 GenerateAuthenticatorResponsePlain
697 (char *secret, int secret_len,
698 u_char NTResponse[24], u_char PeerChallenge[16],
699 u_char *rchallenge, char *username,
700 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
702 u_char unicodePassword[MAX_NT_PASSWORD * 2];
703 u_char PasswordHash[MD4_SIGNATURE_SIZE];
704 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
706 /* Hash (x2) the Unicode version of the secret (== password). */
707 ascii2unicode(secret, secret_len, unicodePassword);
708 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
709 NTPasswordHash(PasswordHash, sizeof(PasswordHash),
712 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
713 rchallenge, username, authResponse);
720 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
723 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
725 u_char unicodePassword[MAX_NT_PASSWORD * 2];
726 u_char PasswordHash[MD4_SIGNATURE_SIZE];
727 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
729 /* Hash (x2) the Unicode version of the secret (== password). */
730 ascii2unicode(secret, secret_len, unicodePassword);
731 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
732 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
734 mppe_set_chapv1(rchallenge, PasswordHashHash);
738 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
741 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
743 u_char unicodePassword[MAX_NT_PASSWORD * 2];
744 u_char PasswordHash[MD4_SIGNATURE_SIZE];
745 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
746 /* Hash (x2) the Unicode version of the secret (== password). */
747 ascii2unicode(secret, secret_len, unicodePassword);
748 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
749 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
750 mppe_set_chapv2(PasswordHashHash, NTResponse, IsServer);
757 ChapMS(u_char *rchallenge, char *secret, int secret_len,
758 unsigned char *response)
760 BZERO(response, MS_CHAP_RESPONSE_LEN);
762 ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
765 ChapMS_LANMan(rchallenge, secret, secret_len,
766 &response[MS_CHAP_LANMANRESP]);
768 /* preferred method is set by option */
769 response[MS_CHAP_USENT] = !ms_lanman;
771 response[MS_CHAP_USENT] = 1;
775 Set_Start_Key(rchallenge, secret, secret_len);
781 * If PeerChallenge is NULL, one is generated and the PeerChallenge
782 * field of response is filled in. Call this way when generating a response.
783 * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
784 * Call this way when verifying a response (or debugging).
785 * Do not call with PeerChallenge = response.
787 * The PeerChallenge field of response is then used for calculation of the
788 * Authenticator Response.
791 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
792 char *user, char *secret, int secret_len, unsigned char *response,
793 u_char authResponse[], int authenticator)
796 u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
799 BZERO(response, MS_CHAP2_RESPONSE_LEN);
801 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
803 for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
804 *p++ = (u_char) (drand48() * 0xff);
806 BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
807 MS_CHAP2_PEER_CHAL_LEN);
809 /* Generate the NT-Response */
810 ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
811 secret, secret_len, &response[MS_CHAP2_NTRESP]);
813 /* Generate the Authenticator Response. */
814 GenerateAuthenticatorResponsePlain(secret, secret_len,
815 &response[MS_CHAP2_NTRESP],
816 &response[MS_CHAP2_PEER_CHALLENGE],
817 rchallenge, user, authResponse);
820 SetMasterKeys(secret, secret_len,
821 &response[MS_CHAP2_NTRESP], authenticator);
826 static struct chap_digest_type chapms_digest = {
827 CHAP_MICROSOFT, /* code */
828 chapms_generate_challenge,
829 chapms_verify_response,
830 chapms_make_response,
831 NULL, /* check_success */
832 chapms_handle_failure,
835 static struct chap_digest_type chapms2_digest = {
836 CHAP_MICROSOFT_V2, /* code */
837 chapms2_generate_challenge,
838 chapms2_verify_response,
839 chapms2_make_response,
840 chapms2_check_success,
841 chapms_handle_failure,
847 chap_register_digest(&chapms_digest);
848 chap_register_digest(&chapms2_digest);
849 add_options(chapms_option_list);