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"
28 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState
*creds
,
29 const struct netr_Credential
*in
,
30 struct netr_Credential
*out
)
32 des_crypt112(out
->data
, in
->data
, creds
->session_key
, 1);
36 initialise the credentials state for old-style 64 bit session keys
38 this call is made after the netr_ServerReqChallenge call
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
)
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);
54 ZERO_STRUCT(creds
->session_key
);
56 des_crypt128(creds
->session_key
, sum2
, machine_password
->hash
);
60 initialise the credentials state for ADS-style 128 bit session keys
62 this call is made after the netr_ServerReqChallenge call
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
)
69 unsigned char zero
[4], tmp
[16];
71 struct MD5Context md5
;
73 ZERO_STRUCT(creds
->session_key
);
75 memset(zero
, 0, sizeof(zero
));
77 hmac_md5_init_rfc2104(machine_password
->hash
, sizeof(machine_password
->hash
), &ctx
);
79 MD5Update(&md5
, zero
, sizeof(zero
));
80 MD5Update(&md5
, client_challenge
->data
, 8);
81 MD5Update(&md5
, server_challenge
->data
, 8);
83 hmac_md5_update(tmp
, sizeof(tmp
), &ctx
);
84 hmac_md5_final(creds
->session_key
, &ctx
);
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
)
91 netlogon_creds_step_crypt(creds
, client_challenge
, &creds
->client
);
93 netlogon_creds_step_crypt(creds
, server_challenge
, &creds
->server
);
95 creds
->seed
= creds
->client
;
99 step the credentials to the next element in the chain, updating the
100 current client and server credentials and the seed
102 static void netlogon_creds_step(struct netlogon_creds_CredentialState
*creds
)
104 struct netr_Credential time_cred
;
106 DEBUG(5,("\tseed %08x:%08x\n",
107 IVAL(creds
->seed
.data
, 0), IVAL(creds
->seed
.data
, 4)));
109 SIVAL(time_cred
.data
, 0, IVAL(creds
->seed
.data
, 0) + creds
->sequence
);
110 SIVAL(time_cred
.data
, 4, IVAL(creds
->seed
.data
, 4));
112 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred
.data
, 0), IVAL(time_cred
.data
, 4)));
114 netlogon_creds_step_crypt(creds
, &time_cred
, &creds
->client
);
116 DEBUG(5,("\tCLIENT %08x:%08x\n",
117 IVAL(creds
->client
.data
, 0), IVAL(creds
->client
.data
, 4)));
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));
122 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
123 IVAL(time_cred
.data
, 0), IVAL(time_cred
.data
, 4)));
125 netlogon_creds_step_crypt(creds
, &time_cred
, &creds
->server
);
127 DEBUG(5,("\tSERVER %08x:%08x\n",
128 IVAL(creds
->server
.data
, 0), IVAL(creds
->server
.data
, 4)));
130 creds
->seed
= time_cred
;
135 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
137 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState
*creds
, struct netr_LMSessionKey
*key
)
139 struct netr_LMSessionKey tmp
;
140 des_crypt56(tmp
.key
, key
->key
, creds
->session_key
, 1);
145 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
147 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState
*creds
, struct netr_LMSessionKey
*key
)
149 struct netr_LMSessionKey tmp
;
150 des_crypt56(tmp
.key
, key
->key
, creds
->session_key
, 0);
155 DES encrypt a 16 byte password buffer using the session key
157 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState
*creds
, struct samr_Password
*pass
)
159 struct samr_Password tmp
;
160 des_crypt112_16(tmp
.hash
, pass
->hash
, creds
->session_key
, 1);
165 DES decrypt a 16 byte password buffer using the session key
167 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState
*creds
, struct samr_Password
*pass
)
169 struct samr_Password tmp
;
170 des_crypt112_16(tmp
.hash
, pass
->hash
, creds
->session_key
, 0);
175 ARCFOUR encrypt/decrypt a password buffer using the session key
177 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState
*creds
, uint8_t *data
, size_t len
)
179 DATA_BLOB session_key
= data_blob(creds
->session_key
, 16);
181 arcfour_crypt_blob(data
, len
, &session_key
);
183 data_blob_free(&session_key
);
186 /*****************************************************************
187 The above functions are common to the client and server interface
188 next comes the client specific functions
189 ******************************************************************/
192 initialise the credentials chain and return the first client
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
)
205 struct netlogon_creds_CredentialState
*creds
= talloc(mem_ctx
, struct netlogon_creds_CredentialState
);
211 creds
->sequence
= time(NULL
);
212 creds
->negotiate_flags
= negotiate_flags
;
214 creds
->computer_name
= talloc_strdup(creds
, client_computer_name
);
215 if (!creds
->computer_name
) {
219 creds
->account_name
= talloc_strdup(creds
, client_account
);
220 if (!creds
->account_name
) {
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
));
229 if (negotiate_flags
& NETLOGON_NEG_128BIT
) {
230 netlogon_creds_init_128bit(creds
, client_challenge
, server_challenge
, machine_password
);
232 netlogon_creds_init_64bit(creds
, client_challenge
, server_challenge
, machine_password
);
235 netlogon_creds_first_step(creds
, client_challenge
, server_challenge
);
237 dump_data_pw("Session key", creds
->session_key
, 16);
238 dump_data_pw("Credential ", creds
->client
.data
, 8);
240 *initial_credential
= creds
->client
;
245 initialise the credentials structure with only a session key. The caller better know what they are doing!
248 struct netlogon_creds_CredentialState
*netlogon_creds_client_init_session_key(TALLOC_CTX
*mem_ctx
,
249 const uint8_t session_key
[16])
251 struct netlogon_creds_CredentialState
*creds
;
253 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
258 memcpy(creds
->session_key
, session_key
, 16);
264 step the credentials to the next element in the chain, updating the
265 current client and server credentials and the seed
267 produce the next authenticator in the sequence ready to send to
270 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState
*creds
,
271 struct netr_Authenticator
*next
)
273 creds
->sequence
+= 2;
274 netlogon_creds_step(creds
);
276 next
->cred
= creds
->client
;
277 next
->timestamp
= creds
->sequence
;
281 check that a credentials reply from a server is correct
283 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState
*creds
,
284 const struct netr_Credential
*received_credentials
)
286 if (!received_credentials
||
287 memcmp(received_credentials
->data
, creds
->server
.data
, 8) != 0) {
288 DEBUG(2,("credentials check failed\n"));
295 /*****************************************************************
296 The above functions are common to the client and server interface
297 next comes the server specific functions
298 ******************************************************************/
301 check that a credentials reply from a server is correct
303 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState
*creds
,
304 const struct netr_Credential
*received_credentials
)
306 if (memcmp(received_credentials
->data
, creds
->client
.data
, 8) != 0) {
307 DEBUG(2,("credentials check failed\n"));
308 dump_data_pw("client creds", creds
->client
.data
, 8);
309 dump_data_pw("calc creds", received_credentials
->data
, 8);
316 initialise the credentials chain and return the first server
319 struct netlogon_creds_CredentialState
*netlogon_creds_server_init(TALLOC_CTX
*mem_ctx
,
320 const char *client_account
,
321 const char *client_computer_name
,
322 uint16_t secure_channel_type
,
323 const struct netr_Credential
*client_challenge
,
324 const struct netr_Credential
*server_challenge
,
325 const struct samr_Password
*machine_password
,
326 struct netr_Credential
*credentials_in
,
327 struct netr_Credential
*credentials_out
,
328 uint32_t negotiate_flags
)
331 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
337 creds
->negotiate_flags
= negotiate_flags
;
338 creds
->secure_channel_type
= secure_channel_type
;
340 creds
->computer_name
= talloc_strdup(creds
, client_computer_name
);
341 if (!creds
->computer_name
) {
345 creds
->account_name
= talloc_strdup(creds
, client_account
);
346 if (!creds
->account_name
) {
351 if (negotiate_flags
& NETLOGON_NEG_128BIT
) {
352 netlogon_creds_init_128bit(creds
, client_challenge
, server_challenge
,
355 netlogon_creds_init_64bit(creds
, client_challenge
, server_challenge
,
359 netlogon_creds_first_step(creds
, client_challenge
, server_challenge
);
361 /* And before we leak information about the machine account
362 * password, check that they got the first go right */
363 if (!netlogon_creds_server_check_internal(creds
, credentials_in
)) {
368 *credentials_out
= creds
->server
;
373 NTSTATUS
netlogon_creds_server_step_check(struct netlogon_creds_CredentialState
*creds
,
374 struct netr_Authenticator
*received_authenticator
,
375 struct netr_Authenticator
*return_authenticator
)
377 if (!received_authenticator
|| !return_authenticator
) {
378 return NT_STATUS_INVALID_PARAMETER
;
382 return NT_STATUS_ACCESS_DENIED
;
385 /* TODO: this may allow the a replay attack on a non-signed
386 connection. Should we check that this is increasing? */
387 creds
->sequence
= received_authenticator
->timestamp
;
388 netlogon_creds_step(creds
);
389 if (netlogon_creds_server_check_internal(creds
, &received_authenticator
->cred
)) {
390 return_authenticator
->cred
= creds
->server
;
391 return_authenticator
->timestamp
= creds
->sequence
;
394 ZERO_STRUCTP(return_authenticator
);
395 return NT_STATUS_ACCESS_DENIED
;
399 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState
*creds
,
400 uint16_t validation_level
,
401 union netr_Validation
*validation
)
403 static const char zeros
[16];
405 struct netr_SamBaseInfo
*base
= NULL
;
406 switch (validation_level
) {
408 if (validation
->sam2
) {
409 base
= &validation
->sam2
->base
;
413 if (validation
->sam3
) {
414 base
= &validation
->sam3
->base
;
418 if (validation
->sam6
) {
419 base
= &validation
->sam6
->base
;
423 /* If we can't find it, we can't very well decrypt it */
431 /* find and decyrpt the session keys, return in parameters above */
432 if (validation_level
== 6) {
433 /* they aren't encrypted! */
434 } else if (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
) {
435 if (memcmp(base
->key
.key
, zeros
,
436 sizeof(base
->key
.key
)) != 0) {
437 netlogon_creds_arcfour_crypt(creds
,
439 sizeof(base
->key
.key
));
442 if (memcmp(base
->LMSessKey
.key
, zeros
,
443 sizeof(base
->LMSessKey
.key
)) != 0) {
444 netlogon_creds_arcfour_crypt(creds
,
446 sizeof(base
->LMSessKey
.key
));
449 if (memcmp(base
->LMSessKey
.key
, zeros
,
450 sizeof(base
->LMSessKey
.key
)) != 0) {
451 netlogon_creds_des_decrypt_LMKey(creds
,