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, see <http://www.gnu.org/licenses/>.
23 /****************************************************************************
24 Represent a credential as a string.
25 ****************************************************************************/
27 char *credstr(const unsigned char *cred)
30 result = talloc_asprintf(talloc_tos(),
31 "%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 SMB_ASSERT(result != NULL);
38 /****************************************************************************
39 Setup the session key and the client and server creds in dc.
40 ADS-style 128 bit session keys.
41 Used by both client and server creds setup.
42 ****************************************************************************/
44 static void creds_init_128(struct dcinfo *dc,
45 const DOM_CHAL *clnt_chal_in,
46 const DOM_CHAL *srv_chal_in,
47 const unsigned char mach_pw[16])
49 unsigned char zero[4], tmp[16];
51 struct MD5Context md5;
53 /* Just in case this isn't already there */
54 memcpy(dc->mach_pw, mach_pw, 16);
56 ZERO_STRUCT(dc->sess_key);
58 memset(zero, 0, sizeof(zero));
60 hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
62 MD5Update(&md5, zero, sizeof(zero));
63 MD5Update(&md5, clnt_chal_in->data, 8);
64 MD5Update(&md5, srv_chal_in->data, 8);
66 hmac_md5_update(tmp, sizeof(tmp), &ctx);
67 hmac_md5_final(dc->sess_key, &ctx);
70 DEBUG(5,("creds_init_128\n"));
71 DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
72 DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
73 dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
75 /* Generate the next client and server creds. */
77 des_crypt112(dc->clnt_chal.data, /* output */
78 clnt_chal_in->data, /* input */
79 dc->sess_key, /* input */
82 des_crypt112(dc->srv_chal.data, /* output */
83 srv_chal_in->data, /* input */
84 dc->sess_key, /* input */
87 /* Seed is the client chal. */
88 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
91 /****************************************************************************
92 Setup the session key and the client and server creds in dc.
93 Used by both client and server creds setup.
94 ****************************************************************************/
96 static void creds_init_64(struct dcinfo *dc,
97 const DOM_CHAL *clnt_chal_in,
98 const DOM_CHAL *srv_chal_in,
99 const unsigned char mach_pw[16])
102 unsigned char sum2[8];
104 /* Just in case this isn't already there */
105 if (dc->mach_pw != mach_pw) {
106 memcpy(dc->mach_pw, mach_pw, 16);
109 sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
110 sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
112 SIVAL(sum2,0,sum[0]);
113 SIVAL(sum2,4,sum[1]);
115 ZERO_STRUCT(dc->sess_key);
117 des_crypt128(dc->sess_key, sum2, dc->mach_pw);
120 DEBUG(5,("creds_init_64\n"));
121 DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
122 DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
123 DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
124 DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
126 /* Generate the next client and server creds. */
128 des_crypt112(dc->clnt_chal.data, /* output */
129 clnt_chal_in->data, /* input */
130 dc->sess_key, /* input */
133 des_crypt112(dc->srv_chal.data, /* output */
134 srv_chal_in->data, /* input */
135 dc->sess_key, /* input */
138 /* Seed is the client chal. */
139 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
142 /****************************************************************************
143 Utility function to step credential chain one forward.
144 Deliberately doesn't update the seed. See reseed comment below.
145 ****************************************************************************/
147 static void creds_step(struct dcinfo *dc)
151 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
153 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
155 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
156 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
158 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
160 des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
162 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
164 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
165 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
167 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
169 des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
171 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
174 /****************************************************************************
175 Create a server credential struct.
176 ****************************************************************************/
178 void creds_server_init(uint32 neg_flags,
182 const unsigned char mach_pw[16],
183 DOM_CHAL *init_chal_out)
185 DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
186 DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
187 DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
188 dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
190 /* Generate the session key and the next client and server creds. */
191 if (neg_flags & NETLOGON_NEG_128BIT) {
203 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
205 DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
206 DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
207 DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
209 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
212 /****************************************************************************
213 Check a credential sent by the client.
214 ****************************************************************************/
216 bool creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
218 if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
219 DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
220 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
221 DEBUG(2,("creds_server_check: credentials check failed.\n"));
224 DEBUG(10,("creds_server_check: credentials check OK.\n"));
228 bool netlogon_creds_server_check(const struct dcinfo *dc,
229 const struct netr_Credential *rcv_cli_chal_in)
231 if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
232 DEBUG(5,("netlogon_creds_server_check: challenge : %s\n",
233 credstr(rcv_cli_chal_in->data)));
234 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
235 DEBUG(2,("netlogon_creds_server_check: credentials check failed.\n"));
239 DEBUG(10,("netlogon_creds_server_check: credentials check OK.\n"));
243 /****************************************************************************
244 Replace current seed chal. Internal function - due to split server step below.
245 ****************************************************************************/
247 static void creds_reseed(struct dcinfo *dc)
251 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
252 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
254 dc->seed_chal = time_chal;
256 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
259 /****************************************************************************
260 Step the server credential chain one forward.
261 ****************************************************************************/
263 bool creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
266 struct dcinfo tmp_dc = *dc;
268 /* Do all operations on a temporary copy of the dc,
269 which we throw away if the checks fail. */
271 tmp_dc.sequence = received_cred->timestamp.time;
275 /* Create the outgoing credentials */
276 cred_out->timestamp.time = tmp_dc.sequence + 1;
277 cred_out->challenge = tmp_dc.srv_chal;
279 creds_reseed(&tmp_dc);
281 ret = creds_server_check(&tmp_dc, &received_cred->challenge);
286 /* creds step succeeded - replace the current creds. */
291 bool netlogon_creds_server_step(struct dcinfo *dc,
292 const struct netr_Authenticator *received_cred,
293 struct netr_Authenticator *cred_out)
296 struct dcinfo tmp_dc = *dc;
298 /* Do all operations on a temporary copy of the dc,
299 which we throw away if the checks fail. */
301 tmp_dc.sequence = received_cred->timestamp;
305 /* Create the outgoing credentials */
306 cred_out->timestamp = tmp_dc.sequence + 1;
307 memcpy(&cred_out->cred, &tmp_dc.srv_chal, sizeof(cred_out->cred));
309 creds_reseed(&tmp_dc);
311 ret = netlogon_creds_server_check(&tmp_dc, &received_cred->cred);
316 /* creds step succeeded - replace the current creds. */
321 /****************************************************************************
322 Create a client credential struct.
323 ****************************************************************************/
325 void creds_client_init(uint32 neg_flags,
329 const unsigned char mach_pw[16],
330 DOM_CHAL *init_chal_out)
332 dc->sequence = time(NULL);
334 DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
335 DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
336 DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
337 dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
339 /* Generate the session key and the next client and server creds. */
340 if (neg_flags & NETLOGON_NEG_128BIT) {
352 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
354 DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
355 DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
356 DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
358 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
361 /****************************************************************************
362 Check a credential returned by the server.
363 ****************************************************************************/
365 bool creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
367 if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
368 DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
369 DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
370 DEBUG(0,("creds_client_check: credentials check failed.\n"));
373 DEBUG(10,("creds_client_check: credentials check OK.\n"));
377 bool netlogon_creds_client_check(const struct dcinfo *dc,
378 const struct netr_Credential *rcv_srv_chal_in)
380 if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data,
381 sizeof(dc->srv_chal.data))) {
383 DEBUG(0,("netlogon_creds_client_check: credentials check failed.\n"));
384 DEBUGADD(5,("netlogon_creds_client_check: challenge : %s\n",
385 credstr(rcv_srv_chal_in->data)));
386 DEBUGADD(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
390 DEBUG(10,("netlogon_creds_client_check: credentials check OK.\n"));
396 /****************************************************************************
397 Step the client credentials to the next element in the chain, updating the
398 current client and server credentials and the seed
399 produce the next authenticator in the sequence ready to send to
401 ****************************************************************************/
403 void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
409 next_cred_out->challenge = dc->clnt_chal;
410 next_cred_out->timestamp.time = dc->sequence;
413 void netlogon_creds_client_step(struct dcinfo *dc,
414 struct netr_Authenticator *next_cred_out)
420 memcpy(&next_cred_out->cred.data, &dc->clnt_chal.data,
421 sizeof(next_cred_out->cred.data));
422 next_cred_out->timestamp = dc->sequence;