2 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
4 * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
5 * http://www.strataware.com/
9 * Redistribution and use in source and binary forms are permitted
10 * provided that the above copyright notice and this paragraph are
11 * duplicated in all such forms and that any documentation,
12 * advertising materials, and other materials related to such
13 * distribution and use acknowledge that the software was developed
14 * by Eric Rosenquist. The name of the author may not be used to
15 * endorse or promote products derived from this software without
16 * specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
26 * Implemented LANManager type password response to MS-CHAP challenges.
27 * Now pppd provides both NT style and LANMan style blocks, and the
28 * prefered is set by option "ms-lanman". Default is to use NT.
29 * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
31 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
35 * Modifications by Frank Cusack, frank@google.com, March 2002.
37 * Implemented MS-CHAPv2 functionality, heavily based on sample
38 * implementation in RFC 2759. Implemented MPPE functionality,
39 * heavily based on sample implementation in RFC 3079.
40 * Copyright (c) 2002 Google, Inc.
43 #define RCSID "$Id: chap_ms.c,v 1.24 2002/11/13 12:26:03 fcusack Exp $"
51 #include <sys/types.h>
62 static const char rcsid[] = RCSID;
65 static void ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
66 static void ascii2unicode __P((char[], int, u_char[]));
67 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
68 static void ChallengeResponse __P((u_char *, u_char *, u_char[24]));
69 static void ChapMS_NT __P((u_char *, char *, int, u_char[24]));
70 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
72 static void GenerateAuthenticatorResponse __P((char*, int, u_char[24],
76 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
80 static void Set_Start_Key __P((u_char *, char *, int));
81 static void SetMasterKeys __P((char *, int, u_char[24], int));
84 extern double drand48 __P((void));
87 bool ms_lanman = 0; /* Use LanMan password instead of NT */
88 /* Has meaning only with MS-CHAP challenges */
92 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
93 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
97 ChallengeResponse(u_char *challenge,
98 u_char PasswordHash[MD4_SIGNATURE_SIZE],
101 u_char ZPasswordHash[21];
103 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
104 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
107 dbglog("ChallengeResponse - ZPasswordHash %.*B",
108 sizeof(ZPasswordHash), ZPasswordHash);
111 (void) DesSetkey(ZPasswordHash + 0);
112 DesEncrypt(challenge, response + 0);
113 (void) DesSetkey(ZPasswordHash + 7);
114 DesEncrypt(challenge, response + 8);
115 (void) DesSetkey(ZPasswordHash + 14);
116 DesEncrypt(challenge, response + 16);
119 dbglog("ChallengeResponse - response %.24B", response);
124 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
125 char *username, u_char Challenge[8])
128 SHA1_CTX sha1Context;
129 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
132 /* remove domain from "domain\username" */
133 if ((user = strrchr(username, '\\')) != NULL)
138 SHA1_Init(&sha1Context);
139 SHA1_Update(&sha1Context, PeerChallenge, 16);
140 SHA1_Update(&sha1Context, rchallenge, 16);
141 SHA1_Update(&sha1Context, user, strlen(user));
142 SHA1_Final(sha1Hash, &sha1Context);
144 BCOPY(sha1Hash, Challenge, 8);
148 * Convert the ASCII version of the password to Unicode.
149 * This implicitly supports 8-bit ISO8859/1 characters.
150 * This gives us the little-endian representation, which
151 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
152 * is machine-dependent.)
155 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
159 BZERO(unicode, ascii_len * 2);
160 for (i = 0; i < ascii_len; i++)
161 unicode[i * 2] = (u_char) ascii[i];
165 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
168 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
169 int mdlen = secret_len;
171 int mdlen = secret_len * 8;
175 MD4Init(&md4Context);
176 MD4Update(&md4Context, secret, mdlen);
177 MD4Final(hash, &md4Context);
182 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
183 u_char NTResponse[24])
185 u_char unicodePassword[MAX_NT_PASSWORD * 2];
186 u_char PasswordHash[MD4_SIGNATURE_SIZE];
188 /* Hash the Unicode version of the secret (== password). */
189 ascii2unicode(secret, secret_len, unicodePassword);
190 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
192 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
196 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
197 char *secret, int secret_len, u_char NTResponse[24])
199 u_char unicodePassword[MAX_NT_PASSWORD * 2];
200 u_char PasswordHash[MD4_SIGNATURE_SIZE];
203 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
205 /* Hash the Unicode version of the secret (== password). */
206 ascii2unicode(secret, secret_len, unicodePassword);
207 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
209 ChallengeResponse(Challenge, PasswordHash, NTResponse);
213 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
216 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
217 MS_ChapResponse *response)
220 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
221 u_char PasswordHash[MD4_SIGNATURE_SIZE];
223 /* LANMan password is case insensitive */
224 BZERO(UcasePassword, sizeof(UcasePassword));
225 for (i = 0; i < secret_len; i++)
226 UcasePassword[i] = (u_char)toupper(secret[i]);
227 (void) DesSetkey(UcasePassword + 0);
228 DesEncrypt( StdText, PasswordHash + 0 );
229 (void) DesSetkey(UcasePassword + 7);
230 DesEncrypt( StdText, PasswordHash + 8 );
231 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
237 GenerateAuthenticatorResponse(char *secret, int secret_len,
238 u_char NTResponse[24], u_char PeerChallenge[16],
239 u_char *rchallenge, char *username,
240 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
243 * "Magic" constants used in response generation, from RFC 2759.
245 u_char Magic1[39] = /* "Magic server to client signing constant" */
246 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
247 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
248 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
249 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
250 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
251 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
252 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
253 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
254 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
258 SHA1_CTX sha1Context;
259 u_char unicodePassword[MAX_NT_PASSWORD * 2];
260 u_char PasswordHash[MD4_SIGNATURE_SIZE];
261 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
262 u_char Digest[SHA1_SIGNATURE_SIZE];
265 /* Hash (x2) the Unicode version of the secret (== password). */
266 ascii2unicode(secret, secret_len, unicodePassword);
267 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
268 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
270 SHA1_Init(&sha1Context);
271 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
272 SHA1_Update(&sha1Context, NTResponse, 24);
273 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
274 SHA1_Final(Digest, &sha1Context);
276 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
278 SHA1_Init(&sha1Context);
279 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
280 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
281 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
282 SHA1_Final(Digest, &sha1Context);
284 /* Convert to ASCII hex string. */
285 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
286 sprintf(&authResponse[i * 2], "%02X", Digest[i]);
292 * Set mppe_xxxx_key from the NTPasswordHashHash.
293 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
296 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
298 SHA1_CTX sha1Context;
299 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
301 SHA1_Init(&sha1Context);
302 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
303 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
304 SHA1_Update(&sha1Context, rchallenge, 8);
305 SHA1_Final(Digest, &sha1Context);
307 /* Same key in both directions. */
308 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
309 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
313 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
316 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
318 u_char unicodePassword[MAX_NT_PASSWORD * 2];
319 u_char PasswordHash[MD4_SIGNATURE_SIZE];
320 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
322 /* Hash (x2) the Unicode version of the secret (== password). */
323 ascii2unicode(secret, secret_len, unicodePassword);
324 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
325 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
327 mppe_set_keys(rchallenge, PasswordHashHash);
331 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
334 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
336 SHA1_CTX sha1Context;
337 u_char unicodePassword[MAX_NT_PASSWORD * 2];
338 u_char PasswordHash[MD4_SIGNATURE_SIZE];
339 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
340 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
341 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
344 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
349 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
350 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
351 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
352 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
354 /* "This is the MPPE Master Key" */
356 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
357 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
358 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
359 /* "On the client side, this is the send key; "
360 "on the server side, it is the receive key." */
362 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
363 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
364 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
365 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
366 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
367 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
368 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
369 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
370 0x6b, 0x65, 0x79, 0x2e };
371 /* "On the client side, this is the receive key; "
372 "on the server side, it is the send key." */
374 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
375 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
376 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
377 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
378 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
379 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
380 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
381 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
382 0x6b, 0x65, 0x79, 0x2e };
385 /* Hash (x2) the Unicode version of the secret (== password). */
386 ascii2unicode(secret, secret_len, unicodePassword);
387 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
388 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
390 SHA1_Init(&sha1Context);
391 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
392 SHA1_Update(&sha1Context, NTResponse, 24);
393 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
394 SHA1_Final(MasterKey, &sha1Context);
403 SHA1_Init(&sha1Context);
404 SHA1_Update(&sha1Context, MasterKey, 16);
405 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
406 SHA1_Update(&sha1Context, s, 84);
407 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
408 SHA1_Final(Digest, &sha1Context);
410 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
419 SHA1_Init(&sha1Context);
420 SHA1_Update(&sha1Context, MasterKey, 16);
421 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
422 SHA1_Update(&sha1Context, s, 84);
423 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
424 SHA1_Final(Digest, &sha1Context);
426 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
433 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
434 MS_ChapResponse *response)
437 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
439 BZERO(response, sizeof(*response));
441 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
444 ChapMS_LANMan(rchallenge, secret, secret_len, response);
446 /* preferred method is set by option */
447 response->UseNT[0] = !ms_lanman;
449 response->UseNT[0] = 1;
452 cstate->resp_length = MS_CHAP_RESPONSE_LEN;
455 Set_Start_Key(rchallenge, secret, secret_len);
461 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
462 * is filled in. Call this way when generating a response.
463 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
464 * Call this way when verifying a response (or debugging).
465 * Do not call with PeerChallenge = response->PeerChallenge.
467 * response->PeerChallenge is then used for calculation of the
468 * Authenticator Response.
471 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
472 char *user, char *secret, int secret_len, MS_Chap2Response *response,
473 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator)
476 u_char *p = response->PeerChallenge;
479 BZERO(response, sizeof(*response));
481 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
483 for (i = 0; i < sizeof(response->PeerChallenge); i++)
484 *p++ = (u_char) (drand48() * 0xff);
486 BCOPY(PeerChallenge, response->PeerChallenge,
487 sizeof(response->PeerChallenge));
489 /* Generate the NT-Response */
490 ChapMS2_NT(rchallenge, response->PeerChallenge, user,
491 secret, secret_len, response->NTResp);
493 /* Generate the Authenticator Response. */
494 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
495 response->PeerChallenge, rchallenge,
498 cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
501 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);