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"
28 initialise the credentials state for old-style 64 bit session keys
30 this call is made after the netr_ServerReqChallenge call
32 static void creds_init_64bit(struct creds_CredentialState *creds,
33 const struct netr_Credential *client_challenge,
34 const struct netr_Credential *server_challenge,
35 const struct samr_Password *machine_password)
40 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
41 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
46 ZERO_STRUCT(creds->session_key);
48 des_crypt128(creds->session_key, sum2, machine_password->hash);
50 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
51 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
53 creds->seed = creds->client;
57 initialise the credentials state for ADS-style 128 bit session keys
59 this call is made after the netr_ServerReqChallenge call
61 static void creds_init_128bit(struct creds_CredentialState *creds,
62 const struct netr_Credential *client_challenge,
63 const struct netr_Credential *server_challenge,
64 const struct samr_Password *machine_password)
66 unsigned char zero[4], tmp[16];
68 struct MD5Context md5;
70 ZERO_STRUCT(creds->session_key);
72 memset(zero, 0, sizeof(zero));
74 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
76 MD5Update(&md5, zero, sizeof(zero));
77 MD5Update(&md5, client_challenge->data, 8);
78 MD5Update(&md5, server_challenge->data, 8);
80 hmac_md5_update(tmp, sizeof(tmp), &ctx);
81 hmac_md5_final(creds->session_key, &ctx);
83 creds->client = *client_challenge;
84 creds->server = *server_challenge;
86 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
87 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
89 creds->seed = creds->client;
94 step the credentials to the next element in the chain, updating the
95 current client and server credentials and the seed
97 static void creds_step(struct creds_CredentialState *creds)
99 struct netr_Credential time_cred;
101 DEBUG(5,("\tseed %08x:%08x\n",
102 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
104 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
105 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
107 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
109 des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
111 DEBUG(5,("\tCLIENT %08x:%08x\n",
112 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
114 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
115 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
117 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
118 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
120 des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
122 DEBUG(5,("\tSERVER %08x:%08x\n",
123 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
125 creds->seed = time_cred;
130 DES encrypt a 16 byte password buffer using the session key
132 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
134 struct samr_Password tmp;
135 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
140 DES decrypt a 16 byte password buffer using the session key
142 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
144 struct samr_Password tmp;
145 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
150 ARCFOUR encrypt/decrypt a password buffer using the session key
152 void creds_arcfour_crypt(struct creds_CredentialState *creds, char *data, size_t len)
154 DATA_BLOB session_key = data_blob(creds->session_key, 16);
156 arcfour_crypt_blob(data, len, &session_key);
158 data_blob_free(&session_key);
161 /*****************************************************************
162 The above functions are common to the client and server interface
163 next comes the client specific functions
164 ******************************************************************/
167 initialise the credentials chain and return the first client
170 void creds_client_init(struct creds_CredentialState *creds,
171 const struct netr_Credential *client_challenge,
172 const struct netr_Credential *server_challenge,
173 const struct samr_Password *machine_password,
174 struct netr_Credential *initial_credential,
175 uint32_t negotiate_flags)
177 creds->sequence = time(NULL);
178 creds->negotiate_flags = negotiate_flags;
180 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
181 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
182 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
184 if (negotiate_flags & NETLOGON_NEG_128BIT) {
185 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
187 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
190 dump_data_pw("Session key", creds->session_key, 16);
191 dump_data_pw("Credential ", creds->client.data, 8);
193 *initial_credential = creds->client;
197 step the credentials to the next element in the chain, updating the
198 current client and server credentials and the seed
200 produce the next authenticator in the sequence ready to send to
203 void creds_client_authenticator(struct creds_CredentialState *creds,
204 struct netr_Authenticator *next)
206 creds->sequence += 2;
209 next->cred = creds->client;
210 next->timestamp = creds->sequence;
214 check that a credentials reply from a server is correct
216 BOOL creds_client_check(struct creds_CredentialState *creds,
217 const struct netr_Credential *received_credentials)
219 if (!received_credentials ||
220 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
221 DEBUG(2,("credentials check failed\n"));
228 /*****************************************************************
229 The above functions are common to the client and server interface
230 next comes the server specific functions
231 ******************************************************************/
234 initialise the credentials chain and return the first server
237 void creds_server_init(struct creds_CredentialState *creds,
238 const struct netr_Credential *client_challenge,
239 const struct netr_Credential *server_challenge,
240 const struct samr_Password *machine_password,
241 struct netr_Credential *initial_credential,
242 uint32_t negotiate_flags)
244 if (negotiate_flags & NETLOGON_NEG_128BIT) {
245 creds_init_128bit(creds, client_challenge, server_challenge,
248 creds_init_64bit(creds, client_challenge, server_challenge,
252 *initial_credential = creds->server;
256 check that a credentials reply from a server is correct
258 BOOL creds_server_check(const struct creds_CredentialState *creds,
259 const struct netr_Credential *received_credentials)
261 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
262 DEBUG(2,("credentials check failed\n"));
263 dump_data_pw("client creds", creds->client.data, 8);
264 dump_data_pw("calc creds", received_credentials->data, 8);
270 BOOL creds_server_step_check(struct creds_CredentialState *creds,
271 struct netr_Authenticator *received_authenticator,
272 struct netr_Authenticator *return_authenticator)
274 /* TODO: this may allow the a replay attack on a non-signed
275 connection. Should we check that this is increasing? */
276 creds->sequence = received_authenticator->timestamp;
278 if (creds_server_check(creds, &received_authenticator->cred)) {
279 return_authenticator->cred = creds->server;
280 return_authenticator->timestamp = creds->sequence;
283 ZERO_STRUCTP(return_authenticator);