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"
27 #include "heimdal/lib/hcrypto/aes.h"
29 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
30 const struct netr_Credential *in,
31 struct netr_Credential *out)
33 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
35 uint8_t aes_in[AES_BLOCK_SIZE];
36 uint8_t aes_out[AES_BLOCK_SIZE];
38 AES_set_encrypt_key(creds->session_key, 128, &key);
41 memcpy(aes_in, in->data, 8);
42 AES_encrypt(aes_in, aes_out, &key);
43 memcpy(out->data, aes_out, 8);
49 des_crypt112(out->data, in->data, creds->session_key, 1);
54 initialise the credentials state for old-style 64 bit session keys
56 this call is made after the netr_ServerReqChallenge call
58 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
59 const struct netr_Credential *client_challenge,
60 const struct netr_Credential *server_challenge,
61 const struct samr_Password *machine_password)
66 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
67 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
72 ZERO_STRUCT(creds->session_key);
74 des_crypt128(creds->session_key, sum2, machine_password->hash);
78 initialise the credentials state for ADS-style 128 bit session keys
80 this call is made after the netr_ServerReqChallenge call
82 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
83 const struct netr_Credential *client_challenge,
84 const struct netr_Credential *server_challenge,
85 const struct samr_Password *machine_password)
87 unsigned char zero[4], tmp[16];
89 struct MD5Context md5;
91 ZERO_STRUCT(creds->session_key);
93 memset(zero, 0, sizeof(zero));
95 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
97 MD5Update(&md5, zero, sizeof(zero));
98 MD5Update(&md5, client_challenge->data, 8);
99 MD5Update(&md5, server_challenge->data, 8);
101 hmac_md5_update(tmp, sizeof(tmp), &ctx);
102 hmac_md5_final(creds->session_key, &ctx);
106 initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
108 this call is made after the netr_ServerReqChallenge call
110 static void netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
111 const struct netr_Credential *client_challenge,
112 const struct netr_Credential *server_challenge,
113 const struct samr_Password *machine_password)
115 struct HMACSHA256Context ctx;
116 uint8_t digest[SHA256_DIGEST_LENGTH];
118 ZERO_STRUCT(creds->session_key);
120 hmac_sha256_init(machine_password->hash,
121 sizeof(machine_password->hash),
123 hmac_sha256_update(client_challenge->data, 8, &ctx);
124 hmac_sha256_update(server_challenge->data, 8, &ctx);
125 hmac_sha256_final(digest, &ctx);
127 memcpy(creds->session_key, digest, sizeof(creds->session_key));
133 static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
134 const struct netr_Credential *client_challenge,
135 const struct netr_Credential *server_challenge)
137 netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
139 netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
141 creds->seed = creds->client;
145 step the credentials to the next element in the chain, updating the
146 current client and server credentials and the seed
148 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
150 struct netr_Credential time_cred;
152 DEBUG(5,("\tseed %08x:%08x\n",
153 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
155 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
156 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
158 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
160 netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
162 DEBUG(5,("\tCLIENT %08x:%08x\n",
163 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
165 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
166 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
168 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
169 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
171 netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
173 DEBUG(5,("\tSERVER %08x:%08x\n",
174 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
176 creds->seed = time_cred;
181 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
183 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
185 struct netr_LMSessionKey tmp;
186 des_crypt56(tmp.key, key->key, creds->session_key, 1);
191 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
193 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
195 struct netr_LMSessionKey tmp;
196 des_crypt56(tmp.key, key->key, creds->session_key, 0);
201 DES encrypt a 16 byte password buffer using the session key
203 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
205 struct samr_Password tmp;
206 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
211 DES decrypt a 16 byte password buffer using the session key
213 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
215 struct samr_Password tmp;
216 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
221 ARCFOUR encrypt/decrypt a password buffer using the session key
223 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
225 DATA_BLOB session_key = data_blob(creds->session_key, 16);
227 arcfour_crypt_blob(data, len, &session_key);
229 data_blob_free(&session_key);
232 /*****************************************************************
233 The above functions are common to the client and server interface
234 next comes the client specific functions
235 ******************************************************************/
238 initialise the credentials chain and return the first client
242 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
243 const char *client_account,
244 const char *client_computer_name,
245 const struct netr_Credential *client_challenge,
246 const struct netr_Credential *server_challenge,
247 const struct samr_Password *machine_password,
248 struct netr_Credential *initial_credential,
249 uint32_t negotiate_flags)
251 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
257 creds->sequence = time(NULL);
258 creds->negotiate_flags = negotiate_flags;
260 creds->computer_name = talloc_strdup(creds, client_computer_name);
261 if (!creds->computer_name) {
265 creds->account_name = talloc_strdup(creds, client_account);
266 if (!creds->account_name) {
271 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
272 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
273 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
275 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
276 netlogon_creds_init_hmac_sha256(creds,
280 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
281 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
283 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
286 netlogon_creds_first_step(creds, client_challenge, server_challenge);
288 dump_data_pw("Session key", creds->session_key, 16);
289 dump_data_pw("Credential ", creds->client.data, 8);
291 *initial_credential = creds->client;
296 initialise the credentials structure with only a session key. The caller better know what they are doing!
299 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
300 const uint8_t session_key[16])
302 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
308 memcpy(creds->session_key, session_key, 16);
314 step the credentials to the next element in the chain, updating the
315 current client and server credentials and the seed
317 produce the next authenticator in the sequence ready to send to
320 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
321 struct netr_Authenticator *next)
323 creds->sequence += 2;
324 netlogon_creds_step(creds);
326 next->cred = creds->client;
327 next->timestamp = creds->sequence;
331 check that a credentials reply from a server is correct
333 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
334 const struct netr_Credential *received_credentials)
336 if (!received_credentials ||
337 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
338 DEBUG(2,("credentials check failed\n"));
345 /*****************************************************************
346 The above functions are common to the client and server interface
347 next comes the server specific functions
348 ******************************************************************/
351 check that a credentials reply from a server is correct
353 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
354 const struct netr_Credential *received_credentials)
356 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
357 DEBUG(2,("credentials check failed\n"));
358 dump_data_pw("client creds", creds->client.data, 8);
359 dump_data_pw("calc creds", received_credentials->data, 8);
366 initialise the credentials chain and return the first server
369 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
370 const char *client_account,
371 const char *client_computer_name,
372 uint16_t secure_channel_type,
373 const struct netr_Credential *client_challenge,
374 const struct netr_Credential *server_challenge,
375 const struct samr_Password *machine_password,
376 struct netr_Credential *credentials_in,
377 struct netr_Credential *credentials_out,
378 uint32_t negotiate_flags)
380 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
383 bool try_strong = true;
384 bool try_weak = true;
385 bool fallback = false;
391 creds->negotiate_flags = negotiate_flags;
392 creds->secure_channel_type = secure_channel_type;
394 creds->computer_name = talloc_strdup(creds, client_computer_name);
395 if (!creds->computer_name) {
399 creds->account_name = talloc_strdup(creds, client_account);
400 if (!creds->account_name) {
405 if (!ok && try_aes) {
407 DEBUG(2,("credentials check fallback to aes key\n"));
409 creds->negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
410 netlogon_creds_init_hmac_sha256(creds,
414 netlogon_creds_first_step(creds, client_challenge, server_challenge);
415 ok = netlogon_creds_server_check_internal(creds, credentials_in);
417 creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
422 if (!ok && try_strong) {
424 DEBUG(2,("credentials check fallback to strong key\n"));
426 creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
427 creds->negotiate_flags |= NETLOGON_NEG_STRONG_KEYS;
428 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
430 netlogon_creds_first_step(creds, client_challenge, server_challenge);
431 ok = netlogon_creds_server_check_internal(creds, credentials_in);
433 creds->negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
438 if (!ok && try_weak) {
440 DEBUG(2,("credentials check fallback to weak key\n"));
442 creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
443 creds->negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
444 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
446 netlogon_creds_first_step(creds, client_challenge, server_challenge);
447 ok = netlogon_creds_server_check_internal(creds, credentials_in);
450 /* And before we leak information about the machine account
451 * password, check that they got the first go right */
457 *credentials_out = creds->server;
462 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
463 struct netr_Authenticator *received_authenticator,
464 struct netr_Authenticator *return_authenticator)
466 if (!received_authenticator || !return_authenticator) {
467 return NT_STATUS_INVALID_PARAMETER;
471 return NT_STATUS_ACCESS_DENIED;
474 /* TODO: this may allow the a replay attack on a non-signed
475 connection. Should we check that this is increasing? */
476 creds->sequence = received_authenticator->timestamp;
477 netlogon_creds_step(creds);
478 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
479 return_authenticator->cred = creds->server;
480 return_authenticator->timestamp = creds->sequence;
483 ZERO_STRUCTP(return_authenticator);
484 return NT_STATUS_ACCESS_DENIED;
488 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
489 uint16_t validation_level,
490 union netr_Validation *validation)
492 static const char zeros[16];
494 struct netr_SamBaseInfo *base = NULL;
495 switch (validation_level) {
497 if (validation->sam2) {
498 base = &validation->sam2->base;
502 if (validation->sam3) {
503 base = &validation->sam3->base;
507 if (validation->sam6) {
508 base = &validation->sam6->base;
512 /* If we can't find it, we can't very well decrypt it */
520 /* find and decyrpt the session keys, return in parameters above */
521 if (validation_level == 6) {
522 /* they aren't encrypted! */
523 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
524 if (memcmp(base->key.key, zeros,
525 sizeof(base->key.key)) != 0) {
526 netlogon_creds_arcfour_crypt(creds,
528 sizeof(base->key.key));
531 if (memcmp(base->LMSessKey.key, zeros,
532 sizeof(base->LMSessKey.key)) != 0) {
533 netlogon_creds_arcfour_crypt(creds,
535 sizeof(base->LMSessKey.key));
538 if (memcmp(base->LMSessKey.key, zeros,
539 sizeof(base->LMSessKey.key)) != 0) {
540 netlogon_creds_des_decrypt_LMKey(creds,