2 Unix SMB/CIFS implementation.
4 code to manipulate domain credentials
6 Copyright (C) Andrew Tridgell 1997-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 initialise the credentials state for old-style 64 bit session keys
29 this call is made after the netr_ServerReqChallenge call
31 static void creds_init_64bit(struct creds_CredentialState *creds,
32 const struct netr_Credential *client_challenge,
33 const struct netr_Credential *server_challenge,
34 const struct samr_Password *machine_password)
39 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
40 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
45 ZERO_STRUCT(creds->session_key);
47 des_crypt128(creds->session_key, sum2, machine_password->hash);
49 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
50 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
52 creds->seed = creds->client;
56 initialise the credentials state for ADS-style 128 bit session keys
58 this call is made after the netr_ServerReqChallenge call
60 static void creds_init_128bit(struct creds_CredentialState *creds,
61 const struct netr_Credential *client_challenge,
62 const struct netr_Credential *server_challenge,
63 const struct samr_Password *machine_password)
65 unsigned char zero[4], tmp[16];
67 struct MD5Context md5;
69 ZERO_STRUCT(creds->session_key);
71 memset(zero, 0, sizeof(zero));
73 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
75 MD5Update(&md5, zero, sizeof(zero));
76 MD5Update(&md5, client_challenge->data, 8);
77 MD5Update(&md5, server_challenge->data, 8);
79 hmac_md5_update(tmp, sizeof(tmp), &ctx);
80 hmac_md5_final(creds->session_key, &ctx);
82 creds->client = *client_challenge;
83 creds->server = *server_challenge;
85 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
86 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
88 creds->seed = creds->client;
93 step the credentials to the next element in the chain, updating the
94 current client and server credentials and the seed
96 static void creds_step(struct creds_CredentialState *creds)
98 struct netr_Credential time_cred;
100 DEBUG(5,("\tseed %08x:%08x\n",
101 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
103 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
104 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
106 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
108 des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
110 DEBUG(5,("\tCLIENT %08x:%08x\n",
111 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
113 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
114 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
116 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
117 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
119 des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
121 DEBUG(5,("\tSERVER %08x:%08x\n",
122 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
124 creds->seed = time_cred;
129 DES encrypt a 16 byte password buffer using the session key
131 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
133 struct samr_Password tmp;
134 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
139 DES decrypt a 16 byte password buffer using the session key
141 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
143 struct samr_Password tmp;
144 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
149 ARCFOUR encrypt/decrypt a password buffer using the session key
151 void creds_arcfour_crypt(struct creds_CredentialState *creds, char *data, size_t len)
153 DATA_BLOB session_key = data_blob(creds->session_key, 16);
155 arcfour_crypt_blob(data, len, &session_key);
157 data_blob_free(&session_key);
160 /*****************************************************************
161 The above functions are common to the client and server interface
162 next comes the client specific functions
163 ******************************************************************/
166 initialise the credentials chain and return the first client
169 void creds_client_init(struct creds_CredentialState *creds,
170 const struct netr_Credential *client_challenge,
171 const struct netr_Credential *server_challenge,
172 const struct samr_Password *machine_password,
173 struct netr_Credential *initial_credential,
174 uint32_t negotiate_flags)
176 creds->sequence = time(NULL);
177 creds->negotiate_flags = negotiate_flags;
179 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
180 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
181 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
183 if (negotiate_flags & NETLOGON_NEG_128BIT) {
184 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
186 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
189 dump_data_pw("Session key", creds->session_key, 16);
190 dump_data_pw("Credential ", creds->client.data, 8);
192 *initial_credential = creds->client;
196 step the credentials to the next element in the chain, updating the
197 current client and server credentials and the seed
199 produce the next authenticator in the sequence ready to send to
202 void creds_client_authenticator(struct creds_CredentialState *creds,
203 struct netr_Authenticator *next)
205 creds->sequence += 2;
208 next->cred = creds->client;
209 next->timestamp = creds->sequence;
213 check that a credentials reply from a server is correct
215 BOOL creds_client_check(struct creds_CredentialState *creds,
216 const struct netr_Credential *received_credentials)
218 if (!received_credentials ||
219 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
220 DEBUG(2,("credentials check failed\n"));
227 /*****************************************************************
228 The above functions are common to the client and server interface
229 next comes the server specific functions
230 ******************************************************************/
233 initialise the credentials chain and return the first server
236 void creds_server_init(struct creds_CredentialState *creds,
237 const struct netr_Credential *client_challenge,
238 const struct netr_Credential *server_challenge,
239 const struct samr_Password *machine_password,
240 struct netr_Credential *initial_credential,
241 uint32_t negotiate_flags)
243 if (negotiate_flags & NETLOGON_NEG_128BIT) {
244 creds_init_128bit(creds, client_challenge, server_challenge,
247 creds_init_64bit(creds, client_challenge, server_challenge,
251 *initial_credential = creds->server;
255 check that a credentials reply from a server is correct
257 BOOL creds_server_check(const struct creds_CredentialState *creds,
258 const struct netr_Credential *received_credentials)
260 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
261 DEBUG(2,("credentials check failed\n"));
262 dump_data_pw("client creds", creds->client.data, 8);
263 dump_data_pw("calc creds", received_credentials->data, 8);
269 BOOL creds_server_step_check(struct creds_CredentialState *creds,
270 struct netr_Authenticator *received_authenticator,
271 struct netr_Authenticator *return_authenticator)
273 /* TODO: this may allow the a replay attack on a non-signed
274 connection. Should we check that this is increasing? */
275 creds->sequence = received_authenticator->timestamp;
277 if (creds_server_check(creds, &received_authenticator->cred)) {
278 return_authenticator->cred = creds->server;
279 return_authenticator->timestamp = creds->sequence;
282 ZERO_STRUCTP(return_authenticator);