blob: aea9daca600ae4b63368c1c9667626ac6271a6ce [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3 *
4 * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
5 * http://www.strataware.com/
6 *
7 * All rights reserved.
8 *
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.
17 *
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.
21 */
22
23/*
24 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
25 *
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.
30 *
31 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
32 */
33
34#define RCSID "$Id: chap_ms.c,v 1.1 2008-08-04 06:11:51 winfred Exp $"
35
36#ifdef CHAPMS
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/types.h>
43#include <sys/time.h>
44#include <unistd.h>
45#ifdef HAVE_CRYPT_H
46#include <crypt.h>
47#endif
48
49#include "pppd.h"
50#include "chap.h"
51#include "chap_ms.h"
52#include <openssl/sha.h>
53#include "fsm.h"
54#include "lcp.h"
55#ifdef MPPE
56#include "mppe.h"
57#endif
58#include "extra_crypto.h"
59
60static const char rcsid[] = RCSID;
61
62typedef struct {
63 u_char LANManResp[24];
64 u_char NTResp[24];
65 u_char UseNT; /* If 1, ignore the LANMan response field */
66} MS_ChapResponse;
67/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
68 in case this struct gets padded. */
69
70typedef struct {
71 u_char PeerChallenge[16];
72 u_char Reserved[8];
73 u_char NTResp[24];
74 u_char Flags;
75} MS_ChapResponse_v2;
76
77static void ChallengeResponse __P((u_char *, u_char *, u_char *));
78static void ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *));
79#ifdef MSLANMAN
80static void ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *));
81#endif
82
83#ifdef MSLANMAN
84bool ms_lanman = 0; /* Use LanMan password instead of NT */
85 /* Has meaning only with MS-CHAP challenges */
86#endif
87
88static void
89ChallengeResponse(challenge, pwHash, response)
90 u_char *challenge; /* IN 8 octets */
91 u_char *pwHash; /* IN 16 octets */
92 u_char *response; /* OUT 24 octets */
93{
94 char ZPasswordHash[21];
95
96 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
97 BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
98
99
100 DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
101 DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
102 DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
103
104}
105
106
107static void
108ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
109 char *rchallenge;
110 int rchallenge_len;
111 char *secret;
112 int secret_len;
113 MS_ChapResponse *response;
114{
115 u_char hash[MD4_SIGNATURE_SIZE];
116
117 NtPasswordHash(secret, secret_len, hash);
118 ChallengeResponse(rchallenge, hash, response->NTResp);
119}
120
121#ifdef MSLANMAN
122static void
123ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
124 char *rchallenge;
125 int rchallenge_len;
126 char *secret;
127 int secret_len;
128 MS_ChapResponse *response;
129{
130 u_char PasswordHash[MD4_SIGNATURE_SIZE];
131
132 LmPasswordHash(secret, secret_len, PasswordHash);
133 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
134}
135#endif
136
137void
138ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
139 chap_state *cstate;
140 char *rchallenge;
141 int rchallenge_len;
142 char *secret;
143 int secret_len;
144{
145 MS_ChapResponse response;
146
147 BZERO(&response, sizeof(response));
148
149 /* Calculate both always */
150 ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
151
152#ifdef MSLANMAN
153 ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
154
155 /* prefered method is set by option */
156 response.UseNT = !ms_lanman;
157#else
158 response.UseNT = 1;
159#endif
160
161#ifdef MPPE
162 mppe_gen_master_key(secret, secret_len, rchallenge);
163#endif
164 BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
165 cstate->resp_length = MS_CHAP_RESPONSE_LEN;
166}
167
168int
169ChapMS_Resp(cstate, secret, secret_len, remmd)
170 chap_state *cstate;
171 char *secret;
172 int secret_len;
173 u_char *remmd;
174{
175 MS_ChapResponse local;
176 MS_ChapResponse *response = (MS_ChapResponse *)remmd;
177 int i;
178
179 BZERO(&local, sizeof(response));
180
181 if(response->UseNT)
182 {
183 ChapMS_NT(cstate->challenge,cstate->chal_len, secret, secret_len, &local);
184 i = memcmp(local.NTResp, response->NTResp, sizeof(local.NTResp));
185
186#ifdef MPPE
187 if(i == 0)
188 mppe_gen_master_key(secret, secret_len, cstate->challenge);
189#endif
190 return(i);
191 }
192
193#ifdef MSLANMAN
194 ChapMS_LANMan(cstate->challenge, cstate->chal_len, secret, secret_len,
195 &local);
196 if(memcmp(local.LANManResp, response->LANManResp,
197 sizeof(local.LANManResp)) == 0) {
198#ifdef MPPE
199 mppe_gen_master_key(secret, secret_len, cstate->challenge);
200#endif
201 return(0);
202 }
203#endif /* MSLANMAN */
204 return(1);
205}
206
207void
208ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge)
209 char *PeerChallenge;
210 char *AuthenticatorChallenge;
211 char *UserName;
212 char *Challenge;
213{
214 SHA_CTX Context;
215 u_char Digest[SHA_DIGEST_LENGTH];
216 char *username;
217
218 if((username = strrchr(UserName, '\\')) != (char *)NULL)
219 ++username;
220 else
221 username = UserName;
222 SHA1_Init(&Context);
223 SHA1_Update(&Context, PeerChallenge, 16);
224 SHA1_Update(&Context, AuthenticatorChallenge, 16);
225 SHA1_Update(&Context, username, strlen(username));
226 SHA1_Final(Digest, &Context);
227 BCOPY(Digest, Challenge, 8);
228}
229
230void
231ChapMS_v2(cstate, AuthenticatorChallenge, AuthenticatorChallengeLen, Password, PasswordLen)
232 chap_state *cstate;
233 char *AuthenticatorChallenge;
234 int AuthenticatorChallengeLen;
235 char *Password;
236 int PasswordLen;
237{
238 u_char Challenge[8];
239 u_char PasswordHash[MD4_SIGNATURE_SIZE];
240 MS_ChapResponse_v2 response;
241
242 BZERO(&response, sizeof(response));
243 ChapGenChallenge(cstate);
244 BCOPY(cstate->challenge, response.PeerChallenge,
245 sizeof(response.PeerChallenge));
246 ChallengeHash(response.PeerChallenge, AuthenticatorChallenge,
247 cstate->resp_name, Challenge);
248 NtPasswordHash(Password, PasswordLen, PasswordHash);
249 ChallengeResponse(Challenge, PasswordHash, response.NTResp);
250 BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
251 cstate->resp_length = MS_CHAP_RESPONSE_LEN;
252#ifdef MPPE
253 mppe_gen_master_key_v2(Password, PasswordLen, response.NTResp, 0);
254#endif
255}
256
257int
258ChapMS_v2_Resp(cstate, Password, PasswordLen, remmd, UserName)
259 chap_state *cstate;
260 char *Password;
261 int PasswordLen;
262 u_char *remmd;
263 char *UserName;
264{
265 u_char Challenge[8];
266 u_char PasswordHash[MD4_SIGNATURE_SIZE];
267 MS_ChapResponse_v2 response, response1;
268 int i;
269
270 BCOPY(remmd, &response, MS_CHAP_RESPONSE_LEN);
271 ChallengeHash(response.PeerChallenge,cstate->challenge,UserName,Challenge);
272 NtPasswordHash(Password, PasswordLen, PasswordHash);
273 ChallengeResponse(Challenge, PasswordHash, response1.NTResp);
274 i = memcmp(response.NTResp, response1.NTResp, sizeof(response.NTResp));
275#ifdef MPPE
276 if(i == 0)
277 mppe_gen_master_key_v2(Password, PasswordLen, response1.NTResp, 1);
278#endif
279 return(i);
280}
281
282void
283ChapMS_v2_Auth(cstate, Password, PasswordLen, remmd, UserName)
284 chap_state *cstate;
285 char *Password;
286 int PasswordLen;
287 u_char *remmd;
288 char *UserName;
289{
290 u_char PasswordHash[MD4_SIGNATURE_SIZE];
291 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
292 u_char Challenge[8];
293 static char Magic1[] = "Magic server to client signing constant";
294 static char Magic2[] = "Pad to make it do more than one iteration";
295
296 SHA_CTX Context;
297 u_char Digest[SHA_DIGEST_LENGTH];
298 MS_ChapResponse_v2 *response = (MS_ChapResponse_v2 *)remmd;
299 char StrResponse[SHA_DIGEST_LENGTH * 2 + 3], *s;
300 int i;
301 static char HexDigs[] = "0123456789ABCDEF";
302
303 NtPasswordHash(Password, PasswordLen, PasswordHash);
304 md4(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
305
306 SHA1_Init(&Context);
307 SHA1_Update(&Context, PasswordHashHash, 16);
308 SHA1_Update(&Context, response->NTResp, 24);
309 SHA1_Update(&Context, Magic1, sizeof(Magic1) - 1);
310 SHA1_Final(Digest, &Context);
311
312 ChallengeHash(response->PeerChallenge,cstate->challenge,UserName,Challenge);
313
314 SHA1_Init(&Context);
315 SHA1_Update(&Context, Digest, SHA_DIGEST_LENGTH);
316 SHA1_Update(&Context, Challenge, 8);
317 SHA1_Update(&Context, Magic2, sizeof(Magic2) - 1);
318 SHA1_Final(Digest, &Context);
319 s = stpcpy(StrResponse, "S=");
320 for(i = 0; i < SHA_DIGEST_LENGTH; ++i) {
321 *s++ = HexDigs[Digest[i] >> 4];
322 *s++ = HexDigs[Digest[i] & 0x0F];
323 }
324 *s = '\0';
325 BCOPY(StrResponse, cstate->response, sizeof(StrResponse));
326 cstate->resp_length = sizeof(StrResponse) - 1;
327}
328
329/*
330 * functions called from config options
331 */
332int
333reqchapms(char **argv)
334{
335 lcp_wantoptions[0].neg_chap = 1;
336 lcp_wantoptions[0].use_chapms = 1;
337 auth_required = 1;
338
339 return 1;
340}
341
342int
343nochapms(char **argv)
344{
345 lcp_wantoptions[0].use_chapms = 0;
346 return 1;
347}
348
349int
350reqchapms_v2(char **argv)
351{
352 lcp_wantoptions[0].neg_chap = 1;
353 lcp_wantoptions[0].use_chapms_v2 = 1;
354 auth_required = 1;
355
356 return 1;
357}
358
359int
360nochapms_v2(char **argv)
361{
362 lcp_wantoptions[0].use_chapms_v2 = 0;
363 return 1;
364}
365
366#endif /* CHAPMS */