source: vendor/3.5.0/libcli/auth/credentials.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 13.5 KB
Line 
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
28static 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*/
40static 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*/
64static 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
87static 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*/
102static 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*/
137void 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*/
147void 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*/
157void 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*/
167void 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*/
177void 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/*****************************************************************
187The above functions are common to the client and server interface
188next comes the client specific functions
189******************************************************************/
190
191/*
192 initialise the credentials chain and return the first client
193 credentials
194*/
195
196struct 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_128BIT) {
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
248struct 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*/
269void 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*/
282bool 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/*****************************************************************
295The above functions are common to the client and server interface
296next comes the server specific functions
297******************************************************************/
298
299/*
300 check that a credentials reply from a server is correct
301*/
302static 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*/
318struct 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
330 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
331
332 if (!creds) {
333 return NULL;
334 }
335
336 creds->negotiate_flags = negotiate_flags;
337 creds->secure_channel_type = secure_channel_type;
338
339 creds->computer_name = talloc_strdup(creds, client_computer_name);
340 if (!creds->computer_name) {
341 talloc_free(creds);
342 return NULL;
343 }
344 creds->account_name = talloc_strdup(creds, client_account);
345 if (!creds->account_name) {
346 talloc_free(creds);
347 return NULL;
348 }
349
350 if (negotiate_flags & NETLOGON_NEG_128BIT) {
351 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
352 machine_password);
353 } else {
354 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
355 machine_password);
356 }
357
358 netlogon_creds_first_step(creds, client_challenge, server_challenge);
359
360 /* And before we leak information about the machine account
361 * password, check that they got the first go right */
362 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
363 talloc_free(creds);
364 return NULL;
365 }
366
367 *credentials_out = creds->server;
368
369 return creds;
370}
371
372NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
373 struct netr_Authenticator *received_authenticator,
374 struct netr_Authenticator *return_authenticator)
375{
376 if (!received_authenticator || !return_authenticator) {
377 return NT_STATUS_INVALID_PARAMETER;
378 }
379
380 if (!creds) {
381 return NT_STATUS_ACCESS_DENIED;
382 }
383
384 /* TODO: this may allow the a replay attack on a non-signed
385 connection. Should we check that this is increasing? */
386 creds->sequence = received_authenticator->timestamp;
387 netlogon_creds_step(creds);
388 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
389 return_authenticator->cred = creds->server;
390 return_authenticator->timestamp = creds->sequence;
391 return NT_STATUS_OK;
392 } else {
393 ZERO_STRUCTP(return_authenticator);
394 return NT_STATUS_ACCESS_DENIED;
395 }
396}
397
398void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
399 uint16_t validation_level,
400 union netr_Validation *validation)
401{
402 static const char zeros[16];
403
404 struct netr_SamBaseInfo *base = NULL;
405 switch (validation_level) {
406 case 2:
407 if (validation->sam2) {
408 base = &validation->sam2->base;
409 }
410 break;
411 case 3:
412 if (validation->sam3) {
413 base = &validation->sam3->base;
414 }
415 break;
416 case 6:
417 if (validation->sam6) {
418 base = &validation->sam6->base;
419 }
420 break;
421 default:
422 /* If we can't find it, we can't very well decrypt it */
423 return;
424 }
425
426 if (!base) {
427 return;
428 }
429
430 /* find and decyrpt the session keys, return in parameters above */
431 if (validation_level == 6) {
432 /* they aren't encrypted! */
433 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
434 if (memcmp(base->key.key, zeros,
435 sizeof(base->key.key)) != 0) {
436 netlogon_creds_arcfour_crypt(creds,
437 base->key.key,
438 sizeof(base->key.key));
439 }
440
441 if (memcmp(base->LMSessKey.key, zeros,
442 sizeof(base->LMSessKey.key)) != 0) {
443 netlogon_creds_arcfour_crypt(creds,
444 base->LMSessKey.key,
445 sizeof(base->LMSessKey.key));
446 }
447 } else {
448 if (memcmp(base->LMSessKey.key, zeros,
449 sizeof(base->LMSessKey.key)) != 0) {
450 netlogon_creds_des_decrypt_LMKey(creds,
451 &base->LMSessKey);
452 }
453 }
454}
455
Note: See TracBrowser for help on using the repository browser.