]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
Fixed uninitialized 'pw' variable in HAS_SHADOW logic in session.c due
[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.38 2007/12/01 20:10:51 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     ascii2unicode __P((char[], int, u_char[]));
101 static void     NTPasswordHash __P((u_char *, int, u_char[MD4_SIGNATURE_SIZE]));
102 static void     ChallengeResponse __P((u_char *, u_char *, u_char[24]));
103 static void     ChapMS_NT __P((u_char *, char *, int, u_char[24]));
104 static void     ChapMS2_NT __P((u_char *, u_char[16], char *, char *, int,
105                                 u_char[24]));
106 static void     GenerateAuthenticatorResponsePlain
107                         __P((char*, int, u_char[24], u_char[16], u_char *,
108                              char *, u_char[41]));
109 #ifdef MSLANMAN
110 static void     ChapMS_LANMan __P((u_char *, char *, int, u_char *));
111 #endif
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         unsigned char md[MS_CHAP_RESPONSE_LEN];
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 #ifndef MSLANMAN
204         if (!response[MS_CHAP_USENT]) {
205                 /* Should really propagate this into the error packet. */
206                 notice("Peer request for LANMAN auth not supported");
207                 goto bad;
208         }
209 #endif
210
211         /* Generate the expected response. */
212         ChapMS(challenge, (char *)secret, secret_len, md);
213
214 #ifdef MSLANMAN
215         /* Determine which part of response to verify against */
216         if (!response[MS_CHAP_USENT])
217                 diff = memcmp(&response[MS_CHAP_LANMANRESP],
218                               &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
219         else
220 #endif
221                 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
222                               MS_CHAP_NTRESP_LEN);
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         unsigned char md[MS_CHAP2_RESPONSE_LEN];
243         char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
244         int challenge_len, response_len;
245
246         challenge_len = *challenge++;   /* skip length, is 16 */
247         response_len = *response++;
248         if (response_len != MS_CHAP2_RESPONSE_LEN)
249                 goto bad;       /* not even the right length */
250
251         /* Generate the expected response and our mutual auth. */
252         ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,
253                 (char *)secret, secret_len, md,
254                 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
255
256         /* compare MDs and send the appropriate status */
257         /*
258          * Per RFC 2759, success message must be formatted as
259          *     "S=<auth_string> M=<message>"
260          * where
261          *     <auth_string> is the Authenticator Response (mutual auth)
262          *     <message> is a text message
263          *
264          * However, some versions of Windows (win98 tested) do not know
265          * about the M=<message> part (required per RFC 2759) and flag
266          * it as an error (reported incorrectly as an encryption error
267          * to the user).  Since the RFC requires it, and it can be
268          * useful information, we supply it if the peer is a conforming
269          * system.  Luckily (?), win98 sets the Flags field to 0x04
270          * (contrary to RFC requirements) so we can use that to
271          * distinguish between conforming and non-conforming systems.
272          *
273          * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
274          * help debugging this.
275          */
276         if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
277                    MS_CHAP2_NTRESP_LEN) == 0) {
278                 if (response[MS_CHAP2_FLAGS])
279                         slprintf(message, message_space, "S=%s", saresponse);
280                 else
281                         slprintf(message, message_space, "S=%s M=%s",
282                                  saresponse, "Access granted");
283                 return 1;
284         }
285
286  bad:
287         /*
288          * Failure message must be formatted as
289          *     "E=e R=r C=c V=v M=m"
290          * where
291          *     e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
292          *     r = retry (we use 1, ok to retry)
293          *     c = challenge to use for next response, we reuse previous
294          *     v = Change Password version supported, we use 0
295          *     m = text message
296          *
297          * The M=m part is only for MS-CHAPv2.  Neither win2k nor
298          * win98 (others untested) display the message to the user anyway.
299          * They also both ignore the E=e code.
300          *
301          * Note that it's safe to reuse the same challenge as we don't
302          * actually accept another response based on the error message
303          * (and no clients try to resend a response anyway).
304          *
305          * Basically, this whole bit is useless code, even the small
306          * implementation here is only because of overspecification.
307          */
308         slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
309                  challenge_len, challenge, "Access denied");
310         return 0;
311 }
312
313 static void
314 chapms_make_response(unsigned char *response, int id, char *our_name,
315                      unsigned char *challenge, char *secret, int secret_len,
316                      unsigned char *private)
317 {
318         challenge++;    /* skip length, should be 8 */
319         *response++ = MS_CHAP_RESPONSE_LEN;
320         ChapMS(challenge, secret, secret_len, response);
321 }
322
323 static void
324 chapms2_make_response(unsigned char *response, int id, char *our_name,
325                       unsigned char *challenge, char *secret, int secret_len,
326                       unsigned char *private)
327 {
328         challenge++;    /* skip length, should be 16 */
329         *response++ = MS_CHAP2_RESPONSE_LEN;
330         ChapMS2(challenge,
331 #ifdef DEBUGMPPEKEY
332                 mschap2_peer_challenge,
333 #else
334                 NULL,
335 #endif
336                 our_name, secret, secret_len, response, private,
337                 MS_CHAP2_AUTHENTICATEE);
338 }
339
340 static int
341 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
342 {
343         if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
344             strncmp((char *)msg, "S=", 2) != 0) {
345                 /* Packet does not start with "S=" */
346                 error("MS-CHAPv2 Success packet is badly formed.");
347                 return 0;
348         }
349         msg += 2;
350         len -= 2;
351         if (len < MS_AUTH_RESPONSE_LENGTH
352             || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
353                 /* Authenticator Response did not match expected. */
354                 error("MS-CHAPv2 mutual authentication failed.");
355                 return 0;
356         }
357         /* Authenticator Response matches. */
358         msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
359         len -= MS_AUTH_RESPONSE_LENGTH;
360         if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
361                 msg += 3; /* Eat the delimiter */
362         } else if (len) {
363                 /* Packet has extra text which does not begin " M=" */
364                 error("MS-CHAPv2 Success packet is badly formed.");
365                 return 0;
366         }
367         return 1;
368 }
369
370 static void
371 chapms_handle_failure(unsigned char *inp, int len)
372 {
373         int err;
374         char *p, *msg;
375
376         /* We want a null-terminated string for strxxx(). */
377         msg = malloc(len + 1);
378         if (!msg) {
379                 notice("Out of memory in chapms_handle_failure");
380                 return;
381         }
382         BCOPY(inp, msg, len);
383         msg[len] = 0;
384         p = msg;
385
386         /*
387          * Deal with MS-CHAP formatted failure messages; just print the
388          * M=<message> part (if any).  For MS-CHAP we're not really supposed
389          * to use M=<message>, but it shouldn't hurt.  See
390          * chapms[2]_verify_response.
391          */
392         if (!strncmp(p, "E=", 2))
393                 err = strtol(p+2, NULL, 10); /* Remember the error code. */
394         else
395                 goto print_msg; /* Message is badly formatted. */
396
397         if (len && ((p = strstr(p, " M=")) != NULL)) {
398                 /* M=<message> field found. */
399                 p += 3;
400         } else {
401                 /* No M=<message>; use the error code. */
402                 switch (err) {
403                 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
404                         p = "E=646 Restricted logon hours";
405                         break;
406
407                 case MS_CHAP_ERROR_ACCT_DISABLED:
408                         p = "E=647 Account disabled";
409                         break;
410
411                 case MS_CHAP_ERROR_PASSWD_EXPIRED:
412                         p = "E=648 Password expired";
413                         break;
414
415                 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
416                         p = "E=649 No dialin permission";
417                         break;
418
419                 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
420                         p = "E=691 Authentication failure";
421                         break;
422
423                 case MS_CHAP_ERROR_CHANGING_PASSWORD:
424                         /* Should never see this, we don't support Change Password. */
425                         p = "E=709 Error changing password";
426                         break;
427
428                 default:
429                         free(msg);
430                         error("Unknown MS-CHAP authentication failure: %.*v",
431                               len, inp);
432                         return;
433                 }
434         }
435 print_msg:
436         if (p != NULL)
437                 error("MS-CHAP authentication failed: %v", p);
438         free(msg);
439 }
440
441 static void
442 ChallengeResponse(u_char *challenge,
443                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
444                   u_char response[24])
445 {
446     u_char    ZPasswordHash[21];
447
448     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
449     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
450
451 #if 0
452     dbglog("ChallengeResponse - ZPasswordHash %.*B",
453            sizeof(ZPasswordHash), ZPasswordHash);
454 #endif
455
456     (void) DesSetkey(ZPasswordHash + 0);
457     DesEncrypt(challenge, response + 0);
458     (void) DesSetkey(ZPasswordHash + 7);
459     DesEncrypt(challenge, response + 8);
460     (void) DesSetkey(ZPasswordHash + 14);
461     DesEncrypt(challenge, response + 16);
462
463 #if 0
464     dbglog("ChallengeResponse - response %.24B", response);
465 #endif
466 }
467
468 void
469 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
470               char *username, u_char Challenge[8])
471     
472 {
473     SHA1_CTX    sha1Context;
474     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
475     char        *user;
476
477     /* remove domain from "domain\username" */
478     if ((user = strrchr(username, '\\')) != NULL)
479         ++user;
480     else
481         user = username;
482
483     SHA1_Init(&sha1Context);
484     SHA1_Update(&sha1Context, PeerChallenge, 16);
485     SHA1_Update(&sha1Context, rchallenge, 16);
486     SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
487     SHA1_Final(sha1Hash, &sha1Context);
488
489     BCOPY(sha1Hash, Challenge, 8);
490 }
491
492 /*
493  * Convert the ASCII version of the password to Unicode.
494  * This implicitly supports 8-bit ISO8859/1 characters.
495  * This gives us the little-endian representation, which
496  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
497  * is machine-dependent.)
498  */
499 static void
500 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
501 {
502     int i;
503
504     BZERO(unicode, ascii_len * 2);
505     for (i = 0; i < ascii_len; i++)
506         unicode[i * 2] = (u_char) ascii[i];
507 }
508
509 static void
510 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
511 {
512 #ifdef __NetBSD__
513     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
514     int                 mdlen = secret_len;
515 #else
516     int                 mdlen = secret_len * 8;
517 #endif
518     MD4_CTX             md4Context;
519
520     MD4Init(&md4Context);
521     /* MD4Update can take at most 64 bytes at a time */
522     while (mdlen > 512) {
523         MD4Update(&md4Context, secret, 512);
524         secret += 64;
525         mdlen -= 512;
526     }
527     MD4Update(&md4Context, secret, mdlen);
528     MD4Final(hash, &md4Context);
529
530 }
531
532 static void
533 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
534           u_char NTResponse[24])
535 {
536     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
537     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
538
539     /* Hash the Unicode version of the secret (== password). */
540     ascii2unicode(secret, secret_len, unicodePassword);
541     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
542
543     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
544 }
545
546 static void
547 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
548            char *secret, int secret_len, u_char NTResponse[24])
549 {
550     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
551     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
552     u_char      Challenge[8];
553
554     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
555
556     /* Hash the Unicode version of the secret (== password). */
557     ascii2unicode(secret, secret_len, unicodePassword);
558     NTPasswordHash(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               unsigned char *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[MS_CHAP_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(unicodePassword, secret_len * 2, PasswordHash);
647     NTPasswordHash(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        unsigned char *response)
816 {
817     BZERO(response, MS_CHAP_RESPONSE_LEN);
818
819     ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
820
821 #ifdef MSLANMAN
822     ChapMS_LANMan(rchallenge, secret, secret_len,
823                   &response[MS_CHAP_LANMANRESP]);
824
825     /* preferred method is set by option  */
826     response[MS_CHAP_USENT] = !ms_lanman;
827 #else
828     response[MS_CHAP_USENT] = 1;
829 #endif
830
831 #ifdef MPPE
832     Set_Start_Key(rchallenge, secret, secret_len);
833 #endif
834 }
835
836
837 /*
838  * If PeerChallenge is NULL, one is generated and the PeerChallenge
839  * field of response is filled in.  Call this way when generating a response.
840  * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
841  * Call this way when verifying a response (or debugging).
842  * Do not call with PeerChallenge = response.
843  *
844  * The PeerChallenge field of response is then used for calculation of the
845  * Authenticator Response.
846  */
847 void
848 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
849         char *user, char *secret, int secret_len, unsigned char *response,
850         u_char authResponse[], int authenticator)
851 {
852     /* ARGSUSED */
853     u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
854     int i;
855
856     BZERO(response, MS_CHAP2_RESPONSE_LEN);
857
858     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
859     if (!PeerChallenge)
860         for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
861             *p++ = (u_char) (drand48() * 0xff);
862     else
863         BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
864               MS_CHAP2_PEER_CHAL_LEN);
865
866     /* Generate the NT-Response */
867     ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
868                secret, secret_len, &response[MS_CHAP2_NTRESP]);
869
870     /* Generate the Authenticator Response. */
871     GenerateAuthenticatorResponsePlain(secret, secret_len,
872                                        &response[MS_CHAP2_NTRESP],
873                                        &response[MS_CHAP2_PEER_CHALLENGE],
874                                        rchallenge, user, authResponse);
875
876 #ifdef MPPE
877     SetMasterKeys(secret, secret_len,
878                   &response[MS_CHAP2_NTRESP], authenticator);
879 #endif
880 }
881
882 #ifdef MPPE
883 /*
884  * Set MPPE options from plugins.
885  */
886 void
887 set_mppe_enc_types(int policy, int types)
888 {
889     /* Early exit for unknown policies. */
890     if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
891         policy != MPPE_ENC_POL_ENC_REQUIRED)
892         return;
893
894     /* Don't modify MPPE if it's optional and wasn't already configured. */
895     if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
896         return;
897
898     /*
899      * Disable undesirable encryption types.  Note that we don't ENABLE
900      * any encryption types, to avoid overriding manual configuration.
901      */
902     switch(types) {
903         case MPPE_ENC_TYPES_RC4_40:
904             ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;   /* disable 128-bit */
905             break;
906         case MPPE_ENC_TYPES_RC4_128:
907             ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;    /* disable 40-bit */
908             break;
909         default:
910             break;
911     }
912 }
913 #endif /* MPPE */
914
915 static struct chap_digest_type chapms_digest = {
916         CHAP_MICROSOFT,         /* code */
917         chapms_generate_challenge,
918         chapms_verify_response,
919         chapms_make_response,
920         NULL,                   /* check_success */
921         chapms_handle_failure,
922 };
923
924 static struct chap_digest_type chapms2_digest = {
925         CHAP_MICROSOFT_V2,      /* code */
926         chapms2_generate_challenge,
927         chapms2_verify_response,
928         chapms2_make_response,
929         chapms2_check_success,
930         chapms_handle_failure,
931 };
932
933 void
934 chapms_init(void)
935 {
936         chap_register_digest(&chapms_digest);
937         chap_register_digest(&chapms2_digest);
938         add_options(chapms_option_list);
939 }
940
941 #endif /* CHAPMS */