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