/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- creds_init_64bit
- creds_init_128bit
- creds_step
- creds_des_encrypt_LMKey
- creds_des_decrypt_LMKey
- creds_des_encrypt
- creds_des_decrypt
- creds_arcfour_crypt
- creds_client_init
- creds_client_authenticator
- creds_client_check
- creds_server_init
- creds_server_check
- creds_server_step_check
- creds_decrypt_samlogon
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 "auth/auth.h"
26 #include "../lib/crypto/crypto.h"
27 #include "libcli/auth/libcli_auth.h"
28
29 /*
30 initialise the credentials state for old-style 64 bit session keys
31
32 this call is made after the netr_ServerReqChallenge call
33 */
34 static void creds_init_64bit(struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
35 const struct netr_Credential *client_challenge,
36 const struct netr_Credential *server_challenge,
37 const struct samr_Password *machine_password)
38 {
39 uint32_t sum[2];
40 uint8_t sum2[8];
41
42 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
43 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
44
45 SIVAL(sum2,0,sum[0]);
46 SIVAL(sum2,4,sum[1]);
47
48 ZERO_STRUCT(creds->session_key);
49
50 des_crypt128(creds->session_key, sum2, machine_password->hash);
51
52 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
53 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
54
55 creds->seed = creds->client;
56 }
57
58 /*
59 initialise the credentials state for ADS-style 128 bit session keys
60
61 this call is made after the netr_ServerReqChallenge call
62 */
63 static void creds_init_128bit(struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
64 const struct netr_Credential *client_challenge,
65 const struct netr_Credential *server_challenge,
66 const struct samr_Password *machine_password)
67 {
68 unsigned char zero[4], tmp[16];
69 HMACMD5Context ctx;
70 struct MD5Context md5;
71
72 ZERO_STRUCT(creds->session_key);
73
74 memset(zero, 0, sizeof(zero));
75
76 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
77 MD5Init(&md5);
78 MD5Update(&md5, zero, sizeof(zero));
79 MD5Update(&md5, client_challenge->data, 8);
80 MD5Update(&md5, server_challenge->data, 8);
81 MD5Final(tmp, &md5);
82 hmac_md5_update(tmp, sizeof(tmp), &ctx);
83 hmac_md5_final(creds->session_key, &ctx);
84
85 creds->client = *client_challenge;
86 creds->server = *server_challenge;
87
88 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
89 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
90
91 creds->seed = creds->client;
92 }
93
94
95 /*
96 step the credentials to the next element in the chain, updating the
97 current client and server credentials and the seed
98 */
99 static void creds_step(struct creds_CredentialState *creds)
/* [<][>][^][v][top][bottom][index][help] */
100 {
101 struct netr_Credential time_cred;
102
103 DEBUG(5,("\tseed %08x:%08x\n",
104 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
105
106 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
107 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
108
109 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
110
111 des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
112
113 DEBUG(5,("\tCLIENT %08x:%08x\n",
114 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
115
116 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
117 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
118
119 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
120 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
121
122 des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
123
124 DEBUG(5,("\tSERVER %08x:%08x\n",
125 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
126
127 creds->seed = time_cred;
128 }
129
130
131 /*
132 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
133 */
134 void creds_des_encrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
/* [<][>][^][v][top][bottom][index][help] */
135 {
136 struct netr_LMSessionKey tmp;
137 des_crypt56(tmp.key, key->key, creds->session_key, 1);
138 *key = tmp;
139 }
140
141 /*
142 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
143 */
144 void creds_des_decrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
/* [<][>][^][v][top][bottom][index][help] */
145 {
146 struct netr_LMSessionKey tmp;
147 des_crypt56(tmp.key, key->key, creds->session_key, 0);
148 *key = tmp;
149 }
150
151 /*
152 DES encrypt a 16 byte password buffer using the session key
153 */
154 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
/* [<][>][^][v][top][bottom][index][help] */
155 {
156 struct samr_Password tmp;
157 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
158 *pass = tmp;
159 }
160
161 /*
162 DES decrypt a 16 byte password buffer using the session key
163 */
164 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
/* [<][>][^][v][top][bottom][index][help] */
165 {
166 struct samr_Password tmp;
167 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
168 *pass = tmp;
169 }
170
171 /*
172 ARCFOUR encrypt/decrypt a password buffer using the session key
173 */
174 void creds_arcfour_crypt(struct creds_CredentialState *creds, uint8_t *data, size_t len)
/* [<][>][^][v][top][bottom][index][help] */
175 {
176 DATA_BLOB session_key = data_blob(creds->session_key, 16);
177
178 arcfour_crypt_blob(data, len, &session_key);
179
180 data_blob_free(&session_key);
181 }
182
183 /*****************************************************************
184 The above functions are common to the client and server interface
185 next comes the client specific functions
186 ******************************************************************/
187
188 /*
189 initialise the credentials chain and return the first client
190 credentials
191 */
192 void creds_client_init(struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
193 const struct netr_Credential *client_challenge,
194 const struct netr_Credential *server_challenge,
195 const struct samr_Password *machine_password,
196 struct netr_Credential *initial_credential,
197 uint32_t negotiate_flags)
198 {
199 creds->sequence = time(NULL);
200 creds->negotiate_flags = negotiate_flags;
201
202 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
203 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
204 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
205
206 if (negotiate_flags & NETLOGON_NEG_128BIT) {
207 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
208 } else {
209 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
210 }
211
212 dump_data_pw("Session key", creds->session_key, 16);
213 dump_data_pw("Credential ", creds->client.data, 8);
214
215 *initial_credential = creds->client;
216 }
217
218 /*
219 step the credentials to the next element in the chain, updating the
220 current client and server credentials and the seed
221
222 produce the next authenticator in the sequence ready to send to
223 the server
224 */
225 void creds_client_authenticator(struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
226 struct netr_Authenticator *next)
227 {
228 creds->sequence += 2;
229 creds_step(creds);
230
231 next->cred = creds->client;
232 next->timestamp = creds->sequence;
233 }
234
235 /*
236 check that a credentials reply from a server is correct
237 */
238 bool creds_client_check(struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
239 const struct netr_Credential *received_credentials)
240 {
241 if (!received_credentials ||
242 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
243 DEBUG(2,("credentials check failed\n"));
244 return false;
245 }
246 return true;
247 }
248
249
250 /*****************************************************************
251 The above functions are common to the client and server interface
252 next comes the server specific functions
253 ******************************************************************/
254
255 /*
256 initialise the credentials chain and return the first server
257 credentials
258 */
259 void creds_server_init(struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
260 const struct netr_Credential *client_challenge,
261 const struct netr_Credential *server_challenge,
262 const struct samr_Password *machine_password,
263 struct netr_Credential *initial_credential,
264 uint32_t negotiate_flags)
265 {
266 if (negotiate_flags & NETLOGON_NEG_128BIT) {
267 creds_init_128bit(creds, client_challenge, server_challenge,
268 machine_password);
269 } else {
270 creds_init_64bit(creds, client_challenge, server_challenge,
271 machine_password);
272 }
273
274 *initial_credential = creds->server;
275 creds->negotiate_flags = negotiate_flags;
276 }
277
278 /*
279 check that a credentials reply from a server is correct
280 */
281 bool creds_server_check(const struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
282 const struct netr_Credential *received_credentials)
283 {
284 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
285 DEBUG(2,("credentials check failed\n"));
286 dump_data_pw("client creds", creds->client.data, 8);
287 dump_data_pw("calc creds", received_credentials->data, 8);
288 return false;
289 }
290 return true;
291 }
292
293 NTSTATUS creds_server_step_check(struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
294 struct netr_Authenticator *received_authenticator,
295 struct netr_Authenticator *return_authenticator)
296 {
297 if (!received_authenticator || !return_authenticator) {
298 return NT_STATUS_INVALID_PARAMETER;
299 }
300
301 if (!creds) {
302 return NT_STATUS_ACCESS_DENIED;
303 }
304
305 /* TODO: this may allow the a replay attack on a non-signed
306 connection. Should we check that this is increasing? */
307 creds->sequence = received_authenticator->timestamp;
308 creds_step(creds);
309 if (creds_server_check(creds, &received_authenticator->cred)) {
310 return_authenticator->cred = creds->server;
311 return_authenticator->timestamp = creds->sequence;
312 return NT_STATUS_OK;
313 } else {
314 ZERO_STRUCTP(return_authenticator);
315 return NT_STATUS_ACCESS_DENIED;
316 }
317 }
318
319 void creds_decrypt_samlogon(struct creds_CredentialState *creds,
/* [<][>][^][v][top][bottom][index][help] */
320 uint16_t validation_level,
321 union netr_Validation *validation)
322 {
323 static const char zeros[16];
324
325 struct netr_SamBaseInfo *base = NULL;
326 switch (validation_level) {
327 case 2:
328 if (validation->sam2) {
329 base = &validation->sam2->base;
330 }
331 break;
332 case 3:
333 if (validation->sam3) {
334 base = &validation->sam3->base;
335 }
336 break;
337 case 6:
338 if (validation->sam6) {
339 base = &validation->sam6->base;
340 }
341 break;
342 default:
343 /* If we can't find it, we can't very well decrypt it */
344 return;
345 }
346
347 if (!base) {
348 return;
349 }
350
351 /* find and decyrpt the session keys, return in parameters above */
352 if (validation_level == 6) {
353 /* they aren't encrypted! */
354 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
355 if (memcmp(base->key.key, zeros,
356 sizeof(base->key.key)) != 0) {
357 creds_arcfour_crypt(creds,
358 base->key.key,
359 sizeof(base->key.key));
360 }
361
362 if (memcmp(base->LMSessKey.key, zeros,
363 sizeof(base->LMSessKey.key)) != 0) {
364 creds_arcfour_crypt(creds,
365 base->LMSessKey.key,
366 sizeof(base->LMSessKey.key));
367 }
368 } else {
369 if (memcmp(base->LMSessKey.key, zeros,
370 sizeof(base->LMSessKey.key)) != 0) {
371 creds_des_decrypt_LMKey(creds,
372 &base->LMSessKey);
373 }
374 }
375 }