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