]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
Patches from Frank Cusack.
[ppp.git] / pppd / chap_ms.c
1 /*
2  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3  *
4  * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
5  * http://www.strataware.com/
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that the above copyright notice and this paragraph are
11  * duplicated in all such forms and that any documentation,
12  * advertising materials, and other materials related to such
13  * distribution and use acknowledge that the software was developed
14  * by Eric Rosenquist.  The name of the author may not be used to
15  * endorse or promote products derived from this software without
16  * specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  */
22
23 /*
24  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
25  *
26  *   Implemented LANManager type password response to MS-CHAP challenges.
27  *   Now pppd provides both NT style and LANMan style blocks, and the
28  *   prefered is set by option "ms-lanman". Default is to use NT.
29  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
30  *
31  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
32  */
33
34 /*
35  * Modifications by Frank Cusack, frank@google.com, March 2002.
36  *
37  *   Implemented MS-CHAPv2 functionality, heavily based on sample
38  *   implementation in RFC 2759.  Implemented MPPE functionality,
39  *   heavily based on sample implementation in RFC 3079.
40  *   Copyright (c) 2002 Google, Inc.
41  */
42
43 #define RCSID   "$Id: chap_ms.c,v 1.21 2002/09/01 12:00:15 dfs Exp $"
44
45 #ifdef CHAPMS
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <sys/types.h>
52 #include <sys/time.h>
53 #include <unistd.h>
54 #ifdef HAVE_CRYPT_H
55 #include <crypt.h>
56 #endif
57
58 #include "pppd.h"
59 #include "chap.h"
60 #include "chap_ms.h"
61 #include "md4.h"
62 #include "sha1.h"
63
64 #ifndef USE_CRYPT
65 #include <des.h>
66 #endif
67
68 static const char rcsid[] = RCSID;
69
70
71 static void     ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
72 static void     ascii2unicode __P((char[], int, u_char[]));
73 static void     NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
74 static void     ChallengeResponse __P((u_char *, u_char *, u_char[24]));
75 static void     DesEncrypt __P((u_char *, u_char *, u_char[8]));
76 static void     MakeKey __P((u_char *, u_char *));
77 static u_char   Get7Bits __P((u_char *, int));
78 static void     ChapMS_NT __P((u_char *, char *, int, u_char[24]));
79 static void     ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
80                                 u_char[24]));
81 static void     GenerateAuthenticatorResponse __P((char*, int, u_char[24],
82                                                    u_char[16], u_char *,
83                                                    char *, u_char[41]));
84 #ifdef MSLANMAN
85 static void     ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
86 #endif
87
88 #ifdef USE_CRYPT
89 static void     Expand __P((u_char *, u_char *));
90 static void     Collapse __P((u_char *, u_char *));
91 #endif
92
93 #ifdef MPPE
94 static void     Set_Start_Key __P((u_char *, char *, int));
95 static void     SetMasterKeys __P((char *, int, u_char[24], int));
96 #endif
97
98 extern double drand48 __P((void));
99
100 #ifdef MSLANMAN
101 bool    ms_lanman = 0;          /* Use LanMan password instead of NT */
102                                 /* Has meaning only with MS-CHAP challenges */
103 #endif
104
105 #ifdef MPPE
106 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
107 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
108 #endif
109
110 static void
111 ChallengeResponse(u_char *challenge,
112                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
113                   u_char response[24])
114 {
115     char    ZPasswordHash[21];
116
117     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
118     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
119
120 #if 0
121     dbglog("ChallengeResponse - ZPasswordHash %.*B",
122            sizeof(ZPasswordHash), ZPasswordHash);
123 #endif
124
125     DesEncrypt(challenge, ZPasswordHash +  0, &response[0]);
126     DesEncrypt(challenge, ZPasswordHash +  7, &response[8]);
127     DesEncrypt(challenge, ZPasswordHash + 14, &response[16]);
128
129 #if 0
130     dbglog("ChallengeResponse - response %.24B", response);
131 #endif
132 }
133
134
135 #ifdef USE_CRYPT
136 static void
137 DesEncrypt(u_char *clear, u_char *key, u_char cipher[8])
138 {
139     u_char des_key[8];
140     u_char crypt_key[66];
141     u_char des_input[66];
142
143     MakeKey(key, des_key);
144
145     Expand(des_key, crypt_key);
146     setkey(crypt_key);
147
148 #if 0
149     CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
150 #endif
151
152     Expand(clear, des_input);
153     encrypt(des_input, 0);
154     Collapse(des_input, cipher);
155
156 #if 0
157     CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
158 #endif
159 }
160
161 #else /* USE_CRYPT */
162
163 static void
164 DesEncrypt(u_char *clear, u_char *key, u_char cipher[8])
165 {
166     des_cblock          des_key;
167     des_key_schedule    key_schedule;
168
169     MakeKey(key, des_key);
170
171     des_set_key(&des_key, key_schedule);
172
173 #if 0
174     CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
175 #endif
176
177     des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
178
179 #if 0
180     CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
181 #endif
182 }
183
184 #endif /* USE_CRYPT */
185
186
187 static u_char Get7Bits(u_char *input, int startBit)
188 {
189     register unsigned int       word;
190
191     word  = (unsigned)input[startBit / 8] << 8;
192     word |= (unsigned)input[startBit / 8 + 1];
193
194     word >>= 15 - (startBit % 8 + 7);
195
196     return word & 0xFE;
197 }
198
199 #ifdef USE_CRYPT
200
201 /* in == 8-byte string (expanded version of the 56-bit key)
202  * out == 64-byte string where each byte is either 1 or 0
203  * Note that the low-order "bit" is always ignored by by setkey()
204  */
205 static void Expand(u_char *in, u_char *out)
206 {
207         int j, c;
208         int i;
209
210         for(i = 0; i < 64; in++){
211                 c = *in;
212                 for(j = 7; j >= 0; j--)
213                         *out++ = (c >> j) & 01;
214                 i += 8;
215         }
216 }
217
218 /* The inverse of Expand
219  */
220 static void Collapse(u_char *in, u_char *out)
221 {
222         int j;
223         int i;
224         unsigned int c;
225
226         for (i = 0; i < 64; i += 8, out++) {
227             c = 0;
228             for (j = 7; j >= 0; j--, in++)
229                 c |= *in << j;
230             *out = c & 0xff;
231         }
232 }
233 #endif
234
235 static void MakeKey(u_char *key, u_char *des_key)
236 {
237     des_key[0] = Get7Bits(key,  0);
238     des_key[1] = Get7Bits(key,  7);
239     des_key[2] = Get7Bits(key, 14);
240     des_key[3] = Get7Bits(key, 21);
241     des_key[4] = Get7Bits(key, 28);
242     des_key[5] = Get7Bits(key, 35);
243     des_key[6] = Get7Bits(key, 42);
244     des_key[7] = Get7Bits(key, 49);
245
246 #ifndef USE_CRYPT
247     des_set_odd_parity((des_cblock *)des_key);
248 #endif
249
250 #if 0
251     CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
252     CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
253 #endif
254 }
255
256
257 static void
258 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
259               char *username, u_char Challenge[8])
260     
261 {
262     SHA1_CTX    sha1Context;
263     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
264     char        *user;
265
266     /* remove domain from "domain\username" */
267     if ((user = strrchr(username, '\\')) != NULL)
268         ++user;
269     else
270         user = username;
271
272     SHA1_Init(&sha1Context);
273     SHA1_Update(&sha1Context, PeerChallenge, 16);
274     SHA1_Update(&sha1Context, rchallenge, 16);
275     SHA1_Update(&sha1Context, user, strlen(user));
276     SHA1_Final(sha1Hash, &sha1Context);
277
278     BCOPY(sha1Hash, Challenge, 8);
279 }
280
281 /*
282  * Convert the ASCII version of the password to Unicode.
283  * This implicitly supports 8-bit ISO8859/1 characters.
284  * This gives us the little-endian representation, which
285  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
286  * is machine-dependent.)
287  */
288 static void
289 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
290 {
291     int i;
292
293     BZERO(unicode, ascii_len * 2);
294     for (i = 0; i < ascii_len; i++)
295         unicode[i * 2] = (u_char) ascii[i];
296 }
297
298 static void
299 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
300 {
301 #ifdef __NetBSD__
302     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
303     int                 mdlen = secret_len;
304 #else
305     int                 mdlen = secret_len * 8;
306 #endif
307     MD4_CTX             md4Context;
308
309     MD4Init(&md4Context);
310     MD4Update(&md4Context, secret, mdlen);
311     MD4Final(hash, &md4Context);
312
313 }
314
315 static void
316 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
317           u_char NTResponse[24])
318 {
319     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
320     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
321
322     /* Hash the Unicode version of the secret (== password). */
323     ascii2unicode(secret, secret_len, unicodePassword);
324     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
325
326     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
327 }
328
329 static void
330 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
331            char *secret, int secret_len, u_char NTResponse[24])
332 {
333     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
334     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
335     u_char      Challenge[8];
336
337     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
338
339     /* Hash the Unicode version of the secret (== password). */
340     ascii2unicode(secret, secret_len, unicodePassword);
341     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
342
343     ChallengeResponse(Challenge, PasswordHash, NTResponse);
344 }
345
346 #ifdef MSLANMAN
347 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
348
349 static void
350 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
351               u_char LMResponse[24])
352 {
353     int                 i;
354     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
355     u_char              PasswordHash[MD4_SIGNATURE_SIZE];
356
357     /* LANMan password is case insensitive */
358     BZERO(UcasePassword, sizeof(UcasePassword));
359     for (i = 0; i < secret_len; i++)
360        UcasePassword[i] = (u_char)toupper(secret[i]);
361     DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
362     DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
363     ChallengeResponse(rchallenge, PasswordHash, LMResponse);
364 }
365 #endif
366
367
368 static void
369 GenerateAuthenticatorResponse(char *secret, int secret_len,
370                               u_char NTResponse[24], u_char PeerChallenge[16],
371                               u_char *rchallenge, char *username,
372                               u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
373 {
374     /*
375      * "Magic" constants used in response generation, from RFC 2759.
376      */
377     u_char Magic1[39] = /* "Magic server to client signing constant" */
378         { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
379           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
380           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
381           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
382     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
383         { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
384           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
385           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
386           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
387           0x6E };
388
389     int         i;
390     SHA1_CTX    sha1Context;
391     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
392     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
393     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
394     u_char      Digest[SHA1_SIGNATURE_SIZE];
395     u_char      Challenge[8];
396
397     /* Hash (x2) the Unicode version of the secret (== password). */
398     ascii2unicode(secret, secret_len, unicodePassword);
399     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
400     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
401
402     SHA1_Init(&sha1Context);
403     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
404     SHA1_Update(&sha1Context, NTResponse, 24);
405     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
406     SHA1_Final(Digest, &sha1Context);
407
408     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
409
410     SHA1_Init(&sha1Context);
411     SHA1_Update(&sha1Context, Digest, sizeof(Digest));
412     SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
413     SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
414     SHA1_Final(Digest, &sha1Context);
415
416     /* Convert to ASCII hex string. */
417     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
418         sprintf(&authResponse[i * 2], "%02X", Digest[i]);
419 }
420
421
422 #ifdef MPPE
423 /*
424  * Set mppe_xxxx_key from the NTPasswordHashHash.
425  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
426  */
427 void
428 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
429 {
430     SHA1_CTX    sha1Context;
431     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
432
433     SHA1_Init(&sha1Context);
434     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
435     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
436     SHA1_Update(&sha1Context, rchallenge, 8);
437     SHA1_Final(Digest, &sha1Context);
438
439     /* Same key in both directions. */
440     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
441     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
442 }
443
444 /*
445  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
446  */
447 static void
448 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
449 {
450     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
451     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
452     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
453
454     /* Hash (x2) the Unicode version of the secret (== password). */
455     ascii2unicode(secret, secret_len, unicodePassword);
456     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
457     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
458
459     mppe_set_keys(rchallenge, PasswordHashHash);
460 }
461
462 /*
463  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
464  */
465 static void
466 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
467 {
468     SHA1_CTX    sha1Context;
469     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
470     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
471     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
472     u_char      MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
473     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
474
475     u_char SHApad1[40] =
476         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
477           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
478           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
479           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
480     u_char SHApad2[40] =
481         { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
482           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
483           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
484           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
485
486     /* "This is the MPPE Master Key" */
487     u_char Magic1[27] =
488         { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
489           0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
490           0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
491     /* "On the client side, this is the send key; "
492        "on the server side, it is the receive key." */
493     u_char Magic2[84] =
494         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
495           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
496           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
497           0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
498           0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
499           0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
500           0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
501           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
502           0x6b, 0x65, 0x79, 0x2e };
503     /* "On the client side, this is the receive key; "
504        "on the server side, it is the send key." */
505     u_char Magic3[84] =
506         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
507           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
508           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
509           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
510           0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
511           0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
512           0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
513           0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
514           0x6b, 0x65, 0x79, 0x2e };
515     u_char *s;
516
517     /* Hash (x2) the Unicode version of the secret (== password). */
518     ascii2unicode(secret, secret_len, unicodePassword);
519     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
520     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
521
522     SHA1_Init(&sha1Context);
523     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
524     SHA1_Update(&sha1Context, NTResponse, 24);
525     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
526     SHA1_Final(MasterKey, &sha1Context);
527
528     /*
529      * generate send key
530      */
531     if (IsServer)
532         s = Magic3;
533     else
534         s = Magic2;
535     SHA1_Init(&sha1Context);
536     SHA1_Update(&sha1Context, MasterKey, 16);
537     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
538     SHA1_Update(&sha1Context, s, 84);
539     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
540     SHA1_Final(Digest, &sha1Context);
541
542     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
543
544     /*
545      * generate recv key
546      */
547     if (IsServer)
548         s = Magic2;
549     else
550         s = Magic3;
551     SHA1_Init(&sha1Context);
552     SHA1_Update(&sha1Context, MasterKey, 16);
553     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
554     SHA1_Update(&sha1Context, s, 84);
555     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
556     SHA1_Final(Digest, &sha1Context);
557
558     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
559 }
560
561 #endif /* MPPE */
562
563
564 void
565 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
566        MS_ChapResponse *response)
567 {
568 #if 0
569     CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
570 #endif
571     BZERO(response, sizeof(*response));
572
573     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
574
575 #ifdef MSLANMAN
576     ChapMS_LANMan(rchallenge, secret, secret_len, response);
577
578     /* preferred method is set by option  */
579     response->UseNT[0] = !ms_lanman;
580 #else
581     response->UseNT[0] = 1;
582 #endif
583
584     cstate->resp_length = MS_CHAP_RESPONSE_LENGTH;
585
586 #ifdef MPPE
587     Set_Start_Key(rchallenge, secret, secret_len);
588 #endif
589 }
590
591
592 /*
593  * If PeerChallenge is NULL, one is generated and response->PeerChallenge
594  * is filled in.  Call this way when generating a response.
595  * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
596  * Call this way when verifying a response (or debugging).
597  * Do not call with PeerChallenge = response->PeerChallenge.
598  *
599  * response->PeerChallenge is then used for calculation of the
600  * Authenticator Response.
601  */
602 void
603 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
604         char *user, char *secret, int secret_len, MS_Chap2Response *response,
605         u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator)
606 {
607     /* ARGSUSED */
608     u_char *p = response->PeerChallenge;
609     int i;
610
611     BZERO(response, sizeof(*response));
612
613     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
614     if (!PeerChallenge)
615         for (i = 0; i < sizeof(response->PeerChallenge); i++)
616             *p++ = (u_char) (drand48() * 0xff);
617     else
618         BCOPY(PeerChallenge, response->PeerChallenge,
619               sizeof(response->PeerChallenge));
620
621     /* Generate the NT-Response */
622     ChapMS2_NT(rchallenge, response->PeerChallenge, user,
623                secret, secret_len, response->NTResp);
624
625     /* Generate the Authenticator Response. */
626     GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
627                                   response->PeerChallenge, rchallenge,
628                                   user, authResponse);
629
630     cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
631
632 #ifdef MPPE
633     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
634 #endif
635 }
636
637
638 #endif /* CHAPMS */