2 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
4 * Copyright (c) 1995 Eric Rosenquist. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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
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.
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.
32 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
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.
39 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
43 * Modifications by Frank Cusack, frank@google.com, March 2002.
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.
51 #define RCSID "$Id: chap_ms.c,v 1.27 2002/12/24 03:43:35 fcusack Exp $"
59 #include <sys/types.h>
70 static const char rcsid[] = RCSID;
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,
80 static void GenerateAuthenticatorResponse __P((char*, int, u_char[24],
84 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
88 static void Set_Start_Key __P((u_char *, char *, int));
89 static void SetMasterKeys __P((char *, int, u_char[24], int));
92 extern double drand48 __P((void));
95 bool ms_lanman = 0; /* Use LanMan password instead of NT */
96 /* Has meaning only with MS-CHAP challenges */
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? */
104 #include "fsm.h" /* Need to poke MPPE options */
106 #include <net/ppp-comp.h>
110 ChallengeResponse(u_char *challenge,
111 u_char PasswordHash[MD4_SIGNATURE_SIZE],
114 u_char ZPasswordHash[21];
116 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
117 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
120 dbglog("ChallengeResponse - ZPasswordHash %.*B",
121 sizeof(ZPasswordHash), ZPasswordHash);
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);
132 dbglog("ChallengeResponse - response %.24B", response);
137 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
138 char *username, u_char Challenge[8])
141 SHA1_CTX sha1Context;
142 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
145 /* remove domain from "domain\username" */
146 if ((user = strrchr(username, '\\')) != NULL)
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);
157 BCOPY(sha1Hash, Challenge, 8);
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.)
168 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
172 BZERO(unicode, ascii_len * 2);
173 for (i = 0; i < ascii_len; i++)
174 unicode[i * 2] = (u_char) ascii[i];
178 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
181 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
182 int mdlen = secret_len;
184 int mdlen = secret_len * 8;
188 MD4Init(&md4Context);
189 MD4Update(&md4Context, secret, mdlen);
190 MD4Final(hash, &md4Context);
195 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
196 u_char NTResponse[24])
198 u_char unicodePassword[MAX_NT_PASSWORD * 2];
199 u_char PasswordHash[MD4_SIGNATURE_SIZE];
201 /* Hash the Unicode version of the secret (== password). */
202 ascii2unicode(secret, secret_len, unicodePassword);
203 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
205 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
209 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
210 char *secret, int secret_len, u_char NTResponse[24])
212 u_char unicodePassword[MAX_NT_PASSWORD * 2];
213 u_char PasswordHash[MD4_SIGNATURE_SIZE];
216 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
218 /* Hash the Unicode version of the secret (== password). */
219 ascii2unicode(secret, secret_len, unicodePassword);
220 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
222 ChallengeResponse(Challenge, PasswordHash, NTResponse);
226 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
229 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
230 MS_ChapResponse *response)
233 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
234 u_char PasswordHash[MD4_SIGNATURE_SIZE];
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);
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])
256 * "Magic" constants used in response generation, from RFC 2759.
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,
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];
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);
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);
289 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
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);
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]);
305 * Set mppe_xxxx_key from the NTPasswordHashHash.
306 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
309 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
311 SHA1_CTX sha1Context;
312 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
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);
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));
326 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
329 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
331 u_char unicodePassword[MAX_NT_PASSWORD * 2];
332 u_char PasswordHash[MD4_SIGNATURE_SIZE];
333 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
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);
340 mppe_set_keys(rchallenge, PasswordHashHash);
344 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
347 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
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 */
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 };
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 };
367 /* "This is the MPPE Master Key" */
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." */
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." */
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 };
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);
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);
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);
423 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
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);
439 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
446 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
447 MS_ChapResponse *response)
450 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
452 BZERO(response, sizeof(*response));
454 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
457 ChapMS_LANMan(rchallenge, secret, secret_len, response);
459 /* preferred method is set by option */
460 response->UseNT[0] = !ms_lanman;
462 response->UseNT[0] = 1;
465 cstate->resp_length = MS_CHAP_RESPONSE_LEN;
468 Set_Start_Key(rchallenge, secret, secret_len);
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.
481 * response->PeerChallenge is then used for calculation of the
482 * Authenticator Response.
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)
490 u_char *p = response->PeerChallenge;
493 BZERO(response, sizeof(*response));
495 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
497 for (i = 0; i < sizeof(response->PeerChallenge); i++)
498 *p++ = (u_char) (drand48() * 0xff);
500 BCOPY(PeerChallenge, response->PeerChallenge,
501 sizeof(response->PeerChallenge));
503 /* Generate the NT-Response */
504 ChapMS2_NT(rchallenge, response->PeerChallenge, user,
505 secret, secret_len, response->NTResp);
507 /* Generate the Authenticator Response. */
508 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
509 response->PeerChallenge, rchallenge,
512 cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
515 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
522 * Set MPPE options from plugins.
525 set_mppe_enc_types(int policy, int types)
527 /* Early exit for unknown policies. */
528 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
529 policy != MPPE_ENC_POL_ENC_REQUIRED)
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)
537 * Disable undesirable encryption types. Note that we don't ENABLE
538 * any encryption types, to avoid overriding manual configuration.
541 case MPPE_ENC_TYPES_RC4_40:
542 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
544 case MPPE_ENC_TYPES_RC4_128:
545 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */