]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
When using the notty option, close off stdin and stdout once the
[ppp.git] / pppd / chap_ms.c
1 /*
2  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3  *
4  * Copyright (c) 1995 Eric Rosenquist.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
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.
17  *
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.
21  *
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.
29  */
30
31 /*
32  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
33  *
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.
38  *
39  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
40  */
41
42 /*
43  * Modifications by Frank Cusack, frank@google.com, March 2002.
44  *
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.
48  *
49  * Copyright (c) 2002 Google, Inc.  All rights reserved.
50  *
51  * Redistribution and use in source and binary forms, with or without
52  * modification, are permitted provided that the following conditions
53  * are met:
54  *
55  * 1. Redistributions of source code must retain the above copyright
56  *    notice, this list of conditions and the following disclaimer.
57  *
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.
62  *
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.
66  *
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.
74  *
75  */
76
77 #define RCSID   "$Id: chap_ms.c,v 1.32 2004/11/04 12:00:07 paulus Exp $"
78
79 #ifdef CHAPMS
80
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>
88
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"
96
97 static const char rcsid[] = RCSID;
98
99
100 static void     ascii2unicode __P((char[], int, u_char[]));
101 static void     NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
102 static void     ChallengeResponse __P((u_char *, u_char *, u_char[24]));
103 static void     ChapMS_NT __P((u_char *, char *, int, u_char[24]));
104 static void     ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
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, MS_ChapResponse *));
111 #endif
112
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
117
118 #ifdef MSLANMAN
119 bool    ms_lanman = 0;          /* Use LanMan password instead of NT */
120                                 /* Has meaning only with MS-CHAP challenges */
121 #endif
122
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? */
127
128 /* For MPPE debug */
129 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
130 static char *mschap_challenge = NULL;
131 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
132 static char *mschap2_peer_challenge = NULL;
133
134 #include "fsm.h"                /* Need to poke MPPE options */
135 #include "ccp.h"
136 #include <net/ppp-comp.h>
137 #endif
138
139 /*
140  * Command-line options.
141  */
142 static option_t chapms_option_list[] = {
143 #ifdef MSLANMAN
144         { "ms-lanman", o_bool, &ms_lanman,
145           "Use LanMan passwd when using MS-CHAP", 1 },
146 #endif
147 #ifdef DEBUGMPPEKEY
148         { "mschap-challenge", o_string, &mschap_challenge,
149           "specify CHAP challenge" },
150         { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
151           "specify CHAP peer challenge" },
152 #endif
153         { NULL }
154 };
155
156 /*
157  * chapms_generate_challenge - generate a challenge for MS-CHAP.
158  * For MS-CHAP the challenge length is fixed at 8 bytes.
159  * The length goes in challenge[0] and the actual challenge starts
160  * at challenge[1].
161  */
162 static void
163 chapms_generate_challenge(unsigned char *challenge)
164 {
165         *challenge++ = 8;
166 #ifdef DEBUGMPPEKEY
167         if (mschap_challenge && strlen(mschap_challenge) == 8)
168                 memcpy(challenge, mschap_challenge, 8);
169         else
170 #endif
171                 random_bytes(challenge, 8);
172 }
173
174 static void
175 chapms2_generate_challenge(unsigned char *challenge)
176 {
177         *challenge++ = 16;
178 #ifdef DEBUGMPPEKEY
179         if (mschap_challenge && strlen(mschap_challenge) == 16)
180                 memcpy(challenge, mschap_challenge, 16);
181         else
182 #endif
183                 random_bytes(challenge, 16);
184 }
185
186 static int
187 chapms_verify_response(int id, char *name,
188                        unsigned char *secret, int secret_len,
189                        unsigned char *challenge, unsigned char *response,
190                        char *message, int message_space)
191 {
192         MS_ChapResponse *rmd;
193         MS_ChapResponse md;
194         int diff;
195         int challenge_len, response_len;
196
197         challenge_len = *challenge++;   /* skip length, is 8 */
198         response_len = *response++;
199         if (response_len != MS_CHAP_RESPONSE_LEN)
200                 goto bad;
201
202         rmd = (MS_ChapResponse *) response;
203
204 #ifndef MSLANMAN
205         if (!rmd->UseNT[0]) {
206                 /* Should really propagate this into the error packet. */
207                 notice("Peer request for LANMAN auth not supported");
208                 goto bad;
209         }
210 #endif
211
212         /* Generate the expected response. */
213         ChapMS(challenge, (char *)secret, secret_len, &md);
214
215 #ifdef MSLANMAN
216         /* Determine which part of response to verify against */
217         if (!rmd->UseNT[0])
218                 diff = memcmp(&rmd->LANManResp, &md.LANManResp,
219                               sizeof(md.LANManResp));
220         else
221 #endif
222                 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
223
224         if (diff == 0) {
225                 slprintf(message, message_space, "Access granted");
226                 return 1;
227         }
228
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;
234 }
235
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)
241 {
242         MS_Chap2Response *rmd;
243         MS_Chap2Response md;
244         char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
245         int challenge_len, response_len;
246
247         challenge_len = *challenge++;   /* skip length, is 16 */
248         response_len = *response++;
249         if (response_len != MS_CHAP2_RESPONSE_LEN)
250                 goto bad;       /* not even the right length */
251
252         rmd = (MS_Chap2Response *) response;
253
254         /* Generate the expected response and our mutual auth. */
255         ChapMS2(challenge, rmd->PeerChallenge, name,
256                 (char *)secret, secret_len, &md,
257                 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
258
259         /* compare MDs and send the appropriate status */
260         /*
261          * Per RFC 2759, success message must be formatted as
262          *     "S=<auth_string> M=<message>"
263          * where
264          *     <auth_string> is the Authenticator Response (mutual auth)
265          *     <message> is a text message
266          *
267          * However, some versions of Windows (win98 tested) do not know
268          * about the M=<message> part (required per RFC 2759) and flag
269          * it as an error (reported incorrectly as an encryption error
270          * to the user).  Since the RFC requires it, and it can be
271          * useful information, we supply it if the peer is a conforming
272          * system.  Luckily (?), win98 sets the Flags field to 0x04
273          * (contrary to RFC requirements) so we can use that to
274          * distinguish between conforming and non-conforming systems.
275          *
276          * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
277          * help debugging this.
278          */
279         if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
280                 if (rmd->Flags[0])
281                         slprintf(message, message_space, "S=%s", saresponse);
282                 else
283                         slprintf(message, message_space, "S=%s M=%s",
284                                  saresponse, "Access granted");
285                 return 1;
286         }
287
288  bad:
289         /*
290          * Failure message must be formatted as
291          *     "E=e R=r C=c V=v M=m"
292          * where
293          *     e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
294          *     r = retry (we use 1, ok to retry)
295          *     c = challenge to use for next response, we reuse previous
296          *     v = Change Password version supported, we use 0
297          *     m = text message
298          *
299          * The M=m part is only for MS-CHAPv2.  Neither win2k nor
300          * win98 (others untested) display the message to the user anyway.
301          * They also both ignore the E=e code.
302          *
303          * Note that it's safe to reuse the same challenge as we don't
304          * actually accept another response based on the error message
305          * (and no clients try to resend a response anyway).
306          *
307          * Basically, this whole bit is useless code, even the small
308          * implementation here is only because of overspecification.
309          */
310         slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
311                  challenge_len, challenge, "Access denied");
312         return 0;
313 }
314
315 static void
316 chapms_make_response(unsigned char *response, int id, char *our_name,
317                      unsigned char *challenge, char *secret, int secret_len,
318                      unsigned char *private)
319 {
320         challenge++;    /* skip length, should be 8 */
321         *response++ = MS_CHAP_RESPONSE_LEN;
322         ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
323 }
324
325 static void
326 chapms2_make_response(unsigned char *response, int id, char *our_name,
327                       unsigned char *challenge, char *secret, int secret_len,
328                       unsigned char *private)
329 {
330         challenge++;    /* skip length, should be 16 */
331         *response++ = MS_CHAP2_RESPONSE_LEN;
332         ChapMS2(challenge,
333 #ifdef DEBUGMPPEKEY
334                 mschap2_peer_challenge,
335 #else
336                 NULL,
337 #endif
338                 our_name, secret, secret_len,
339                 (MS_Chap2Response *) response, private,
340                 MS_CHAP2_AUTHENTICATEE);
341 }
342
343 static int
344 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
345 {
346         if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
347             strncmp((char *)msg, "S=", 2) != 0) {
348                 /* Packet does not start with "S=" */
349                 error("MS-CHAPv2 Success packet is badly formed.");
350                 return 0;
351         }
352         msg += 2;
353         len -= 2;
354         if (len < MS_AUTH_RESPONSE_LENGTH
355             || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
356                 /* Authenticator Response did not match expected. */
357                 error("MS-CHAPv2 mutual authentication failed.");
358                 return 0;
359         }
360         /* Authenticator Response matches. */
361         msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
362         len -= MS_AUTH_RESPONSE_LENGTH;
363         if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
364                 msg += 3; /* Eat the delimiter */
365         } else if (len) {
366                 /* Packet has extra text which does not begin " M=" */
367                 error("MS-CHAPv2 Success packet is badly formed.");
368                 return 0;
369         }
370         return 1;
371 }
372
373 static void
374 chapms_handle_failure(unsigned char *inp, int len)
375 {
376         int err;
377         char *p, *msg;
378
379         /* We want a null-terminated string for strxxx(). */
380         msg = malloc(len + 1);
381         if (!msg) {
382                 notice("Out of memory in chapms_handle_failure");
383                 return;
384         }
385         BCOPY(inp, msg, len);
386         msg[len] = 0;
387         p = msg;
388
389         /*
390          * Deal with MS-CHAP formatted failure messages; just print the
391          * M=<message> part (if any).  For MS-CHAP we're not really supposed
392          * to use M=<message>, but it shouldn't hurt.  See
393          * chapms[2]_verify_response.
394          */
395         if (!strncmp(p, "E=", 2))
396                 err = strtol(p, NULL, 10); /* Remember the error code. */
397         else
398                 goto print_msg; /* Message is badly formatted. */
399
400         if (len && ((p = strstr(p, " M=")) != NULL)) {
401                 /* M=<message> field found. */
402                 p += 3;
403         } else {
404                 /* No M=<message>; use the error code. */
405                 switch (err) {
406                 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
407                         p = "E=646 Restricted logon hours";
408                         break;
409
410                 case MS_CHAP_ERROR_ACCT_DISABLED:
411                         p = "E=647 Account disabled";
412                         break;
413
414                 case MS_CHAP_ERROR_PASSWD_EXPIRED:
415                         p = "E=648 Password expired";
416                         break;
417
418                 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
419                         p = "E=649 No dialin permission";
420                         break;
421
422                 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
423                         p = "E=691 Authentication failure";
424                         break;
425
426                 case MS_CHAP_ERROR_CHANGING_PASSWORD:
427                         /* Should never see this, we don't support Change Password. */
428                         p = "E=709 Error changing password";
429                         break;
430
431                 default:
432                         free(msg);
433                         error("Unknown MS-CHAP authentication failure: %.*v",
434                               len, inp);
435                         return;
436                 }
437         }
438 print_msg:
439         if (p != NULL)
440                 error("MS-CHAP authentication failed: %v", p);
441         free(msg);
442 }
443
444 static void
445 ChallengeResponse(u_char *challenge,
446                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
447                   u_char response[24])
448 {
449     u_char    ZPasswordHash[21];
450
451     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
452     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
453
454 #if 0
455     dbglog("ChallengeResponse - ZPasswordHash %.*B",
456            sizeof(ZPasswordHash), ZPasswordHash);
457 #endif
458
459     (void) DesSetkey(ZPasswordHash + 0);
460     DesEncrypt(challenge, response + 0);
461     (void) DesSetkey(ZPasswordHash + 7);
462     DesEncrypt(challenge, response + 8);
463     (void) DesSetkey(ZPasswordHash + 14);
464     DesEncrypt(challenge, response + 16);
465
466 #if 0
467     dbglog("ChallengeResponse - response %.24B", response);
468 #endif
469 }
470
471 void
472 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
473               char *username, u_char Challenge[8])
474     
475 {
476     SHA1_CTX    sha1Context;
477     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
478     char        *user;
479
480     /* remove domain from "domain\username" */
481     if ((user = strrchr(username, '\\')) != NULL)
482         ++user;
483     else
484         user = username;
485
486     SHA1_Init(&sha1Context);
487     SHA1_Update(&sha1Context, PeerChallenge, 16);
488     SHA1_Update(&sha1Context, rchallenge, 16);
489     SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
490     SHA1_Final(sha1Hash, &sha1Context);
491
492     BCOPY(sha1Hash, Challenge, 8);
493 }
494
495 /*
496  * Convert the ASCII version of the password to Unicode.
497  * This implicitly supports 8-bit ISO8859/1 characters.
498  * This gives us the little-endian representation, which
499  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
500  * is machine-dependent.)
501  */
502 static void
503 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
504 {
505     int i;
506
507     BZERO(unicode, ascii_len * 2);
508     for (i = 0; i < ascii_len; i++)
509         unicode[i * 2] = (u_char) ascii[i];
510 }
511
512 static void
513 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
514 {
515 #ifdef __NetBSD__
516     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
517     int                 mdlen = secret_len;
518 #else
519     int                 mdlen = secret_len * 8;
520 #endif
521     MD4_CTX             md4Context;
522
523     MD4Init(&md4Context);
524     MD4Update(&md4Context, (unsigned char *)secret, mdlen);
525     MD4Final(hash, &md4Context);
526
527 }
528
529 static void
530 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
531           u_char NTResponse[24])
532 {
533     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
534     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
535
536     /* Hash the Unicode version of the secret (== password). */
537     ascii2unicode(secret, secret_len, unicodePassword);
538     NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
539
540     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
541 }
542
543 static void
544 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
545            char *secret, int secret_len, u_char NTResponse[24])
546 {
547     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
548     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
549     u_char      Challenge[8];
550
551     ChallengeHash(PeerChallenge, (unsigned char *)rchallenge, username,
552                   Challenge);
553
554     /* Hash the Unicode version of the secret (== password). */
555     ascii2unicode(secret, secret_len, unicodePassword);
556     NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
557
558     ChallengeResponse(Challenge, PasswordHash, NTResponse);
559 }
560
561 #ifdef MSLANMAN
562 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
563
564 static void
565 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
566               MS_ChapResponse *response)
567 {
568     int                 i;
569     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
570     u_char              PasswordHash[MD4_SIGNATURE_SIZE];
571
572     /* LANMan password is case insensitive */
573     BZERO(UcasePassword, sizeof(UcasePassword));
574     for (i = 0; i < secret_len; i++)
575        UcasePassword[i] = (u_char)toupper(secret[i]);
576     (void) DesSetkey(UcasePassword + 0);
577     DesEncrypt( StdText, PasswordHash + 0 );
578     (void) DesSetkey(UcasePassword + 7);
579     DesEncrypt( StdText, PasswordHash + 8 );
580     ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
581 }
582 #endif
583
584
585 void
586 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
587                               u_char NTResponse[24], u_char PeerChallenge[16],
588                               u_char *rchallenge, char *username,
589                               u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
590 {
591     /*
592      * "Magic" constants used in response generation, from RFC 2759.
593      */
594     u_char Magic1[39] = /* "Magic server to client signing constant" */
595         { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
596           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
597           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
598           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
599     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
600         { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
601           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
602           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
603           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
604           0x6E };
605
606     int         i;
607     SHA1_CTX    sha1Context;
608     u_char      Digest[SHA1_SIGNATURE_SIZE];
609     u_char      Challenge[8];
610
611     SHA1_Init(&sha1Context);
612     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
613     SHA1_Update(&sha1Context, NTResponse, 24);
614     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
615     SHA1_Final(Digest, &sha1Context);
616
617     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
618
619     SHA1_Init(&sha1Context);
620     SHA1_Update(&sha1Context, Digest, sizeof(Digest));
621     SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
622     SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
623     SHA1_Final(Digest, &sha1Context);
624
625     /* Convert to ASCII hex string. */
626     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
627         sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
628 }
629
630
631 static void
632 GenerateAuthenticatorResponsePlain
633                 (char *secret, int secret_len,
634                  u_char NTResponse[24], u_char PeerChallenge[16],
635                  u_char *rchallenge, char *username,
636                  u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
637 {
638     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
639     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
640     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
641
642     /* Hash (x2) the Unicode version of the secret (== password). */
643     ascii2unicode(secret, secret_len, unicodePassword);
644     NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
645     NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
646                    PasswordHashHash);
647
648     GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
649                                   rchallenge, username, authResponse);
650 }
651
652
653 #ifdef MPPE
654 /*
655  * Set mppe_xxxx_key from the NTPasswordHashHash.
656  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
657  */
658 void
659 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
660 {
661     SHA1_CTX    sha1Context;
662     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
663
664     SHA1_Init(&sha1Context);
665     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
666     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
667     SHA1_Update(&sha1Context, rchallenge, 8);
668     SHA1_Final(Digest, &sha1Context);
669
670     /* Same key in both directions. */
671     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
672     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
673
674     mppe_keys_set = 1;
675 }
676
677 /*
678  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
679  */
680 static void
681 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
682 {
683     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
684     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
685     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
686
687     /* Hash (x2) the Unicode version of the secret (== password). */
688     ascii2unicode(secret, secret_len, unicodePassword);
689     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
690     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
691
692     mppe_set_keys(rchallenge, PasswordHashHash);
693 }
694
695 /*
696  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
697  *
698  * This helper function used in the Winbind module, which gets the
699  * NTHashHash from the server.
700  */
701 void
702 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
703                u_char NTResponse[24], int IsServer)
704 {
705     SHA1_CTX    sha1Context;
706     u_char      MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
707     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
708
709     u_char SHApad1[40] =
710         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
714     u_char SHApad2[40] =
715         { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
716           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
717           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
718           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
719
720     /* "This is the MPPE Master Key" */
721     u_char Magic1[27] =
722         { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
723           0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
724           0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
725     /* "On the client side, this is the send key; "
726        "on the server side, it is the receive key." */
727     u_char Magic2[84] =
728         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
729           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
730           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
731           0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
732           0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
733           0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
734           0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
735           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
736           0x6b, 0x65, 0x79, 0x2e };
737     /* "On the client side, this is the receive key; "
738        "on the server side, it is the send key." */
739     u_char Magic3[84] =
740         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
741           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
742           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
743           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
744           0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
745           0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
746           0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
747           0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
748           0x6b, 0x65, 0x79, 0x2e };
749     u_char *s;
750
751     SHA1_Init(&sha1Context);
752     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
753     SHA1_Update(&sha1Context, NTResponse, 24);
754     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
755     SHA1_Final(MasterKey, &sha1Context);
756
757     /*
758      * generate send key
759      */
760     if (IsServer)
761         s = Magic3;
762     else
763         s = Magic2;
764     SHA1_Init(&sha1Context);
765     SHA1_Update(&sha1Context, MasterKey, 16);
766     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
767     SHA1_Update(&sha1Context, s, 84);
768     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
769     SHA1_Final(Digest, &sha1Context);
770
771     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
772
773     /*
774      * generate recv key
775      */
776     if (IsServer)
777         s = Magic2;
778     else
779         s = Magic3;
780     SHA1_Init(&sha1Context);
781     SHA1_Update(&sha1Context, MasterKey, 16);
782     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
783     SHA1_Update(&sha1Context, s, 84);
784     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
785     SHA1_Final(Digest, &sha1Context);
786
787     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
788
789     mppe_keys_set = 1;
790 }
791
792 /*
793  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
794  */
795 static void
796 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
797 {
798     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
799     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
800     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
801     /* Hash (x2) the Unicode version of the secret (== password). */
802     ascii2unicode(secret, secret_len, unicodePassword);
803     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
804     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
805     mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
806 }
807
808 #endif /* MPPE */
809
810
811 void
812 ChapMS(u_char *rchallenge, char *secret, int secret_len,
813        MS_ChapResponse *response)
814 {
815     BZERO(response, sizeof(*response));
816
817     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
818
819 #ifdef MSLANMAN
820     ChapMS_LANMan(rchallenge, secret, secret_len, response);
821
822     /* preferred method is set by option  */
823     response->UseNT[0] = !ms_lanman;
824 #else
825     response->UseNT[0] = 1;
826 #endif
827
828 #ifdef MPPE
829     Set_Start_Key(rchallenge, secret, secret_len);
830 #endif
831 }
832
833
834 /*
835  * If PeerChallenge is NULL, one is generated and response->PeerChallenge
836  * is filled in.  Call this way when generating a response.
837  * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
838  * Call this way when verifying a response (or debugging).
839  * Do not call with PeerChallenge = response->PeerChallenge.
840  *
841  * response->PeerChallenge is then used for calculation of the
842  * Authenticator Response.
843  */
844 void
845 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
846         char *user, char *secret, int secret_len, MS_Chap2Response *response,
847         u_char authResponse[], int authenticator)
848 {
849     /* ARGSUSED */
850     u_char *p = response->PeerChallenge;
851     int i;
852
853     BZERO(response, sizeof(*response));
854
855     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
856     if (!PeerChallenge)
857         for (i = 0; i < sizeof(response->PeerChallenge); i++)
858             *p++ = (u_char) (drand48() * 0xff);
859     else
860         BCOPY(PeerChallenge, response->PeerChallenge,
861               sizeof(response->PeerChallenge));
862
863     /* Generate the NT-Response */
864     ChapMS2_NT((char *)rchallenge, response->PeerChallenge, user,
865                secret, secret_len, response->NTResp);
866
867     /* Generate the Authenticator Response. */
868     GenerateAuthenticatorResponsePlain(secret, secret_len, response->NTResp,
869                                        response->PeerChallenge, rchallenge,
870                                        user, authResponse);
871
872 #ifdef MPPE
873     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
874 #endif
875 }
876
877 #ifdef MPPE
878 /*
879  * Set MPPE options from plugins.
880  */
881 void
882 set_mppe_enc_types(int policy, int types)
883 {
884     /* Early exit for unknown policies. */
885     if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
886         policy != MPPE_ENC_POL_ENC_REQUIRED)
887         return;
888
889     /* Don't modify MPPE if it's optional and wasn't already configured. */
890     if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
891         return;
892
893     /*
894      * Disable undesirable encryption types.  Note that we don't ENABLE
895      * any encryption types, to avoid overriding manual configuration.
896      */
897     switch(types) {
898         case MPPE_ENC_TYPES_RC4_40:
899             ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;   /* disable 128-bit */
900             break;
901         case MPPE_ENC_TYPES_RC4_128:
902             ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;    /* disable 40-bit */
903             break;
904         default:
905             break;
906     }
907 }
908 #endif /* MPPE */
909
910 static struct chap_digest_type chapms_digest = {
911         CHAP_MICROSOFT,         /* code */
912         chapms_generate_challenge,
913         chapms_verify_response,
914         chapms_make_response,
915         NULL,                   /* check_success */
916         chapms_handle_failure,
917 };
918
919 static struct chap_digest_type chapms2_digest = {
920         CHAP_MICROSOFT_V2,      /* code */
921         chapms2_generate_challenge,
922         chapms2_verify_response,
923         chapms2_make_response,
924         chapms2_check_success,
925         chapms_handle_failure,
926 };
927
928 void
929 chapms_init(void)
930 {
931         chap_register_digest(&chapms_digest);
932         chap_register_digest(&chapms2_digest);
933         add_options(chapms_option_list);
934 }
935
936 #endif /* CHAPMS */