docs: man ndrdump: Add missing meta data.
[Samba/gebeck_regimport.git] / libcli / auth / credentials.c
blobdfbfdb356aa65abc3027f4581491a685a15d43f1
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);
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
232 credentials
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);
246 if (!creds) {
247 return NULL;
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) {
255 talloc_free(creds);
256 return NULL;
258 creds->account_name = talloc_strdup(creds, client_account);
259 if (!creds->account_name) {
260 talloc_free(creds);
261 return NULL;
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,
270 client_challenge,
271 server_challenge,
272 machine_password);
273 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
274 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
275 } else {
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;
285 return creds;
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);
298 if (!creds) {
299 return NULL;
302 memcpy(creds->session_key, session_key, 16);
304 return creds;
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
312 the server
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"));
333 return false;
335 return true;
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);
354 return false;
356 return true;
360 initialise the credentials chain and return the first server
361 credentials
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);
377 if (!creds) {
378 return NULL;
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) {
390 talloc_free(creds);
391 return NULL;
393 creds->account_name = talloc_strdup(creds, client_account);
394 if (!creds->account_name) {
395 talloc_free(creds);
396 return NULL;
399 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
400 netlogon_creds_init_hmac_sha256(creds,
401 client_challenge,
402 server_challenge,
403 machine_password);
404 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
405 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
406 machine_password);
407 } else {
408 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
409 machine_password);
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)) {
423 talloc_free(creds);
424 return NULL;
427 *credentials_out = creds->server;
429 dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
431 return creds;
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;
442 if (!creds) {
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;
453 return NT_STATUS_OK;
454 } else {
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) {
468 case 2:
469 if (validation->sam2) {
470 base = &validation->sam2->base;
472 break;
473 case 3:
474 if (validation->sam3) {
475 base = &validation->sam3->base;
477 break;
478 case 6:
479 if (validation->sam6) {
480 base = &validation->sam6->base;
482 break;
483 default:
484 /* If we can't find it, we can't very well decrypt it */
485 return;
488 if (!base) {
489 return;
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,
499 base->key.key,
500 sizeof(base->key.key));
503 if (memcmp(base->LMSessKey.key, zeros,
504 sizeof(base->LMSessKey.key)) != 0) {
505 netlogon_creds_arcfour_crypt(creds,
506 base->LMSessKey.key,
507 sizeof(base->LMSessKey.key));
509 } else {
510 if (memcmp(base->LMSessKey.key, zeros,
511 sizeof(base->LMSessKey.key)) != 0) {
512 netlogon_creds_des_decrypt_LMKey(creds,
513 &base->LMSessKey);
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);
527 if (!creds) {
528 return NULL;
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) {
537 talloc_free(creds);
538 return NULL;
540 creds->account_name = talloc_strdup(creds, creds_in->account_name);
541 if (!creds->account_name) {
542 talloc_free(creds);
543 return NULL;
546 if (creds_in->sid) {
547 creds->sid = dom_sid_dup(creds, creds_in->sid);
548 if (!creds->sid) {
549 talloc_free(creds);
550 return NULL;
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));
559 return creds;