63407e798871f592a53a4dbbba5d6b90dbda5f38
[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 "../lib/crypto/crypto.h"
26 #include "libcli/auth/libcli_auth.h"
27 #include "../libcli/security/dom_sid.h"
28
29 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
30                                       const struct netr_Credential *in,
31                                       struct netr_Credential *out)
32 {
33         if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
34                 AES_KEY key;
35                 uint8_t iv[AES_BLOCK_SIZE];
36
37                 AES_set_encrypt_key(creds->session_key, 128, &key);
38                 ZERO_STRUCT(iv);
39
40                 aes_cfb8_encrypt(in->data, out->data, 8, &key, iv, AES_ENCRYPT);
41         } else {
42                 des_crypt112(out->data, in->data, creds->session_key, 1);
43         }
44 }
45
46 /*
47   initialise the credentials state for old-style 64 bit session keys
48
49   this call is made after the netr_ServerReqChallenge call
50 */
51 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
52                                       const struct netr_Credential *client_challenge,
53                                       const struct netr_Credential *server_challenge,
54                                       const struct samr_Password *machine_password)
55 {
56         uint32_t sum[2];
57         uint8_t sum2[8];
58
59         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
60         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
61
62         SIVAL(sum2,0,sum[0]);
63         SIVAL(sum2,4,sum[1]);
64
65         ZERO_STRUCT(creds->session_key);
66
67         des_crypt128(creds->session_key, sum2, machine_password->hash);
68 }
69
70 /*
71   initialise the credentials state for ADS-style 128 bit session keys
72
73   this call is made after the netr_ServerReqChallenge call
74 */
75 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
76                                        const struct netr_Credential *client_challenge,
77                                        const struct netr_Credential *server_challenge,
78                                        const struct samr_Password *machine_password)
79 {
80         unsigned char zero[4], tmp[16];
81         HMACMD5Context ctx;
82         struct MD5Context md5;
83
84         ZERO_STRUCT(creds->session_key);
85
86         memset(zero, 0, sizeof(zero));
87
88         hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
89         MD5Init(&md5);
90         MD5Update(&md5, zero, sizeof(zero));
91         MD5Update(&md5, client_challenge->data, 8);
92         MD5Update(&md5, server_challenge->data, 8);
93         MD5Final(tmp, &md5);
94         hmac_md5_update(tmp, sizeof(tmp), &ctx);
95         hmac_md5_final(creds->session_key, &ctx);
96 }
97
98 /*
99   initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
100
101   this call is made after the netr_ServerReqChallenge call
102 */
103 static void netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
104                                             const struct netr_Credential *client_challenge,
105                                             const struct netr_Credential *server_challenge,
106                                             const struct samr_Password *machine_password)
107 {
108         struct HMACSHA256Context ctx;
109         uint8_t digest[SHA256_DIGEST_LENGTH];
110
111         ZERO_STRUCT(creds->session_key);
112
113         hmac_sha256_init(machine_password->hash,
114                          sizeof(machine_password->hash),
115                          &ctx);
116         hmac_sha256_update(client_challenge->data, 8, &ctx);
117         hmac_sha256_update(server_challenge->data, 8, &ctx);
118         hmac_sha256_final(digest, &ctx);
119
120         memcpy(creds->session_key, digest, sizeof(creds->session_key));
121
122         ZERO_STRUCT(digest);
123         ZERO_STRUCT(ctx);
124 }
125
126 static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
127                                       const struct netr_Credential *client_challenge,
128                                       const struct netr_Credential *server_challenge)
129 {
130         netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
131
132         netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
133
134         creds->seed = creds->client;
135 }
136
137 /*
138   step the credentials to the next element in the chain, updating the
139   current client and server credentials and the seed
140 */
141 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
142 {
143         struct netr_Credential time_cred;
144
145         DEBUG(5,("\tseed        %08x:%08x\n",
146                  IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
147
148         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
149         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
150
151         DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
152
153         netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
154
155         DEBUG(5,("\tCLIENT      %08x:%08x\n",
156                  IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
157
158         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
159         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
160
161         DEBUG(5,("\tseed+time+1 %08x:%08x\n",
162                  IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
163
164         netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
165
166         DEBUG(5,("\tSERVER      %08x:%08x\n",
167                  IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
168
169         creds->seed = time_cred;
170 }
171
172
173 /*
174   DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
175 */
176 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
177 {
178         struct netr_LMSessionKey tmp;
179         des_crypt56(tmp.key, key->key, creds->session_key, 1);
180         *key = tmp;
181 }
182
183 /*
184   DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
185 */
186 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
187 {
188         struct netr_LMSessionKey tmp;
189         des_crypt56(tmp.key, key->key, creds->session_key, 0);
190         *key = tmp;
191 }
192
193 /*
194   DES encrypt a 16 byte password buffer using the session key
195 */
196 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
197 {
198         struct samr_Password tmp;
199         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
200         *pass = tmp;
201 }
202
203 /*
204   DES decrypt a 16 byte password buffer using the session key
205 */
206 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
207 {
208         struct samr_Password tmp;
209         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
210         *pass = tmp;
211 }
212
213 /*
214   ARCFOUR encrypt/decrypt a password buffer using the session key
215 */
216 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
217 {
218         DATA_BLOB session_key = data_blob(creds->session_key, 16);
219
220         arcfour_crypt_blob(data, len, &session_key);
221
222         data_blob_free(&session_key);
223 }
224
225 /*
226   AES encrypt a password buffer using the session key
227 */
228 void netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
229 {
230         AES_KEY key;
231         uint8_t iv[AES_BLOCK_SIZE];
232
233         AES_set_encrypt_key(creds->session_key, 128, &key);
234         ZERO_STRUCT(iv);
235
236         aes_cfb8_encrypt(data, data, len, &key, iv, AES_ENCRYPT);
237 }
238
239 /*
240   AES decrypt a password buffer using the session key
241 */
242 void netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
243 {
244         AES_KEY key;
245         uint8_t iv[AES_BLOCK_SIZE];
246
247         AES_set_encrypt_key(creds->session_key, 128, &key);
248         ZERO_STRUCT(iv);
249
250         aes_cfb8_encrypt(data, data, len, &key, iv, AES_DECRYPT);
251 }
252
253 /*****************************************************************
254 The above functions are common to the client and server interface
255 next comes the client specific functions
256 ******************************************************************/
257
258 /*
259   initialise the credentials chain and return the first client
260   credentials
261 */
262
263 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
264                                                                   const char *client_account,
265                                                                   const char *client_computer_name,
266                                                                   const struct netr_Credential *client_challenge,
267                                                                   const struct netr_Credential *server_challenge,
268                                                                   const struct samr_Password *machine_password,
269                                                                   struct netr_Credential *initial_credential,
270                                                                   uint32_t negotiate_flags)
271 {
272         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
273
274         if (!creds) {
275                 return NULL;
276         }
277
278         creds->sequence = time(NULL);
279         creds->negotiate_flags = negotiate_flags;
280
281         creds->computer_name = talloc_strdup(creds, client_computer_name);
282         if (!creds->computer_name) {
283                 talloc_free(creds);
284                 return NULL;
285         }
286         creds->account_name = talloc_strdup(creds, client_account);
287         if (!creds->account_name) {
288                 talloc_free(creds);
289                 return NULL;
290         }
291
292         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
293         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
294         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
295
296         if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
297                 netlogon_creds_init_hmac_sha256(creds,
298                                                 client_challenge,
299                                                 server_challenge,
300                                                 machine_password);
301         } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
302                 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
303         } else {
304                 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
305         }
306
307         netlogon_creds_first_step(creds, client_challenge, server_challenge);
308
309         dump_data_pw("Session key", creds->session_key, 16);
310         dump_data_pw("Credential ", creds->client.data, 8);
311
312         *initial_credential = creds->client;
313         return creds;
314 }
315
316 /*
317   initialise the credentials structure with only a session key.  The caller better know what they are doing!
318  */
319
320 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
321                                                                               const uint8_t session_key[16])
322 {
323         struct netlogon_creds_CredentialState *creds;
324
325         creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
326         if (!creds) {
327                 return NULL;
328         }
329
330         memcpy(creds->session_key, session_key, 16);
331
332         return creds;
333 }
334
335 /*
336   step the credentials to the next element in the chain, updating the
337   current client and server credentials and the seed
338
339   produce the next authenticator in the sequence ready to send to
340   the server
341 */
342 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
343                                 struct netr_Authenticator *next)
344 {
345         creds->sequence += 2;
346         netlogon_creds_step(creds);
347
348         next->cred = creds->client;
349         next->timestamp = creds->sequence;
350 }
351
352 /*
353   check that a credentials reply from a server is correct
354 */
355 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
356                         const struct netr_Credential *received_credentials)
357 {
358         if (!received_credentials ||
359             memcmp(received_credentials->data, creds->server.data, 8) != 0) {
360                 DEBUG(2,("credentials check failed\n"));
361                 return false;
362         }
363         return true;
364 }
365
366
367 /*****************************************************************
368 The above functions are common to the client and server interface
369 next comes the server specific functions
370 ******************************************************************/
371
372 /*
373   check that a credentials reply from a server is correct
374 */
375 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
376                                                  const struct netr_Credential *received_credentials)
377 {
378         if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
379                 DEBUG(2,("credentials check failed\n"));
380                 dump_data_pw("client creds", creds->client.data, 8);
381                 dump_data_pw("calc   creds", received_credentials->data, 8);
382                 return false;
383         }
384         return true;
385 }
386
387 /*
388   initialise the credentials chain and return the first server
389   credentials
390 */
391 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
392                                                                   const char *client_account,
393                                                                   const char *client_computer_name,
394                                                                   uint16_t secure_channel_type,
395                                                                   const struct netr_Credential *client_challenge,
396                                                                   const struct netr_Credential *server_challenge,
397                                                                   const struct samr_Password *machine_password,
398                                                                   struct netr_Credential *credentials_in,
399                                                                   struct netr_Credential *credentials_out,
400                                                                   uint32_t negotiate_flags)
401 {
402
403         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
404
405         if (!creds) {
406                 return NULL;
407         }
408
409         creds->negotiate_flags = negotiate_flags;
410         creds->secure_channel_type = secure_channel_type;
411
412         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
413         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
414         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
415
416         creds->computer_name = talloc_strdup(creds, client_computer_name);
417         if (!creds->computer_name) {
418                 talloc_free(creds);
419                 return NULL;
420         }
421         creds->account_name = talloc_strdup(creds, client_account);
422         if (!creds->account_name) {
423                 talloc_free(creds);
424                 return NULL;
425         }
426
427         if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
428                 netlogon_creds_init_hmac_sha256(creds,
429                                                 client_challenge,
430                                                 server_challenge,
431                                                 machine_password);
432         } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
433                 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
434                                            machine_password);
435         } else {
436                 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
437                                           machine_password);
438         }
439
440         netlogon_creds_first_step(creds, client_challenge, server_challenge);
441
442         dump_data_pw("Session key", creds->session_key, 16);
443         dump_data_pw("Client Credential ", creds->client.data, 8);
444         dump_data_pw("Server Credential ", creds->server.data, 8);
445
446         dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
447
448         /* And before we leak information about the machine account
449          * password, check that they got the first go right */
450         if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
451                 talloc_free(creds);
452                 return NULL;
453         }
454
455         *credentials_out = creds->server;
456
457         dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
458
459         return creds;
460 }
461
462 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
463                                  struct netr_Authenticator *received_authenticator,
464                                  struct netr_Authenticator *return_authenticator)
465 {
466         if (!received_authenticator || !return_authenticator) {
467                 return NT_STATUS_INVALID_PARAMETER;
468         }
469
470         if (!creds) {
471                 return NT_STATUS_ACCESS_DENIED;
472         }
473
474         /* TODO: this may allow the a replay attack on a non-signed
475            connection. Should we check that this is increasing? */
476         creds->sequence = received_authenticator->timestamp;
477         netlogon_creds_step(creds);
478         if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
479                 return_authenticator->cred = creds->server;
480                 return_authenticator->timestamp = creds->sequence;
481                 return NT_STATUS_OK;
482         } else {
483                 ZERO_STRUCTP(return_authenticator);
484                 return NT_STATUS_ACCESS_DENIED;
485         }
486 }
487
488 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
489                             uint16_t validation_level,
490                             union netr_Validation *validation)
491 {
492         static const char zeros[16];
493
494         struct netr_SamBaseInfo *base = NULL;
495         switch (validation_level) {
496         case 2:
497                 if (validation->sam2) {
498                         base = &validation->sam2->base;
499                 }
500                 break;
501         case 3:
502                 if (validation->sam3) {
503                         base = &validation->sam3->base;
504                 }
505                 break;
506         case 6:
507                 if (validation->sam6) {
508                         base = &validation->sam6->base;
509                 }
510                 break;
511         default:
512                 /* If we can't find it, we can't very well decrypt it */
513                 return;
514         }
515
516         if (!base) {
517                 return;
518         }
519
520         /* find and decyrpt the session keys, return in parameters above */
521         if (validation_level == 6) {
522                 /* they aren't encrypted! */
523         } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
524                 if (memcmp(base->key.key, zeros,
525                            sizeof(base->key.key)) != 0) {
526                         netlogon_creds_aes_decrypt(creds,
527                                             base->key.key,
528                                             sizeof(base->key.key));
529                 }
530
531                 if (memcmp(base->LMSessKey.key, zeros,
532                            sizeof(base->LMSessKey.key)) != 0) {
533                         netlogon_creds_aes_decrypt(creds,
534                                             base->LMSessKey.key,
535                                             sizeof(base->LMSessKey.key));
536                 }
537         } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
538                 if (memcmp(base->key.key, zeros,
539                            sizeof(base->key.key)) != 0) {
540                         netlogon_creds_arcfour_crypt(creds,
541                                             base->key.key,
542                                             sizeof(base->key.key));
543                 }
544
545                 if (memcmp(base->LMSessKey.key, zeros,
546                            sizeof(base->LMSessKey.key)) != 0) {
547                         netlogon_creds_arcfour_crypt(creds,
548                                             base->LMSessKey.key,
549                                             sizeof(base->LMSessKey.key));
550                 }
551         } else {
552                 if (memcmp(base->LMSessKey.key, zeros,
553                            sizeof(base->LMSessKey.key)) != 0) {
554                         netlogon_creds_des_decrypt_LMKey(creds,
555                                                 &base->LMSessKey);
556                 }
557         }
558 }
559
560 /*
561   copy a netlogon_creds_CredentialState struct
562 */
563
564 struct netlogon_creds_CredentialState *netlogon_creds_copy(TALLOC_CTX *mem_ctx,
565                                                            struct netlogon_creds_CredentialState *creds_in)
566 {
567         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
568
569         if (!creds) {
570                 return NULL;
571         }
572
573         creds->sequence                 = creds_in->sequence;
574         creds->negotiate_flags          = creds_in->negotiate_flags;
575         creds->secure_channel_type      = creds_in->secure_channel_type;
576
577         creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
578         if (!creds->computer_name) {
579                 talloc_free(creds);
580                 return NULL;
581         }
582         creds->account_name = talloc_strdup(creds, creds_in->account_name);
583         if (!creds->account_name) {
584                 talloc_free(creds);
585                 return NULL;
586         }
587
588         if (creds_in->sid) {
589                 creds->sid = dom_sid_dup(creds, creds_in->sid);
590                 if (!creds->sid) {
591                         talloc_free(creds);
592                         return NULL;
593                 }
594         }
595
596         memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
597         memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
598         memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
599         memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
600
601         return creds;
602 }