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