TODO: libcli/auth: add support for AES/HMAC-SHA256 schannel support
[metze/samba/wip.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 "heimdal/lib/hcrypto/aes.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 aes_in[AES_BLOCK_SIZE];
36                 uint8_t aes_out[AES_BLOCK_SIZE];
37
38                 AES_set_encrypt_key(creds->session_key, 128, &key);
39
40                 ZERO_STRUCT(aes_in);
41                 memcpy(aes_in, in->data, 8);
42                 AES_encrypt(aes_in, aes_out, &key);
43                 memcpy(out->data, aes_out, 8);
44
45                 ZERO_STRUCT(key);
46                 ZERO_STRUCT(aes_in);
47                 ZERO_STRUCT(aes_out);
48         } else {
49                 des_crypt112(out->data, in->data, creds->session_key, 1);
50         }
51 }
52
53 /*
54   initialise the credentials state for old-style 64 bit session keys
55
56   this call is made after the netr_ServerReqChallenge call
57 */
58 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
59                                       const struct netr_Credential *client_challenge,
60                                       const struct netr_Credential *server_challenge,
61                                       const struct samr_Password *machine_password)
62 {
63         uint32_t sum[2];
64         uint8_t sum2[8];
65
66         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
67         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
68
69         SIVAL(sum2,0,sum[0]);
70         SIVAL(sum2,4,sum[1]);
71
72         ZERO_STRUCT(creds->session_key);
73
74         des_crypt128(creds->session_key, sum2, machine_password->hash);
75 }
76
77 /*
78   initialise the credentials state for ADS-style 128 bit session keys
79
80   this call is made after the netr_ServerReqChallenge call
81 */
82 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
83                                        const struct netr_Credential *client_challenge,
84                                        const struct netr_Credential *server_challenge,
85                                        const struct samr_Password *machine_password)
86 {
87         unsigned char zero[4], tmp[16];
88         HMACMD5Context ctx;
89         struct MD5Context md5;
90
91         ZERO_STRUCT(creds->session_key);
92
93         memset(zero, 0, sizeof(zero));
94
95         hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);    
96         MD5Init(&md5);
97         MD5Update(&md5, zero, sizeof(zero));
98         MD5Update(&md5, client_challenge->data, 8);
99         MD5Update(&md5, server_challenge->data, 8);
100         MD5Final(tmp, &md5);
101         hmac_md5_update(tmp, sizeof(tmp), &ctx);
102         hmac_md5_final(creds->session_key, &ctx);
103 }
104
105 /*
106   initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
107
108   this call is made after the netr_ServerReqChallenge call
109 */
110 static void netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
111                                             const struct netr_Credential *client_challenge,
112                                             const struct netr_Credential *server_challenge,
113                                             const struct samr_Password *machine_password)
114 {
115         struct HMACSHA256Context ctx;
116         uint8_t digest[SHA256_DIGEST_LENGTH];
117
118         ZERO_STRUCT(creds->session_key);
119
120         hmac_sha256_init(machine_password->hash,
121                          sizeof(machine_password->hash),
122                          &ctx);
123         hmac_sha256_update(client_challenge->data, 8, &ctx);
124         hmac_sha256_update(server_challenge->data, 8, &ctx);
125         hmac_sha256_final(digest, &ctx);
126
127         memcpy(creds->session_key, digest, sizeof(creds->session_key));
128
129         ZERO_STRUCT(digest);
130         ZERO_STRUCT(ctx);
131 }
132
133 static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
134                                       const struct netr_Credential *client_challenge,
135                                       const struct netr_Credential *server_challenge)
136 {
137         netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
138
139         netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
140
141         creds->seed = creds->client;
142 }
143
144 /*
145   step the credentials to the next element in the chain, updating the
146   current client and server credentials and the seed
147 */
148 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
149 {
150         struct netr_Credential time_cred;
151
152         DEBUG(5,("\tseed        %08x:%08x\n", 
153                  IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
154
155         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
156         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
157
158         DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
159
160         netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
161
162         DEBUG(5,("\tCLIENT      %08x:%08x\n", 
163                  IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
164
165         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
166         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
167
168         DEBUG(5,("\tseed+time+1 %08x:%08x\n", 
169                  IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
170
171         netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
172
173         DEBUG(5,("\tSERVER      %08x:%08x\n", 
174                  IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
175
176         creds->seed = time_cred;
177 }
178
179
180 /*
181   DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
182 */
183 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
184 {
185         struct netr_LMSessionKey tmp;
186         des_crypt56(tmp.key, key->key, creds->session_key, 1);
187         *key = tmp;
188 }
189
190 /*
191   DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
192 */
193 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
194 {
195         struct netr_LMSessionKey tmp;
196         des_crypt56(tmp.key, key->key, creds->session_key, 0);
197         *key = tmp;
198 }
199
200 /*
201   DES encrypt a 16 byte password buffer using the session key
202 */
203 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
204 {
205         struct samr_Password tmp;
206         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
207         *pass = tmp;
208 }
209
210 /*
211   DES decrypt a 16 byte password buffer using the session key
212 */
213 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
214 {
215         struct samr_Password tmp;
216         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
217         *pass = tmp;
218 }
219
220 /*
221   ARCFOUR encrypt/decrypt a password buffer using the session key
222 */
223 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
224 {
225         DATA_BLOB session_key = data_blob(creds->session_key, 16);
226
227         arcfour_crypt_blob(data, len, &session_key);
228
229         data_blob_free(&session_key);
230 }
231
232 /*****************************************************************
233 The above functions are common to the client and server interface
234 next comes the client specific functions
235 ******************************************************************/
236
237 /*
238   initialise the credentials chain and return the first client
239   credentials
240 */
241  
242 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx, 
243                                                                   const char *client_account,
244                                                                   const char *client_computer_name, 
245                                                                   const struct netr_Credential *client_challenge,
246                                                                   const struct netr_Credential *server_challenge,
247                                                                   const struct samr_Password *machine_password,
248                                                                   struct netr_Credential *initial_credential,
249                                                                   uint32_t negotiate_flags)
250 {
251         struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
252         
253         if (!creds) {
254                 return NULL;
255         }
256         
257         creds->sequence = time(NULL);
258         creds->negotiate_flags = negotiate_flags;
259
260         creds->computer_name = talloc_strdup(creds, client_computer_name);
261         if (!creds->computer_name) {
262                 talloc_free(creds);
263                 return NULL;
264         }
265         creds->account_name = talloc_strdup(creds, client_account);
266         if (!creds->account_name) {
267                 talloc_free(creds);
268                 return NULL;
269         }
270
271         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
272         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
273         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
274
275         if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
276                 netlogon_creds_init_hmac_sha256(creds,
277                                                 client_challenge,
278                                                 server_challenge,
279                                                 machine_password);
280         } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
281                 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
282         } else {
283                 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
284         }
285
286         netlogon_creds_first_step(creds, client_challenge, server_challenge);
287
288         dump_data_pw("Session key", creds->session_key, 16);
289         dump_data_pw("Credential ", creds->client.data, 8);
290
291         *initial_credential = creds->client;
292         return creds;
293 }
294
295 /*
296   initialise the credentials structure with only a session key.  The caller better know what they are doing!
297  */
298
299 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx, 
300                                                                               const uint8_t session_key[16])
301 {
302         struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
303         
304         if (!creds) {
305                 return NULL;
306         }
307         
308         memcpy(creds->session_key, session_key, 16);
309
310         return creds;
311 }
312
313 /*
314   step the credentials to the next element in the chain, updating the
315   current client and server credentials and the seed
316
317   produce the next authenticator in the sequence ready to send to 
318   the server
319 */
320 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
321                                 struct netr_Authenticator *next)
322 {       
323         creds->sequence += 2;
324         netlogon_creds_step(creds);
325
326         next->cred = creds->client;
327         next->timestamp = creds->sequence;
328 }
329
330 /*
331   check that a credentials reply from a server is correct
332 */
333 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
334                         const struct netr_Credential *received_credentials)
335 {
336         if (!received_credentials || 
337             memcmp(received_credentials->data, creds->server.data, 8) != 0) {
338                 DEBUG(2,("credentials check failed\n"));
339                 return false;
340         }
341         return true;
342 }
343
344
345 /*****************************************************************
346 The above functions are common to the client and server interface
347 next comes the server specific functions
348 ******************************************************************/
349
350 /*
351   check that a credentials reply from a server is correct
352 */
353 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
354                                                  const struct netr_Credential *received_credentials)
355 {
356         if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
357                 DEBUG(2,("credentials check failed\n"));
358                 dump_data_pw("client creds", creds->client.data, 8);
359                 dump_data_pw("calc   creds", received_credentials->data, 8);
360                 return false;
361         }
362         return true;
363 }
364
365 /*
366   initialise the credentials chain and return the first server
367   credentials
368 */
369 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx, 
370                                                                   const char *client_account,
371                                                                   const char *client_computer_name, 
372                                                                   uint16_t secure_channel_type,
373                                                                   const struct netr_Credential *client_challenge,
374                                                                   const struct netr_Credential *server_challenge,
375                                                                   const struct samr_Password *machine_password,
376                                                                   struct netr_Credential *credentials_in,
377                                                                   struct netr_Credential *credentials_out,
378                                                                   uint32_t negotiate_flags)
379 {
380         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
381         bool ok = false;
382         bool try_aes = true;
383         bool try_strong = true;
384         bool try_weak = true;
385         bool fallback = false;
386
387         if (!creds) {
388                 return NULL;
389         }
390         
391         creds->negotiate_flags = negotiate_flags;
392         creds->secure_channel_type = secure_channel_type;
393
394         creds->computer_name = talloc_strdup(creds, client_computer_name);
395         if (!creds->computer_name) {
396                 talloc_free(creds);
397                 return NULL;
398         }
399         creds->account_name = talloc_strdup(creds, client_account);
400         if (!creds->account_name) {
401                 talloc_free(creds);
402                 return NULL;
403         }
404
405         if (!ok && try_aes) {
406                 if (fallback) {
407                         DEBUG(2,("credentials check fallback to aes key\n"));
408                 }
409                 creds->negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
410                 netlogon_creds_init_hmac_sha256(creds,
411                                                 client_challenge,
412                                                 server_challenge,
413                                                 machine_password);
414                 netlogon_creds_first_step(creds, client_challenge, server_challenge);
415                 ok = netlogon_creds_server_check_internal(creds, credentials_in);
416                 if (!ok) {
417                         creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
418                         fallback = true;
419                 }
420         }
421
422         if (!ok && try_strong) {
423                 if (fallback) {
424                         DEBUG(2,("credentials check fallback to strong key\n"));
425                 }
426                 creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
427                 creds->negotiate_flags |= NETLOGON_NEG_STRONG_KEYS;
428                 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, 
429                                            machine_password);
430                 netlogon_creds_first_step(creds, client_challenge, server_challenge);
431                 ok = netlogon_creds_server_check_internal(creds, credentials_in);
432                 if (!ok) {
433                         creds->negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
434                         fallback = true;
435                 }
436         }
437
438         if (!ok && try_weak) {
439                 if (fallback) {
440                         DEBUG(2,("credentials check fallback to weak key\n"));
441                 }
442                 creds->negotiate_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
443                 creds->negotiate_flags &= ~NETLOGON_NEG_STRONG_KEYS;
444                 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, 
445                                           machine_password);
446                 netlogon_creds_first_step(creds, client_challenge, server_challenge);
447                 ok = netlogon_creds_server_check_internal(creds, credentials_in);
448         }
449
450         /* And before we leak information about the machine account
451          * password, check that they got the first go right */
452         if (!ok) {
453                 talloc_free(creds);
454                 return NULL;
455         }
456
457         *credentials_out = creds->server;
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_ARCFOUR) {
524                 if (memcmp(base->key.key, zeros,  
525                            sizeof(base->key.key)) != 0) {
526                         netlogon_creds_arcfour_crypt(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_arcfour_crypt(creds, 
534                                             base->LMSessKey.key, 
535                                             sizeof(base->LMSessKey.key));
536                 }
537         } else {
538                 if (memcmp(base->LMSessKey.key, zeros,  
539                            sizeof(base->LMSessKey.key)) != 0) {
540                         netlogon_creds_des_decrypt_LMKey(creds, 
541                                                 &base->LMSessKey);
542                 }
543         }
544 }       
545