]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
Ensure that MPPE keys are available when using a plugin.
[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  *   Copyright (c) 2002 Google, Inc.
49  */
50
51 #define RCSID   "$Id: chap_ms.c,v 1.26 2002/12/23 23:24:37 fcusack Exp $"
52
53 #ifdef CHAPMS
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <ctype.h>
59 #include <sys/types.h>
60 #include <sys/time.h>
61 #include <unistd.h>
62
63 #include "pppd.h"
64 #include "chap.h"
65 #include "chap_ms.h"
66 #include "md4.h"
67 #include "sha1.h"
68 #include "pppcrypt.h"
69
70 static const char rcsid[] = RCSID;
71
72
73 static void     ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
74 static void     ascii2unicode __P((char[], int, u_char[]));
75 static void     NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
76 static void     ChallengeResponse __P((u_char *, u_char *, u_char[24]));
77 static void     ChapMS_NT __P((u_char *, char *, int, u_char[24]));
78 static void     ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
79                                 u_char[24]));
80 static void     GenerateAuthenticatorResponse __P((char*, int, u_char[24],
81                                                    u_char[16], u_char *,
82                                                    char *, u_char[41]));
83 #ifdef MSLANMAN
84 static void     ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
85 #endif
86
87 #ifdef MPPE
88 static void     Set_Start_Key __P((u_char *, char *, int));
89 static void     SetMasterKeys __P((char *, int, u_char[24], int));
90 #endif
91
92 extern double drand48 __P((void));
93
94 #ifdef MSLANMAN
95 bool    ms_lanman = 0;          /* Use LanMan password instead of NT */
96                                 /* Has meaning only with MS-CHAP challenges */
97 #endif
98
99 #ifdef MPPE
100 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
101 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
102 int mppe_keys_set = 0;          /* Have the MPPE keys been set? */
103 #endif
104
105 static void
106 ChallengeResponse(u_char *challenge,
107                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
108                   u_char response[24])
109 {
110     u_char    ZPasswordHash[21];
111
112     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
113     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
114
115 #if 0
116     dbglog("ChallengeResponse - ZPasswordHash %.*B",
117            sizeof(ZPasswordHash), ZPasswordHash);
118 #endif
119
120     (void) DesSetkey(ZPasswordHash + 0);
121     DesEncrypt(challenge, response + 0);
122     (void) DesSetkey(ZPasswordHash + 7);
123     DesEncrypt(challenge, response + 8);
124     (void) DesSetkey(ZPasswordHash + 14);
125     DesEncrypt(challenge, response + 16);
126
127 #if 0
128     dbglog("ChallengeResponse - response %.24B", response);
129 #endif
130 }
131
132 static void
133 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
134               char *username, u_char Challenge[8])
135     
136 {
137     SHA1_CTX    sha1Context;
138     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
139     char        *user;
140
141     /* remove domain from "domain\username" */
142     if ((user = strrchr(username, '\\')) != NULL)
143         ++user;
144     else
145         user = username;
146
147     SHA1_Init(&sha1Context);
148     SHA1_Update(&sha1Context, PeerChallenge, 16);
149     SHA1_Update(&sha1Context, rchallenge, 16);
150     SHA1_Update(&sha1Context, user, strlen(user));
151     SHA1_Final(sha1Hash, &sha1Context);
152
153     BCOPY(sha1Hash, Challenge, 8);
154 }
155
156 /*
157  * Convert the ASCII version of the password to Unicode.
158  * This implicitly supports 8-bit ISO8859/1 characters.
159  * This gives us the little-endian representation, which
160  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
161  * is machine-dependent.)
162  */
163 static void
164 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
165 {
166     int i;
167
168     BZERO(unicode, ascii_len * 2);
169     for (i = 0; i < ascii_len; i++)
170         unicode[i * 2] = (u_char) ascii[i];
171 }
172
173 static void
174 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
175 {
176 #ifdef __NetBSD__
177     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
178     int                 mdlen = secret_len;
179 #else
180     int                 mdlen = secret_len * 8;
181 #endif
182     MD4_CTX             md4Context;
183
184     MD4Init(&md4Context);
185     MD4Update(&md4Context, secret, mdlen);
186     MD4Final(hash, &md4Context);
187
188 }
189
190 static void
191 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
192           u_char NTResponse[24])
193 {
194     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
195     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
196
197     /* Hash the Unicode version of the secret (== password). */
198     ascii2unicode(secret, secret_len, unicodePassword);
199     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
200
201     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
202 }
203
204 static void
205 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
206            char *secret, int secret_len, u_char NTResponse[24])
207 {
208     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
209     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
210     u_char      Challenge[8];
211
212     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
213
214     /* Hash the Unicode version of the secret (== password). */
215     ascii2unicode(secret, secret_len, unicodePassword);
216     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
217
218     ChallengeResponse(Challenge, PasswordHash, NTResponse);
219 }
220
221 #ifdef MSLANMAN
222 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
223
224 static void
225 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
226               MS_ChapResponse *response)
227 {
228     int                 i;
229     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
230     u_char              PasswordHash[MD4_SIGNATURE_SIZE];
231
232     /* LANMan password is case insensitive */
233     BZERO(UcasePassword, sizeof(UcasePassword));
234     for (i = 0; i < secret_len; i++)
235        UcasePassword[i] = (u_char)toupper(secret[i]);
236     (void) DesSetkey(UcasePassword + 0);
237     DesEncrypt( StdText, PasswordHash + 0 );
238     (void) DesSetkey(UcasePassword + 7);
239     DesEncrypt( StdText, PasswordHash + 8 );
240     ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
241 }
242 #endif
243
244
245 static void
246 GenerateAuthenticatorResponse(char *secret, int secret_len,
247                               u_char NTResponse[24], u_char PeerChallenge[16],
248                               u_char *rchallenge, char *username,
249                               u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
250 {
251     /*
252      * "Magic" constants used in response generation, from RFC 2759.
253      */
254     u_char Magic1[39] = /* "Magic server to client signing constant" */
255         { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
256           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
257           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
258           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
259     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
260         { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
261           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
262           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
263           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
264           0x6E };
265
266     int         i;
267     SHA1_CTX    sha1Context;
268     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
269     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
270     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
271     u_char      Digest[SHA1_SIGNATURE_SIZE];
272     u_char      Challenge[8];
273
274     /* Hash (x2) the Unicode version of the secret (== password). */
275     ascii2unicode(secret, secret_len, unicodePassword);
276     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
277     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
278
279     SHA1_Init(&sha1Context);
280     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
281     SHA1_Update(&sha1Context, NTResponse, 24);
282     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
283     SHA1_Final(Digest, &sha1Context);
284
285     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
286
287     SHA1_Init(&sha1Context);
288     SHA1_Update(&sha1Context, Digest, sizeof(Digest));
289     SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
290     SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
291     SHA1_Final(Digest, &sha1Context);
292
293     /* Convert to ASCII hex string. */
294     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
295         sprintf(&authResponse[i * 2], "%02X", Digest[i]);
296 }
297
298
299 #ifdef MPPE
300 /*
301  * Set mppe_xxxx_key from the NTPasswordHashHash.
302  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
303  */
304 void
305 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
306 {
307     SHA1_CTX    sha1Context;
308     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
309
310     SHA1_Init(&sha1Context);
311     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
312     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
313     SHA1_Update(&sha1Context, rchallenge, 8);
314     SHA1_Final(Digest, &sha1Context);
315
316     /* Same key in both directions. */
317     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
318     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
319 }
320
321 /*
322  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
323  */
324 static void
325 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
326 {
327     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
328     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
329     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
330
331     /* Hash (x2) the Unicode version of the secret (== password). */
332     ascii2unicode(secret, secret_len, unicodePassword);
333     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
334     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
335
336     mppe_set_keys(rchallenge, PasswordHashHash);
337 }
338
339 /*
340  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
341  */
342 static void
343 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
344 {
345     SHA1_CTX    sha1Context;
346     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
347     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
348     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
349     u_char      MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
350     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
351
352     u_char SHApad1[40] =
353         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
357     u_char SHApad2[40] =
358         { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
359           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
360           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
361           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
362
363     /* "This is the MPPE Master Key" */
364     u_char Magic1[27] =
365         { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
366           0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
367           0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
368     /* "On the client side, this is the send key; "
369        "on the server side, it is the receive key." */
370     u_char Magic2[84] =
371         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
372           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
373           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
374           0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
375           0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
376           0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
377           0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
378           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
379           0x6b, 0x65, 0x79, 0x2e };
380     /* "On the client side, this is the receive key; "
381        "on the server side, it is the send key." */
382     u_char Magic3[84] =
383         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
384           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
385           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
386           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
387           0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
388           0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
389           0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
390           0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
391           0x6b, 0x65, 0x79, 0x2e };
392     u_char *s;
393
394     /* Hash (x2) the Unicode version of the secret (== password). */
395     ascii2unicode(secret, secret_len, unicodePassword);
396     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
397     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
398
399     SHA1_Init(&sha1Context);
400     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
401     SHA1_Update(&sha1Context, NTResponse, 24);
402     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
403     SHA1_Final(MasterKey, &sha1Context);
404
405     /*
406      * generate send key
407      */
408     if (IsServer)
409         s = Magic3;
410     else
411         s = Magic2;
412     SHA1_Init(&sha1Context);
413     SHA1_Update(&sha1Context, MasterKey, 16);
414     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
415     SHA1_Update(&sha1Context, s, 84);
416     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
417     SHA1_Final(Digest, &sha1Context);
418
419     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
420
421     /*
422      * generate recv key
423      */
424     if (IsServer)
425         s = Magic2;
426     else
427         s = Magic3;
428     SHA1_Init(&sha1Context);
429     SHA1_Update(&sha1Context, MasterKey, 16);
430     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
431     SHA1_Update(&sha1Context, s, 84);
432     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
433     SHA1_Final(Digest, &sha1Context);
434
435     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
436 }
437
438 #endif /* MPPE */
439
440
441 void
442 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
443        MS_ChapResponse *response)
444 {
445 #if 0
446     CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
447 #endif
448     BZERO(response, sizeof(*response));
449
450     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
451
452 #ifdef MSLANMAN
453     ChapMS_LANMan(rchallenge, secret, secret_len, response);
454
455     /* preferred method is set by option  */
456     response->UseNT[0] = !ms_lanman;
457 #else
458     response->UseNT[0] = 1;
459 #endif
460
461     cstate->resp_length = MS_CHAP_RESPONSE_LEN;
462
463 #ifdef MPPE
464     Set_Start_Key(rchallenge, secret, secret_len);
465     mppe_keys_set = 1;
466 #endif
467 }
468
469
470 /*
471  * If PeerChallenge is NULL, one is generated and response->PeerChallenge
472  * is filled in.  Call this way when generating a response.
473  * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
474  * Call this way when verifying a response (or debugging).
475  * Do not call with PeerChallenge = response->PeerChallenge.
476  *
477  * response->PeerChallenge is then used for calculation of the
478  * Authenticator Response.
479  */
480 void
481 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
482         char *user, char *secret, int secret_len, MS_Chap2Response *response,
483         u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator)
484 {
485     /* ARGSUSED */
486     u_char *p = response->PeerChallenge;
487     int i;
488
489     BZERO(response, sizeof(*response));
490
491     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
492     if (!PeerChallenge)
493         for (i = 0; i < sizeof(response->PeerChallenge); i++)
494             *p++ = (u_char) (drand48() * 0xff);
495     else
496         BCOPY(PeerChallenge, response->PeerChallenge,
497               sizeof(response->PeerChallenge));
498
499     /* Generate the NT-Response */
500     ChapMS2_NT(rchallenge, response->PeerChallenge, user,
501                secret, secret_len, response->NTResp);
502
503     /* Generate the Authenticator Response. */
504     GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
505                                   response->PeerChallenge, rchallenge,
506                                   user, authResponse);
507
508     cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
509
510 #ifdef MPPE
511     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
512     mppe_keys_set = 1;
513 #endif
514 }
515
516
517 #endif /* CHAPMS */