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