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 slprintf(buf, sizeof(buf) - 1, "%02X%02X%02X%02X%02X%02X%02X%02X",
31 cred[0], cred[1], cred[2], cred[3],
32 cred[4], cred[5], cred[6], cred[7]);
36 /****************************************************************************
37 Setup the session key and the client and server creds in dc.
38 ADS-style 128 bit session keys.
39 Used by both client and server creds setup.
40 ****************************************************************************/
42 static void creds_init_128(struct dcinfo *dc,
43 const DOM_CHAL *clnt_chal_in,
44 const DOM_CHAL *srv_chal_in,
45 const unsigned char mach_pw[16])
47 unsigned char zero[4], tmp[16];
49 struct MD5Context md5;
51 /* Just in case this isn't already there */
52 memcpy(dc->mach_pw, mach_pw, 16);
54 ZERO_STRUCT(dc->sess_key);
56 memset(zero, 0, sizeof(zero));
58 hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
60 MD5Update(&md5, zero, sizeof(zero));
61 MD5Update(&md5, clnt_chal_in->data, 8);
62 MD5Update(&md5, srv_chal_in->data, 8);
64 hmac_md5_update(tmp, sizeof(tmp), &ctx);
65 hmac_md5_final(dc->sess_key, &ctx);
68 DEBUG(5,("creds_init_128\n"));
69 DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
70 DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
71 dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
73 /* Generate the next client and server creds. */
75 des_crypt112(dc->clnt_chal.data, /* output */
76 clnt_chal_in->data, /* input */
77 dc->sess_key, /* input */
80 des_crypt112(dc->srv_chal.data, /* output */
81 srv_chal_in->data, /* input */
82 dc->sess_key, /* input */
85 /* Seed is the client chal. */
86 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
89 /****************************************************************************
90 Setup the session key and the client and server creds in dc.
91 Used by both client and server creds setup.
92 ****************************************************************************/
94 static void creds_init_64(struct dcinfo *dc,
95 const DOM_CHAL *clnt_chal_in,
96 const DOM_CHAL *srv_chal_in,
97 const unsigned char mach_pw[16])
100 unsigned char sum2[8];
102 /* Just in case this isn't already there */
103 if (dc->mach_pw != mach_pw) {
104 memcpy(dc->mach_pw, mach_pw, 16);
107 sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
108 sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
110 SIVAL(sum2,0,sum[0]);
111 SIVAL(sum2,4,sum[1]);
113 ZERO_STRUCT(dc->sess_key);
115 des_crypt128(dc->sess_key, sum2, dc->mach_pw);
118 DEBUG(5,("creds_init_64\n"));
119 DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
120 DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
121 DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
122 DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
124 /* Generate the next client and server creds. */
126 des_crypt112(dc->clnt_chal.data, /* output */
127 clnt_chal_in->data, /* input */
128 dc->sess_key, /* input */
131 des_crypt112(dc->srv_chal.data, /* output */
132 srv_chal_in->data, /* input */
133 dc->sess_key, /* input */
136 /* Seed is the client chal. */
137 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
140 /****************************************************************************
141 Utility function to step credential chain one forward.
142 Deliberately doesn't update the seed. See reseed comment below.
143 ****************************************************************************/
145 static void creds_step(struct dcinfo *dc)
149 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
151 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
153 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
154 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
156 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
158 des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
160 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
162 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
163 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
165 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
167 des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
169 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
172 /****************************************************************************
173 Create a server credential struct.
174 ****************************************************************************/
176 void creds_server_init(uint32 neg_flags,
180 const unsigned char mach_pw[16],
181 DOM_CHAL *init_chal_out)
183 DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
184 DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
185 DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
186 dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
188 /* Generate the session key and the next client and server creds. */
189 if (neg_flags & NETLOGON_NEG_128BIT) {
201 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
203 DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
204 DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
205 DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
207 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
210 /****************************************************************************
211 Check a credential sent by the client.
212 ****************************************************************************/
214 BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
216 if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
217 DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
218 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
219 DEBUG(2,("creds_server_check: credentials check failed.\n"));
222 DEBUG(10,("creds_server_check: credentials check OK.\n"));
226 /****************************************************************************
227 Replace current seed chal. Internal function - due to split server step below.
228 ****************************************************************************/
230 static void creds_reseed(struct dcinfo *dc)
234 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
235 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
237 dc->seed_chal = time_chal;
239 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
242 /****************************************************************************
243 Step the server credential chain one forward.
244 ****************************************************************************/
246 BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
249 struct dcinfo tmp_dc = *dc;
251 /* Do all operations on a temporary copy of the dc,
252 which we throw away if the checks fail. */
254 tmp_dc.sequence = received_cred->timestamp.time;
258 /* Create the outgoing credentials */
259 cred_out->timestamp.time = tmp_dc.sequence + 1;
260 cred_out->challenge = tmp_dc.srv_chal;
262 creds_reseed(&tmp_dc);
264 ret = creds_server_check(&tmp_dc, &received_cred->challenge);
269 /* creds step succeeded - replace the current creds. */
274 /****************************************************************************
275 Create a client credential struct.
276 ****************************************************************************/
278 void creds_client_init(uint32 neg_flags,
282 const unsigned char mach_pw[16],
283 DOM_CHAL *init_chal_out)
285 dc->sequence = time(NULL);
287 DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
288 DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
289 DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
290 dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
292 /* Generate the session key and the next client and server creds. */
293 if (neg_flags & NETLOGON_NEG_128BIT) {
305 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
307 DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
308 DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
309 DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
311 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
314 /****************************************************************************
315 Check a credential returned by the server.
316 ****************************************************************************/
318 BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
320 if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
321 DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
322 DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
323 DEBUG(0,("creds_client_check: credentials check failed.\n"));
326 DEBUG(10,("creds_client_check: credentials check OK.\n"));
330 /****************************************************************************
331 Step the client credentials to the next element in the chain, updating the
332 current client and server credentials and the seed
333 produce the next authenticator in the sequence ready to send to
335 ****************************************************************************/
337 void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
343 next_cred_out->challenge = dc->clnt_chal;
344 next_cred_out->timestamp.time = dc->sequence;