build: Build with system md5.h on OpenIndiana
[bbaumbach/samba-autobuild/.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         MD5_CTX 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 static void netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
489                                                      uint16_t validation_level,
490                                                      union netr_Validation *validation,
491                                                      bool encrypt)
492 {
493         static const char zeros[16];
494
495         struct netr_SamBaseInfo *base = NULL;
496         switch (validation_level) {
497         case 2:
498                 if (validation->sam2) {
499                         base = &validation->sam2->base;
500                 }
501                 break;
502         case 3:
503                 if (validation->sam3) {
504                         base = &validation->sam3->base;
505                 }
506                 break;
507         case 6:
508                 if (validation->sam6) {
509                         base = &validation->sam6->base;
510                 }
511                 break;
512         default:
513                 /* If we can't find it, we can't very well decrypt it */
514                 return;
515         }
516
517         if (!base) {
518                 return;
519         }
520
521         /* find and decyrpt the session keys, return in parameters above */
522         if (validation_level == 6) {
523                 /* they aren't encrypted! */
524         } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
525                 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
526                 if (memcmp(base->key.key, zeros,
527                            sizeof(base->key.key)) != 0) {
528                         if (encrypt) {
529                                 netlogon_creds_aes_encrypt(creds,
530                                             base->key.key,
531                                             sizeof(base->key.key));
532                         } else {
533                                 netlogon_creds_aes_decrypt(creds,
534                                             base->key.key,
535                                             sizeof(base->key.key));
536                         }
537                 }
538
539                 if (memcmp(base->LMSessKey.key, zeros,
540                            sizeof(base->LMSessKey.key)) != 0) {
541                         if (encrypt) {
542                                 netlogon_creds_aes_encrypt(creds,
543                                             base->LMSessKey.key,
544                                             sizeof(base->LMSessKey.key));
545
546                         } else {
547                                 netlogon_creds_aes_decrypt(creds,
548                                             base->LMSessKey.key,
549                                             sizeof(base->LMSessKey.key));
550                         }
551                 }
552         } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
553                 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
554                 if (memcmp(base->key.key, zeros,
555                            sizeof(base->key.key)) != 0) {
556                         netlogon_creds_arcfour_crypt(creds,
557                                             base->key.key,
558                                             sizeof(base->key.key));
559                 }
560
561                 if (memcmp(base->LMSessKey.key, zeros,
562                            sizeof(base->LMSessKey.key)) != 0) {
563                         netlogon_creds_arcfour_crypt(creds,
564                                             base->LMSessKey.key,
565                                             sizeof(base->LMSessKey.key));
566                 }
567         } else {
568                 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
569                 if (memcmp(base->LMSessKey.key, zeros,
570                            sizeof(base->LMSessKey.key)) != 0) {
571                         if (encrypt) {
572                                 netlogon_creds_des_encrypt_LMKey(creds,
573                                                 &base->LMSessKey);
574                         } else {
575                                 netlogon_creds_des_decrypt_LMKey(creds,
576                                                 &base->LMSessKey);
577                         }
578                 }
579         }
580 }
581
582 void netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
583                                                 uint16_t validation_level,
584                                                 union netr_Validation *validation)
585 {
586         netlogon_creds_crypt_samlogon_validation(creds, validation_level,
587                                                         validation, false);
588 }
589
590 void netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
591                                                 uint16_t validation_level,
592                                                 union netr_Validation *validation)
593 {
594         netlogon_creds_crypt_samlogon_validation(creds, validation_level,
595                                                         validation, true);
596 }
597
598 /*
599   copy a netlogon_creds_CredentialState struct
600 */
601
602 struct netlogon_creds_CredentialState *netlogon_creds_copy(TALLOC_CTX *mem_ctx,
603                                                            struct netlogon_creds_CredentialState *creds_in)
604 {
605         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
606
607         if (!creds) {
608                 return NULL;
609         }
610
611         creds->sequence                 = creds_in->sequence;
612         creds->negotiate_flags          = creds_in->negotiate_flags;
613         creds->secure_channel_type      = creds_in->secure_channel_type;
614
615         creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
616         if (!creds->computer_name) {
617                 talloc_free(creds);
618                 return NULL;
619         }
620         creds->account_name = talloc_strdup(creds, creds_in->account_name);
621         if (!creds->account_name) {
622                 talloc_free(creds);
623                 return NULL;
624         }
625
626         if (creds_in->sid) {
627                 creds->sid = dom_sid_dup(creds, creds_in->sid);
628                 if (!creds->sid) {
629                         talloc_free(creds);
630                         return NULL;
631                 }
632         }
633
634         memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
635         memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
636         memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
637         memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
638
639         return creds;
640 }