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.
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 3 of the License, or
10 (at your option) any later version.
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.
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.
24 /****************************************************************************
25 Represent a credential as a string.
26 ****************************************************************************/
28 char *credstr(const unsigned char *cred)
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]);
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 ****************************************************************************/
43 static 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])
48 unsigned char zero[4], tmp[16];
50 struct MD5Context md5;
52 /* Just in case this isn't already there */
53 memcpy(dc->mach_pw, mach_pw, 16);
55 ZERO_STRUCT(dc->sess_key);
57 memset(zero, 0, sizeof(zero));
59 hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
61 MD5Update(&md5, zero, sizeof(zero));
62 MD5Update(&md5, clnt_chal_in->data, 8);
63 MD5Update(&md5, srv_chal_in->data, 8);
65 hmac_md5_update(tmp, sizeof(tmp), &ctx);
66 hmac_md5_final(dc->sess_key, &ctx);
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);
74 /* Generate the next client and server creds. */
76 des_crypt112(dc->clnt_chal.data, /* output */
77 clnt_chal_in->data, /* input */
78 dc->sess_key, /* input */
81 des_crypt112(dc->srv_chal.data, /* output */
82 srv_chal_in->data, /* input */
83 dc->sess_key, /* input */
86 /* Seed is the client chal. */
87 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
90 /****************************************************************************
91 Setup the session key and the client and server creds in dc.
92 Used by both client and server creds setup.
93 ****************************************************************************/
95 static 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])
101 unsigned char sum2[8];
103 /* Just in case this isn't already there */
104 if (dc->mach_pw != mach_pw) {
105 memcpy(dc->mach_pw, mach_pw, 16);
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);
111 SIVAL(sum2,0,sum[0]);
112 SIVAL(sum2,4,sum[1]);
114 ZERO_STRUCT(dc->sess_key);
116 des_crypt128(dc->sess_key, sum2, dc->mach_pw);
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)));
125 /* Generate the next client and server creds. */
127 des_crypt112(dc->clnt_chal.data, /* output */
128 clnt_chal_in->data, /* input */
129 dc->sess_key, /* input */
132 des_crypt112(dc->srv_chal.data, /* output */
133 srv_chal_in->data, /* input */
134 dc->sess_key, /* input */
137 /* Seed is the client chal. */
138 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
141 /****************************************************************************
142 Utility function to step credential chain one forward.
143 Deliberately doesn't update the seed. See reseed comment below.
144 ****************************************************************************/
146 static void creds_step(struct dcinfo *dc)
150 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
152 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
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));
157 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
159 des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
161 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
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));
166 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
168 des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
170 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
173 /****************************************************************************
174 Create a server credential struct.
175 ****************************************************************************/
177 void creds_server_init(uint32 neg_flags,
181 const unsigned char mach_pw[16],
182 DOM_CHAL *init_chal_out)
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);
189 /* Generate the session key and the next client and server creds. */
190 if (neg_flags & NETLOGON_NEG_128BIT) {
202 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
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) ));
208 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
211 /****************************************************************************
212 Check a credential sent by the client.
213 ****************************************************************************/
215 BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
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"));
223 DEBUG(10,("creds_server_check: credentials check OK.\n"));
227 /****************************************************************************
228 Replace current seed chal. Internal function - due to split server step below.
229 ****************************************************************************/
231 static void creds_reseed(struct dcinfo *dc)
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));
238 dc->seed_chal = time_chal;
240 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
243 /****************************************************************************
244 Step the server credential chain one forward.
245 ****************************************************************************/
247 BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
250 struct dcinfo tmp_dc = *dc;
252 /* Do all operations on a temporary copy of the dc,
253 which we throw away if the checks fail. */
255 tmp_dc.sequence = received_cred->timestamp.time;
259 /* Create the outgoing credentials */
260 cred_out->timestamp.time = tmp_dc.sequence + 1;
261 cred_out->challenge = tmp_dc.srv_chal;
263 creds_reseed(&tmp_dc);
265 ret = creds_server_check(&tmp_dc, &received_cred->challenge);
270 /* creds step succeeded - replace the current creds. */
275 /****************************************************************************
276 Create a client credential struct.
277 ****************************************************************************/
279 void creds_client_init(uint32 neg_flags,
283 const unsigned char mach_pw[16],
284 DOM_CHAL *init_chal_out)
286 dc->sequence = time(NULL);
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);
293 /* Generate the session key and the next client and server creds. */
294 if (neg_flags & NETLOGON_NEG_128BIT) {
306 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
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) ));
312 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
315 /****************************************************************************
316 Check a credential returned by the server.
317 ****************************************************************************/
319 BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
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"));
327 DEBUG(10,("creds_client_check: credentials check OK.\n"));
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
336 ****************************************************************************/
338 void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
344 next_cred_out->challenge = dc->clnt_chal;
345 next_cred_out->timestamp.time = dc->sequence;