libsmbclient: Make cli_connect_sock async
[Samba/gebeck_regimport.git] / libcli / auth / credentials.c
blob2f143745e8d064189d8051e9f7535ea7fbf74fa8
1 /*
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/>.
23 #include "includes.h"
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) {
34 AES_KEY key;
35 uint8_t iv[AES_BLOCK_SIZE];
37 AES_set_encrypt_key(creds->session_key, 128, &key);
38 ZERO_STRUCT(iv);
40 aes_cfb8_encrypt(in->data, out->data, 8, &key, iv, AES_ENCRYPT);
41 } else {
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)
56 uint32_t sum[2];
57 uint8_t sum2[8];
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);
62 SIVAL(sum2,0,sum[0]);
63 SIVAL(sum2,4,sum[1]);
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];
81 HMACMD5Context ctx;
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);
89 MD5Init(&md5);
90 MD5Update(&md5, zero, sizeof(zero));
91 MD5Update(&md5, client_challenge->data, 8);
92 MD5Update(&md5, server_challenge->data, 8);
93 MD5Final(tmp, &md5);
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),
115 &ctx);
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));
122 ZERO_STRUCT(digest);
123 ZERO_STRUCT(ctx);
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);
180 *key = tmp;
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);
190 *key = tmp;
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);
200 *pass = tmp;
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);
210 *pass = tmp;
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)
230 AES_KEY key;
231 uint8_t iv[AES_BLOCK_SIZE];
233 AES_set_encrypt_key(creds->session_key, 128, &key);
234 ZERO_STRUCT(iv);
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)
244 AES_KEY key;
245 uint8_t iv[AES_BLOCK_SIZE];
247 AES_set_encrypt_key(creds->session_key, 128, &key);
248 ZERO_STRUCT(iv);
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
260 credentials
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 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 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
274 if (!creds) {
275 return NULL;
278 creds->sequence = time(NULL);
279 creds->negotiate_flags = negotiate_flags;
281 creds->computer_name = talloc_strdup(creds, client_computer_name);
282 if (!creds->computer_name) {
283 talloc_free(creds);
284 return NULL;
286 creds->account_name = talloc_strdup(creds, client_account);
287 if (!creds->account_name) {
288 talloc_free(creds);
289 return NULL;
292 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
293 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
294 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
296 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
297 netlogon_creds_init_hmac_sha256(creds,
298 client_challenge,
299 server_challenge,
300 machine_password);
301 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
302 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
303 } else {
304 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
307 netlogon_creds_first_step(creds, client_challenge, server_challenge);
309 dump_data_pw("Session key", creds->session_key, 16);
310 dump_data_pw("Credential ", creds->client.data, 8);
312 *initial_credential = creds->client;
313 return creds;
317 initialise the credentials structure with only a session key. The caller better know what they are doing!
320 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
321 const uint8_t session_key[16])
323 struct netlogon_creds_CredentialState *creds;
325 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
326 if (!creds) {
327 return NULL;
330 memcpy(creds->session_key, session_key, 16);
332 return creds;
336 step the credentials to the next element in the chain, updating the
337 current client and server credentials and the seed
339 produce the next authenticator in the sequence ready to send to
340 the server
342 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
343 struct netr_Authenticator *next)
345 creds->sequence += 2;
346 netlogon_creds_step(creds);
348 next->cred = creds->client;
349 next->timestamp = creds->sequence;
353 check that a credentials reply from a server is correct
355 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
356 const struct netr_Credential *received_credentials)
358 if (!received_credentials ||
359 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
360 DEBUG(2,("credentials check failed\n"));
361 return false;
363 return true;
367 /*****************************************************************
368 The above functions are common to the client and server interface
369 next comes the server specific functions
370 ******************************************************************/
373 check that a credentials reply from a server is correct
375 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
376 const struct netr_Credential *received_credentials)
378 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
379 DEBUG(2,("credentials check failed\n"));
380 dump_data_pw("client creds", creds->client.data, 8);
381 dump_data_pw("calc creds", received_credentials->data, 8);
382 return false;
384 return true;
388 initialise the credentials chain and return the first server
389 credentials
391 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
392 const char *client_account,
393 const char *client_computer_name,
394 uint16_t secure_channel_type,
395 const struct netr_Credential *client_challenge,
396 const struct netr_Credential *server_challenge,
397 const struct samr_Password *machine_password,
398 struct netr_Credential *credentials_in,
399 struct netr_Credential *credentials_out,
400 uint32_t negotiate_flags)
403 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
405 if (!creds) {
406 return NULL;
409 creds->negotiate_flags = negotiate_flags;
410 creds->secure_channel_type = secure_channel_type;
412 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
413 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
414 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
416 creds->computer_name = talloc_strdup(creds, client_computer_name);
417 if (!creds->computer_name) {
418 talloc_free(creds);
419 return NULL;
421 creds->account_name = talloc_strdup(creds, client_account);
422 if (!creds->account_name) {
423 talloc_free(creds);
424 return NULL;
427 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
428 netlogon_creds_init_hmac_sha256(creds,
429 client_challenge,
430 server_challenge,
431 machine_password);
432 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
433 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
434 machine_password);
435 } else {
436 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
437 machine_password);
440 netlogon_creds_first_step(creds, client_challenge, server_challenge);
442 dump_data_pw("Session key", creds->session_key, 16);
443 dump_data_pw("Client Credential ", creds->client.data, 8);
444 dump_data_pw("Server Credential ", creds->server.data, 8);
446 dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
448 /* And before we leak information about the machine account
449 * password, check that they got the first go right */
450 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
451 talloc_free(creds);
452 return NULL;
455 *credentials_out = creds->server;
457 dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
459 return creds;
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;
470 if (!creds) {
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;
481 return NT_STATUS_OK;
482 } else {
483 ZERO_STRUCTP(return_authenticator);
484 return NT_STATUS_ACCESS_DENIED;
488 static void netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
489 uint16_t validation_level,
490 union netr_Validation *validation,
491 bool encrypt)
493 static const char zeros[16];
495 struct netr_SamBaseInfo *base = NULL;
496 switch (validation_level) {
497 case 2:
498 if (validation->sam2) {
499 base = &validation->sam2->base;
501 break;
502 case 3:
503 if (validation->sam3) {
504 base = &validation->sam3->base;
506 break;
507 case 6:
508 if (validation->sam6) {
509 base = &validation->sam6->base;
511 break;
512 default:
513 /* If we can't find it, we can't very well decrypt it */
514 return;
517 if (!base) {
518 return;
521 /* find and decyrpt the session keys, return in parameters above */
522 if (validation_level == 6) {
523 /* they aren't encrypted! */
524 } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
525 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
526 if (memcmp(base->key.key, zeros,
527 sizeof(base->key.key)) != 0) {
528 if (encrypt) {
529 netlogon_creds_aes_encrypt(creds,
530 base->key.key,
531 sizeof(base->key.key));
532 } else {
533 netlogon_creds_aes_decrypt(creds,
534 base->key.key,
535 sizeof(base->key.key));
539 if (memcmp(base->LMSessKey.key, zeros,
540 sizeof(base->LMSessKey.key)) != 0) {
541 if (encrypt) {
542 netlogon_creds_aes_encrypt(creds,
543 base->LMSessKey.key,
544 sizeof(base->LMSessKey.key));
546 } else {
547 netlogon_creds_aes_decrypt(creds,
548 base->LMSessKey.key,
549 sizeof(base->LMSessKey.key));
552 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
553 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
554 if (memcmp(base->key.key, zeros,
555 sizeof(base->key.key)) != 0) {
556 netlogon_creds_arcfour_crypt(creds,
557 base->key.key,
558 sizeof(base->key.key));
561 if (memcmp(base->LMSessKey.key, zeros,
562 sizeof(base->LMSessKey.key)) != 0) {
563 netlogon_creds_arcfour_crypt(creds,
564 base->LMSessKey.key,
565 sizeof(base->LMSessKey.key));
567 } else {
568 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
569 if (memcmp(base->LMSessKey.key, zeros,
570 sizeof(base->LMSessKey.key)) != 0) {
571 if (encrypt) {
572 netlogon_creds_des_encrypt_LMKey(creds,
573 &base->LMSessKey);
574 } else {
575 netlogon_creds_des_decrypt_LMKey(creds,
576 &base->LMSessKey);
582 void netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
583 uint16_t validation_level,
584 union netr_Validation *validation)
586 netlogon_creds_crypt_samlogon_validation(creds, validation_level,
587 validation, false);
590 void netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
591 uint16_t validation_level,
592 union netr_Validation *validation)
594 netlogon_creds_crypt_samlogon_validation(creds, validation_level,
595 validation, true);
599 copy a netlogon_creds_CredentialState struct
602 struct netlogon_creds_CredentialState *netlogon_creds_copy(TALLOC_CTX *mem_ctx,
603 struct netlogon_creds_CredentialState *creds_in)
605 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
607 if (!creds) {
608 return NULL;
611 creds->sequence = creds_in->sequence;
612 creds->negotiate_flags = creds_in->negotiate_flags;
613 creds->secure_channel_type = creds_in->secure_channel_type;
615 creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
616 if (!creds->computer_name) {
617 talloc_free(creds);
618 return NULL;
620 creds->account_name = talloc_strdup(creds, creds_in->account_name);
621 if (!creds->account_name) {
622 talloc_free(creds);
623 return NULL;
626 if (creds_in->sid) {
627 creds->sid = dom_sid_dup(creds, creds_in->sid);
628 if (!creds->sid) {
629 talloc_free(creds);
630 return NULL;
634 memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
635 memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
636 memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
637 memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
639 return creds;