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 $"
85 #include <sys/types.h>
98 static void ascii2unicode (char[], int, u_char[]);
99 static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
100 static void ChallengeResponse (u_char *, u_char *, u_char[24]);
101 static void ChapMS_NT (u_char *, char *, int, u_char[24]);
102 static void ChapMS2_NT (u_char *, u_char[16], char *, char *, int,
104 static void GenerateAuthenticatorResponsePlain
105 (char*, int, u_char[24], u_char[16], u_char *,
108 static void ChapMS_LANMan (u_char *, char *, int, u_char *);
112 bool ms_lanman = 0; /* Use LanMan password instead of NT */
113 /* Has meaning only with MS-CHAP challenges */
119 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
120 static char *mschap_challenge = NULL;
121 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
122 static char *mschap2_peer_challenge = NULL;
125 #include "fsm.h" /* Need to poke MPPE options */
127 #include <net/ppp-comp.h>
131 * Command-line options.
133 static option_t chapms_option_list[] = {
135 { "ms-lanman", o_bool, &ms_lanman,
136 "Use LanMan passwd when using MS-CHAP", 1 },
139 { "mschap-challenge", o_string, &mschap_challenge,
140 "specify CHAP challenge" },
141 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
142 "specify CHAP peer challenge" },
148 * chapms_generate_challenge - generate a challenge for MS-CHAP.
149 * For MS-CHAP the challenge length is fixed at 8 bytes.
150 * The length goes in challenge[0] and the actual challenge starts
154 chapms_generate_challenge(unsigned char *challenge)
158 if (mschap_challenge && strlen(mschap_challenge) == 8)
159 memcpy(challenge, mschap_challenge, 8);
162 random_bytes(challenge, 8);
166 chapms2_generate_challenge(unsigned char *challenge)
170 if (mschap_challenge && strlen(mschap_challenge) == 16)
171 memcpy(challenge, mschap_challenge, 16);
174 random_bytes(challenge, 16);
178 chapms_verify_response(int id, char *name,
179 unsigned char *secret, int secret_len,
180 unsigned char *challenge, unsigned char *response,
181 char *message, int message_space)
183 unsigned char md[MS_CHAP_RESPONSE_LEN];
185 int challenge_len, response_len;
187 challenge_len = *challenge++; /* skip length, is 8 */
188 response_len = *response++;
189 if (response_len != MS_CHAP_RESPONSE_LEN)
193 if (!response[MS_CHAP_USENT]) {
194 /* Should really propagate this into the error packet. */
195 notice("Peer request for LANMAN auth not supported");
200 /* Generate the expected response. */
201 ChapMS(challenge, (char *)secret, secret_len, md);
204 /* Determine which part of response to verify against */
205 if (!response[MS_CHAP_USENT])
206 diff = memcmp(&response[MS_CHAP_LANMANRESP],
207 &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
210 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
214 slprintf(message, message_space, "Access granted");
219 /* See comments below for MS-CHAP V2 */
220 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
221 challenge_len, challenge);
226 chapms2_verify_response(int id, char *name,
227 unsigned char *secret, int secret_len,
228 unsigned char *challenge, unsigned char *response,
229 char *message, int message_space)
231 unsigned char md[MS_CHAP2_RESPONSE_LEN];
232 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
233 int challenge_len, response_len;
235 challenge_len = *challenge++; /* skip length, is 16 */
236 response_len = *response++;
237 if (response_len != MS_CHAP2_RESPONSE_LEN)
238 goto bad; /* not even the right length */
240 /* Generate the expected response and our mutual auth. */
241 ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,
242 (char *)secret, secret_len, md,
243 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
245 /* compare MDs and send the appropriate status */
247 * Per RFC 2759, success message must be formatted as
248 * "S=<auth_string> M=<message>"
250 * <auth_string> is the Authenticator Response (mutual auth)
251 * <message> is a text message
253 * However, some versions of Windows (win98 tested) do not know
254 * about the M=<message> part (required per RFC 2759) and flag
255 * it as an error (reported incorrectly as an encryption error
256 * to the user). Since the RFC requires it, and it can be
257 * useful information, we supply it if the peer is a conforming
258 * system. Luckily (?), win98 sets the Flags field to 0x04
259 * (contrary to RFC requirements) so we can use that to
260 * distinguish between conforming and non-conforming systems.
262 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
263 * help debugging this.
265 if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
266 MS_CHAP2_NTRESP_LEN) == 0) {
267 if (response[MS_CHAP2_FLAGS])
268 slprintf(message, message_space, "S=%s", saresponse);
270 slprintf(message, message_space, "S=%s M=%s",
271 saresponse, "Access granted");
277 * Failure message must be formatted as
278 * "E=e R=r C=c V=v M=m"
280 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
281 * r = retry (we use 1, ok to retry)
282 * c = challenge to use for next response, we reuse previous
283 * v = Change Password version supported, we use 0
286 * The M=m part is only for MS-CHAPv2. Neither win2k nor
287 * win98 (others untested) display the message to the user anyway.
288 * They also both ignore the E=e code.
290 * Note that it's safe to reuse the same challenge as we don't
291 * actually accept another response based on the error message
292 * (and no clients try to resend a response anyway).
294 * Basically, this whole bit is useless code, even the small
295 * implementation here is only because of overspecification.
297 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
298 challenge_len, challenge, "Access denied");
303 chapms_make_response(unsigned char *response, int id, char *our_name,
304 unsigned char *challenge, char *secret, int secret_len,
305 unsigned char *private)
307 challenge++; /* skip length, should be 8 */
308 *response++ = MS_CHAP_RESPONSE_LEN;
309 ChapMS(challenge, secret, secret_len, response);
312 struct chapms2_response_cache_entry {
314 unsigned char challenge[16];
315 unsigned char response[MS_CHAP2_RESPONSE_LEN];
316 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
319 #define CHAPMS2_MAX_RESPONSE_CACHE_SIZE 10
320 static struct chapms2_response_cache_entry
321 chapms2_response_cache[CHAPMS2_MAX_RESPONSE_CACHE_SIZE];
322 static int chapms2_response_cache_next_index = 0;
323 static int chapms2_response_cache_size = 0;
326 chapms2_add_to_response_cache(int id, unsigned char *challenge,
327 unsigned char *response,
328 unsigned char *auth_response)
330 int i = chapms2_response_cache_next_index;
332 chapms2_response_cache[i].id = id;
333 memcpy(chapms2_response_cache[i].challenge, challenge, 16);
334 memcpy(chapms2_response_cache[i].response, response,
335 MS_CHAP2_RESPONSE_LEN);
336 memcpy(chapms2_response_cache[i].auth_response,
337 auth_response, MS_AUTH_RESPONSE_LENGTH);
338 chapms2_response_cache_next_index =
339 (i + 1) % CHAPMS2_MAX_RESPONSE_CACHE_SIZE;
340 if (chapms2_response_cache_next_index > chapms2_response_cache_size)
341 chapms2_response_cache_size = chapms2_response_cache_next_index;
342 dbglog("added response cache entry %d", i);
345 static struct chapms2_response_cache_entry*
346 chapms2_find_in_response_cache(int id, unsigned char *challenge,
347 unsigned char *auth_response)
351 for (i = 0; i < chapms2_response_cache_size; i++) {
352 if (id == chapms2_response_cache[i].id
355 chapms2_response_cache[i].challenge,
358 || memcmp(auth_response,
359 chapms2_response_cache[i].auth_response,
360 MS_AUTH_RESPONSE_LENGTH) == 0)) {
361 dbglog("response found in cache (entry %d)", i);
362 return &chapms2_response_cache[i];
365 return NULL; /* not found */
369 chapms2_make_response(unsigned char *response, int id, char *our_name,
370 unsigned char *challenge, char *secret, int secret_len,
371 unsigned char *private)
373 const struct chapms2_response_cache_entry *cache_entry;
374 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH+1];
376 challenge++; /* skip length, should be 16 */
377 *response++ = MS_CHAP2_RESPONSE_LEN;
378 cache_entry = chapms2_find_in_response_cache(id, challenge, NULL);
380 memcpy(response, cache_entry->response, MS_CHAP2_RESPONSE_LEN);
385 mschap2_peer_challenge,
389 our_name, secret, secret_len, response, auth_response,
390 MS_CHAP2_AUTHENTICATEE);
391 chapms2_add_to_response_cache(id, challenge, response, auth_response);
395 chapms2_check_success(int id, unsigned char *msg, int len)
397 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
398 strncmp((char *)msg, "S=", 2) != 0) {
399 /* Packet does not start with "S=" */
400 error("MS-CHAPv2 Success packet is badly formed.");
405 if (len < MS_AUTH_RESPONSE_LENGTH
406 || !chapms2_find_in_response_cache(id, NULL /* challenge */, msg)) {
407 /* Authenticator Response did not match expected. */
408 error("MS-CHAPv2 mutual authentication failed.");
411 /* Authenticator Response matches. */
412 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
413 len -= MS_AUTH_RESPONSE_LENGTH;
414 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
415 msg += 3; /* Eat the delimiter */
416 } else if ((len >= 2) && !strncmp((char *)msg, "M=", 2)) {
417 msg += 2; /* Eat the delimiter */
419 /* Packet has extra text which does not begin " M=" */
420 error("MS-CHAPv2 Success packet is badly formed.");
427 chapms_handle_failure(unsigned char *inp, int len)
432 /* We want a null-terminated string for strxxx(). */
433 msg = malloc(len + 1);
435 notice("Out of memory in chapms_handle_failure");
438 BCOPY(inp, msg, len);
443 * Deal with MS-CHAP formatted failure messages; just print the
444 * M=<message> part (if any). For MS-CHAP we're not really supposed
445 * to use M=<message>, but it shouldn't hurt. See
446 * chapms[2]_verify_response.
448 if (!strncmp(p, "E=", 2))
449 err = strtol(p+2, NULL, 10); /* Remember the error code. */
451 goto print_msg; /* Message is badly formatted. */
453 if (len && ((p = strstr(p, " M=")) != NULL)) {
454 /* M=<message> field found. */
457 /* No M=<message>; use the error code. */
459 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
460 p = "E=646 Restricted logon hours";
463 case MS_CHAP_ERROR_ACCT_DISABLED:
464 p = "E=647 Account disabled";
467 case MS_CHAP_ERROR_PASSWD_EXPIRED:
468 p = "E=648 Password expired";
471 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
472 p = "E=649 No dialin permission";
475 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
476 p = "E=691 Authentication failure";
479 case MS_CHAP_ERROR_CHANGING_PASSWORD:
480 /* Should never see this, we don't support Change Password. */
481 p = "E=709 Error changing password";
486 error("Unknown MS-CHAP authentication failure: %.*v",
493 error("MS-CHAP authentication failed: %v", p);
498 ChallengeResponse(u_char *challenge,
499 u_char PasswordHash[MD4_SIGNATURE_SIZE],
502 u_char ZPasswordHash[21];
504 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
505 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
508 dbglog("ChallengeResponse - ZPasswordHash %.*B",
509 sizeof(ZPasswordHash), ZPasswordHash);
512 (void) DesSetkey(ZPasswordHash + 0);
513 DesEncrypt(challenge, response + 0);
514 (void) DesSetkey(ZPasswordHash + 7);
515 DesEncrypt(challenge, response + 8);
516 (void) DesSetkey(ZPasswordHash + 14);
517 DesEncrypt(challenge, response + 16);
520 dbglog("ChallengeResponse - response %.24B", response);
525 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
526 char *username, u_char Challenge[8])
529 SHA1_CTX sha1Context;
530 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
533 /* remove domain from "domain\username" */
534 if ((user = strrchr(username, '\\')) != NULL)
539 SHA1_Init(&sha1Context);
540 SHA1_Update(&sha1Context, PeerChallenge, 16);
541 SHA1_Update(&sha1Context, rchallenge, 16);
542 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
543 SHA1_Final(sha1Hash, &sha1Context);
545 BCOPY(sha1Hash, Challenge, 8);
549 * Convert the ASCII version of the password to Unicode.
550 * This implicitly supports 8-bit ISO8859/1 characters.
551 * This gives us the little-endian representation, which
552 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
553 * is machine-dependent.)
556 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
560 BZERO(unicode, ascii_len * 2);
561 for (i = 0; i < ascii_len; i++)
562 unicode[i * 2] = (u_char) ascii[i];
566 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
569 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
570 int mdlen = secret_len;
572 int mdlen = secret_len * 8;
576 MD4Init(&md4Context);
577 /* MD4Update can take at most 64 bytes at a time */
578 while (mdlen > 512) {
579 MD4Update(&md4Context, secret, 512);
583 MD4Update(&md4Context, secret, mdlen);
584 MD4Final(hash, &md4Context);
589 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
590 u_char NTResponse[24])
592 u_char unicodePassword[MAX_NT_PASSWORD * 2];
593 u_char PasswordHash[MD4_SIGNATURE_SIZE];
595 /* Hash the Unicode version of the secret (== password). */
596 ascii2unicode(secret, secret_len, unicodePassword);
597 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
599 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
603 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
604 char *secret, int secret_len, u_char NTResponse[24])
606 u_char unicodePassword[MAX_NT_PASSWORD * 2];
607 u_char PasswordHash[MD4_SIGNATURE_SIZE];
610 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
612 /* Hash the Unicode version of the secret (== password). */
613 ascii2unicode(secret, secret_len, unicodePassword);
614 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
616 ChallengeResponse(Challenge, PasswordHash, NTResponse);
620 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
623 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
624 unsigned char *response)
627 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
628 u_char PasswordHash[MD4_SIGNATURE_SIZE];
630 /* LANMan password is case insensitive */
631 BZERO(UcasePassword, sizeof(UcasePassword));
632 for (i = 0; i < secret_len; i++)
633 UcasePassword[i] = (u_char)toupper(secret[i]);
634 (void) DesSetkey(UcasePassword + 0);
635 DesEncrypt( StdText, PasswordHash + 0 );
636 (void) DesSetkey(UcasePassword + 7);
637 DesEncrypt( StdText, PasswordHash + 8 );
638 ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
644 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
645 u_char NTResponse[24], u_char PeerChallenge[16],
646 u_char *rchallenge, char *username,
647 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
650 * "Magic" constants used in response generation, from RFC 2759.
652 u_char Magic1[39] = /* "Magic server to client signing constant" */
653 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
654 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
655 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
656 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
657 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
658 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
659 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
660 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
661 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
665 SHA1_CTX sha1Context;
666 u_char Digest[SHA1_SIGNATURE_SIZE];
669 SHA1_Init(&sha1Context);
670 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
671 SHA1_Update(&sha1Context, NTResponse, 24);
672 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
673 SHA1_Final(Digest, &sha1Context);
675 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
677 SHA1_Init(&sha1Context);
678 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
679 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
680 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
681 SHA1_Final(Digest, &sha1Context);
683 /* Convert to ASCII hex string. */
684 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
685 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
690 GenerateAuthenticatorResponsePlain
691 (char *secret, int secret_len,
692 u_char NTResponse[24], u_char PeerChallenge[16],
693 u_char *rchallenge, char *username,
694 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
696 u_char unicodePassword[MAX_NT_PASSWORD * 2];
697 u_char PasswordHash[MD4_SIGNATURE_SIZE];
698 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
700 /* Hash (x2) the Unicode version of the secret (== password). */
701 ascii2unicode(secret, secret_len, unicodePassword);
702 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
703 NTPasswordHash(PasswordHash, sizeof(PasswordHash),
706 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
707 rchallenge, username, authResponse);
714 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
717 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
719 u_char unicodePassword[MAX_NT_PASSWORD * 2];
720 u_char PasswordHash[MD4_SIGNATURE_SIZE];
721 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
723 /* Hash (x2) the Unicode version of the secret (== password). */
724 ascii2unicode(secret, secret_len, unicodePassword);
725 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
726 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
728 mppe_set_chapv1(rchallenge, PasswordHashHash);
732 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
735 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
737 u_char unicodePassword[MAX_NT_PASSWORD * 2];
738 u_char PasswordHash[MD4_SIGNATURE_SIZE];
739 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
740 /* Hash (x2) the Unicode version of the secret (== password). */
741 ascii2unicode(secret, secret_len, unicodePassword);
742 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
743 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
744 mppe_set_chapv2(PasswordHashHash, NTResponse, IsServer);
751 ChapMS(u_char *rchallenge, char *secret, int secret_len,
752 unsigned char *response)
754 BZERO(response, MS_CHAP_RESPONSE_LEN);
756 ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
759 ChapMS_LANMan(rchallenge, secret, secret_len,
760 &response[MS_CHAP_LANMANRESP]);
762 /* preferred method is set by option */
763 response[MS_CHAP_USENT] = !ms_lanman;
765 response[MS_CHAP_USENT] = 1;
769 Set_Start_Key(rchallenge, secret, secret_len);
775 * If PeerChallenge is NULL, one is generated and the PeerChallenge
776 * field of response is filled in. Call this way when generating a response.
777 * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
778 * Call this way when verifying a response (or debugging).
779 * Do not call with PeerChallenge = response.
781 * The PeerChallenge field of response is then used for calculation of the
782 * Authenticator Response.
785 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
786 char *user, char *secret, int secret_len, unsigned char *response,
787 u_char authResponse[], int authenticator)
790 u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
793 BZERO(response, MS_CHAP2_RESPONSE_LEN);
795 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
797 for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
798 *p++ = (u_char) (drand48() * 0xff);
800 BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
801 MS_CHAP2_PEER_CHAL_LEN);
803 /* Generate the NT-Response */
804 ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
805 secret, secret_len, &response[MS_CHAP2_NTRESP]);
807 /* Generate the Authenticator Response. */
808 GenerateAuthenticatorResponsePlain(secret, secret_len,
809 &response[MS_CHAP2_NTRESP],
810 &response[MS_CHAP2_PEER_CHALLENGE],
811 rchallenge, user, authResponse);
814 SetMasterKeys(secret, secret_len,
815 &response[MS_CHAP2_NTRESP], authenticator);
820 static struct chap_digest_type chapms_digest = {
821 CHAP_MICROSOFT, /* code */
822 chapms_generate_challenge,
823 chapms_verify_response,
824 chapms_make_response,
825 NULL, /* check_success */
826 chapms_handle_failure,
829 static struct chap_digest_type chapms2_digest = {
830 CHAP_MICROSOFT_V2, /* code */
831 chapms2_generate_challenge,
832 chapms2_verify_response,
833 chapms2_make_response,
834 chapms2_check_success,
835 chapms_handle_failure,
841 chap_register_digest(&chapms_digest);
842 chap_register_digest(&chapms2_digest);
843 add_options(chapms_option_list);