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