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