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 "../libcli/security/dom_sid.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 iv[AES_BLOCK_SIZE];
37 AES_set_encrypt_key(creds->session_key, 128, &key);
40 aes_cfb8_encrypt(in->data, out->data, 8, &key, iv, AES_ENCRYPT);
42 des_crypt112(out->data, in->data, creds->session_key, 1);
47 initialise the credentials state for old-style 64 bit session keys
49 this call is made after the netr_ServerReqChallenge call
51 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
52 const struct netr_Credential *client_challenge,
53 const struct netr_Credential *server_challenge,
54 const struct samr_Password *machine_password)
59 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
60 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
65 ZERO_STRUCT(creds->session_key);
67 des_crypt128(creds->session_key, sum2, machine_password->hash);
71 initialise the credentials state for ADS-style 128 bit session keys
73 this call is made after the netr_ServerReqChallenge call
75 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
76 const struct netr_Credential *client_challenge,
77 const struct netr_Credential *server_challenge,
78 const struct samr_Password *machine_password)
80 unsigned char zero[4], tmp[16];
84 ZERO_STRUCT(creds->session_key);
86 memset(zero, 0, sizeof(zero));
88 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
90 MD5Update(&md5, zero, sizeof(zero));
91 MD5Update(&md5, client_challenge->data, 8);
92 MD5Update(&md5, server_challenge->data, 8);
94 hmac_md5_update(tmp, sizeof(tmp), &ctx);
95 hmac_md5_final(creds->session_key, &ctx);
99 initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
101 this call is made after the netr_ServerReqChallenge call
103 static void netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
104 const struct netr_Credential *client_challenge,
105 const struct netr_Credential *server_challenge,
106 const struct samr_Password *machine_password)
108 struct HMACSHA256Context ctx;
109 uint8_t digest[SHA256_DIGEST_LENGTH];
111 ZERO_STRUCT(creds->session_key);
113 hmac_sha256_init(machine_password->hash,
114 sizeof(machine_password->hash),
116 hmac_sha256_update(client_challenge->data, 8, &ctx);
117 hmac_sha256_update(server_challenge->data, 8, &ctx);
118 hmac_sha256_final(digest, &ctx);
120 memcpy(creds->session_key, digest, sizeof(creds->session_key));
126 static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
127 const struct netr_Credential *client_challenge,
128 const struct netr_Credential *server_challenge)
130 netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
132 netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
134 creds->seed = creds->client;
138 step the credentials to the next element in the chain, updating the
139 current client and server credentials and the seed
141 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
143 struct netr_Credential time_cred;
145 DEBUG(5,("\tseed %08x:%08x\n",
146 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
148 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
149 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
151 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
153 netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
155 DEBUG(5,("\tCLIENT %08x:%08x\n",
156 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
158 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
159 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
161 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
162 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
164 netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
166 DEBUG(5,("\tSERVER %08x:%08x\n",
167 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
169 creds->seed = time_cred;
174 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
176 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
178 struct netr_LMSessionKey tmp;
179 des_crypt56(tmp.key, key->key, creds->session_key, 1);
184 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
186 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
188 struct netr_LMSessionKey tmp;
189 des_crypt56(tmp.key, key->key, creds->session_key, 0);
194 DES encrypt a 16 byte password buffer using the session key
196 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
198 struct samr_Password tmp;
199 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
204 DES decrypt a 16 byte password buffer using the session key
206 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
208 struct samr_Password tmp;
209 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
214 ARCFOUR encrypt/decrypt a password buffer using the session key
216 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
218 DATA_BLOB session_key = data_blob(creds->session_key, 16);
220 arcfour_crypt_blob(data, len, &session_key);
222 data_blob_free(&session_key);
226 AES encrypt a password buffer using the session key
228 void netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
231 uint8_t iv[AES_BLOCK_SIZE];
233 AES_set_encrypt_key(creds->session_key, 128, &key);
236 aes_cfb8_encrypt(data, data, len, &key, iv, AES_ENCRYPT);
240 AES decrypt a password buffer using the session key
242 void netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
245 uint8_t iv[AES_BLOCK_SIZE];
247 AES_set_encrypt_key(creds->session_key, 128, &key);
250 aes_cfb8_encrypt(data, data, len, &key, iv, AES_DECRYPT);
253 /*****************************************************************
254 The above functions are common to the client and server interface
255 next comes the client specific functions
256 ******************************************************************/
259 initialise the credentials chain and return the first client
263 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
264 const char *client_account,
265 const char *client_computer_name,
266 uint16_t secure_channel_type,
267 const struct netr_Credential *client_challenge,
268 const struct netr_Credential *server_challenge,
269 const struct samr_Password *machine_password,
270 struct netr_Credential *initial_credential,
271 uint32_t negotiate_flags)
273 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
279 creds->sequence = time(NULL);
280 creds->negotiate_flags = negotiate_flags;
281 creds->secure_channel_type = secure_channel_type;
283 creds->computer_name = talloc_strdup(creds, client_computer_name);
284 if (!creds->computer_name) {
288 creds->account_name = talloc_strdup(creds, client_account);
289 if (!creds->account_name) {
294 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
295 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
296 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
298 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
299 netlogon_creds_init_hmac_sha256(creds,
303 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
304 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
306 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
309 netlogon_creds_first_step(creds, client_challenge, server_challenge);
311 dump_data_pw("Session key", creds->session_key, 16);
312 dump_data_pw("Credential ", creds->client.data, 8);
314 *initial_credential = creds->client;
319 initialise the credentials structure with only a session key. The caller better know what they are doing!
322 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
323 const uint8_t session_key[16])
325 struct netlogon_creds_CredentialState *creds;
327 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
332 memcpy(creds->session_key, session_key, 16);
338 step the credentials to the next element in the chain, updating the
339 current client and server credentials and the seed
341 produce the next authenticator in the sequence ready to send to
344 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
345 struct netr_Authenticator *next)
347 creds->sequence += 2;
348 netlogon_creds_step(creds);
350 next->cred = creds->client;
351 next->timestamp = creds->sequence;
355 check that a credentials reply from a server is correct
357 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
358 const struct netr_Credential *received_credentials)
360 if (!received_credentials ||
361 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
362 DEBUG(2,("credentials check failed\n"));
369 /*****************************************************************
370 The above functions are common to the client and server interface
371 next comes the server specific functions
372 ******************************************************************/
375 check that a credentials reply from a server is correct
377 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
378 const struct netr_Credential *received_credentials)
380 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
381 DEBUG(2,("credentials check failed\n"));
382 dump_data_pw("client creds", creds->client.data, 8);
383 dump_data_pw("calc creds", received_credentials->data, 8);
390 initialise the credentials chain and return the first server
393 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
394 const char *client_account,
395 const char *client_computer_name,
396 uint16_t secure_channel_type,
397 const struct netr_Credential *client_challenge,
398 const struct netr_Credential *server_challenge,
399 const struct samr_Password *machine_password,
400 struct netr_Credential *credentials_in,
401 struct netr_Credential *credentials_out,
402 uint32_t negotiate_flags)
405 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
411 creds->negotiate_flags = negotiate_flags;
412 creds->secure_channel_type = secure_channel_type;
414 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
415 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
416 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
418 creds->computer_name = talloc_strdup(creds, client_computer_name);
419 if (!creds->computer_name) {
423 creds->account_name = talloc_strdup(creds, client_account);
424 if (!creds->account_name) {
429 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
430 netlogon_creds_init_hmac_sha256(creds,
434 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
435 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
438 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
442 netlogon_creds_first_step(creds, client_challenge, server_challenge);
444 dump_data_pw("Session key", creds->session_key, 16);
445 dump_data_pw("Client Credential ", creds->client.data, 8);
446 dump_data_pw("Server Credential ", creds->server.data, 8);
448 dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
450 /* And before we leak information about the machine account
451 * password, check that they got the first go right */
452 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
457 *credentials_out = creds->server;
459 dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
464 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
465 struct netr_Authenticator *received_authenticator,
466 struct netr_Authenticator *return_authenticator)
468 if (!received_authenticator || !return_authenticator) {
469 return NT_STATUS_INVALID_PARAMETER;
473 return NT_STATUS_ACCESS_DENIED;
476 /* TODO: this may allow the a replay attack on a non-signed
477 connection. Should we check that this is increasing? */
478 creds->sequence = received_authenticator->timestamp;
479 netlogon_creds_step(creds);
480 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
481 return_authenticator->cred = creds->server;
482 return_authenticator->timestamp = 0;
485 ZERO_STRUCTP(return_authenticator);
486 return NT_STATUS_ACCESS_DENIED;
490 static void netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
491 uint16_t validation_level,
492 union netr_Validation *validation,
495 static const char zeros[16];
496 struct netr_SamBaseInfo *base = NULL;
498 if (validation == NULL) {
502 switch (validation_level) {
504 if (validation->sam2) {
505 base = &validation->sam2->base;
509 if (validation->sam3) {
510 base = &validation->sam3->base;
514 if (validation->sam6) {
515 base = &validation->sam6->base;
519 /* If we can't find it, we can't very well decrypt it */
527 /* find and decyrpt the session keys, return in parameters above */
528 if (validation_level == 6) {
529 /* they aren't encrypted! */
530 } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
531 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
532 if (memcmp(base->key.key, zeros,
533 sizeof(base->key.key)) != 0) {
535 netlogon_creds_aes_encrypt(creds,
537 sizeof(base->key.key));
539 netlogon_creds_aes_decrypt(creds,
541 sizeof(base->key.key));
545 if (memcmp(base->LMSessKey.key, zeros,
546 sizeof(base->LMSessKey.key)) != 0) {
548 netlogon_creds_aes_encrypt(creds,
550 sizeof(base->LMSessKey.key));
553 netlogon_creds_aes_decrypt(creds,
555 sizeof(base->LMSessKey.key));
558 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
559 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
560 if (memcmp(base->key.key, zeros,
561 sizeof(base->key.key)) != 0) {
562 netlogon_creds_arcfour_crypt(creds,
564 sizeof(base->key.key));
567 if (memcmp(base->LMSessKey.key, zeros,
568 sizeof(base->LMSessKey.key)) != 0) {
569 netlogon_creds_arcfour_crypt(creds,
571 sizeof(base->LMSessKey.key));
574 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
575 if (memcmp(base->LMSessKey.key, zeros,
576 sizeof(base->LMSessKey.key)) != 0) {
578 netlogon_creds_des_encrypt_LMKey(creds,
581 netlogon_creds_des_decrypt_LMKey(creds,
588 void netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
589 uint16_t validation_level,
590 union netr_Validation *validation)
592 netlogon_creds_crypt_samlogon_validation(creds, validation_level,
596 void netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
597 uint16_t validation_level,
598 union netr_Validation *validation)
600 netlogon_creds_crypt_samlogon_validation(creds, validation_level,
604 static void netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
605 enum netr_LogonInfoClass level,
606 union netr_LogonLevel *logon,
609 static const char zeros[16];
616 case NetlogonInteractiveInformation:
617 case NetlogonInteractiveTransitiveInformation:
618 case NetlogonServiceInformation:
619 case NetlogonServiceTransitiveInformation:
620 if (logon->password == NULL) {
624 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
627 h = logon->password->lmpassword.hash;
628 if (memcmp(h, zeros, 16) != 0) {
630 netlogon_creds_aes_encrypt(creds, h, 16);
632 netlogon_creds_aes_decrypt(creds, h, 16);
636 h = logon->password->ntpassword.hash;
637 if (memcmp(h, zeros, 16) != 0) {
639 netlogon_creds_aes_encrypt(creds, h, 16);
641 netlogon_creds_aes_decrypt(creds, h, 16);
644 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
647 h = logon->password->lmpassword.hash;
648 if (memcmp(h, zeros, 16) != 0) {
649 netlogon_creds_arcfour_crypt(creds, h, 16);
652 h = logon->password->ntpassword.hash;
653 if (memcmp(h, zeros, 16) != 0) {
654 netlogon_creds_arcfour_crypt(creds, h, 16);
657 struct samr_Password *p;
659 p = &logon->password->lmpassword;
660 if (memcmp(p->hash, zeros, 16) != 0) {
662 netlogon_creds_des_encrypt(creds, p);
664 netlogon_creds_des_decrypt(creds, p);
667 p = &logon->password->ntpassword;
668 if (memcmp(p->hash, zeros, 16) != 0) {
670 netlogon_creds_des_encrypt(creds, p);
672 netlogon_creds_des_decrypt(creds, p);
678 case NetlogonNetworkInformation:
679 case NetlogonNetworkTransitiveInformation:
682 case NetlogonGenericInformation:
683 if (logon->generic == NULL) {
687 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
689 netlogon_creds_aes_encrypt(creds,
690 logon->generic->data,
691 logon->generic->length);
693 netlogon_creds_aes_decrypt(creds,
694 logon->generic->data,
695 logon->generic->length);
697 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
698 netlogon_creds_arcfour_crypt(creds,
699 logon->generic->data,
700 logon->generic->length);
702 /* Using DES to verify kerberos tickets makes no sense */
708 void netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
709 enum netr_LogonInfoClass level,
710 union netr_LogonLevel *logon)
712 netlogon_creds_crypt_samlogon_logon(creds, level, logon, false);
715 void netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
716 enum netr_LogonInfoClass level,
717 union netr_LogonLevel *logon)
719 netlogon_creds_crypt_samlogon_logon(creds, level, logon, true);
722 union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
723 enum netr_LogonInfoClass level,
724 const union netr_LogonLevel *in)
726 union netr_LogonLevel *out;
732 out = talloc(mem_ctx, union netr_LogonLevel);
740 case NetlogonInteractiveInformation:
741 case NetlogonInteractiveTransitiveInformation:
742 case NetlogonServiceInformation:
743 case NetlogonServiceTransitiveInformation:
744 if (in->password == NULL) {
748 out->password = talloc(out, struct netr_PasswordInfo);
749 if (out->password == NULL) {
753 *out->password = *in->password;
757 case NetlogonNetworkInformation:
758 case NetlogonNetworkTransitiveInformation:
761 case NetlogonGenericInformation:
762 if (in->generic == NULL) {
766 out->generic = talloc(out, struct netr_GenericInfo);
767 if (out->generic == NULL) {
771 *out->generic = *in->generic;
773 if (in->generic->data == NULL) {
777 if (in->generic->length == 0) {
781 out->generic->data = talloc_memdup(out->generic,
783 in->generic->length);
784 if (out->generic->data == NULL) {
796 copy a netlogon_creds_CredentialState struct
799 struct netlogon_creds_CredentialState *netlogon_creds_copy(TALLOC_CTX *mem_ctx,
800 struct netlogon_creds_CredentialState *creds_in)
802 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
808 creds->sequence = creds_in->sequence;
809 creds->negotiate_flags = creds_in->negotiate_flags;
810 creds->secure_channel_type = creds_in->secure_channel_type;
812 creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
813 if (!creds->computer_name) {
817 creds->account_name = talloc_strdup(creds, creds_in->account_name);
818 if (!creds->account_name) {
824 creds->sid = dom_sid_dup(creds, creds_in->sid);
831 memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
832 memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
833 memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
834 memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));