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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "system/time.h"
26 #include "auth/auth.h"
27 #include "lib/crypto/crypto.h"
28 #include "librpc/gen_ndr/ndr_netlogon.h"
31 initialise the credentials state for old-style 64 bit session keys
33 this call is made after the netr_ServerReqChallenge call
35 static void creds_init_64bit(struct creds_CredentialState *creds,
36 const struct netr_Credential *client_challenge,
37 const struct netr_Credential *server_challenge,
38 const struct samr_Password *machine_password)
43 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
44 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
49 ZERO_STRUCT(creds->session_key);
51 des_crypt128(creds->session_key, sum2, machine_password->hash);
53 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
54 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
56 creds->seed = creds->client;
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 creds_init_128bit(struct 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);
86 creds->client = *client_challenge;
87 creds->server = *server_challenge;
89 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
90 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
92 creds->seed = creds->client;
97 step the credentials to the next element in the chain, updating the
98 current client and server credentials and the seed
100 static void creds_step(struct creds_CredentialState *creds)
102 struct netr_Credential time_cred;
104 DEBUG(5,("\tseed %08x:%08x\n",
105 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
107 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
108 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
110 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
112 des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
114 DEBUG(5,("\tCLIENT %08x:%08x\n",
115 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
117 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
118 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
120 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
121 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
123 des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
125 DEBUG(5,("\tSERVER %08x:%08x\n",
126 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
128 creds->seed = time_cred;
133 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
135 void creds_des_encrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
137 struct netr_LMSessionKey tmp;
138 des_crypt56(tmp.key, key->key, creds->session_key, 1);
143 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
145 void creds_des_decrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
147 struct netr_LMSessionKey tmp;
148 des_crypt56(tmp.key, key->key, creds->session_key, 0);
153 DES encrypt a 16 byte password buffer using the session key
155 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
157 struct samr_Password tmp;
158 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
163 DES decrypt a 16 byte password buffer using the session key
165 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
167 struct samr_Password tmp;
168 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
173 ARCFOUR encrypt/decrypt a password buffer using the session key
175 void creds_arcfour_crypt(struct creds_CredentialState *creds, uint8_t *data, size_t len)
177 DATA_BLOB session_key = data_blob(creds->session_key, 16);
179 arcfour_crypt_blob(data, len, &session_key);
181 data_blob_free(&session_key);
184 /*****************************************************************
185 The above functions are common to the client and server interface
186 next comes the client specific functions
187 ******************************************************************/
190 initialise the credentials chain and return the first client
193 void creds_client_init(struct creds_CredentialState *creds,
194 const struct netr_Credential *client_challenge,
195 const struct netr_Credential *server_challenge,
196 const struct samr_Password *machine_password,
197 struct netr_Credential *initial_credential,
198 uint32_t negotiate_flags)
200 creds->sequence = time(NULL);
201 creds->negotiate_flags = negotiate_flags;
203 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
204 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
205 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
207 if (negotiate_flags & NETLOGON_NEG_128BIT) {
208 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
210 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
213 dump_data_pw("Session key", creds->session_key, 16);
214 dump_data_pw("Credential ", creds->client.data, 8);
216 *initial_credential = creds->client;
220 step the credentials to the next element in the chain, updating the
221 current client and server credentials and the seed
223 produce the next authenticator in the sequence ready to send to
226 void creds_client_authenticator(struct creds_CredentialState *creds,
227 struct netr_Authenticator *next)
229 creds->sequence += 2;
232 next->cred = creds->client;
233 next->timestamp = creds->sequence;
237 check that a credentials reply from a server is correct
239 BOOL creds_client_check(struct creds_CredentialState *creds,
240 const struct netr_Credential *received_credentials)
242 if (!received_credentials ||
243 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
244 DEBUG(2,("credentials check failed\n"));
251 /*****************************************************************
252 The above functions are common to the client and server interface
253 next comes the server specific functions
254 ******************************************************************/
257 initialise the credentials chain and return the first server
260 void creds_server_init(struct creds_CredentialState *creds,
261 const struct netr_Credential *client_challenge,
262 const struct netr_Credential *server_challenge,
263 const struct samr_Password *machine_password,
264 struct netr_Credential *initial_credential,
265 uint32_t negotiate_flags)
267 if (negotiate_flags & NETLOGON_NEG_128BIT) {
268 creds_init_128bit(creds, client_challenge, server_challenge,
271 creds_init_64bit(creds, client_challenge, server_challenge,
275 *initial_credential = creds->server;
276 creds->negotiate_flags = negotiate_flags;
280 check that a credentials reply from a server is correct
282 BOOL creds_server_check(const struct creds_CredentialState *creds,
283 const struct netr_Credential *received_credentials)
285 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
286 DEBUG(2,("credentials check failed\n"));
287 dump_data_pw("client creds", creds->client.data, 8);
288 dump_data_pw("calc creds", received_credentials->data, 8);
294 NTSTATUS creds_server_step_check(struct creds_CredentialState *creds,
295 struct netr_Authenticator *received_authenticator,
296 struct netr_Authenticator *return_authenticator)
298 if (!received_authenticator || !return_authenticator) {
299 return NT_STATUS_INVALID_PARAMETER;
303 return NT_STATUS_ACCESS_DENIED;
306 /* TODO: this may allow the a replay attack on a non-signed
307 connection. Should we check that this is increasing? */
308 creds->sequence = received_authenticator->timestamp;
310 if (creds_server_check(creds, &received_authenticator->cred)) {
311 return_authenticator->cred = creds->server;
312 return_authenticator->timestamp = creds->sequence;
315 ZERO_STRUCTP(return_authenticator);
316 return NT_STATUS_ACCESS_DENIED;