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