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