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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "system/time.h"
25 #include "../lib/crypto/crypto.h"
26 #include "libcli/auth/libcli_auth.h"
28 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
29 const struct netr_Credential *in,
30 struct netr_Credential *out)
32 des_crypt112(out->data, in->data, creds->session_key, 1);
36 initialise the credentials state for old-style 64 bit session keys
38 this call is made after the netr_ServerReqChallenge call
40 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
41 const struct netr_Credential *client_challenge,
42 const struct netr_Credential *server_challenge,
43 const struct samr_Password *machine_password)
48 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
49 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
54 ZERO_STRUCT(creds->session_key);
56 des_crypt128(creds->session_key, sum2, machine_password->hash);
60 initialise the credentials state for ADS-style 128 bit session keys
62 this call is made after the netr_ServerReqChallenge call
64 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
65 const struct netr_Credential *client_challenge,
66 const struct netr_Credential *server_challenge,
67 const struct samr_Password *machine_password)
69 unsigned char zero[4], tmp[16];
71 struct MD5Context md5;
73 ZERO_STRUCT(creds->session_key);
75 memset(zero, 0, sizeof(zero));
77 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
79 MD5Update(&md5, zero, sizeof(zero));
80 MD5Update(&md5, client_challenge->data, 8);
81 MD5Update(&md5, server_challenge->data, 8);
83 hmac_md5_update(tmp, sizeof(tmp), &ctx);
84 hmac_md5_final(creds->session_key, &ctx);
87 static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
88 const struct netr_Credential *client_challenge,
89 const struct netr_Credential *server_challenge)
91 netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
93 netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
95 creds->seed = creds->client;
99 step the credentials to the next element in the chain, updating the
100 current client and server credentials and the seed
102 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
104 struct netr_Credential time_cred;
106 DEBUG(5,("\tseed %08x:%08x\n",
107 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
109 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
110 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
112 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
114 netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
116 DEBUG(5,("\tCLIENT %08x:%08x\n",
117 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
119 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
120 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
122 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
123 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
125 netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
127 DEBUG(5,("\tSERVER %08x:%08x\n",
128 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
130 creds->seed = time_cred;
135 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
137 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
139 struct netr_LMSessionKey tmp;
140 des_crypt56(tmp.key, key->key, creds->session_key, 1);
145 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
147 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
149 struct netr_LMSessionKey tmp;
150 des_crypt56(tmp.key, key->key, creds->session_key, 0);
155 DES encrypt a 16 byte password buffer using the session key
157 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
159 struct samr_Password tmp;
160 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
165 DES decrypt a 16 byte password buffer using the session key
167 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
169 struct samr_Password tmp;
170 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
175 ARCFOUR encrypt/decrypt a password buffer using the session key
177 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
179 DATA_BLOB session_key = data_blob(creds->session_key, 16);
181 arcfour_crypt_blob(data, len, &session_key);
183 data_blob_free(&session_key);
186 /*****************************************************************
187 The above functions are common to the client and server interface
188 next comes the client specific functions
189 ******************************************************************/
192 initialise the credentials chain and return the first client
196 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
197 const char *client_account,
198 const char *client_computer_name,
199 const struct netr_Credential *client_challenge,
200 const struct netr_Credential *server_challenge,
201 const struct samr_Password *machine_password,
202 struct netr_Credential *initial_credential,
203 uint32_t negotiate_flags)
205 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
211 creds->sequence = time(NULL);
212 creds->negotiate_flags = negotiate_flags;
214 creds->computer_name = talloc_strdup(creds, client_computer_name);
215 if (!creds->computer_name) {
219 creds->account_name = talloc_strdup(creds, client_account);
220 if (!creds->account_name) {
225 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
226 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
227 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
229 if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
230 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
232 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
235 netlogon_creds_first_step(creds, client_challenge, server_challenge);
237 dump_data_pw("Session key", creds->session_key, 16);
238 dump_data_pw("Credential ", creds->client.data, 8);
240 *initial_credential = creds->client;
245 initialise the credentials structure with only a session key. The caller better know what they are doing!
248 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
249 const uint8_t session_key[16])
251 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
257 memcpy(creds->session_key, session_key, 16);
263 step the credentials to the next element in the chain, updating the
264 current client and server credentials and the seed
266 produce the next authenticator in the sequence ready to send to
269 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
270 struct netr_Authenticator *next)
272 creds->sequence += 2;
273 netlogon_creds_step(creds);
275 next->cred = creds->client;
276 next->timestamp = creds->sequence;
280 check that a credentials reply from a server is correct
282 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
283 const struct netr_Credential *received_credentials)
285 if (!received_credentials ||
286 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
287 DEBUG(2,("credentials check failed\n"));
294 /*****************************************************************
295 The above functions are common to the client and server interface
296 next comes the server specific functions
297 ******************************************************************/
300 check that a credentials reply from a server is correct
302 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
303 const struct netr_Credential *received_credentials)
305 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
306 DEBUG(2,("credentials check failed\n"));
307 dump_data_pw("client creds", creds->client.data, 8);
308 dump_data_pw("calc creds", received_credentials->data, 8);
315 initialise the credentials chain and return the first server
318 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
319 const char *client_account,
320 const char *client_computer_name,
321 uint16_t secure_channel_type,
322 const struct netr_Credential *client_challenge,
323 const struct netr_Credential *server_challenge,
324 const struct samr_Password *machine_password,
325 struct netr_Credential *credentials_in,
326 struct netr_Credential *credentials_out,
327 uint32_t negotiate_flags)
329 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
331 bool try_strong = true;
332 bool try_weak = true;
333 bool fallback = false;
339 creds->negotiate_flags = negotiate_flags;
340 creds->secure_channel_type = secure_channel_type;
342 creds->computer_name = talloc_strdup(creds, client_computer_name);
343 if (!creds->computer_name) {
347 creds->account_name = talloc_strdup(creds, client_account);
348 if (!creds->account_name) {
353 if (!ok && try_strong) {
355 DEBUG(2,("credentials check fallback to strong key\n"));
357 creds->negotiate_flags |= NETLOGON_NEG_STRONG_KEYS;
358 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
360 netlogon_creds_first_step(creds, client_challenge, server_challenge);
361 ok = netlogon_creds_server_check_internal(creds, credentials_in);
363 creds->negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
368 if (!ok && try_weak) {
370 DEBUG(2,("credentials check fallback to weak key\n"));
372 creds->negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
373 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
375 netlogon_creds_first_step(creds, client_challenge, server_challenge);
376 ok = netlogon_creds_server_check_internal(creds, credentials_in);
379 /* And before we leak information about the machine account
380 * password, check that they got the first go right */
386 *credentials_out = creds->server;
391 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
392 struct netr_Authenticator *received_authenticator,
393 struct netr_Authenticator *return_authenticator)
395 if (!received_authenticator || !return_authenticator) {
396 return NT_STATUS_INVALID_PARAMETER;
400 return NT_STATUS_ACCESS_DENIED;
403 /* TODO: this may allow the a replay attack on a non-signed
404 connection. Should we check that this is increasing? */
405 creds->sequence = received_authenticator->timestamp;
406 netlogon_creds_step(creds);
407 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
408 return_authenticator->cred = creds->server;
409 return_authenticator->timestamp = creds->sequence;
412 ZERO_STRUCTP(return_authenticator);
413 return NT_STATUS_ACCESS_DENIED;
417 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
418 uint16_t validation_level,
419 union netr_Validation *validation)
421 static const char zeros[16];
423 struct netr_SamBaseInfo *base = NULL;
424 switch (validation_level) {
426 if (validation->sam2) {
427 base = &validation->sam2->base;
431 if (validation->sam3) {
432 base = &validation->sam3->base;
436 if (validation->sam6) {
437 base = &validation->sam6->base;
441 /* If we can't find it, we can't very well decrypt it */
449 /* find and decyrpt the session keys, return in parameters above */
450 if (validation_level == 6) {
451 /* they aren't encrypted! */
452 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
453 if (memcmp(base->key.key, zeros,
454 sizeof(base->key.key)) != 0) {
455 netlogon_creds_arcfour_crypt(creds,
457 sizeof(base->key.key));
460 if (memcmp(base->LMSessKey.key, zeros,
461 sizeof(base->LMSessKey.key)) != 0) {
462 netlogon_creds_arcfour_crypt(creds,
464 sizeof(base->LMSessKey.key));
467 if (memcmp(base->LMSessKey.key, zeros,
468 sizeof(base->LMSessKey.key)) != 0) {
469 netlogon_creds_des_decrypt_LMKey(creds,