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];
82 struct MD5Context md5
;
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
);
225 /*****************************************************************
226 The above functions are common to the client and server interface
227 next comes the client specific functions
228 ******************************************************************/
231 initialise the credentials chain and return the first client
235 struct netlogon_creds_CredentialState
*netlogon_creds_client_init(TALLOC_CTX
*mem_ctx
,
236 const char *client_account
,
237 const char *client_computer_name
,
238 const struct netr_Credential
*client_challenge
,
239 const struct netr_Credential
*server_challenge
,
240 const struct samr_Password
*machine_password
,
241 struct netr_Credential
*initial_credential
,
242 uint32_t negotiate_flags
)
244 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
250 creds
->sequence
= time(NULL
);
251 creds
->negotiate_flags
= negotiate_flags
;
253 creds
->computer_name
= talloc_strdup(creds
, client_computer_name
);
254 if (!creds
->computer_name
) {
258 creds
->account_name
= talloc_strdup(creds
, client_account
);
259 if (!creds
->account_name
) {
264 dump_data_pw("Client chall", client_challenge
->data
, sizeof(client_challenge
->data
));
265 dump_data_pw("Server chall", server_challenge
->data
, sizeof(server_challenge
->data
));
266 dump_data_pw("Machine Pass", machine_password
->hash
, sizeof(machine_password
->hash
));
268 if (negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
269 netlogon_creds_init_hmac_sha256(creds
,
273 } else if (negotiate_flags
& NETLOGON_NEG_STRONG_KEYS
) {
274 netlogon_creds_init_128bit(creds
, client_challenge
, server_challenge
, machine_password
);
276 netlogon_creds_init_64bit(creds
, client_challenge
, server_challenge
, machine_password
);
279 netlogon_creds_first_step(creds
, client_challenge
, server_challenge
);
281 dump_data_pw("Session key", creds
->session_key
, 16);
282 dump_data_pw("Credential ", creds
->client
.data
, 8);
284 *initial_credential
= creds
->client
;
289 initialise the credentials structure with only a session key. The caller better know what they are doing!
292 struct netlogon_creds_CredentialState
*netlogon_creds_client_init_session_key(TALLOC_CTX
*mem_ctx
,
293 const uint8_t session_key
[16])
295 struct netlogon_creds_CredentialState
*creds
;
297 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
302 memcpy(creds
->session_key
, session_key
, 16);
308 step the credentials to the next element in the chain, updating the
309 current client and server credentials and the seed
311 produce the next authenticator in the sequence ready to send to
314 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState
*creds
,
315 struct netr_Authenticator
*next
)
317 creds
->sequence
+= 2;
318 netlogon_creds_step(creds
);
320 next
->cred
= creds
->client
;
321 next
->timestamp
= creds
->sequence
;
325 check that a credentials reply from a server is correct
327 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState
*creds
,
328 const struct netr_Credential
*received_credentials
)
330 if (!received_credentials
||
331 memcmp(received_credentials
->data
, creds
->server
.data
, 8) != 0) {
332 DEBUG(2,("credentials check failed\n"));
339 /*****************************************************************
340 The above functions are common to the client and server interface
341 next comes the server specific functions
342 ******************************************************************/
345 check that a credentials reply from a server is correct
347 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState
*creds
,
348 const struct netr_Credential
*received_credentials
)
350 if (memcmp(received_credentials
->data
, creds
->client
.data
, 8) != 0) {
351 DEBUG(2,("credentials check failed\n"));
352 dump_data_pw("client creds", creds
->client
.data
, 8);
353 dump_data_pw("calc creds", received_credentials
->data
, 8);
360 initialise the credentials chain and return the first server
363 struct netlogon_creds_CredentialState
*netlogon_creds_server_init(TALLOC_CTX
*mem_ctx
,
364 const char *client_account
,
365 const char *client_computer_name
,
366 uint16_t secure_channel_type
,
367 const struct netr_Credential
*client_challenge
,
368 const struct netr_Credential
*server_challenge
,
369 const struct samr_Password
*machine_password
,
370 struct netr_Credential
*credentials_in
,
371 struct netr_Credential
*credentials_out
,
372 uint32_t negotiate_flags
)
375 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
381 creds
->negotiate_flags
= negotiate_flags
;
382 creds
->secure_channel_type
= secure_channel_type
;
384 dump_data_pw("Client chall", client_challenge
->data
, sizeof(client_challenge
->data
));
385 dump_data_pw("Server chall", server_challenge
->data
, sizeof(server_challenge
->data
));
386 dump_data_pw("Machine Pass", machine_password
->hash
, sizeof(machine_password
->hash
));
388 creds
->computer_name
= talloc_strdup(creds
, client_computer_name
);
389 if (!creds
->computer_name
) {
393 creds
->account_name
= talloc_strdup(creds
, client_account
);
394 if (!creds
->account_name
) {
399 if (negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
400 netlogon_creds_init_hmac_sha256(creds
,
404 } else if (negotiate_flags
& NETLOGON_NEG_STRONG_KEYS
) {
405 netlogon_creds_init_128bit(creds
, client_challenge
, server_challenge
,
408 netlogon_creds_init_64bit(creds
, client_challenge
, server_challenge
,
412 netlogon_creds_first_step(creds
, client_challenge
, server_challenge
);
414 dump_data_pw("Session key", creds
->session_key
, 16);
415 dump_data_pw("Client Credential ", creds
->client
.data
, 8);
416 dump_data_pw("Server Credential ", creds
->server
.data
, 8);
418 dump_data_pw("Credentials in", credentials_in
->data
, sizeof(credentials_in
->data
));
420 /* And before we leak information about the machine account
421 * password, check that they got the first go right */
422 if (!netlogon_creds_server_check_internal(creds
, credentials_in
)) {
427 *credentials_out
= creds
->server
;
429 dump_data_pw("Credentials out", credentials_out
->data
, sizeof(credentials_out
->data
));
434 NTSTATUS
netlogon_creds_server_step_check(struct netlogon_creds_CredentialState
*creds
,
435 struct netr_Authenticator
*received_authenticator
,
436 struct netr_Authenticator
*return_authenticator
)
438 if (!received_authenticator
|| !return_authenticator
) {
439 return NT_STATUS_INVALID_PARAMETER
;
443 return NT_STATUS_ACCESS_DENIED
;
446 /* TODO: this may allow the a replay attack on a non-signed
447 connection. Should we check that this is increasing? */
448 creds
->sequence
= received_authenticator
->timestamp
;
449 netlogon_creds_step(creds
);
450 if (netlogon_creds_server_check_internal(creds
, &received_authenticator
->cred
)) {
451 return_authenticator
->cred
= creds
->server
;
452 return_authenticator
->timestamp
= creds
->sequence
;
455 ZERO_STRUCTP(return_authenticator
);
456 return NT_STATUS_ACCESS_DENIED
;
460 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState
*creds
,
461 uint16_t validation_level
,
462 union netr_Validation
*validation
)
464 static const char zeros
[16];
466 struct netr_SamBaseInfo
*base
= NULL
;
467 switch (validation_level
) {
469 if (validation
->sam2
) {
470 base
= &validation
->sam2
->base
;
474 if (validation
->sam3
) {
475 base
= &validation
->sam3
->base
;
479 if (validation
->sam6
) {
480 base
= &validation
->sam6
->base
;
484 /* If we can't find it, we can't very well decrypt it */
492 /* find and decyrpt the session keys, return in parameters above */
493 if (validation_level
== 6) {
494 /* they aren't encrypted! */
495 } else if (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
) {
496 if (memcmp(base
->key
.key
, zeros
,
497 sizeof(base
->key
.key
)) != 0) {
498 netlogon_creds_arcfour_crypt(creds
,
500 sizeof(base
->key
.key
));
503 if (memcmp(base
->LMSessKey
.key
, zeros
,
504 sizeof(base
->LMSessKey
.key
)) != 0) {
505 netlogon_creds_arcfour_crypt(creds
,
507 sizeof(base
->LMSessKey
.key
));
510 if (memcmp(base
->LMSessKey
.key
, zeros
,
511 sizeof(base
->LMSessKey
.key
)) != 0) {
512 netlogon_creds_des_decrypt_LMKey(creds
,
519 copy a netlogon_creds_CredentialState struct
522 struct netlogon_creds_CredentialState
*netlogon_creds_copy(TALLOC_CTX
*mem_ctx
,
523 struct netlogon_creds_CredentialState
*creds_in
)
525 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
531 creds
->sequence
= creds_in
->sequence
;
532 creds
->negotiate_flags
= creds_in
->negotiate_flags
;
533 creds
->secure_channel_type
= creds_in
->secure_channel_type
;
535 creds
->computer_name
= talloc_strdup(creds
, creds_in
->computer_name
);
536 if (!creds
->computer_name
) {
540 creds
->account_name
= talloc_strdup(creds
, creds_in
->account_name
);
541 if (!creds
->account_name
) {
547 creds
->sid
= dom_sid_dup(creds
, creds_in
->sid
);
554 memcpy(creds
->session_key
, creds_in
->session_key
, sizeof(creds
->session_key
));
555 memcpy(creds
->seed
.data
, creds_in
->seed
.data
, sizeof(creds
->seed
.data
));
556 memcpy(creds
->client
.data
, creds_in
->client
.data
, sizeof(creds
->client
.data
));
557 memcpy(creds
->server
.data
, creds_in
->server
.data
, sizeof(creds
->server
.data
));