From Marco D'Itri.
[mpls-ppp.git] / pppd / chap_ms.c
blob05c6225a720612fe01afc43c917c59dd58a37ea3
1 /*
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
8 * are met:
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
16 * distribution.
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
53 * are met:
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
61 * distribution.
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.34 2004/11/15 22:13:26 paulus Exp $"
79 #ifdef CHAPMS
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <ctype.h>
85 #include <sys/types.h>
86 #include <sys/time.h>
87 #include <unistd.h>
89 #include "pppd.h"
90 #include "chap-new.h"
91 #include "chap_ms.h"
92 #include "md4.h"
93 #include "sha1.h"
94 #include "pppcrypt.h"
95 #include "magic.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((u_char *, u_char[16], char *, char *, int,
105 u_char[24]));
106 static void GenerateAuthenticatorResponsePlain
107 __P((char*, int, u_char[24], u_char[16], u_char *,
108 char *, u_char[41]));
109 #ifdef MSLANMAN
110 static void ChapMS_LANMan __P((u_char *, char *, int, u_char *));
111 #endif
113 #ifdef MPPE
114 static void Set_Start_Key __P((u_char *, char *, int));
115 static void SetMasterKeys __P((char *, int, u_char[24], int));
116 #endif
118 #ifdef MSLANMAN
119 bool ms_lanman = 0; /* Use LanMan password instead of NT */
120 /* Has meaning only with MS-CHAP challenges */
121 #endif
123 #ifdef MPPE
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? */
128 #ifdef DEBUGMPPEKEY
129 /* For MPPE debug */
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;
134 #endif
136 #include "fsm.h" /* Need to poke MPPE options */
137 #include "ccp.h"
138 #include <net/ppp-comp.h>
139 #endif
142 * Command-line options.
144 static option_t chapms_option_list[] = {
145 #ifdef MSLANMAN
146 { "ms-lanman", o_bool, &ms_lanman,
147 "Use LanMan passwd when using MS-CHAP", 1 },
148 #endif
149 #ifdef DEBUGMPPEKEY
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" },
154 #endif
155 { NULL }
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
162 * at challenge[1].
164 static void
165 chapms_generate_challenge(unsigned char *challenge)
167 *challenge++ = 8;
168 #ifdef DEBUGMPPEKEY
169 if (mschap_challenge && strlen(mschap_challenge) == 8)
170 memcpy(challenge, mschap_challenge, 8);
171 else
172 #endif
173 random_bytes(challenge, 8);
176 static void
177 chapms2_generate_challenge(unsigned char *challenge)
179 *challenge++ = 16;
180 #ifdef DEBUGMPPEKEY
181 if (mschap_challenge && strlen(mschap_challenge) == 16)
182 memcpy(challenge, mschap_challenge, 16);
183 else
184 #endif
185 random_bytes(challenge, 16);
188 static int
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 unsigned char md[MS_CHAP_RESPONSE_LEN];
195 int diff;
196 int challenge_len, response_len;
198 challenge_len = *challenge++; /* skip length, is 8 */
199 response_len = *response++;
200 if (response_len != MS_CHAP_RESPONSE_LEN)
201 goto bad;
203 #ifndef MSLANMAN
204 if (!response[MS_CHAP_USENT]) {
205 /* Should really propagate this into the error packet. */
206 notice("Peer request for LANMAN auth not supported");
207 goto bad;
209 #endif
211 /* Generate the expected response. */
212 ChapMS(challenge, (char *)secret, secret_len, md);
214 #ifdef MSLANMAN
215 /* Determine which part of response to verify against */
216 if (!response[MS_CHAP_USENT])
217 diff = memcmp(&response[MS_CHAP_LANMANRESP],
218 &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
219 else
220 #endif
221 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
222 MS_CHAP_NTRESP_LEN);
224 if (diff == 0) {
225 slprintf(message, message_space, "Access granted");
226 return 1;
229 bad:
230 /* See comments below for MS-CHAP V2 */
231 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
232 challenge_len, challenge);
233 return 0;
236 static int
237 chapms2_verify_response(int id, char *name,
238 unsigned char *secret, int secret_len,
239 unsigned char *challenge, unsigned char *response,
240 char *message, int message_space)
242 unsigned char md[MS_CHAP2_RESPONSE_LEN];
243 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
244 int challenge_len, response_len;
246 challenge_len = *challenge++; /* skip length, is 16 */
247 response_len = *response++;
248 if (response_len != MS_CHAP2_RESPONSE_LEN)
249 goto bad; /* not even the right length */
251 /* Generate the expected response and our mutual auth. */
252 ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,
253 (char *)secret, secret_len, md,
254 (unsigned char *)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>"
260 * where
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[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
277 MS_CHAP2_NTRESP_LEN) == 0) {
278 if (response[MS_CHAP2_FLAGS])
279 slprintf(message, message_space, "S=%s", saresponse);
280 else
281 slprintf(message, message_space, "S=%s M=%s",
282 saresponse, "Access granted");
283 return 1;
286 bad:
288 * Failure message must be formatted as
289 * "E=e R=r C=c V=v M=m"
290 * where
291 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
292 * r = retry (we use 1, ok to retry)
293 * c = challenge to use for next response, we reuse previous
294 * v = Change Password version supported, we use 0
295 * m = text message
297 * The M=m part is only for MS-CHAPv2. Neither win2k nor
298 * win98 (others untested) display the message to the user anyway.
299 * They also both ignore the E=e code.
301 * Note that it's safe to reuse the same challenge as we don't
302 * actually accept another response based on the error message
303 * (and no clients try to resend a response anyway).
305 * Basically, this whole bit is useless code, even the small
306 * implementation here is only because of overspecification.
308 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
309 challenge_len, challenge, "Access denied");
310 return 0;
313 static void
314 chapms_make_response(unsigned char *response, int id, char *our_name,
315 unsigned char *challenge, char *secret, int secret_len,
316 unsigned char *private)
318 challenge++; /* skip length, should be 8 */
319 *response++ = MS_CHAP_RESPONSE_LEN;
320 ChapMS(challenge, secret, secret_len, response);
323 static void
324 chapms2_make_response(unsigned char *response, int id, char *our_name,
325 unsigned char *challenge, char *secret, int secret_len,
326 unsigned char *private)
328 challenge++; /* skip length, should be 16 */
329 *response++ = MS_CHAP2_RESPONSE_LEN;
330 ChapMS2(challenge,
331 #ifdef DEBUGMPPEKEY
332 mschap2_peer_challenge,
333 #else
334 NULL,
335 #endif
336 our_name, secret, secret_len, response, private,
337 MS_CHAP2_AUTHENTICATEE);
340 static int
341 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
343 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
344 strncmp((char *)msg, "S=", 2) != 0) {
345 /* Packet does not start with "S=" */
346 error("MS-CHAPv2 Success packet is badly formed.");
347 return 0;
349 msg += 2;
350 len -= 2;
351 if (len < MS_AUTH_RESPONSE_LENGTH
352 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
353 /* Authenticator Response did not match expected. */
354 error("MS-CHAPv2 mutual authentication failed.");
355 return 0;
357 /* Authenticator Response matches. */
358 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
359 len -= MS_AUTH_RESPONSE_LENGTH;
360 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
361 msg += 3; /* Eat the delimiter */
362 } else if (len) {
363 /* Packet has extra text which does not begin " M=" */
364 error("MS-CHAPv2 Success packet is badly formed.");
365 return 0;
367 return 1;
370 static void
371 chapms_handle_failure(unsigned char *inp, int len)
373 int err;
374 char *p, *msg;
376 /* We want a null-terminated string for strxxx(). */
377 msg = malloc(len + 1);
378 if (!msg) {
379 notice("Out of memory in chapms_handle_failure");
380 return;
382 BCOPY(inp, msg, len);
383 msg[len] = 0;
384 p = msg;
387 * Deal with MS-CHAP formatted failure messages; just print the
388 * M=<message> part (if any). For MS-CHAP we're not really supposed
389 * to use M=<message>, but it shouldn't hurt. See
390 * chapms[2]_verify_response.
392 if (!strncmp(p, "E=", 2))
393 err = strtol(p, NULL, 10); /* Remember the error code. */
394 else
395 goto print_msg; /* Message is badly formatted. */
397 if (len && ((p = strstr(p, " M=")) != NULL)) {
398 /* M=<message> field found. */
399 p += 3;
400 } else {
401 /* No M=<message>; use the error code. */
402 switch (err) {
403 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
404 p = "E=646 Restricted logon hours";
405 break;
407 case MS_CHAP_ERROR_ACCT_DISABLED:
408 p = "E=647 Account disabled";
409 break;
411 case MS_CHAP_ERROR_PASSWD_EXPIRED:
412 p = "E=648 Password expired";
413 break;
415 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
416 p = "E=649 No dialin permission";
417 break;
419 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
420 p = "E=691 Authentication failure";
421 break;
423 case MS_CHAP_ERROR_CHANGING_PASSWORD:
424 /* Should never see this, we don't support Change Password. */
425 p = "E=709 Error changing password";
426 break;
428 default:
429 free(msg);
430 error("Unknown MS-CHAP authentication failure: %.*v",
431 len, inp);
432 return;
435 print_msg:
436 if (p != NULL)
437 error("MS-CHAP authentication failed: %v", p);
438 free(msg);
441 static void
442 ChallengeResponse(u_char *challenge,
443 u_char PasswordHash[MD4_SIGNATURE_SIZE],
444 u_char response[24])
446 u_char ZPasswordHash[21];
448 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
449 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
451 #if 0
452 dbglog("ChallengeResponse - ZPasswordHash %.*B",
453 sizeof(ZPasswordHash), ZPasswordHash);
454 #endif
456 (void) DesSetkey(ZPasswordHash + 0);
457 DesEncrypt(challenge, response + 0);
458 (void) DesSetkey(ZPasswordHash + 7);
459 DesEncrypt(challenge, response + 8);
460 (void) DesSetkey(ZPasswordHash + 14);
461 DesEncrypt(challenge, response + 16);
463 #if 0
464 dbglog("ChallengeResponse - response %.24B", response);
465 #endif
468 void
469 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
470 char *username, u_char Challenge[8])
473 SHA1_CTX sha1Context;
474 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
475 char *user;
477 /* remove domain from "domain\username" */
478 if ((user = strrchr(username, '\\')) != NULL)
479 ++user;
480 else
481 user = username;
483 SHA1_Init(&sha1Context);
484 SHA1_Update(&sha1Context, PeerChallenge, 16);
485 SHA1_Update(&sha1Context, rchallenge, 16);
486 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
487 SHA1_Final(sha1Hash, &sha1Context);
489 BCOPY(sha1Hash, Challenge, 8);
493 * Convert the ASCII version of the password to Unicode.
494 * This implicitly supports 8-bit ISO8859/1 characters.
495 * This gives us the little-endian representation, which
496 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
497 * is machine-dependent.)
499 static void
500 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
502 int i;
504 BZERO(unicode, ascii_len * 2);
505 for (i = 0; i < ascii_len; i++)
506 unicode[i * 2] = (u_char) ascii[i];
509 static void
510 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
512 #ifdef __NetBSD__
513 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
514 int mdlen = secret_len;
515 #else
516 int mdlen = secret_len * 8;
517 #endif
518 MD4_CTX md4Context;
520 MD4Init(&md4Context);
521 MD4Update(&md4Context, (unsigned char *)secret, mdlen);
522 MD4Final(hash, &md4Context);
526 static void
527 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
528 u_char NTResponse[24])
530 u_char unicodePassword[MAX_NT_PASSWORD * 2];
531 u_char PasswordHash[MD4_SIGNATURE_SIZE];
533 /* Hash the Unicode version of the secret (== password). */
534 ascii2unicode(secret, secret_len, unicodePassword);
535 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
537 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
540 static void
541 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
542 char *secret, int secret_len, u_char NTResponse[24])
544 u_char unicodePassword[MAX_NT_PASSWORD * 2];
545 u_char PasswordHash[MD4_SIGNATURE_SIZE];
546 u_char Challenge[8];
548 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
550 /* Hash the Unicode version of the secret (== password). */
551 ascii2unicode(secret, secret_len, unicodePassword);
552 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
554 ChallengeResponse(Challenge, PasswordHash, NTResponse);
557 #ifdef MSLANMAN
558 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
560 static void
561 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
562 unsigned char *response)
564 int i;
565 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
566 u_char PasswordHash[MD4_SIGNATURE_SIZE];
568 /* LANMan password is case insensitive */
569 BZERO(UcasePassword, sizeof(UcasePassword));
570 for (i = 0; i < secret_len; i++)
571 UcasePassword[i] = (u_char)toupper(secret[i]);
572 (void) DesSetkey(UcasePassword + 0);
573 DesEncrypt( StdText, PasswordHash + 0 );
574 (void) DesSetkey(UcasePassword + 7);
575 DesEncrypt( StdText, PasswordHash + 8 );
576 ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
578 #endif
581 void
582 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
583 u_char NTResponse[24], u_char PeerChallenge[16],
584 u_char *rchallenge, char *username,
585 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
588 * "Magic" constants used in response generation, from RFC 2759.
590 u_char Magic1[39] = /* "Magic server to client signing constant" */
591 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
592 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
593 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
594 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
595 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
596 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
597 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
598 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
599 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
600 0x6E };
602 int i;
603 SHA1_CTX sha1Context;
604 u_char Digest[SHA1_SIGNATURE_SIZE];
605 u_char Challenge[8];
607 SHA1_Init(&sha1Context);
608 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
609 SHA1_Update(&sha1Context, NTResponse, 24);
610 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
611 SHA1_Final(Digest, &sha1Context);
613 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
615 SHA1_Init(&sha1Context);
616 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
617 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
618 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
619 SHA1_Final(Digest, &sha1Context);
621 /* Convert to ASCII hex string. */
622 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
623 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
627 static void
628 GenerateAuthenticatorResponsePlain
629 (char *secret, int secret_len,
630 u_char NTResponse[24], u_char PeerChallenge[16],
631 u_char *rchallenge, char *username,
632 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
634 u_char unicodePassword[MAX_NT_PASSWORD * 2];
635 u_char PasswordHash[MD4_SIGNATURE_SIZE];
636 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
638 /* Hash (x2) the Unicode version of the secret (== password). */
639 ascii2unicode(secret, secret_len, unicodePassword);
640 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
641 NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
642 PasswordHashHash);
644 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
645 rchallenge, username, authResponse);
649 #ifdef MPPE
651 * Set mppe_xxxx_key from the NTPasswordHashHash.
652 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
654 void
655 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
657 SHA1_CTX sha1Context;
658 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
660 SHA1_Init(&sha1Context);
661 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
662 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
663 SHA1_Update(&sha1Context, rchallenge, 8);
664 SHA1_Final(Digest, &sha1Context);
666 /* Same key in both directions. */
667 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
668 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
670 mppe_keys_set = 1;
674 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
676 static void
677 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
679 u_char unicodePassword[MAX_NT_PASSWORD * 2];
680 u_char PasswordHash[MD4_SIGNATURE_SIZE];
681 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
683 /* Hash (x2) the Unicode version of the secret (== password). */
684 ascii2unicode(secret, secret_len, unicodePassword);
685 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
686 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
688 mppe_set_keys(rchallenge, PasswordHashHash);
692 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
694 * This helper function used in the Winbind module, which gets the
695 * NTHashHash from the server.
697 void
698 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
699 u_char NTResponse[24], int IsServer)
701 SHA1_CTX sha1Context;
702 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
703 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
705 u_char SHApad1[40] =
706 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
709 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
710 u_char SHApad2[40] =
711 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
712 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
713 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
714 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
716 /* "This is the MPPE Master Key" */
717 u_char Magic1[27] =
718 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
719 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
720 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
721 /* "On the client side, this is the send key; "
722 "on the server side, it is the receive key." */
723 u_char Magic2[84] =
724 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
725 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
726 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
727 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
728 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
729 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
730 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
731 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
732 0x6b, 0x65, 0x79, 0x2e };
733 /* "On the client side, this is the receive key; "
734 "on the server side, it is the send key." */
735 u_char Magic3[84] =
736 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
737 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
738 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
739 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
740 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
741 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
742 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
743 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
744 0x6b, 0x65, 0x79, 0x2e };
745 u_char *s;
747 SHA1_Init(&sha1Context);
748 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
749 SHA1_Update(&sha1Context, NTResponse, 24);
750 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
751 SHA1_Final(MasterKey, &sha1Context);
754 * generate send key
756 if (IsServer)
757 s = Magic3;
758 else
759 s = Magic2;
760 SHA1_Init(&sha1Context);
761 SHA1_Update(&sha1Context, MasterKey, 16);
762 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
763 SHA1_Update(&sha1Context, s, 84);
764 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
765 SHA1_Final(Digest, &sha1Context);
767 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
770 * generate recv key
772 if (IsServer)
773 s = Magic2;
774 else
775 s = Magic3;
776 SHA1_Init(&sha1Context);
777 SHA1_Update(&sha1Context, MasterKey, 16);
778 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
779 SHA1_Update(&sha1Context, s, 84);
780 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
781 SHA1_Final(Digest, &sha1Context);
783 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
785 mppe_keys_set = 1;
789 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
791 static void
792 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
794 u_char unicodePassword[MAX_NT_PASSWORD * 2];
795 u_char PasswordHash[MD4_SIGNATURE_SIZE];
796 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
797 /* Hash (x2) the Unicode version of the secret (== password). */
798 ascii2unicode(secret, secret_len, unicodePassword);
799 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
800 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
801 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
804 #endif /* MPPE */
807 void
808 ChapMS(u_char *rchallenge, char *secret, int secret_len,
809 unsigned char *response)
811 BZERO(response, MS_CHAP_RESPONSE_LEN);
813 ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
815 #ifdef MSLANMAN
816 ChapMS_LANMan(rchallenge, secret, secret_len, &response);
818 /* preferred method is set by option */
819 response[MS_CHAP_USENT] = !ms_lanman;
820 #else
821 response[MS_CHAP_USENT] = 1;
822 #endif
824 #ifdef MPPE
825 Set_Start_Key(rchallenge, secret, secret_len);
826 #endif
831 * If PeerChallenge is NULL, one is generated and the PeerChallenge
832 * field of response is filled in. Call this way when generating a response.
833 * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
834 * Call this way when verifying a response (or debugging).
835 * Do not call with PeerChallenge = response.
837 * The PeerChallenge field of response is then used for calculation of the
838 * Authenticator Response.
840 void
841 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
842 char *user, char *secret, int secret_len, unsigned char *response,
843 u_char authResponse[], int authenticator)
845 /* ARGSUSED */
846 u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
847 int i;
849 BZERO(response, sizeof(*response));
851 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
852 if (!PeerChallenge)
853 for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
854 *p++ = (u_char) (drand48() * 0xff);
855 else
856 BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
857 MS_CHAP2_PEER_CHAL_LEN);
859 /* Generate the NT-Response */
860 ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
861 secret, secret_len, &response[MS_CHAP2_NTRESP]);
863 /* Generate the Authenticator Response. */
864 GenerateAuthenticatorResponsePlain(secret, secret_len,
865 &response[MS_CHAP2_NTRESP],
866 &response[MS_CHAP2_PEER_CHALLENGE],
867 rchallenge, user, authResponse);
869 #ifdef MPPE
870 SetMasterKeys(secret, secret_len,
871 &response[MS_CHAP2_NTRESP], authenticator);
872 #endif
875 #ifdef MPPE
877 * Set MPPE options from plugins.
879 void
880 set_mppe_enc_types(int policy, int types)
882 /* Early exit for unknown policies. */
883 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
884 policy != MPPE_ENC_POL_ENC_REQUIRED)
885 return;
887 /* Don't modify MPPE if it's optional and wasn't already configured. */
888 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
889 return;
892 * Disable undesirable encryption types. Note that we don't ENABLE
893 * any encryption types, to avoid overriding manual configuration.
895 switch(types) {
896 case MPPE_ENC_TYPES_RC4_40:
897 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
898 break;
899 case MPPE_ENC_TYPES_RC4_128:
900 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
901 break;
902 default:
903 break;
906 #endif /* MPPE */
908 static struct chap_digest_type chapms_digest = {
909 CHAP_MICROSOFT, /* code */
910 chapms_generate_challenge,
911 chapms_verify_response,
912 chapms_make_response,
913 NULL, /* check_success */
914 chapms_handle_failure,
917 static struct chap_digest_type chapms2_digest = {
918 CHAP_MICROSOFT_V2, /* code */
919 chapms2_generate_challenge,
920 chapms2_verify_response,
921 chapms2_make_response,
922 chapms2_check_success,
923 chapms_handle_failure,
926 void
927 chapms_init(void)
929 chap_register_digest(&chapms_digest);
930 chap_register_digest(&chapms2_digest);
931 add_options(chapms_option_list);
934 #endif /* CHAPMS */