2 Unix SMB/CIFS implementation.
4 code to manipulate domain credentials
6 Copyright (C) Andrew Tridgell 1997-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
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.
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.
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/>.
24 #include "system/time.h"
25 #include "../lib/crypto/crypto.h"
26 #include "libcli/auth/libcli_auth.h"
29 initialise the credentials state for old-style 64 bit session keys
31 this call is made after the netr_ServerReqChallenge call
33 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
34 const struct netr_Credential *client_challenge,
35 const struct netr_Credential *server_challenge,
36 const struct samr_Password *machine_password)
41 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
42 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
47 ZERO_STRUCT(creds->session_key);
49 des_crypt128(creds->session_key, sum2, machine_password->hash);
51 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
52 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
54 creds->seed = creds->client;
58 initialise the credentials state for ADS-style 128 bit session keys
60 this call is made after the netr_ServerReqChallenge call
62 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
63 const struct netr_Credential *client_challenge,
64 const struct netr_Credential *server_challenge,
65 const struct samr_Password *machine_password)
67 unsigned char zero[4], tmp[16];
69 struct MD5Context md5;
71 ZERO_STRUCT(creds->session_key);
73 memset(zero, 0, sizeof(zero));
75 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
77 MD5Update(&md5, zero, sizeof(zero));
78 MD5Update(&md5, client_challenge->data, 8);
79 MD5Update(&md5, server_challenge->data, 8);
81 hmac_md5_update(tmp, sizeof(tmp), &ctx);
82 hmac_md5_final(creds->session_key, &ctx);
84 creds->client = *client_challenge;
85 creds->server = *server_challenge;
87 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
88 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
90 creds->seed = creds->client;
95 step the credentials to the next element in the chain, updating the
96 current client and server credentials and the seed
98 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
100 struct netr_Credential time_cred;
102 DEBUG(5,("\tseed %08x:%08x\n",
103 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
105 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
106 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
108 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
110 des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
112 DEBUG(5,("\tCLIENT %08x:%08x\n",
113 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
115 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
116 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
118 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
119 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
121 des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
123 DEBUG(5,("\tSERVER %08x:%08x\n",
124 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
126 creds->seed = time_cred;
131 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
133 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
135 struct netr_LMSessionKey tmp;
136 des_crypt56(tmp.key, key->key, creds->session_key, 1);
141 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
143 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
145 struct netr_LMSessionKey tmp;
146 des_crypt56(tmp.key, key->key, creds->session_key, 0);
151 DES encrypt a 16 byte password buffer using the session key
153 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
155 struct samr_Password tmp;
156 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
161 DES decrypt a 16 byte password buffer using the session key
163 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
165 struct samr_Password tmp;
166 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
171 ARCFOUR encrypt/decrypt a password buffer using the session key
173 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
175 DATA_BLOB session_key = data_blob(creds->session_key, 16);
177 arcfour_crypt_blob(data, len, &session_key);
179 data_blob_free(&session_key);
182 /*****************************************************************
183 The above functions are common to the client and server interface
184 next comes the client specific functions
185 ******************************************************************/
188 initialise the credentials chain and return the first client
192 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
193 const char *client_account,
194 const char *client_computer_name,
195 const struct netr_Credential *client_challenge,
196 const struct netr_Credential *server_challenge,
197 const struct samr_Password *machine_password,
198 struct netr_Credential *initial_credential,
199 uint32_t negotiate_flags)
201 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
207 creds->sequence = time(NULL);
208 creds->negotiate_flags = negotiate_flags;
210 creds->computer_name = talloc_strdup(creds, client_computer_name);
211 if (!creds->computer_name) {
215 creds->account_name = talloc_strdup(creds, client_account);
216 if (!creds->account_name) {
221 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
222 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
223 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
225 if (negotiate_flags & NETLOGON_NEG_128BIT) {
226 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
228 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
231 dump_data_pw("Session key", creds->session_key, 16);
232 dump_data_pw("Credential ", creds->client.data, 8);
234 *initial_credential = creds->client;
239 initialise the credentials structure with only a session key. The caller better know what they are doing!
242 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
243 const uint8_t session_key[16])
245 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
251 memcpy(creds->session_key, session_key, 16);
257 step the credentials to the next element in the chain, updating the
258 current client and server credentials and the seed
260 produce the next authenticator in the sequence ready to send to
263 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
264 struct netr_Authenticator *next)
266 creds->sequence += 2;
267 netlogon_creds_step(creds);
269 next->cred = creds->client;
270 next->timestamp = creds->sequence;
274 check that a credentials reply from a server is correct
276 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
277 const struct netr_Credential *received_credentials)
279 if (!received_credentials ||
280 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
281 DEBUG(2,("credentials check failed\n"));
288 /*****************************************************************
289 The above functions are common to the client and server interface
290 next comes the server specific functions
291 ******************************************************************/
294 check that a credentials reply from a server is correct
296 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
297 const struct netr_Credential *received_credentials)
299 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
300 DEBUG(2,("credentials check failed\n"));
301 dump_data_pw("client creds", creds->client.data, 8);
302 dump_data_pw("calc creds", received_credentials->data, 8);
309 initialise the credentials chain and return the first server
312 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
313 const char *client_account,
314 const char *client_computer_name,
315 uint16_t secure_channel_type,
316 const struct netr_Credential *client_challenge,
317 const struct netr_Credential *server_challenge,
318 const struct samr_Password *machine_password,
319 struct netr_Credential *credentials_in,
320 struct netr_Credential *credentials_out,
321 uint32_t negotiate_flags)
324 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
330 creds->negotiate_flags = negotiate_flags;
332 creds->computer_name = talloc_strdup(creds, client_computer_name);
333 if (!creds->computer_name) {
337 creds->account_name = talloc_strdup(creds, client_account);
338 if (!creds->account_name) {
343 if (negotiate_flags & NETLOGON_NEG_128BIT) {
344 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
347 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
351 /* And before we leak information about the machine account
352 * password, check that they got the first go right */
353 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
358 *credentials_out = creds->server;
363 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
364 struct netr_Authenticator *received_authenticator,
365 struct netr_Authenticator *return_authenticator)
367 if (!received_authenticator || !return_authenticator) {
368 return NT_STATUS_INVALID_PARAMETER;
372 return NT_STATUS_ACCESS_DENIED;
375 /* TODO: this may allow the a replay attack on a non-signed
376 connection. Should we check that this is increasing? */
377 creds->sequence = received_authenticator->timestamp;
378 netlogon_creds_step(creds);
379 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
380 return_authenticator->cred = creds->server;
381 return_authenticator->timestamp = creds->sequence;
384 ZERO_STRUCTP(return_authenticator);
385 return NT_STATUS_ACCESS_DENIED;
389 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
390 uint16_t validation_level,
391 union netr_Validation *validation)
393 static const char zeros[16];
395 struct netr_SamBaseInfo *base = NULL;
396 switch (validation_level) {
398 if (validation->sam2) {
399 base = &validation->sam2->base;
403 if (validation->sam3) {
404 base = &validation->sam3->base;
408 if (validation->sam6) {
409 base = &validation->sam6->base;
413 /* If we can't find it, we can't very well decrypt it */
421 /* find and decyrpt the session keys, return in parameters above */
422 if (validation_level == 6) {
423 /* they aren't encrypted! */
424 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
425 if (memcmp(base->key.key, zeros,
426 sizeof(base->key.key)) != 0) {
427 netlogon_creds_arcfour_crypt(creds,
429 sizeof(base->key.key));
432 if (memcmp(base->LMSessKey.key, zeros,
433 sizeof(base->LMSessKey.key)) != 0) {
434 netlogon_creds_arcfour_crypt(creds,
436 sizeof(base->LMSessKey.key));
439 if (memcmp(base->LMSessKey.key, zeros,
440 sizeof(base->LMSessKey.key)) != 0) {
441 netlogon_creds_des_decrypt_LMKey(creds,