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.26 2002/12/23 23:24:37 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? */
106 ChallengeResponse(u_char *challenge,
107 u_char PasswordHash[MD4_SIGNATURE_SIZE],
110 u_char ZPasswordHash[21];
112 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
113 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
116 dbglog("ChallengeResponse - ZPasswordHash %.*B",
117 sizeof(ZPasswordHash), ZPasswordHash);
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);
128 dbglog("ChallengeResponse - response %.24B", response);
133 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
134 char *username, u_char Challenge[8])
137 SHA1_CTX sha1Context;
138 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
141 /* remove domain from "domain\username" */
142 if ((user = strrchr(username, '\\')) != NULL)
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);
153 BCOPY(sha1Hash, Challenge, 8);
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.)
164 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
168 BZERO(unicode, ascii_len * 2);
169 for (i = 0; i < ascii_len; i++)
170 unicode[i * 2] = (u_char) ascii[i];
174 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
177 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
178 int mdlen = secret_len;
180 int mdlen = secret_len * 8;
184 MD4Init(&md4Context);
185 MD4Update(&md4Context, secret, mdlen);
186 MD4Final(hash, &md4Context);
191 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
192 u_char NTResponse[24])
194 u_char unicodePassword[MAX_NT_PASSWORD * 2];
195 u_char PasswordHash[MD4_SIGNATURE_SIZE];
197 /* Hash the Unicode version of the secret (== password). */
198 ascii2unicode(secret, secret_len, unicodePassword);
199 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
201 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
205 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
206 char *secret, int secret_len, u_char NTResponse[24])
208 u_char unicodePassword[MAX_NT_PASSWORD * 2];
209 u_char PasswordHash[MD4_SIGNATURE_SIZE];
212 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
214 /* Hash the Unicode version of the secret (== password). */
215 ascii2unicode(secret, secret_len, unicodePassword);
216 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
218 ChallengeResponse(Challenge, PasswordHash, NTResponse);
222 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
225 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
226 MS_ChapResponse *response)
229 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
230 u_char PasswordHash[MD4_SIGNATURE_SIZE];
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);
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])
252 * "Magic" constants used in response generation, from RFC 2759.
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,
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];
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);
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);
285 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
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);
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]);
301 * Set mppe_xxxx_key from the NTPasswordHashHash.
302 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
305 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
307 SHA1_CTX sha1Context;
308 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
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);
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));
322 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
325 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
327 u_char unicodePassword[MAX_NT_PASSWORD * 2];
328 u_char PasswordHash[MD4_SIGNATURE_SIZE];
329 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
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);
336 mppe_set_keys(rchallenge, PasswordHashHash);
340 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
343 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
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 */
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 };
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 };
363 /* "This is the MPPE Master Key" */
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." */
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." */
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 };
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);
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);
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);
419 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
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);
435 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
442 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
443 MS_ChapResponse *response)
446 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
448 BZERO(response, sizeof(*response));
450 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
453 ChapMS_LANMan(rchallenge, secret, secret_len, response);
455 /* preferred method is set by option */
456 response->UseNT[0] = !ms_lanman;
458 response->UseNT[0] = 1;
461 cstate->resp_length = MS_CHAP_RESPONSE_LEN;
464 Set_Start_Key(rchallenge, secret, secret_len);
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.
477 * response->PeerChallenge is then used for calculation of the
478 * Authenticator Response.
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)
486 u_char *p = response->PeerChallenge;
489 BZERO(response, sizeof(*response));
491 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
493 for (i = 0; i < sizeof(response->PeerChallenge); i++)
494 *p++ = (u_char) (drand48() * 0xff);
496 BCOPY(PeerChallenge, response->PeerChallenge,
497 sizeof(response->PeerChallenge));
499 /* Generate the NT-Response */
500 ChapMS2_NT(rchallenge, response->PeerChallenge, user,
501 secret, secret_len, response->NTResp);
503 /* Generate the Authenticator Response. */
504 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
505 response->PeerChallenge, rchallenge,
508 cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
511 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);