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.
25 #include "system/time.h"
26 #include "auth/auth.h"
27 #include "lib/crypto/crypto.h"
30 initialise the credentials state for old-style 64 bit session keys
32 this call is made after the netr_ServerReqChallenge call
34 static void creds_init_64bit(struct creds_CredentialState *creds,
35 const struct netr_Credential *client_challenge,
36 const struct netr_Credential *server_challenge,
37 const struct samr_Password *machine_password)
42 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
43 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
48 ZERO_STRUCT(creds->session_key);
50 des_crypt128(creds->session_key, sum2, machine_password->hash);
52 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
53 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
55 creds->seed = creds->client;
59 initialise the credentials state for ADS-style 128 bit session keys
61 this call is made after the netr_ServerReqChallenge call
63 static void creds_init_128bit(struct creds_CredentialState *creds,
64 const struct netr_Credential *client_challenge,
65 const struct netr_Credential *server_challenge,
66 const struct samr_Password *machine_password)
68 unsigned char zero[4], tmp[16];
70 struct MD5Context md5;
72 ZERO_STRUCT(creds->session_key);
74 memset(zero, 0, sizeof(zero));
76 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
78 MD5Update(&md5, zero, sizeof(zero));
79 MD5Update(&md5, client_challenge->data, 8);
80 MD5Update(&md5, server_challenge->data, 8);
82 hmac_md5_update(tmp, sizeof(tmp), &ctx);
83 hmac_md5_final(creds->session_key, &ctx);
85 creds->client = *client_challenge;
86 creds->server = *server_challenge;
88 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
89 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
91 creds->seed = creds->client;
96 step the credentials to the next element in the chain, updating the
97 current client and server credentials and the seed
99 static void creds_step(struct creds_CredentialState *creds)
101 struct netr_Credential time_cred;
103 DEBUG(5,("\tseed %08x:%08x\n",
104 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
106 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
107 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
109 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
111 des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
113 DEBUG(5,("\tCLIENT %08x:%08x\n",
114 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
116 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
117 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
119 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
120 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
122 des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
124 DEBUG(5,("\tSERVER %08x:%08x\n",
125 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
127 creds->seed = time_cred;
132 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
134 void creds_des_encrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
136 struct netr_LMSessionKey tmp;
137 des_crypt56(tmp.key, key->key, creds->session_key, 1);
142 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
144 void creds_des_decrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
146 struct netr_LMSessionKey tmp;
147 des_crypt56(tmp.key, key->key, creds->session_key, 0);
152 DES encrypt a 16 byte password buffer using the session key
154 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
156 struct samr_Password tmp;
157 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
162 DES decrypt a 16 byte password buffer using the session key
164 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
166 struct samr_Password tmp;
167 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
172 ARCFOUR encrypt/decrypt a password buffer using the session key
174 void creds_arcfour_crypt(struct creds_CredentialState *creds, uint8_t *data, size_t len)
176 DATA_BLOB session_key = data_blob(creds->session_key, 16);
178 arcfour_crypt_blob(data, len, &session_key);
180 data_blob_free(&session_key);
183 /*****************************************************************
184 The above functions are common to the client and server interface
185 next comes the client specific functions
186 ******************************************************************/
189 initialise the credentials chain and return the first client
192 void creds_client_init(struct creds_CredentialState *creds,
193 const struct netr_Credential *client_challenge,
194 const struct netr_Credential *server_challenge,
195 const char *computer_name,
197 const char *account_name,
198 const struct samr_Password *machine_password,
199 struct netr_Credential *initial_credential,
200 uint32_t negotiate_flags)
202 creds->sequence = time(NULL);
203 creds->negotiate_flags = negotiate_flags;
204 creds->computer_name = talloc_strdup(creds, computer_name);
205 creds->domain = talloc_strdup(creds, domain);
206 creds->account_name = talloc_strdup(creds, account_name);
208 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
209 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
210 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
212 if (negotiate_flags & NETLOGON_NEG_128BIT) {
213 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
215 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
218 dump_data_pw("Session key", creds->session_key, 16);
219 dump_data_pw("Credential ", creds->client.data, 8);
221 *initial_credential = creds->client;
225 step the credentials to the next element in the chain, updating the
226 current client and server credentials and the seed
228 produce the next authenticator in the sequence ready to send to
231 void creds_client_authenticator(struct creds_CredentialState *creds,
232 struct netr_Authenticator *next)
234 creds->sequence += 2;
237 next->cred = creds->client;
238 next->timestamp = creds->sequence;
242 check that a credentials reply from a server is correct
244 BOOL creds_client_check(struct creds_CredentialState *creds,
245 const struct netr_Credential *received_credentials)
247 if (!received_credentials ||
248 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
249 DEBUG(2,("credentials check failed\n"));
256 /*****************************************************************
257 The above functions are common to the client and server interface
258 next comes the server specific functions
259 ******************************************************************/
262 initialise the credentials chain and return the first server
265 void creds_server_init(struct creds_CredentialState *creds,
266 const struct netr_Credential *client_challenge,
267 const struct netr_Credential *server_challenge,
268 const struct samr_Password *machine_password,
269 struct netr_Credential *initial_credential,
270 uint32_t negotiate_flags)
272 if (negotiate_flags & NETLOGON_NEG_128BIT) {
273 creds_init_128bit(creds, client_challenge, server_challenge,
276 creds_init_64bit(creds, client_challenge, server_challenge,
280 *initial_credential = creds->server;
281 creds->negotiate_flags = negotiate_flags;
285 check that a credentials reply from a server is correct
287 BOOL creds_server_check(const struct creds_CredentialState *creds,
288 const struct netr_Credential *received_credentials)
290 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
291 DEBUG(2,("credentials check failed\n"));
292 dump_data_pw("client creds", creds->client.data, 8);
293 dump_data_pw("calc creds", received_credentials->data, 8);
299 NTSTATUS creds_server_step_check(struct creds_CredentialState *creds,
300 struct netr_Authenticator *received_authenticator,
301 struct netr_Authenticator *return_authenticator)
303 if (!received_authenticator || !return_authenticator) {
304 return NT_STATUS_INVALID_PARAMETER;
308 return NT_STATUS_ACCESS_DENIED;
311 /* TODO: this may allow the a replay attack on a non-signed
312 connection. Should we check that this is increasing? */
313 creds->sequence = received_authenticator->timestamp;
315 if (creds_server_check(creds, &received_authenticator->cred)) {
316 return_authenticator->cred = creds->server;
317 return_authenticator->timestamp = creds->sequence;
320 ZERO_STRUCTP(return_authenticator);
321 return NT_STATUS_ACCESS_DENIED;