Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : code to manipulate domain credentials
5 :
6 : Copyright (C) Andrew Tridgell 1997-2003
7 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
8 :
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.
13 :
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.
18 :
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/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/time.h"
25 : #include "libcli/auth/libcli_auth.h"
26 : #include "../libcli/security/dom_sid.h"
27 : #include "lib/util/util_str_escape.h"
28 :
29 : #ifndef HAVE_GNUTLS_AES_CFB8
30 : #include "lib/crypto/aes.h"
31 : #endif
32 :
33 : #include "lib/crypto/gnutls_helpers.h"
34 : #include <gnutls/gnutls.h>
35 : #include <gnutls/crypto.h>
36 :
37 12508 : bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge)
38 : {
39 : /*
40 : * If none of the first 5 bytes of the client challenge is unique, the
41 : * server MUST fail session-key negotiation without further processing
42 : * of the following steps.
43 : */
44 :
45 18157 : if (challenge->data[1] == challenge->data[0] &&
46 11354 : challenge->data[2] == challenge->data[0] &&
47 11327 : challenge->data[3] == challenge->data[0] &&
48 5705 : challenge->data[4] == challenge->data[0])
49 : {
50 5699 : return false;
51 : }
52 :
53 6809 : return true;
54 : }
55 :
56 5687 : void netlogon_creds_random_challenge(struct netr_Credential *challenge)
57 : {
58 5687 : ZERO_STRUCTP(challenge);
59 16978 : while (!netlogon_creds_is_random_challenge(challenge)) {
60 5687 : generate_random_buffer(challenge->data, sizeof(challenge->data));
61 : }
62 5687 : }
63 :
64 42034 : static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
65 : const struct netr_Credential *in,
66 : struct netr_Credential *out)
67 : {
68 : NTSTATUS status;
69 : int rc;
70 :
71 42034 : if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
72 20280 : memcpy(out->data, in->data, sizeof(out->data));
73 :
74 20280 : status = netlogon_creds_aes_encrypt(creds,
75 20280 : out->data,
76 : sizeof(out->data));
77 20280 : if (!NT_STATUS_IS_OK(status)) {
78 0 : return status;
79 : }
80 : } else {
81 21754 : rc = des_crypt112(out->data, in->data, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
82 21754 : if (rc != 0) {
83 0 : return gnutls_error_to_ntstatus(rc,
84 : NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
85 : }
86 : }
87 :
88 42034 : return NT_STATUS_OK;
89 : }
90 :
91 : /*
92 : initialise the credentials state for old-style 64 bit session keys
93 :
94 : this call is made after the netr_ServerReqChallenge call
95 : */
96 315 : static NTSTATUS netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
97 : const struct netr_Credential *client_challenge,
98 : const struct netr_Credential *server_challenge,
99 : const struct samr_Password *machine_password)
100 : {
101 : uint32_t sum[2];
102 : uint8_t sum2[8];
103 : int rc;
104 :
105 315 : sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
106 315 : sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
107 :
108 315 : SIVAL(sum2,0,sum[0]);
109 315 : SIVAL(sum2,4,sum[1]);
110 :
111 315 : ZERO_ARRAY(creds->session_key);
112 :
113 315 : rc = des_crypt128(creds->session_key, sum2, machine_password->hash);
114 315 : if (rc != 0) {
115 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
116 : }
117 :
118 315 : return NT_STATUS_OK;
119 : }
120 :
121 : /*
122 : initialise the credentials state for ADS-style 128 bit session keys
123 :
124 : this call is made after the netr_ServerReqChallenge call
125 : */
126 180 : static NTSTATUS netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
127 : const struct netr_Credential *client_challenge,
128 : const struct netr_Credential *server_challenge,
129 : const struct samr_Password *machine_password)
130 180 : {
131 180 : uint8_t zero[4] = {0};
132 720 : uint8_t tmp[gnutls_hash_get_len(GNUTLS_MAC_MD5)];
133 180 : gnutls_hash_hd_t hash_hnd = NULL;
134 : int rc;
135 :
136 180 : ZERO_ARRAY(creds->session_key);
137 :
138 180 : rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
139 180 : if (rc < 0) {
140 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
141 : }
142 :
143 180 : rc = gnutls_hash(hash_hnd, zero, sizeof(zero));
144 180 : if (rc < 0) {
145 0 : gnutls_hash_deinit(hash_hnd, NULL);
146 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
147 : }
148 180 : rc = gnutls_hash(hash_hnd, client_challenge->data, 8);
149 180 : if (rc < 0) {
150 0 : gnutls_hash_deinit(hash_hnd, NULL);
151 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
152 : }
153 180 : rc = gnutls_hash(hash_hnd, server_challenge->data, 8);
154 180 : if (rc < 0) {
155 0 : gnutls_hash_deinit(hash_hnd, NULL);
156 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
157 : }
158 :
159 180 : gnutls_hash_deinit(hash_hnd, tmp);
160 :
161 : /* This doesn't require HMAC MD5 RFC2104 as the hash is only 16 bytes */
162 360 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
163 180 : machine_password->hash,
164 : sizeof(machine_password->hash),
165 : tmp,
166 180 : sizeof(tmp),
167 180 : creds->session_key);
168 360 : ZERO_ARRAY(tmp);
169 :
170 180 : if (rc < 0) {
171 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
172 : }
173 :
174 180 : return NT_STATUS_OK;
175 : }
176 :
177 : /*
178 : initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
179 :
180 : this call is made after the netr_ServerReqChallenge call
181 : */
182 5482 : static NTSTATUS netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
183 : const struct netr_Credential *client_challenge,
184 : const struct netr_Credential *server_challenge,
185 : const struct samr_Password *machine_password)
186 5482 : {
187 5482 : gnutls_hmac_hd_t hmac_hnd = NULL;
188 16363 : uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
189 : int rc;
190 :
191 5482 : ZERO_ARRAY(creds->session_key);
192 :
193 5482 : rc = gnutls_hmac_init(&hmac_hnd,
194 : GNUTLS_MAC_SHA256,
195 5482 : machine_password->hash,
196 : sizeof(machine_password->hash));
197 5482 : if (rc < 0) {
198 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
199 : }
200 5482 : rc = gnutls_hmac(hmac_hnd,
201 5482 : client_challenge->data,
202 : 8);
203 5482 : if (rc < 0) {
204 0 : gnutls_hmac_deinit(hmac_hnd, NULL);
205 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
206 : }
207 5482 : rc = gnutls_hmac(hmac_hnd,
208 5482 : server_challenge->data,
209 : 8);
210 5482 : if (rc < 0) {
211 0 : gnutls_hmac_deinit(hmac_hnd, NULL);
212 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
213 : }
214 5482 : gnutls_hmac_deinit(hmac_hnd, digest);
215 :
216 5482 : memcpy(creds->session_key, digest, sizeof(creds->session_key));
217 :
218 10881 : ZERO_ARRAY(digest);
219 :
220 5482 : return NT_STATUS_OK;
221 : }
222 :
223 5977 : static NTSTATUS netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
224 : const struct netr_Credential *client_challenge,
225 : const struct netr_Credential *server_challenge)
226 : {
227 : NTSTATUS status;
228 :
229 5977 : status = netlogon_creds_step_crypt(creds,
230 : client_challenge,
231 : &creds->client);
232 5977 : if (!NT_STATUS_IS_OK(status)) {
233 0 : return status;
234 : }
235 :
236 5977 : status = netlogon_creds_step_crypt(creds,
237 : server_challenge,
238 : &creds->server);
239 5977 : if (!NT_STATUS_IS_OK(status)) {
240 0 : return status;
241 : }
242 :
243 5977 : creds->seed = creds->client;
244 :
245 5977 : return NT_STATUS_OK;
246 : }
247 :
248 : /*
249 : step the credentials to the next element in the chain, updating the
250 : current client and server credentials and the seed
251 : */
252 15040 : static NTSTATUS netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
253 : {
254 : struct netr_Credential time_cred;
255 : NTSTATUS status;
256 :
257 15040 : DEBUG(5,("\tseed %08x:%08x\n",
258 : IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
259 :
260 15040 : SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
261 15040 : SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
262 :
263 15040 : DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
264 :
265 15040 : status = netlogon_creds_step_crypt(creds,
266 : &time_cred,
267 : &creds->client);
268 15040 : if (!NT_STATUS_IS_OK(status)) {
269 0 : return status;
270 : }
271 :
272 15040 : DEBUG(5,("\tCLIENT %08x:%08x\n",
273 : IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
274 :
275 15040 : SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
276 15040 : SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
277 :
278 15040 : DEBUG(5,("\tseed+time+1 %08x:%08x\n",
279 : IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
280 :
281 15040 : status = netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
282 15040 : if (!NT_STATUS_IS_OK(status)) {
283 0 : return status;
284 : }
285 :
286 15040 : DEBUG(5,("\tSERVER %08x:%08x\n",
287 : IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
288 :
289 15040 : creds->seed = time_cred;
290 :
291 15040 : return NT_STATUS_OK;
292 : }
293 :
294 : /*
295 : DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
296 : */
297 54 : NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds,
298 : struct netr_LMSessionKey *key)
299 : {
300 : int rc;
301 : struct netr_LMSessionKey tmp;
302 :
303 54 : rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
304 54 : if (rc < 0) {
305 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
306 : }
307 54 : *key = tmp;
308 :
309 54 : return NT_STATUS_OK;
310 : }
311 :
312 : /*
313 : DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
314 : */
315 0 : NTSTATUS netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds,
316 : struct netr_LMSessionKey *key)
317 : {
318 : int rc;
319 : struct netr_LMSessionKey tmp;
320 :
321 0 : rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_DECRYPT);
322 0 : if (rc < 0) {
323 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
324 : }
325 0 : *key = tmp;
326 :
327 0 : return NT_STATUS_OK;
328 : }
329 :
330 : /*
331 : DES encrypt a 16 byte password buffer using the session key
332 : */
333 166 : NTSTATUS netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds,
334 : struct samr_Password *pass)
335 : {
336 : struct samr_Password tmp;
337 : int rc;
338 :
339 166 : rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
340 166 : if (rc < 0) {
341 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
342 : }
343 166 : *pass = tmp;
344 :
345 166 : return NT_STATUS_OK;
346 : }
347 :
348 : /*
349 : DES decrypt a 16 byte password buffer using the session key
350 : */
351 48 : NTSTATUS netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds,
352 : struct samr_Password *pass)
353 : {
354 : struct samr_Password tmp;
355 : int rc;
356 :
357 48 : rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_DECRYPT);
358 48 : if (rc < 0) {
359 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
360 : }
361 48 : *pass = tmp;
362 :
363 48 : return NT_STATUS_OK;
364 : }
365 :
366 : /*
367 : ARCFOUR encrypt/decrypt a password buffer using the session key
368 : */
369 7700 : NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
370 : uint8_t *data,
371 : size_t len)
372 : {
373 7700 : gnutls_cipher_hd_t cipher_hnd = NULL;
374 7700 : gnutls_datum_t session_key = {
375 7700 : .data = creds->session_key,
376 : .size = sizeof(creds->session_key),
377 : };
378 : int rc;
379 :
380 7700 : rc = gnutls_cipher_init(&cipher_hnd,
381 : GNUTLS_CIPHER_ARCFOUR_128,
382 : &session_key,
383 : NULL);
384 7700 : if (rc < 0) {
385 0 : return gnutls_error_to_ntstatus(rc,
386 : NT_STATUS_CRYPTO_SYSTEM_INVALID);
387 : }
388 7700 : rc = gnutls_cipher_encrypt(cipher_hnd,
389 : data,
390 : len);
391 7700 : gnutls_cipher_deinit(cipher_hnd);
392 7700 : if (rc < 0) {
393 0 : return gnutls_error_to_ntstatus(rc,
394 : NT_STATUS_CRYPTO_SYSTEM_INVALID);
395 : }
396 :
397 7700 : return NT_STATUS_OK;
398 : }
399 :
400 : /*
401 : AES encrypt a password buffer using the session key
402 : */
403 24410 : NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
404 : uint8_t *data,
405 : size_t len)
406 394 : {
407 : #ifdef HAVE_GNUTLS_AES_CFB8
408 394 : gnutls_cipher_hd_t cipher_hnd = NULL;
409 394 : gnutls_datum_t key = {
410 394 : .data = creds->session_key,
411 : .size = sizeof(creds->session_key),
412 : };
413 : uint32_t iv_size =
414 394 : gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
415 394 : uint8_t _iv[iv_size];
416 394 : gnutls_datum_t iv = {
417 : .data = _iv,
418 : .size = iv_size,
419 : };
420 : int rc;
421 :
422 394 : ZERO_ARRAY(_iv);
423 :
424 394 : rc = gnutls_cipher_init(&cipher_hnd,
425 : GNUTLS_CIPHER_AES_128_CFB8,
426 : &key,
427 : &iv);
428 394 : if (rc < 0) {
429 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
430 : }
431 :
432 394 : rc = gnutls_cipher_encrypt(cipher_hnd, data, len);
433 394 : gnutls_cipher_deinit(cipher_hnd);
434 394 : if (rc < 0) {
435 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
436 : }
437 :
438 : #else /* NOT HAVE_GNUTLS_AES_CFB8 */
439 : AES_KEY key;
440 24016 : uint8_t iv[AES_BLOCK_SIZE] = {0};
441 :
442 24016 : AES_set_encrypt_key(creds->session_key, 128, &key);
443 :
444 24016 : aes_cfb8_encrypt(data, data, len, &key, iv, AES_ENCRYPT);
445 : #endif /* HAVE_GNUTLS_AES_CFB8 */
446 :
447 24410 : return NT_STATUS_OK;
448 : }
449 :
450 : /*
451 : AES decrypt a password buffer using the session key
452 : */
453 2149 : NTSTATUS netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
454 334 : {
455 : #ifdef HAVE_GNUTLS_AES_CFB8
456 334 : gnutls_cipher_hd_t cipher_hnd = NULL;
457 334 : gnutls_datum_t key = {
458 334 : .data = creds->session_key,
459 : .size = sizeof(creds->session_key),
460 : };
461 : uint32_t iv_size =
462 334 : gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
463 334 : uint8_t _iv[iv_size];
464 334 : gnutls_datum_t iv = {
465 : .data = _iv,
466 : .size = iv_size,
467 : };
468 : int rc;
469 :
470 334 : ZERO_ARRAY(_iv);
471 :
472 334 : rc = gnutls_cipher_init(&cipher_hnd,
473 : GNUTLS_CIPHER_AES_128_CFB8,
474 : &key,
475 : &iv);
476 334 : if (rc < 0) {
477 0 : return gnutls_error_to_ntstatus(rc,
478 : NT_STATUS_CRYPTO_SYSTEM_INVALID);
479 : }
480 :
481 334 : rc = gnutls_cipher_decrypt(cipher_hnd, data, len);
482 334 : gnutls_cipher_deinit(cipher_hnd);
483 334 : if (rc < 0) {
484 0 : return gnutls_error_to_ntstatus(rc,
485 : NT_STATUS_CRYPTO_SYSTEM_INVALID);
486 : }
487 :
488 : #else /* NOT HAVE_GNUTLS_AES_CFB8 */
489 : AES_KEY key;
490 1815 : uint8_t iv[AES_BLOCK_SIZE] = {0};
491 :
492 1815 : AES_set_encrypt_key(creds->session_key, 128, &key);
493 :
494 1815 : aes_cfb8_encrypt(data, data, len, &key, iv, AES_DECRYPT);
495 : #endif /* HAVE_GNUTLS_AES_CFB8 */
496 :
497 2149 : return NT_STATUS_OK;
498 : }
499 :
500 : /*****************************************************************
501 : The above functions are common to the client and server interface
502 : next comes the client specific functions
503 : ******************************************************************/
504 :
505 : /*
506 : initialise the credentials chain and return the first client
507 : credentials
508 : */
509 :
510 4855 : struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
511 : const char *client_account,
512 : const char *client_computer_name,
513 : uint16_t secure_channel_type,
514 : const struct netr_Credential *client_challenge,
515 : const struct netr_Credential *server_challenge,
516 : const struct samr_Password *machine_password,
517 : struct netr_Credential *initial_credential,
518 : uint32_t negotiate_flags)
519 : {
520 4855 : struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
521 : NTSTATUS status;
522 :
523 4855 : if (!creds) {
524 0 : return NULL;
525 : }
526 :
527 4855 : creds->sequence = time(NULL);
528 4855 : creds->negotiate_flags = negotiate_flags;
529 4855 : creds->secure_channel_type = secure_channel_type;
530 :
531 4855 : creds->computer_name = talloc_strdup(creds, client_computer_name);
532 4855 : if (!creds->computer_name) {
533 0 : talloc_free(creds);
534 0 : return NULL;
535 : }
536 4855 : creds->account_name = talloc_strdup(creds, client_account);
537 4855 : if (!creds->account_name) {
538 0 : talloc_free(creds);
539 0 : return NULL;
540 : }
541 :
542 4855 : dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
543 4855 : dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
544 4855 : dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
545 :
546 4855 : if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
547 4594 : status = netlogon_creds_init_hmac_sha256(creds,
548 : client_challenge,
549 : server_challenge,
550 : machine_password);
551 4594 : if (!NT_STATUS_IS_OK(status)) {
552 0 : talloc_free(creds);
553 0 : return NULL;
554 : }
555 261 : } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
556 90 : status = netlogon_creds_init_128bit(creds,
557 : client_challenge,
558 : server_challenge,
559 : machine_password);
560 90 : if (!NT_STATUS_IS_OK(status)) {
561 0 : talloc_free(creds);
562 0 : return NULL;
563 : }
564 : } else {
565 171 : status = netlogon_creds_init_64bit(creds,
566 : client_challenge,
567 : server_challenge,
568 : machine_password);
569 171 : if (!NT_STATUS_IS_OK(status)) {
570 0 : talloc_free(creds);
571 0 : return NULL;
572 : }
573 : }
574 :
575 4855 : status = netlogon_creds_first_step(creds,
576 : client_challenge,
577 : server_challenge);
578 4855 : if (!NT_STATUS_IS_OK(status)) {
579 0 : talloc_free(creds);
580 0 : return NULL;
581 : }
582 :
583 4855 : dump_data_pw("Session key", creds->session_key, 16);
584 4855 : dump_data_pw("Credential ", creds->client.data, 8);
585 :
586 4855 : *initial_credential = creds->client;
587 4855 : return creds;
588 : }
589 :
590 : /*
591 : initialise the credentials structure with only a session key. The caller better know what they are doing!
592 : */
593 :
594 0 : struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
595 : const uint8_t session_key[16])
596 : {
597 : struct netlogon_creds_CredentialState *creds;
598 :
599 0 : creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
600 0 : if (!creds) {
601 0 : return NULL;
602 : }
603 :
604 0 : memcpy(creds->session_key, session_key, 16);
605 :
606 0 : return creds;
607 : }
608 :
609 : /*
610 : step the credentials to the next element in the chain, updating the
611 : current client and server credentials and the seed
612 :
613 : produce the next authenticator in the sequence ready to send to
614 : the server
615 : */
616 : NTSTATUS
617 7851 : netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
618 : struct netr_Authenticator *next)
619 : {
620 7851 : uint32_t t32n = (uint32_t)time(NULL);
621 : NTSTATUS status;
622 :
623 : /*
624 : * we always increment and ignore an overflow here
625 : */
626 7851 : creds->sequence += 2;
627 :
628 7851 : if (t32n > creds->sequence) {
629 : /*
630 : * we may increment more
631 : */
632 15 : creds->sequence = t32n;
633 : } else {
634 7836 : uint32_t d = creds->sequence - t32n;
635 :
636 7836 : if (d >= INT32_MAX) {
637 : /*
638 : * got an overflow of time_t vs. uint32_t
639 : */
640 0 : creds->sequence = t32n;
641 : }
642 : }
643 :
644 7851 : status = netlogon_creds_step(creds);
645 7851 : if (!NT_STATUS_IS_OK(status)) {
646 0 : return status;
647 : }
648 :
649 7851 : next->cred = creds->client;
650 7851 : next->timestamp = creds->sequence;
651 :
652 7851 : return NT_STATUS_OK;
653 : }
654 :
655 : /*
656 : check that a credentials reply from a server is correct
657 : */
658 7664 : bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
659 : const struct netr_Credential *received_credentials)
660 : {
661 15300 : if (!received_credentials ||
662 7664 : !mem_equal_const_time(received_credentials->data, creds->server.data, 8)) {
663 9 : DEBUG(2,("credentials check failed\n"));
664 9 : return false;
665 : }
666 7655 : return true;
667 : }
668 :
669 :
670 : /*****************************************************************
671 : The above functions are common to the client and server interface
672 : next comes the server specific functions
673 : ******************************************************************/
674 :
675 : /*
676 : check that a credentials reply from a server is correct
677 : */
678 8311 : static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
679 : const struct netr_Credential *received_credentials)
680 : {
681 8311 : if (!mem_equal_const_time(received_credentials->data, creds->client.data, 8)) {
682 154 : DEBUG(2,("credentials check failed\n"));
683 154 : dump_data_pw("client creds", creds->client.data, 8);
684 154 : dump_data_pw("calc creds", received_credentials->data, 8);
685 154 : return false;
686 : }
687 8157 : return true;
688 : }
689 :
690 : /*
691 : initialise the credentials chain and return the first server
692 : credentials
693 : */
694 1134 : struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
695 : const char *client_account,
696 : const char *client_computer_name,
697 : uint16_t secure_channel_type,
698 : const struct netr_Credential *client_challenge,
699 : const struct netr_Credential *server_challenge,
700 : const struct samr_Password *machine_password,
701 : const struct netr_Credential *credentials_in,
702 : struct netr_Credential *credentials_out,
703 : uint32_t negotiate_flags)
704 : {
705 :
706 1134 : struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
707 : NTSTATUS status;
708 : bool ok;
709 :
710 1134 : if (!creds) {
711 0 : return NULL;
712 : }
713 :
714 1134 : creds->negotiate_flags = negotiate_flags;
715 1134 : creds->secure_channel_type = secure_channel_type;
716 :
717 1134 : dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
718 1134 : dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
719 1134 : dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
720 :
721 1134 : ok = netlogon_creds_is_random_challenge(client_challenge);
722 1134 : if (!ok) {
723 12 : DBG_WARNING("CVE-2020-1472(ZeroLogon): "
724 : "non-random client challenge rejected for "
725 : "client_account[%s] client_computer_name[%s]\n",
726 : log_escape(mem_ctx, client_account),
727 : log_escape(mem_ctx, client_computer_name));
728 12 : dump_data(DBGLVL_WARNING,
729 12 : client_challenge->data,
730 : sizeof(client_challenge->data));
731 12 : talloc_free(creds);
732 12 : return NULL;
733 : }
734 :
735 1122 : creds->computer_name = talloc_strdup(creds, client_computer_name);
736 1122 : if (!creds->computer_name) {
737 0 : talloc_free(creds);
738 0 : return NULL;
739 : }
740 1122 : creds->account_name = talloc_strdup(creds, client_account);
741 1122 : if (!creds->account_name) {
742 0 : talloc_free(creds);
743 0 : return NULL;
744 : }
745 :
746 1122 : if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
747 888 : status = netlogon_creds_init_hmac_sha256(creds,
748 : client_challenge,
749 : server_challenge,
750 : machine_password);
751 888 : if (!NT_STATUS_IS_OK(status)) {
752 0 : talloc_free(creds);
753 0 : return NULL;
754 : }
755 234 : } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
756 90 : status = netlogon_creds_init_128bit(creds,
757 : client_challenge,
758 : server_challenge,
759 : machine_password);
760 90 : if (!NT_STATUS_IS_OK(status)) {
761 0 : talloc_free(creds);
762 0 : return NULL;
763 : }
764 : } else {
765 144 : status = netlogon_creds_init_64bit(creds,
766 : client_challenge,
767 : server_challenge,
768 : machine_password);
769 144 : if (!NT_STATUS_IS_OK(status)) {
770 0 : talloc_free(creds);
771 0 : return NULL;
772 : }
773 : }
774 :
775 1122 : status = netlogon_creds_first_step(creds,
776 : client_challenge,
777 : server_challenge);
778 1122 : if (!NT_STATUS_IS_OK(status)) {
779 0 : talloc_free(creds);
780 0 : return NULL;
781 : }
782 :
783 1122 : dump_data_pw("Session key", creds->session_key, 16);
784 1122 : dump_data_pw("Client Credential ", creds->client.data, 8);
785 1122 : dump_data_pw("Server Credential ", creds->server.data, 8);
786 :
787 1122 : dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
788 :
789 : /* And before we leak information about the machine account
790 : * password, check that they got the first go right */
791 1122 : if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
792 154 : talloc_free(creds);
793 154 : return NULL;
794 : }
795 :
796 968 : *credentials_out = creds->server;
797 :
798 968 : dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
799 :
800 968 : return creds;
801 : }
802 :
803 7189 : NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
804 : const struct netr_Authenticator *received_authenticator,
805 : struct netr_Authenticator *return_authenticator)
806 : {
807 : NTSTATUS status;
808 :
809 7189 : if (!received_authenticator || !return_authenticator) {
810 0 : return NT_STATUS_INVALID_PARAMETER;
811 : }
812 :
813 7189 : if (!creds) {
814 0 : return NT_STATUS_ACCESS_DENIED;
815 : }
816 :
817 7189 : creds->sequence = received_authenticator->timestamp;
818 7189 : status = netlogon_creds_step(creds);
819 7189 : if (!NT_STATUS_IS_OK(status)) {
820 0 : ZERO_STRUCTP(return_authenticator);
821 0 : return status;
822 : }
823 :
824 7189 : if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
825 7189 : return_authenticator->cred = creds->server;
826 7189 : return_authenticator->timestamp = 0;
827 7189 : return NT_STATUS_OK;
828 : } else {
829 0 : ZERO_STRUCTP(return_authenticator);
830 0 : return NT_STATUS_ACCESS_DENIED;
831 : }
832 : }
833 :
834 10251 : static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
835 : uint16_t validation_level,
836 : union netr_Validation *validation,
837 : bool do_encrypt)
838 : {
839 10251 : struct netr_SamBaseInfo *base = NULL;
840 : NTSTATUS status;
841 :
842 10251 : if (validation == NULL) {
843 0 : return NT_STATUS_INVALID_PARAMETER;
844 : }
845 :
846 10251 : switch (validation_level) {
847 3489 : case 2:
848 3489 : if (validation->sam2) {
849 3489 : base = &validation->sam2->base;
850 : }
851 3489 : break;
852 3511 : case 3:
853 3511 : if (validation->sam3) {
854 3511 : base = &validation->sam3->base;
855 : }
856 3511 : break;
857 3227 : case 6:
858 3227 : if (validation->sam6) {
859 3227 : base = &validation->sam6->base;
860 : }
861 3227 : break;
862 24 : default:
863 : /* If we can't find it, we can't very well decrypt it */
864 24 : return NT_STATUS_INVALID_INFO_CLASS;
865 : }
866 :
867 10227 : if (!base) {
868 0 : return NT_STATUS_INVALID_INFO_CLASS;
869 : }
870 :
871 : /* find and decyrpt the session keys, return in parameters above */
872 10227 : if (validation_level == 6) {
873 : /* they aren't encrypted! */
874 7000 : } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
875 : /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
876 1850 : if (!all_zero(base->key.key, sizeof(base->key.key))) {
877 1848 : if (do_encrypt) {
878 1846 : status = netlogon_creds_aes_encrypt(
879 : creds,
880 1846 : base->key.key,
881 : sizeof(base->key.key));
882 : } else {
883 2 : status = netlogon_creds_aes_decrypt(
884 : creds,
885 2 : base->key.key,
886 : sizeof(base->key.key));
887 : }
888 1848 : if (!NT_STATUS_IS_OK(status)) {
889 0 : return status;
890 : }
891 : }
892 :
893 1850 : if (!all_zero(base->LMSessKey.key,
894 : sizeof(base->LMSessKey.key))) {
895 1826 : if (do_encrypt) {
896 1826 : status = netlogon_creds_aes_encrypt(
897 : creds,
898 1826 : base->LMSessKey.key,
899 : sizeof(base->LMSessKey.key));
900 : } else {
901 0 : status = netlogon_creds_aes_decrypt(
902 : creds,
903 0 : base->LMSessKey.key,
904 : sizeof(base->LMSessKey.key));
905 : }
906 1826 : if (!NT_STATUS_IS_OK(status)) {
907 0 : return status;
908 : }
909 : }
910 5150 : } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
911 : /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
912 5096 : if (!all_zero(base->key.key, sizeof(base->key.key))) {
913 4232 : status = netlogon_creds_arcfour_crypt(creds,
914 4232 : base->key.key,
915 : sizeof(base->key.key));
916 4232 : if (!NT_STATUS_IS_OK(status)) {
917 0 : return status;
918 : }
919 : }
920 :
921 5096 : if (!all_zero(base->LMSessKey.key,
922 : sizeof(base->LMSessKey.key))) {
923 2720 : status = netlogon_creds_arcfour_crypt(creds,
924 2720 : base->LMSessKey.key,
925 : sizeof(base->LMSessKey.key));
926 2720 : if (!NT_STATUS_IS_OK(status)) {
927 0 : return status;
928 : }
929 : }
930 : } else {
931 : /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
932 54 : if (!all_zero(base->LMSessKey.key,
933 : sizeof(base->LMSessKey.key))) {
934 54 : if (do_encrypt) {
935 54 : status = netlogon_creds_des_encrypt_LMKey(creds,
936 : &base->LMSessKey);
937 : } else {
938 0 : status = netlogon_creds_des_decrypt_LMKey(creds,
939 : &base->LMSessKey);
940 : }
941 54 : if (!NT_STATUS_IS_OK(status)) {
942 0 : return status;
943 : }
944 : }
945 : }
946 :
947 10227 : return NT_STATUS_OK;
948 : }
949 :
950 3171 : NTSTATUS netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
951 : uint16_t validation_level,
952 : union netr_Validation *validation)
953 : {
954 3171 : return netlogon_creds_crypt_samlogon_validation(creds,
955 : validation_level,
956 : validation,
957 : false);
958 : }
959 :
960 7080 : NTSTATUS netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
961 : uint16_t validation_level,
962 : union netr_Validation *validation)
963 : {
964 7080 : return netlogon_creds_crypt_samlogon_validation(creds,
965 : validation_level,
966 : validation,
967 : true);
968 : }
969 :
970 10839 : static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
971 : enum netr_LogonInfoClass level,
972 : union netr_LogonLevel *logon,
973 : bool do_encrypt)
974 : {
975 : NTSTATUS status;
976 :
977 10839 : if (logon == NULL) {
978 0 : return NT_STATUS_INVALID_PARAMETER;
979 : }
980 :
981 10839 : switch (level) {
982 551 : case NetlogonInteractiveInformation:
983 : case NetlogonInteractiveTransitiveInformation:
984 : case NetlogonServiceInformation:
985 : case NetlogonServiceTransitiveInformation:
986 551 : if (logon->password == NULL) {
987 0 : return NT_STATUS_INVALID_PARAMETER;
988 : }
989 :
990 551 : if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
991 : uint8_t *h;
992 :
993 532 : h = logon->password->lmpassword.hash;
994 532 : if (!all_zero(h, 16)) {
995 532 : if (do_encrypt) {
996 3 : status = netlogon_creds_aes_encrypt(
997 : creds,
998 : h,
999 : 16);
1000 : } else {
1001 529 : status = netlogon_creds_aes_decrypt(
1002 : creds,
1003 : h,
1004 : 16);
1005 : }
1006 532 : if (!NT_STATUS_IS_OK(status)) {
1007 0 : return status;
1008 : }
1009 : }
1010 :
1011 532 : h = logon->password->ntpassword.hash;
1012 532 : if (!all_zero(h, 16)) {
1013 532 : if (do_encrypt) {
1014 3 : status = netlogon_creds_aes_encrypt(creds,
1015 : h,
1016 : 16);
1017 : } else {
1018 529 : status = netlogon_creds_aes_decrypt(creds,
1019 : h,
1020 : 16);
1021 : }
1022 532 : if (!NT_STATUS_IS_OK(status)) {
1023 0 : return status;
1024 : }
1025 : }
1026 19 : } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
1027 : uint8_t *h;
1028 :
1029 19 : h = logon->password->lmpassword.hash;
1030 19 : if (!all_zero(h, 16)) {
1031 19 : status = netlogon_creds_arcfour_crypt(creds,
1032 : h,
1033 : 16);
1034 19 : if (!NT_STATUS_IS_OK(status)) {
1035 0 : return status;
1036 : }
1037 : }
1038 :
1039 19 : h = logon->password->ntpassword.hash;
1040 19 : if (!all_zero(h, 16)) {
1041 19 : status = netlogon_creds_arcfour_crypt(creds,
1042 : h,
1043 : 16);
1044 19 : if (!NT_STATUS_IS_OK(status)) {
1045 0 : return status;
1046 : }
1047 : }
1048 : } else {
1049 : struct samr_Password *p;
1050 :
1051 0 : p = &logon->password->lmpassword;
1052 0 : if (!all_zero(p->hash, 16)) {
1053 0 : if (do_encrypt) {
1054 0 : status = netlogon_creds_des_encrypt(creds, p);
1055 : } else {
1056 0 : status = netlogon_creds_des_decrypt(creds, p);
1057 : }
1058 0 : if (!NT_STATUS_IS_OK(status)) {
1059 0 : return status;
1060 : }
1061 : }
1062 0 : p = &logon->password->ntpassword;
1063 0 : if (!all_zero(p->hash, 16)) {
1064 0 : if (do_encrypt) {
1065 0 : status = netlogon_creds_des_encrypt(creds, p);
1066 : } else {
1067 0 : status = netlogon_creds_des_decrypt(creds, p);
1068 : }
1069 0 : if (!NT_STATUS_IS_OK(status)) {
1070 0 : return status;
1071 : }
1072 : }
1073 : }
1074 551 : break;
1075 :
1076 10168 : case NetlogonNetworkInformation:
1077 : case NetlogonNetworkTransitiveInformation:
1078 10168 : break;
1079 :
1080 120 : case NetlogonGenericInformation:
1081 120 : if (logon->generic == NULL) {
1082 0 : return NT_STATUS_INVALID_PARAMETER;
1083 : }
1084 :
1085 120 : if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1086 60 : if (do_encrypt) {
1087 0 : status = netlogon_creds_aes_encrypt(
1088 : creds,
1089 0 : logon->generic->data,
1090 0 : logon->generic->length);
1091 : } else {
1092 120 : status = netlogon_creds_aes_decrypt(
1093 : creds,
1094 60 : logon->generic->data,
1095 60 : logon->generic->length);
1096 : }
1097 60 : if (!NT_STATUS_IS_OK(status)) {
1098 0 : return status;
1099 : }
1100 60 : } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
1101 120 : status = netlogon_creds_arcfour_crypt(creds,
1102 60 : logon->generic->data,
1103 60 : logon->generic->length);
1104 60 : if (!NT_STATUS_IS_OK(status)) {
1105 0 : return status;
1106 : }
1107 : } else {
1108 : /* Using DES to verify kerberos tickets makes no sense */
1109 : }
1110 120 : break;
1111 : }
1112 :
1113 10839 : return NT_STATUS_OK;
1114 : }
1115 :
1116 10830 : NTSTATUS netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
1117 : enum netr_LogonInfoClass level,
1118 : union netr_LogonLevel *logon)
1119 : {
1120 10830 : return netlogon_creds_crypt_samlogon_logon(creds, level, logon, false);
1121 : }
1122 :
1123 9 : NTSTATUS netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
1124 : enum netr_LogonInfoClass level,
1125 : union netr_LogonLevel *logon)
1126 : {
1127 9 : return netlogon_creds_crypt_samlogon_logon(creds, level, logon, true);
1128 : }
1129 :
1130 31 : union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
1131 : enum netr_LogonInfoClass level,
1132 : const union netr_LogonLevel *in)
1133 : {
1134 : union netr_LogonLevel *out;
1135 :
1136 31 : if (in == NULL) {
1137 0 : return NULL;
1138 : }
1139 :
1140 31 : out = talloc(mem_ctx, union netr_LogonLevel);
1141 31 : if (out == NULL) {
1142 0 : return NULL;
1143 : }
1144 :
1145 31 : *out = *in;
1146 :
1147 31 : switch (level) {
1148 3 : case NetlogonInteractiveInformation:
1149 : case NetlogonInteractiveTransitiveInformation:
1150 : case NetlogonServiceInformation:
1151 : case NetlogonServiceTransitiveInformation:
1152 3 : if (in->password == NULL) {
1153 0 : return out;
1154 : }
1155 :
1156 3 : out->password = talloc(out, struct netr_PasswordInfo);
1157 3 : if (out->password == NULL) {
1158 0 : talloc_free(out);
1159 0 : return NULL;
1160 : }
1161 3 : *out->password = *in->password;
1162 :
1163 3 : return out;
1164 :
1165 28 : case NetlogonNetworkInformation:
1166 : case NetlogonNetworkTransitiveInformation:
1167 28 : break;
1168 :
1169 0 : case NetlogonGenericInformation:
1170 0 : if (in->generic == NULL) {
1171 0 : return out;
1172 : }
1173 :
1174 0 : out->generic = talloc(out, struct netr_GenericInfo);
1175 0 : if (out->generic == NULL) {
1176 0 : talloc_free(out);
1177 0 : return NULL;
1178 : }
1179 0 : *out->generic = *in->generic;
1180 :
1181 0 : if (in->generic->data == NULL) {
1182 0 : return out;
1183 : }
1184 :
1185 0 : if (in->generic->length == 0) {
1186 0 : return out;
1187 : }
1188 :
1189 0 : out->generic->data = talloc_memdup(out->generic,
1190 : in->generic->data,
1191 : in->generic->length);
1192 0 : if (out->generic->data == NULL) {
1193 0 : talloc_free(out);
1194 0 : return NULL;
1195 : }
1196 :
1197 0 : return out;
1198 : }
1199 :
1200 28 : return out;
1201 : }
1202 :
1203 : /*
1204 : copy a netlogon_creds_CredentialState struct
1205 : */
1206 :
1207 2631 : struct netlogon_creds_CredentialState *netlogon_creds_copy(
1208 : TALLOC_CTX *mem_ctx,
1209 : const struct netlogon_creds_CredentialState *creds_in)
1210 : {
1211 2631 : struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
1212 :
1213 2631 : if (!creds) {
1214 0 : return NULL;
1215 : }
1216 :
1217 2631 : creds->sequence = creds_in->sequence;
1218 2631 : creds->negotiate_flags = creds_in->negotiate_flags;
1219 2631 : creds->secure_channel_type = creds_in->secure_channel_type;
1220 :
1221 2631 : creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
1222 2631 : if (!creds->computer_name) {
1223 0 : talloc_free(creds);
1224 0 : return NULL;
1225 : }
1226 2631 : creds->account_name = talloc_strdup(creds, creds_in->account_name);
1227 2631 : if (!creds->account_name) {
1228 0 : talloc_free(creds);
1229 0 : return NULL;
1230 : }
1231 :
1232 2631 : if (creds_in->sid) {
1233 1127 : creds->sid = dom_sid_dup(creds, creds_in->sid);
1234 1127 : if (!creds->sid) {
1235 0 : talloc_free(creds);
1236 0 : return NULL;
1237 : }
1238 : }
1239 :
1240 2631 : memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
1241 2631 : memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
1242 2631 : memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
1243 2631 : memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
1244 :
1245 2631 : return creds;
1246 : }
|