source: branches/samba-3.0/source/libsmb/credentials.c@ 1002

Last change on this file since 1002 was 26, checked in by Paul Smedley, 18 years ago

Updated source to 3.0.25rc1

File size: 11.6 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 code to manipulate domain credentials
4 Copyright (C) Andrew Tridgell 1997-1998
5 Largely rewritten by Jeremy Allison 2005.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23
24/****************************************************************************
25 Represent a credential as a string.
26****************************************************************************/
27
28char *credstr(const unsigned char *cred)
29{
30 static fstring buf;
31 slprintf(buf, sizeof(buf) - 1, "%02X%02X%02X%02X%02X%02X%02X%02X",
32 cred[0], cred[1], cred[2], cred[3],
33 cred[4], cred[5], cred[6], cred[7]);
34 return buf;
35}
36
37/****************************************************************************
38 Setup the session key and the client and server creds in dc.
39 ADS-style 128 bit session keys.
40 Used by both client and server creds setup.
41****************************************************************************/
42
43static void creds_init_128(struct dcinfo *dc,
44 const DOM_CHAL *clnt_chal_in,
45 const DOM_CHAL *srv_chal_in,
46 const unsigned char mach_pw[16])
47{
48 unsigned char zero[4], tmp[16];
49 HMACMD5Context ctx;
50 struct MD5Context md5;
51
52 /* Just in case this isn't already there */
53 memcpy(dc->mach_pw, mach_pw, 16);
54
55 ZERO_STRUCT(dc->sess_key);
56
57 memset(zero, 0, sizeof(zero));
58
59 hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
60 MD5Init(&md5);
61 MD5Update(&md5, zero, sizeof(zero));
62 MD5Update(&md5, clnt_chal_in->data, 8);
63 MD5Update(&md5, srv_chal_in->data, 8);
64 MD5Final(tmp, &md5);
65 hmac_md5_update(tmp, sizeof(tmp), &ctx);
66 hmac_md5_final(dc->sess_key, &ctx);
67
68 /* debug output */
69 DEBUG(5,("creds_init_128\n"));
70 DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
71 DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
72 dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
73
74 /* Generate the next client and server creds. */
75
76 des_crypt112(dc->clnt_chal.data, /* output */
77 clnt_chal_in->data, /* input */
78 dc->sess_key, /* input */
79 1);
80
81 des_crypt112(dc->srv_chal.data, /* output */
82 srv_chal_in->data, /* input */
83 dc->sess_key, /* input */
84 1);
85
86 /* Seed is the client chal. */
87 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
88}
89
90/****************************************************************************
91 Setup the session key and the client and server creds in dc.
92 Used by both client and server creds setup.
93****************************************************************************/
94
95static void creds_init_64(struct dcinfo *dc,
96 const DOM_CHAL *clnt_chal_in,
97 const DOM_CHAL *srv_chal_in,
98 const unsigned char mach_pw[16])
99{
100 uint32 sum[2];
101 unsigned char sum2[8];
102
103 /* Just in case this isn't already there */
104 if (dc->mach_pw != mach_pw) {
105 memcpy(dc->mach_pw, mach_pw, 16);
106 }
107
108 sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
109 sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
110
111 SIVAL(sum2,0,sum[0]);
112 SIVAL(sum2,4,sum[1]);
113
114 ZERO_STRUCT(dc->sess_key);
115
116 des_crypt128(dc->sess_key, sum2, dc->mach_pw);
117
118 /* debug output */
119 DEBUG(5,("creds_init_64\n"));
120 DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
121 DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
122 DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
123 DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
124
125 /* Generate the next client and server creds. */
126
127 des_crypt112(dc->clnt_chal.data, /* output */
128 clnt_chal_in->data, /* input */
129 dc->sess_key, /* input */
130 1);
131
132 des_crypt112(dc->srv_chal.data, /* output */
133 srv_chal_in->data, /* input */
134 dc->sess_key, /* input */
135 1);
136
137 /* Seed is the client chal. */
138 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
139}
140
141/****************************************************************************
142 Utility function to step credential chain one forward.
143 Deliberately doesn't update the seed. See reseed comment below.
144****************************************************************************/
145
146static void creds_step(struct dcinfo *dc)
147{
148 DOM_CHAL time_chal;
149
150 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
151
152 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
153
154 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
155 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
156
157 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
158
159 des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
160
161 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
162
163 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
164 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
165
166 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
167
168 des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
169
170 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
171}
172
173/****************************************************************************
174 Create a server credential struct.
175****************************************************************************/
176
177void creds_server_init(uint32 neg_flags,
178 struct dcinfo *dc,
179 DOM_CHAL *clnt_chal,
180 DOM_CHAL *srv_chal,
181 const unsigned char mach_pw[16],
182 DOM_CHAL *init_chal_out)
183{
184 DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
185 DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
186 DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
187 dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
188
189 /* Generate the session key and the next client and server creds. */
190 if (neg_flags & NETLOGON_NEG_128BIT) {
191 creds_init_128(dc,
192 clnt_chal,
193 srv_chal,
194 mach_pw);
195 } else {
196 creds_init_64(dc,
197 clnt_chal,
198 srv_chal,
199 mach_pw);
200 }
201
202 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
203
204 DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
205 DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
206 DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
207
208 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
209}
210
211/****************************************************************************
212 Check a credential sent by the client.
213****************************************************************************/
214
215BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
216{
217 if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
218 DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
219 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
220 DEBUG(2,("creds_server_check: credentials check failed.\n"));
221 return False;
222 }
223 DEBUG(10,("creds_server_check: credentials check OK.\n"));
224 return True;
225}
226
227/****************************************************************************
228 Replace current seed chal. Internal function - due to split server step below.
229****************************************************************************/
230
231static void creds_reseed(struct dcinfo *dc)
232{
233 DOM_CHAL time_chal;
234
235 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
236 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
237
238 dc->seed_chal = time_chal;
239
240 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
241}
242
243/****************************************************************************
244 Step the server credential chain one forward.
245****************************************************************************/
246
247BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
248{
249 BOOL ret;
250 struct dcinfo tmp_dc = *dc;
251
252 /* Do all operations on a temporary copy of the dc,
253 which we throw away if the checks fail. */
254
255 tmp_dc.sequence = received_cred->timestamp.time;
256
257 creds_step(&tmp_dc);
258
259 /* Create the outgoing credentials */
260 cred_out->timestamp.time = tmp_dc.sequence + 1;
261 cred_out->challenge = tmp_dc.srv_chal;
262
263 creds_reseed(&tmp_dc);
264
265 ret = creds_server_check(&tmp_dc, &received_cred->challenge);
266 if (!ret) {
267 return False;
268 }
269
270 /* creds step succeeded - replace the current creds. */
271 *dc = tmp_dc;
272 return True;
273}
274
275/****************************************************************************
276 Create a client credential struct.
277****************************************************************************/
278
279void creds_client_init(uint32 neg_flags,
280 struct dcinfo *dc,
281 DOM_CHAL *clnt_chal,
282 DOM_CHAL *srv_chal,
283 const unsigned char mach_pw[16],
284 DOM_CHAL *init_chal_out)
285{
286 dc->sequence = time(NULL);
287
288 DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
289 DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
290 DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
291 dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
292
293 /* Generate the session key and the next client and server creds. */
294 if (neg_flags & NETLOGON_NEG_128BIT) {
295 creds_init_128(dc,
296 clnt_chal,
297 srv_chal,
298 mach_pw);
299 } else {
300 creds_init_64(dc,
301 clnt_chal,
302 srv_chal,
303 mach_pw);
304 }
305
306 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
307
308 DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
309 DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
310 DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
311
312 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
313}
314
315/****************************************************************************
316 Check a credential returned by the server.
317****************************************************************************/
318
319BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
320{
321 if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
322 DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
323 DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
324 DEBUG(0,("creds_client_check: credentials check failed.\n"));
325 return False;
326 }
327 DEBUG(10,("creds_client_check: credentials check OK.\n"));
328 return True;
329}
330
331/****************************************************************************
332 Step the client credentials to the next element in the chain, updating the
333 current client and server credentials and the seed
334 produce the next authenticator in the sequence ready to send to
335 the server
336****************************************************************************/
337
338void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
339{
340 dc->sequence += 2;
341 creds_step(dc);
342 creds_reseed(dc);
343
344 next_cred_out->challenge = dc->clnt_chal;
345 next_cred_out->timestamp.time = dc->sequence;
346}
Note: See TracBrowser for help on using the repository browser.