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.
49 * Copyright (c) 2002 Google, Inc. All rights reserved.
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
55 * 1. Redistributions of source code must retain the above copyright
56 * notice, this list of conditions and the following disclaimer.
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
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.
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.
77 #define RCSID "$Id: chap_ms.c,v 1.28 2003/01/10 07:12:36 fcusack Exp $"
85 #include <sys/types.h>
96 static const char rcsid[] = RCSID;
99 static void ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
100 static void ascii2unicode __P((char[], int, u_char[]));
101 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
102 static void ChallengeResponse __P((u_char *, u_char *, u_char[24]));
103 static void ChapMS_NT __P((u_char *, char *, int, u_char[24]));
104 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
106 static void GenerateAuthenticatorResponse __P((char*, int, u_char[24],
107 u_char[16], u_char *,
108 char *, u_char[41]));
110 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
114 static void Set_Start_Key __P((u_char *, char *, int));
115 static void SetMasterKeys __P((char *, int, u_char[24], int));
118 extern double drand48 __P((void));
121 bool ms_lanman = 0; /* Use LanMan password instead of NT */
122 /* Has meaning only with MS-CHAP challenges */
126 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
127 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
128 int mppe_keys_set = 0; /* Have the MPPE keys been set? */
130 #include "fsm.h" /* Need to poke MPPE options */
132 #include <net/ppp-comp.h>
136 ChallengeResponse(u_char *challenge,
137 u_char PasswordHash[MD4_SIGNATURE_SIZE],
140 u_char ZPasswordHash[21];
142 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
143 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
146 dbglog("ChallengeResponse - ZPasswordHash %.*B",
147 sizeof(ZPasswordHash), ZPasswordHash);
150 (void) DesSetkey(ZPasswordHash + 0);
151 DesEncrypt(challenge, response + 0);
152 (void) DesSetkey(ZPasswordHash + 7);
153 DesEncrypt(challenge, response + 8);
154 (void) DesSetkey(ZPasswordHash + 14);
155 DesEncrypt(challenge, response + 16);
158 dbglog("ChallengeResponse - response %.24B", response);
163 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
164 char *username, u_char Challenge[8])
167 SHA1_CTX sha1Context;
168 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
171 /* remove domain from "domain\username" */
172 if ((user = strrchr(username, '\\')) != NULL)
177 SHA1_Init(&sha1Context);
178 SHA1_Update(&sha1Context, PeerChallenge, 16);
179 SHA1_Update(&sha1Context, rchallenge, 16);
180 SHA1_Update(&sha1Context, user, strlen(user));
181 SHA1_Final(sha1Hash, &sha1Context);
183 BCOPY(sha1Hash, Challenge, 8);
187 * Convert the ASCII version of the password to Unicode.
188 * This implicitly supports 8-bit ISO8859/1 characters.
189 * This gives us the little-endian representation, which
190 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
191 * is machine-dependent.)
194 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
198 BZERO(unicode, ascii_len * 2);
199 for (i = 0; i < ascii_len; i++)
200 unicode[i * 2] = (u_char) ascii[i];
204 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
207 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
208 int mdlen = secret_len;
210 int mdlen = secret_len * 8;
214 MD4Init(&md4Context);
215 MD4Update(&md4Context, secret, mdlen);
216 MD4Final(hash, &md4Context);
221 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
222 u_char NTResponse[24])
224 u_char unicodePassword[MAX_NT_PASSWORD * 2];
225 u_char PasswordHash[MD4_SIGNATURE_SIZE];
227 /* Hash the Unicode version of the secret (== password). */
228 ascii2unicode(secret, secret_len, unicodePassword);
229 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
231 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
235 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
236 char *secret, int secret_len, u_char NTResponse[24])
238 u_char unicodePassword[MAX_NT_PASSWORD * 2];
239 u_char PasswordHash[MD4_SIGNATURE_SIZE];
242 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
244 /* Hash the Unicode version of the secret (== password). */
245 ascii2unicode(secret, secret_len, unicodePassword);
246 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
248 ChallengeResponse(Challenge, PasswordHash, NTResponse);
252 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
255 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
256 MS_ChapResponse *response)
259 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
260 u_char PasswordHash[MD4_SIGNATURE_SIZE];
262 /* LANMan password is case insensitive */
263 BZERO(UcasePassword, sizeof(UcasePassword));
264 for (i = 0; i < secret_len; i++)
265 UcasePassword[i] = (u_char)toupper(secret[i]);
266 (void) DesSetkey(UcasePassword + 0);
267 DesEncrypt( StdText, PasswordHash + 0 );
268 (void) DesSetkey(UcasePassword + 7);
269 DesEncrypt( StdText, PasswordHash + 8 );
270 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
276 GenerateAuthenticatorResponse(char *secret, int secret_len,
277 u_char NTResponse[24], u_char PeerChallenge[16],
278 u_char *rchallenge, char *username,
279 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
282 * "Magic" constants used in response generation, from RFC 2759.
284 u_char Magic1[39] = /* "Magic server to client signing constant" */
285 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
286 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
287 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
288 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
289 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
290 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
291 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
292 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
293 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
297 SHA1_CTX sha1Context;
298 u_char unicodePassword[MAX_NT_PASSWORD * 2];
299 u_char PasswordHash[MD4_SIGNATURE_SIZE];
300 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
301 u_char Digest[SHA1_SIGNATURE_SIZE];
304 /* Hash (x2) the Unicode version of the secret (== password). */
305 ascii2unicode(secret, secret_len, unicodePassword);
306 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
307 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
309 SHA1_Init(&sha1Context);
310 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
311 SHA1_Update(&sha1Context, NTResponse, 24);
312 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
313 SHA1_Final(Digest, &sha1Context);
315 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
317 SHA1_Init(&sha1Context);
318 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
319 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
320 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
321 SHA1_Final(Digest, &sha1Context);
323 /* Convert to ASCII hex string. */
324 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
325 sprintf(&authResponse[i * 2], "%02X", Digest[i]);
331 * Set mppe_xxxx_key from the NTPasswordHashHash.
332 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
335 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
337 SHA1_CTX sha1Context;
338 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
340 SHA1_Init(&sha1Context);
341 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
342 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
343 SHA1_Update(&sha1Context, rchallenge, 8);
344 SHA1_Final(Digest, &sha1Context);
346 /* Same key in both directions. */
347 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
348 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
352 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
355 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
357 u_char unicodePassword[MAX_NT_PASSWORD * 2];
358 u_char PasswordHash[MD4_SIGNATURE_SIZE];
359 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
361 /* Hash (x2) the Unicode version of the secret (== password). */
362 ascii2unicode(secret, secret_len, unicodePassword);
363 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
364 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
366 mppe_set_keys(rchallenge, PasswordHashHash);
370 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
373 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
375 SHA1_CTX sha1Context;
376 u_char unicodePassword[MAX_NT_PASSWORD * 2];
377 u_char PasswordHash[MD4_SIGNATURE_SIZE];
378 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
379 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
380 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
383 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
388 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
389 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
390 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
391 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
393 /* "This is the MPPE Master Key" */
395 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
396 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
397 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
398 /* "On the client side, this is the send key; "
399 "on the server side, it is the receive key." */
401 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
402 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
403 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
404 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
405 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
406 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
407 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
408 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
409 0x6b, 0x65, 0x79, 0x2e };
410 /* "On the client side, this is the receive key; "
411 "on the server side, it is the send key." */
413 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
414 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
415 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
416 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
417 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
418 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
419 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
420 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
421 0x6b, 0x65, 0x79, 0x2e };
424 /* Hash (x2) the Unicode version of the secret (== password). */
425 ascii2unicode(secret, secret_len, unicodePassword);
426 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
427 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
429 SHA1_Init(&sha1Context);
430 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
431 SHA1_Update(&sha1Context, NTResponse, 24);
432 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
433 SHA1_Final(MasterKey, &sha1Context);
442 SHA1_Init(&sha1Context);
443 SHA1_Update(&sha1Context, MasterKey, 16);
444 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
445 SHA1_Update(&sha1Context, s, 84);
446 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
447 SHA1_Final(Digest, &sha1Context);
449 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
458 SHA1_Init(&sha1Context);
459 SHA1_Update(&sha1Context, MasterKey, 16);
460 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
461 SHA1_Update(&sha1Context, s, 84);
462 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
463 SHA1_Final(Digest, &sha1Context);
465 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
472 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
473 MS_ChapResponse *response)
476 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
478 BZERO(response, sizeof(*response));
480 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
483 ChapMS_LANMan(rchallenge, secret, secret_len, response);
485 /* preferred method is set by option */
486 response->UseNT[0] = !ms_lanman;
488 response->UseNT[0] = 1;
491 cstate->resp_length = MS_CHAP_RESPONSE_LEN;
494 Set_Start_Key(rchallenge, secret, secret_len);
501 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
502 * is filled in. Call this way when generating a response.
503 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
504 * Call this way when verifying a response (or debugging).
505 * Do not call with PeerChallenge = response->PeerChallenge.
507 * response->PeerChallenge is then used for calculation of the
508 * Authenticator Response.
511 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
512 char *user, char *secret, int secret_len, MS_Chap2Response *response,
513 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator)
516 u_char *p = response->PeerChallenge;
519 BZERO(response, sizeof(*response));
521 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
523 for (i = 0; i < sizeof(response->PeerChallenge); i++)
524 *p++ = (u_char) (drand48() * 0xff);
526 BCOPY(PeerChallenge, response->PeerChallenge,
527 sizeof(response->PeerChallenge));
529 /* Generate the NT-Response */
530 ChapMS2_NT(rchallenge, response->PeerChallenge, user,
531 secret, secret_len, response->NTResp);
533 /* Generate the Authenticator Response. */
534 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
535 response->PeerChallenge, rchallenge,
538 cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
541 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
548 * Set MPPE options from plugins.
551 set_mppe_enc_types(int policy, int types)
553 /* Early exit for unknown policies. */
554 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
555 policy != MPPE_ENC_POL_ENC_REQUIRED)
558 /* Don't modify MPPE if it's optional and wasn't already configured. */
559 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
563 * Disable undesirable encryption types. Note that we don't ENABLE
564 * any encryption types, to avoid overriding manual configuration.
567 case MPPE_ENC_TYPES_RC4_40:
568 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
570 case MPPE_ENC_TYPES_RC4_128:
571 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */