Move DRSUAPI per-attribute decryption into a common file
[jra/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 "auth/auth.h"
26 #include "../lib/crypto/crypto.h"
27 #include "libcli/auth/libcli_auth.h"
28
29 /*
30   initialise the credentials state for old-style 64 bit session keys
31
32   this call is made after the netr_ServerReqChallenge call
33 */
34 static void creds_init_64bit(struct creds_CredentialState *creds,
35                              const struct netr_Credential *client_challenge,
36                              const struct netr_Credential *server_challenge,
37                              const struct samr_Password *machine_password)
38 {
39         uint32_t sum[2];
40         uint8_t sum2[8];
41
42         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
43         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
44
45         SIVAL(sum2,0,sum[0]);
46         SIVAL(sum2,4,sum[1]);
47
48         ZERO_STRUCT(creds->session_key);
49
50         des_crypt128(creds->session_key, sum2, machine_password->hash);
51
52         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
53         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
54
55         creds->seed = creds->client;
56 }
57
58 /*
59   initialise the credentials state for ADS-style 128 bit session keys
60
61   this call is made after the netr_ServerReqChallenge call
62 */
63 static void creds_init_128bit(struct creds_CredentialState *creds,
64                               const struct netr_Credential *client_challenge,
65                               const struct netr_Credential *server_challenge,
66                               const struct samr_Password *machine_password)
67 {
68         unsigned char zero[4], tmp[16];
69         HMACMD5Context ctx;
70         struct MD5Context md5;
71
72         ZERO_STRUCT(creds->session_key);
73
74         memset(zero, 0, sizeof(zero));
75
76         hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);    
77         MD5Init(&md5);
78         MD5Update(&md5, zero, sizeof(zero));
79         MD5Update(&md5, client_challenge->data, 8);
80         MD5Update(&md5, server_challenge->data, 8);
81         MD5Final(tmp, &md5);
82         hmac_md5_update(tmp, sizeof(tmp), &ctx);
83         hmac_md5_final(creds->session_key, &ctx);
84
85         creds->client = *client_challenge;
86         creds->server = *server_challenge;
87
88         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
89         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
90
91         creds->seed = creds->client;
92 }
93
94
95 /*
96   step the credentials to the next element in the chain, updating the
97   current client and server credentials and the seed
98 */
99 static void creds_step(struct creds_CredentialState *creds)
100 {
101         struct netr_Credential time_cred;
102
103         DEBUG(5,("\tseed        %08x:%08x\n", 
104                  IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
105
106         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
107         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
108
109         DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
110
111         des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
112
113         DEBUG(5,("\tCLIENT      %08x:%08x\n", 
114                  IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
115
116         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
117         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
118
119         DEBUG(5,("\tseed+time+1 %08x:%08x\n", 
120                  IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
121
122         des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
123
124         DEBUG(5,("\tSERVER      %08x:%08x\n", 
125                  IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
126
127         creds->seed = time_cred;
128 }
129
130
131 /*
132   DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
133 */
134 void creds_des_encrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
135 {
136         struct netr_LMSessionKey tmp;
137         des_crypt56(tmp.key, key->key, creds->session_key, 1);
138         *key = tmp;
139 }
140
141 /*
142   DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
143 */
144 void creds_des_decrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
145 {
146         struct netr_LMSessionKey tmp;
147         des_crypt56(tmp.key, key->key, creds->session_key, 0);
148         *key = tmp;
149 }
150
151 /*
152   DES encrypt a 16 byte password buffer using the session key
153 */
154 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
155 {
156         struct samr_Password tmp;
157         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
158         *pass = tmp;
159 }
160
161 /*
162   DES decrypt a 16 byte password buffer using the session key
163 */
164 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
165 {
166         struct samr_Password tmp;
167         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
168         *pass = tmp;
169 }
170
171 /*
172   ARCFOUR encrypt/decrypt a password buffer using the session key
173 */
174 void creds_arcfour_crypt(struct creds_CredentialState *creds, uint8_t *data, size_t len)
175 {
176         DATA_BLOB session_key = data_blob(creds->session_key, 16);
177
178         arcfour_crypt_blob(data, len, &session_key);
179
180         data_blob_free(&session_key);
181 }
182
183 /*****************************************************************
184 The above functions are common to the client and server interface
185 next comes the client specific functions
186 ******************************************************************/
187
188 /*
189   initialise the credentials chain and return the first client
190   credentials
191 */
192 void creds_client_init(struct creds_CredentialState *creds,
193                        const struct netr_Credential *client_challenge,
194                        const struct netr_Credential *server_challenge,
195                        const struct samr_Password *machine_password,
196                        struct netr_Credential *initial_credential,
197                        uint32_t negotiate_flags)
198 {
199         creds->sequence = time(NULL);
200         creds->negotiate_flags = negotiate_flags;
201
202         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
203         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
204         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
205
206         if (negotiate_flags & NETLOGON_NEG_128BIT) {
207                 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
208         } else {
209                 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
210         }
211
212         dump_data_pw("Session key", creds->session_key, 16);
213         dump_data_pw("Credential ", creds->client.data, 8);
214
215         *initial_credential = creds->client;
216 }
217
218 /*
219   step the credentials to the next element in the chain, updating the
220   current client and server credentials and the seed
221
222   produce the next authenticator in the sequence ready to send to 
223   the server
224 */
225 void creds_client_authenticator(struct creds_CredentialState *creds,
226                                 struct netr_Authenticator *next)
227 {       
228         creds->sequence += 2;
229         creds_step(creds);
230
231         next->cred = creds->client;
232         next->timestamp = creds->sequence;
233 }
234
235 /*
236   check that a credentials reply from a server is correct
237 */
238 bool creds_client_check(struct creds_CredentialState *creds,
239                         const struct netr_Credential *received_credentials)
240 {
241         if (!received_credentials || 
242             memcmp(received_credentials->data, creds->server.data, 8) != 0) {
243                 DEBUG(2,("credentials check failed\n"));
244                 return false;
245         }
246         return true;
247 }
248
249
250 /*****************************************************************
251 The above functions are common to the client and server interface
252 next comes the server specific functions
253 ******************************************************************/
254
255 /*
256   initialise the credentials chain and return the first server
257   credentials
258 */
259 void creds_server_init(struct creds_CredentialState *creds,
260                        const struct netr_Credential *client_challenge,
261                        const struct netr_Credential *server_challenge,
262                        const struct samr_Password *machine_password,
263                        struct netr_Credential *initial_credential,
264                        uint32_t negotiate_flags)
265 {
266         if (negotiate_flags & NETLOGON_NEG_128BIT) {
267                 creds_init_128bit(creds, client_challenge, server_challenge, 
268                                   machine_password);
269         } else {
270                 creds_init_64bit(creds, client_challenge, server_challenge, 
271                                  machine_password);
272         }
273
274         *initial_credential = creds->server;
275         creds->negotiate_flags = negotiate_flags;
276 }
277
278 /*
279   check that a credentials reply from a server is correct
280 */
281 bool creds_server_check(const struct creds_CredentialState *creds,
282                         const struct netr_Credential *received_credentials)
283 {
284         if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
285                 DEBUG(2,("credentials check failed\n"));
286                 dump_data_pw("client creds", creds->client.data, 8);
287                 dump_data_pw("calc   creds", received_credentials->data, 8);
288                 return false;
289         }
290         return true;
291 }
292
293 NTSTATUS creds_server_step_check(struct creds_CredentialState *creds,
294                                  struct netr_Authenticator *received_authenticator,
295                                  struct netr_Authenticator *return_authenticator) 
296 {
297         if (!received_authenticator || !return_authenticator) {
298                 return NT_STATUS_INVALID_PARAMETER;
299         }
300
301         if (!creds) {
302                 return NT_STATUS_ACCESS_DENIED;
303         }
304
305         /* TODO: this may allow the a replay attack on a non-signed
306            connection. Should we check that this is increasing? */
307         creds->sequence = received_authenticator->timestamp;
308         creds_step(creds);
309         if (creds_server_check(creds, &received_authenticator->cred)) {
310                 return_authenticator->cred = creds->server;
311                 return_authenticator->timestamp = creds->sequence;
312                 return NT_STATUS_OK;
313         } else {
314                 ZERO_STRUCTP(return_authenticator);
315                 return NT_STATUS_ACCESS_DENIED;
316         }
317 }
318
319 void creds_decrypt_samlogon(struct creds_CredentialState *creds,
320                             uint16_t validation_level,
321                             union netr_Validation *validation) 
322 {
323         static const char zeros[16];
324
325         struct netr_SamBaseInfo *base = NULL;
326         switch (validation_level) {
327         case 2:
328                 if (validation->sam2) {
329                         base = &validation->sam2->base;
330                 }
331                 break;
332         case 3:
333                 if (validation->sam3) {
334                         base = &validation->sam3->base;
335                 }
336                 break;
337         case 6:
338                 if (validation->sam6) {
339                         base = &validation->sam6->base;
340                 }
341                 break;
342         default:
343                 /* If we can't find it, we can't very well decrypt it */
344                 return;
345         }
346
347         if (!base) {
348                 return;
349         }
350
351         /* find and decyrpt the session keys, return in parameters above */
352         if (validation_level == 6) {
353                 /* they aren't encrypted! */
354         } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
355                 if (memcmp(base->key.key, zeros,  
356                            sizeof(base->key.key)) != 0) {
357                         creds_arcfour_crypt(creds, 
358                                             base->key.key, 
359                                             sizeof(base->key.key));
360                 }
361                         
362                 if (memcmp(base->LMSessKey.key, zeros,  
363                            sizeof(base->LMSessKey.key)) != 0) {
364                         creds_arcfour_crypt(creds, 
365                                             base->LMSessKey.key, 
366                                             sizeof(base->LMSessKey.key));
367                 }
368         } else {
369                 if (memcmp(base->LMSessKey.key, zeros,  
370                            sizeof(base->LMSessKey.key)) != 0) {
371                         creds_des_decrypt_LMKey(creds, 
372                                                 &base->LMSessKey);
373                 }
374         }
375 }