/src/gss-ntlmssp/src/ntlm_crypto.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2013 Simo Sorce <simo@samba.org>, see COPYING for license */ |
2 | | |
3 | | /* This File implements the NTLM protocol as specified by: |
4 | | * [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol |
5 | | * |
6 | | * Additional cross checking with: |
7 | | * http://davenport.sourceforge.net/ntlm.html |
8 | | */ |
9 | | |
10 | | #include <errno.h> |
11 | | #include <stddef.h> |
12 | | #include <string.h> |
13 | | |
14 | | #include <unicase.h> |
15 | | #include <uniconv.h> |
16 | | |
17 | | #include "ntlm.h" |
18 | | #include "crypto.h" |
19 | | |
20 | | /* signature structure, v1 or v2 */ |
21 | | #pragma pack(push, 1) |
22 | | union wire_msg_signature { |
23 | | struct { |
24 | | uint32_t version; |
25 | | uint32_t random_pad; |
26 | | uint32_t checksum; |
27 | | uint32_t seq_num; |
28 | | } v1; |
29 | | struct { |
30 | | uint32_t version; |
31 | | uint64_t checksum; |
32 | | uint32_t seq_num; |
33 | | } v2; |
34 | | }; |
35 | | #pragma pack(pop) |
36 | | |
37 | | /* the max username is 20 chars, max NB domain len is 15, so 128 should be |
38 | | * plenty including conversion to UTF8 using max lenght for each code point |
39 | | */ |
40 | 0 | #define MAX_USER_DOM_LEN 512 |
41 | | |
42 | | |
43 | | int NTOWFv1(const char *password, struct ntlm_key *result) |
44 | 0 | { |
45 | 0 | struct ntlm_buffer payload; |
46 | 0 | struct ntlm_buffer hash; |
47 | 0 | char *retstr; |
48 | 0 | size_t out; |
49 | 0 | size_t len; |
50 | 0 | int ret; |
51 | |
|
52 | 0 | len = strlen(password); |
53 | 0 | retstr = u8_conv_to_encoding("UTF-16LE", iconveh_error, |
54 | 0 | (const uint8_t *)password, len, |
55 | 0 | NULL, NULL, &out); |
56 | 0 | if (!retstr) return ERR_CRYPTO; |
57 | | |
58 | 0 | payload.data = (uint8_t *)retstr; |
59 | 0 | payload.length = out; |
60 | 0 | hash.data = result->data; |
61 | 0 | hash.length = result->length; |
62 | |
|
63 | 0 | ret = MD4_HASH(&payload, &hash); |
64 | 0 | free(retstr); |
65 | 0 | return ret; |
66 | 0 | } |
67 | | |
68 | | #define DES_CONST "KGS!@#$%" |
69 | | int LMOWFv1(const char *password, struct ntlm_key *result) |
70 | 0 | { |
71 | 0 | struct ntlm_buffer key; |
72 | 0 | struct ntlm_buffer plain; |
73 | 0 | struct ntlm_buffer cipher; |
74 | 0 | char upcased[15]; |
75 | 0 | char *retstr; |
76 | 0 | size_t out; |
77 | 0 | size_t len; |
78 | 0 | int ret; |
79 | |
|
80 | 0 | if (result->length != 16) return EINVAL; |
81 | | |
82 | 0 | len = strlen(password); |
83 | 0 | if (len > 14) { |
84 | 0 | memset(result->data, 0, result->length); |
85 | 0 | return 0; |
86 | 0 | } |
87 | | |
88 | 0 | out = 15; |
89 | 0 | retstr = (char *)u8_toupper((const uint8_t *)password, len, |
90 | 0 | NULL, NULL, (uint8_t *)upcased, &out); |
91 | 0 | if (!retstr) return ERR_CRYPTO; |
92 | 0 | if (retstr != upcased) { |
93 | 0 | free(retstr); |
94 | 0 | ret = EINVAL; |
95 | 0 | } |
96 | 0 | memset(&upcased[len], 0, 15 - len); |
97 | | |
98 | | /* part1 */ |
99 | 0 | key.data = (uint8_t *)upcased; |
100 | 0 | key.length = 7; |
101 | 0 | plain.data = discard_const(DES_CONST); |
102 | 0 | plain.length = 8; |
103 | 0 | cipher.data = result->data; |
104 | 0 | cipher.length = 8; |
105 | 0 | ret = WEAK_DES(&key, &plain, &cipher); |
106 | 0 | if (ret) return ret; |
107 | | |
108 | | /* part2 */ |
109 | 0 | key.data = (uint8_t *)&upcased[7]; |
110 | 0 | key.length = 7; |
111 | 0 | plain.data = discard_const(DES_CONST); |
112 | 0 | plain.length = 8; |
113 | 0 | cipher.data = &result->data[8]; |
114 | 0 | cipher.length = 8; |
115 | 0 | return WEAK_DES(&key, &plain, &cipher); |
116 | 0 | } |
117 | | |
118 | | int ntlm_compute_ext_sec_challenge(uint8_t *server_chal, |
119 | | uint8_t *client_chal, |
120 | | uint8_t *result_chal) |
121 | 0 | { |
122 | 0 | uint8_t scbuf[16]; |
123 | 0 | uint8_t mdbuf[16]; |
124 | 0 | struct ntlm_buffer challenges = { scbuf, 16 }; |
125 | 0 | struct ntlm_buffer msgdigest = { mdbuf, 16 }; |
126 | 0 | int ret; |
127 | |
|
128 | 0 | memcpy(scbuf, server_chal, 8); |
129 | 0 | memcpy(&scbuf[8], client_chal, 8); |
130 | 0 | ret = MD5_HASH(&challenges, &msgdigest); |
131 | 0 | if (ret) return ret; |
132 | | |
133 | 0 | memcpy(result_chal, mdbuf, 8); |
134 | 0 | return 0; |
135 | 0 | } |
136 | | |
137 | | int ntlm_compute_nt_response(struct ntlm_key *nt_key, bool ext_sec, |
138 | | uint8_t server_chal[8], uint8_t client_chal[8], |
139 | | struct ntlm_buffer *nt_response) |
140 | 0 | { |
141 | 0 | struct ntlm_buffer key = { nt_key->data, nt_key->length }; |
142 | 0 | uint8_t chal[8]; |
143 | 0 | struct ntlm_buffer payload = { chal, 8}; |
144 | 0 | int ret; |
145 | |
|
146 | 0 | if (ext_sec) { |
147 | 0 | ret = ntlm_compute_ext_sec_challenge(server_chal, client_chal, chal); |
148 | 0 | if (ret) return ret; |
149 | 0 | } else { |
150 | 0 | memcpy(chal, server_chal, 8); |
151 | 0 | } |
152 | | |
153 | 0 | return DESL(&key, &payload, nt_response); |
154 | 0 | } |
155 | | |
156 | | int ntlm_compute_lm_response(struct ntlm_key *lm_key, bool ext_sec, |
157 | | uint8_t server_chal[8], uint8_t client_chal[8], |
158 | | struct ntlm_buffer *lm_response) |
159 | 0 | { |
160 | 0 | struct ntlm_buffer key = { lm_key->data, lm_key->length }; |
161 | 0 | struct ntlm_buffer payload = { server_chal, 8 }; |
162 | |
|
163 | 0 | if (ext_sec) { |
164 | 0 | memcpy(lm_response->data, client_chal, 8); |
165 | 0 | memset(&lm_response->data[8], 0, 16); |
166 | 0 | return 0; |
167 | 0 | } |
168 | 0 | return DESL(&key, &payload, lm_response); |
169 | 0 | } |
170 | | |
171 | | int ntlm_session_base_key(struct ntlm_key *nt_key, |
172 | | struct ntlm_key *session_base_key) |
173 | 0 | { |
174 | 0 | struct ntlm_buffer payload = { nt_key->data, nt_key->length }; |
175 | 0 | struct ntlm_buffer hash = { session_base_key->data, |
176 | 0 | session_base_key->length }; |
177 | |
|
178 | 0 | return MD4_HASH(&payload, &hash); |
179 | 0 | } |
180 | | |
181 | | int KXKEY(struct ntlm_ctx *ctx, |
182 | | bool ext_sec, |
183 | | bool neg_lm_key, |
184 | | bool non_nt_sess_key, |
185 | | uint8_t server_chal[8], |
186 | | struct ntlm_key *lm_key, |
187 | | struct ntlm_key *session_base_key, |
188 | | struct ntlm_buffer *lm_response, |
189 | | struct ntlm_key *key_exchange_key) |
190 | 0 | { |
191 | 0 | struct ntlm_buffer payload; |
192 | 0 | struct ntlm_buffer result; |
193 | 0 | struct ntlm_buffer key; |
194 | 0 | uint8_t buf[16]; |
195 | 0 | int ret = 0; |
196 | |
|
197 | 0 | if (ext_sec) { |
198 | 0 | key.data = session_base_key->data; |
199 | 0 | key.length = session_base_key->length; |
200 | 0 | memcpy(buf, server_chal, 8); |
201 | 0 | memcpy(&buf[8], lm_response->data, 8); |
202 | 0 | payload.data = buf; |
203 | 0 | payload.length = 16; |
204 | 0 | result.data = key_exchange_key->data; |
205 | 0 | result.length = key_exchange_key->length; |
206 | 0 | ret = HMAC_MD5(&key, &payload, &result); |
207 | 0 | } else if (neg_lm_key) { |
208 | 0 | payload.data = lm_response->data; |
209 | 0 | payload.length = 8; |
210 | 0 | key.data = lm_key->data; |
211 | 0 | key.length = 7; |
212 | 0 | result.data = key_exchange_key->data; |
213 | 0 | result.length = 8; |
214 | 0 | ret = WEAK_DES(&key, &payload, &result); |
215 | 0 | if (ret) return ret; |
216 | 0 | buf[0] = lm_key->data[7]; |
217 | 0 | memset(&buf[1], 0xbd, 6); |
218 | 0 | key.data = buf; |
219 | 0 | result.data = &key_exchange_key->data[8]; |
220 | 0 | result.length = 8; |
221 | 0 | ret = WEAK_DES(&key, &payload, &result); |
222 | 0 | } else if (non_nt_sess_key) { |
223 | 0 | memcpy(key_exchange_key->data, lm_key, 8); |
224 | 0 | memset(&key_exchange_key->data[8], 0, 8); |
225 | 0 | } else { |
226 | 0 | memcpy(key_exchange_key->data, session_base_key->data, 16); |
227 | 0 | } |
228 | 0 | return ret; |
229 | 0 | } |
230 | | |
231 | | int NTOWFv2(struct ntlm_ctx *ctx, struct ntlm_key *nt_hash, |
232 | | const char *user, const char *domain, struct ntlm_key *result) |
233 | 0 | { |
234 | 0 | struct ntlm_buffer key = { nt_hash->data, nt_hash->length }; |
235 | 0 | struct ntlm_buffer hmac = { result->data, result->length }; |
236 | 0 | struct ntlm_buffer payload; |
237 | 0 | uint8_t upcased[MAX_USER_DOM_LEN]; |
238 | 0 | uint8_t *retstr; |
239 | 0 | size_t offs; |
240 | 0 | size_t out; |
241 | 0 | size_t len; |
242 | 0 | int ret; |
243 | |
|
244 | 0 | len = strlen(user); |
245 | 0 | out = MAX_USER_DOM_LEN; |
246 | 0 | retstr = u8_toupper((const uint8_t *)user, len, |
247 | 0 | NULL, NULL, upcased, &out); |
248 | 0 | if (!retstr) return ERR_CRYPTO; |
249 | 0 | offs = out; |
250 | |
|
251 | 0 | if (domain) { |
252 | 0 | len = strlen(domain); |
253 | 0 | memcpy(&upcased[offs], domain, len); |
254 | 0 | offs += len; |
255 | 0 | } |
256 | |
|
257 | 0 | retstr = (uint8_t *)u8_conv_to_encoding("UTF-16LE", iconveh_error, |
258 | 0 | upcased, offs, NULL, NULL, &out); |
259 | 0 | if (!retstr) return ERR_CRYPTO; |
260 | | |
261 | 0 | payload.data = (uint8_t *)retstr; |
262 | 0 | payload.length = out; |
263 | |
|
264 | 0 | ret = HMAC_MD5(&key, &payload, &hmac); |
265 | 0 | free(retstr); |
266 | 0 | return ret; |
267 | 0 | } |
268 | | |
269 | | int ntlmv2_compute_nt_response(struct ntlm_key *ntlmv2_key, |
270 | | uint8_t server_chal[8], uint8_t client_chal[8], |
271 | | uint64_t timestamp, |
272 | | struct ntlm_buffer *target_info, |
273 | | struct ntlm_buffer *nt_response) |
274 | 0 | { |
275 | 0 | union wire_ntlm_response *nt_resp = NULL; |
276 | 0 | struct wire_ntlmv2_cli_chal *r; |
277 | 0 | struct ntlm_buffer key = { ntlmv2_key->data, ntlmv2_key->length }; |
278 | 0 | struct ntlm_buffer payload; |
279 | 0 | struct ntlm_buffer nt_proof; |
280 | 0 | size_t r_len; |
281 | 0 | int ret; |
282 | | |
283 | | /* add additional 4 0s trailing target_info */ |
284 | 0 | r_len = sizeof(struct wire_ntlmv2_cli_chal) + target_info->length + 4; |
285 | 0 | nt_resp = calloc(1, sizeof(nt_resp->v2) + r_len); |
286 | 0 | if (!nt_resp) return ENOMEM; |
287 | | |
288 | 0 | r = (struct wire_ntlmv2_cli_chal *)nt_resp->v2.cli_chal; |
289 | 0 | r->resp_version = 1; |
290 | 0 | r->hi_resp_version = 1; |
291 | 0 | r->timestamp = htole64(timestamp); |
292 | 0 | memcpy(r->client_chal, client_chal, 8); |
293 | 0 | memcpy(r->target_info, target_info->data, target_info->length); |
294 | | |
295 | | /* use nt_resp as a buffer to calculate the NT proof as they share |
296 | | * the cli_chal part */ |
297 | 0 | payload.data = &nt_resp->v2.resp[8]; |
298 | 0 | payload.length = 8 + r_len; |
299 | 0 | memcpy(payload.data, server_chal, 8); |
300 | 0 | nt_proof.data = nt_resp->v2.resp; |
301 | 0 | nt_proof.length = 16; |
302 | 0 | ret = HMAC_MD5(&key, &payload, &nt_proof); |
303 | |
|
304 | 0 | if (ret) { |
305 | 0 | safefree(nt_resp); |
306 | 0 | } else { |
307 | 0 | nt_response->data = (uint8_t *)nt_resp; |
308 | 0 | nt_response->length = 16 + r_len; |
309 | 0 | } |
310 | 0 | return ret; |
311 | 0 | } |
312 | | |
313 | | int ntlmv2_compute_lm_response(struct ntlm_key *ntlmv2_key, |
314 | | uint8_t server_chal[8], uint8_t client_chal[8], |
315 | | struct ntlm_buffer *lm_response) |
316 | 0 | { |
317 | 0 | union wire_ntlm_response *lm_resp = NULL; |
318 | 0 | struct ntlm_buffer key = { ntlmv2_key->data, ntlmv2_key->length }; |
319 | 0 | uint8_t payload_buf[16]; |
320 | 0 | struct ntlm_buffer payload = { payload_buf, 16 }; |
321 | 0 | struct ntlm_buffer lm_proof; |
322 | 0 | int ret; |
323 | | |
324 | | /* now caluclate the LM Proof */ |
325 | 0 | lm_resp = malloc(sizeof(union wire_ntlm_response)); |
326 | 0 | if (!lm_resp) { |
327 | 0 | ret = ENOMEM; |
328 | 0 | goto done; |
329 | 0 | } |
330 | | |
331 | 0 | memcpy(payload.data, server_chal, 8); |
332 | 0 | memcpy(&payload.data[8], client_chal, 8); |
333 | 0 | lm_proof.data = lm_resp->v2.resp; |
334 | 0 | lm_proof.length = 16; |
335 | 0 | ret = HMAC_MD5(&key, &payload, &lm_proof); |
336 | |
|
337 | 0 | done: |
338 | 0 | if (ret) { |
339 | 0 | safefree(lm_resp); |
340 | 0 | } else { |
341 | 0 | memcpy(lm_resp->v2.cli_chal, client_chal, 8); |
342 | |
|
343 | 0 | lm_response->data = (uint8_t *)lm_resp; |
344 | 0 | lm_response->length = 24; |
345 | 0 | } |
346 | 0 | return ret; |
347 | 0 | } |
348 | | |
349 | | int ntlmv2_session_base_key(struct ntlm_key *ntlmv2_key, |
350 | | struct ntlm_buffer *nt_response, |
351 | | struct ntlm_key *session_base_key) |
352 | 0 | { |
353 | 0 | struct ntlm_buffer key = { ntlmv2_key->data, ntlmv2_key->length }; |
354 | 0 | struct ntlm_buffer hmac = { session_base_key->data, |
355 | 0 | session_base_key->length }; |
356 | |
|
357 | 0 | if (session_base_key->length != 16) return EINVAL; |
358 | | |
359 | 0 | return HMAC_MD5(&key, nt_response, &hmac); |
360 | 0 | } |
361 | | |
362 | | int ntlm_exported_session_key(struct ntlm_key *key_exchange_key, |
363 | | bool key_exch, |
364 | | struct ntlm_key *exported_session_key) |
365 | 0 | { |
366 | 0 | struct ntlm_buffer nonce; |
367 | |
|
368 | 0 | if (!key_exch) { |
369 | 0 | *exported_session_key = *key_exchange_key; |
370 | 0 | return 0; |
371 | 0 | } |
372 | | |
373 | 0 | exported_session_key->length = 16; |
374 | 0 | nonce.data = exported_session_key->data; |
375 | 0 | nonce.length = exported_session_key->length; |
376 | 0 | return RAND_BUFFER(&nonce); |
377 | 0 | } |
378 | | |
379 | | int ntlm_encrypted_session_key(struct ntlm_key *key, |
380 | | struct ntlm_key *in, struct ntlm_key *out) |
381 | 0 | { |
382 | 0 | struct ntlm_buffer _key = { key->data, key->length }; |
383 | 0 | struct ntlm_buffer data = { in->data, in->length }; |
384 | 0 | struct ntlm_buffer result = { out->data, out->length }; |
385 | |
|
386 | 0 | return RC4K(&_key, NTLM_CIPHER_ENCRYPT, &data, &result); |
387 | 0 | } |
388 | | |
389 | | static int ntlm_key_derivation_function(struct ntlm_key *key, |
390 | | const char *magic_constant, |
391 | | struct ntlm_key *derived_key) |
392 | 0 | { |
393 | 0 | uint8_t buf[80]; /* key + constant is never larger than 80 */ |
394 | 0 | struct ntlm_buffer payload = { buf, 0 }; |
395 | 0 | struct ntlm_buffer result = { derived_key->data, 16 }; |
396 | 0 | size_t len; |
397 | 0 | int ret; |
398 | |
|
399 | 0 | if (key->length > 16) return ERR_CRYPTO; |
400 | 0 | len = strlen(magic_constant) + 1; |
401 | 0 | if (len > 64) return ERR_CRYPTO; |
402 | | |
403 | 0 | payload.length = key->length; |
404 | 0 | memcpy(payload.data, key->data, key->length); |
405 | 0 | memcpy(&payload.data[payload.length], magic_constant, len); |
406 | 0 | payload.length += len; |
407 | |
|
408 | 0 | ret = MD5_HASH(&payload, &result); |
409 | 0 | if (ret == 0) { |
410 | 0 | derived_key->length = 16; |
411 | 0 | } |
412 | 0 | return ret; |
413 | 0 | } |
414 | | |
415 | 0 | #define NTLM_MODE_CLIENT true |
416 | 0 | #define NTLM_MODE_SERVER false |
417 | | |
418 | | static int ntlm_signkey(bool mode, |
419 | | struct ntlm_key *session_key, |
420 | | struct ntlm_key *signing_key) |
421 | 0 | { |
422 | 0 | const char *mc; |
423 | |
|
424 | 0 | if (mode == NTLM_MODE_CLIENT) { |
425 | 0 | mc = "session key to client-to-server signing key magic constant"; |
426 | 0 | } else { |
427 | 0 | mc = "session key to server-to-client signing key magic constant"; |
428 | 0 | } |
429 | 0 | return ntlm_key_derivation_function(session_key, |
430 | 0 | mc, signing_key); |
431 | 0 | } |
432 | | |
433 | | static int ntlm_sealkey(uint32_t flags, bool mode, |
434 | | struct ntlm_key *session_key, |
435 | | struct ntlm_key *sealing_key) |
436 | 0 | { |
437 | 0 | struct ntlm_key key; |
438 | 0 | const char *mc; |
439 | |
|
440 | 0 | if (flags & NTLMSSP_NEGOTIATE_128) { |
441 | 0 | key.length = 16; |
442 | 0 | } else if (flags & NTLMSSP_NEGOTIATE_56) { |
443 | 0 | key.length = 7; |
444 | 0 | } else { |
445 | 0 | key.length = 5; |
446 | 0 | } |
447 | 0 | memcpy(key.data, session_key->data, key.length); |
448 | |
|
449 | 0 | if (mode == NTLM_MODE_CLIENT) { |
450 | 0 | mc = "session key to client-to-server sealing key magic constant"; |
451 | 0 | } else { |
452 | 0 | mc = "session key to server-to-client sealing key magic constant"; |
453 | 0 | } |
454 | |
|
455 | 0 | return ntlm_key_derivation_function(&key, mc, sealing_key); |
456 | 0 | } |
457 | | |
458 | | static void no_ext_sec_sealkey(uint32_t flags, |
459 | | struct ntlm_key *session_key, |
460 | | struct ntlm_buffer *sealing_key) |
461 | 0 | { |
462 | 0 | if (flags & NTLMSSP_NEGOTIATE_LM_KEY) { |
463 | 0 | if (flags & NTLMSSP_NEGOTIATE_56) { |
464 | 0 | memcpy(sealing_key->data, session_key->data, 7); |
465 | 0 | sealing_key->data[7] = 0xA0; |
466 | 0 | } else { |
467 | 0 | memcpy(sealing_key->data, session_key->data, 5); |
468 | 0 | sealing_key->data[5] = 0xE5; |
469 | 0 | sealing_key->data[6] = 0x38; |
470 | 0 | sealing_key->data[7] = 0xB0; |
471 | 0 | } |
472 | 0 | sealing_key->length = 8; |
473 | 0 | } else { |
474 | 0 | memcpy(sealing_key->data, session_key->data, 16); |
475 | 0 | sealing_key->length = session_key->length; |
476 | 0 | } |
477 | 0 | } |
478 | | |
479 | | static int no_ext_sec_handle(uint32_t flags, |
480 | | struct ntlm_key *session_key, |
481 | | struct ntlm_rc4_handle **seal_handle) |
482 | 0 | { |
483 | 0 | uint8_t skbuf[16]; |
484 | 0 | struct ntlm_buffer sealing_key = { skbuf, 16 }; |
485 | |
|
486 | 0 | no_ext_sec_sealkey(flags, session_key, &sealing_key); |
487 | |
|
488 | 0 | return RC4_INIT(&sealing_key, NTLM_CIPHER_ENCRYPT, seal_handle); |
489 | 0 | } |
490 | | |
491 | | |
492 | | static int ext_sec_keys(uint32_t flags, bool client, |
493 | | struct ntlm_key *session_key, |
494 | | struct ntlm_signseal_state *state) |
495 | 0 | { |
496 | 0 | struct ntlm_buffer rc4_key; |
497 | 0 | bool mode; |
498 | 0 | int ret; |
499 | |
|
500 | 0 | state->ext_sec = true; |
501 | 0 | if (flags & NTLMSSP_NEGOTIATE_DATAGRAM) { |
502 | 0 | state->datagram = true; |
503 | 0 | } |
504 | | |
505 | | /* send key */ |
506 | 0 | mode = client ? NTLM_MODE_CLIENT : NTLM_MODE_SERVER; |
507 | 0 | ret = ntlm_signkey(mode, session_key, &state->send.sign_key); |
508 | 0 | if (ret) return ret; |
509 | | /* recv key */ |
510 | 0 | mode = client ? NTLM_MODE_SERVER : NTLM_MODE_CLIENT; |
511 | 0 | ret = ntlm_signkey(mode, session_key, &state->recv.sign_key); |
512 | 0 | if (ret) return ret; |
513 | | |
514 | | /* send key */ |
515 | 0 | mode = client ? NTLM_MODE_CLIENT : NTLM_MODE_SERVER; |
516 | 0 | ret = ntlm_sealkey(flags, mode, session_key, &state->send.seal_key); |
517 | 0 | if (ret) return ret; |
518 | | /* recv key */ |
519 | 0 | mode = client ? NTLM_MODE_SERVER : NTLM_MODE_CLIENT; |
520 | 0 | ret = ntlm_sealkey(flags, mode, session_key, &state->recv.seal_key); |
521 | 0 | if (ret) return ret; |
522 | | |
523 | 0 | rc4_key.data = state->send.seal_key.data; |
524 | 0 | rc4_key.length = state->send.seal_key.length; |
525 | 0 | ret = RC4_INIT(&rc4_key, NTLM_CIPHER_ENCRYPT, &state->send.seal_handle); |
526 | 0 | if (ret) return ret; |
527 | | |
528 | 0 | rc4_key.data = state->recv.seal_key.data; |
529 | 0 | rc4_key.length = state->recv.seal_key.length; |
530 | 0 | ret = RC4_INIT(&rc4_key, NTLM_CIPHER_DECRYPT, &state->recv.seal_handle); |
531 | 0 | if (ret) return ret; |
532 | | |
533 | 0 | return 0; |
534 | 0 | } |
535 | | |
536 | | int ntlm_signseal_keys(uint32_t flags, bool client, |
537 | | struct ntlm_key *session_key, |
538 | | struct ntlm_signseal_state *state) |
539 | 0 | { |
540 | |
|
541 | 0 | memset(state, 0, sizeof(struct ntlm_signseal_state)); |
542 | |
|
543 | 0 | if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) { |
544 | 0 | state->datagram = (flags & NTLMSSP_NEGOTIATE_DATAGRAM); |
545 | 0 | return ext_sec_keys(flags, client, session_key, state); |
546 | 0 | } else { |
547 | 0 | return no_ext_sec_handle(flags, session_key, |
548 | 0 | &state->send.seal_handle); |
549 | 0 | } |
550 | 0 | } |
551 | | |
552 | | int ntlm_reset_rc4_state(uint32_t flags, bool recv, |
553 | | struct ntlm_key *session_key, |
554 | | struct ntlm_signseal_state *state) |
555 | 0 | { |
556 | 0 | struct ntlm_buffer rc4_key; |
557 | 0 | int ret; |
558 | |
|
559 | 0 | if (!(flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) { |
560 | 0 | return no_ext_sec_handle(flags, session_key, |
561 | 0 | &state->send.seal_handle); |
562 | 0 | } |
563 | | |
564 | 0 | if (recv) { |
565 | 0 | RC4_FREE(&state->recv.seal_handle); |
566 | 0 | rc4_key.data = state->recv.seal_key.data; |
567 | 0 | rc4_key.length = state->recv.seal_key.length; |
568 | 0 | ret = RC4_INIT(&rc4_key, NTLM_CIPHER_DECRYPT, |
569 | 0 | &state->recv.seal_handle); |
570 | 0 | } else { |
571 | 0 | RC4_FREE(&state->send.seal_handle); |
572 | 0 | rc4_key.data = state->send.seal_key.data; |
573 | 0 | rc4_key.length = state->send.seal_key.length; |
574 | 0 | ret = RC4_INIT(&rc4_key, NTLM_CIPHER_ENCRYPT, |
575 | 0 | &state->send.seal_handle); |
576 | 0 | } |
577 | 0 | return ret; |
578 | 0 | } |
579 | | |
580 | | void ntlm_release_rc4_state(struct ntlm_signseal_state *state) |
581 | 1.20k | { |
582 | 1.20k | RC4_FREE(&state->recv.seal_handle); |
583 | 1.20k | RC4_FREE(&state->send.seal_handle); |
584 | 1.20k | } |
585 | | |
586 | | static int ntlm_seal_regen(struct ntlm_signseal_handle *h) |
587 | 0 | { |
588 | 0 | struct ntlm_buffer payload; |
589 | 0 | struct ntlm_buffer result; |
590 | 0 | uint8_t inbuf[20]; |
591 | 0 | uint8_t outbuf[16]; |
592 | 0 | uint32_t le; |
593 | 0 | int ret; |
594 | |
|
595 | 0 | RC4_FREE(&h->seal_handle); |
596 | |
|
597 | 0 | memcpy(inbuf, h->seal_key.data, h->seal_key.length); |
598 | 0 | le = htole32(h->seq_num); |
599 | 0 | memcpy(&inbuf[h->seal_key.length], &le, 4); |
600 | |
|
601 | 0 | payload.data = inbuf; |
602 | 0 | payload.length = h->seal_key.length + 4; |
603 | 0 | result.data = outbuf; |
604 | 0 | result.length = 16; |
605 | |
|
606 | 0 | ret = MD5_HASH(&payload, &result); |
607 | 0 | if (ret) return ret; |
608 | | |
609 | 0 | ret = RC4_INIT(&result, NTLM_CIPHER_ENCRYPT, &h->seal_handle); |
610 | 0 | return ret; |
611 | 0 | } |
612 | | |
613 | | int ntlm_verify_nt_response(struct ntlm_buffer *nt_response, |
614 | | struct ntlm_key *nt_key, bool ext_sec, |
615 | | uint8_t server_chal[8], uint8_t client_chal[8]) |
616 | 0 | { |
617 | 0 | uint8_t buf[24]; |
618 | 0 | struct ntlm_buffer expected_response = { buf, 24 }; |
619 | 0 | int ret; |
620 | |
|
621 | 0 | ret = ntlm_compute_nt_response(nt_key, ext_sec, |
622 | 0 | server_chal, client_chal, |
623 | 0 | &expected_response); |
624 | 0 | if (ret) return ret; |
625 | | |
626 | 0 | ret = EINVAL; |
627 | 0 | if (memcmp(nt_response->data, expected_response.data, 24) == 0) { |
628 | 0 | ret = 0; |
629 | 0 | } |
630 | |
|
631 | 0 | return ret; |
632 | 0 | } |
633 | | |
634 | | int ntlm_verify_lm_response(struct ntlm_buffer *lm_response, |
635 | | struct ntlm_key *lm_key, bool ext_sec, |
636 | | uint8_t server_chal[8], uint8_t client_chal[8]) |
637 | 0 | { |
638 | 0 | uint8_t buf[24]; |
639 | 0 | struct ntlm_buffer expected_response = { buf, 24 }; |
640 | 0 | int ret; |
641 | |
|
642 | 0 | ret = ntlm_compute_lm_response(lm_key, ext_sec, |
643 | 0 | server_chal, client_chal, |
644 | 0 | &expected_response); |
645 | 0 | if (ret) return ret; |
646 | | |
647 | 0 | ret = EINVAL; |
648 | 0 | if (memcmp(lm_response->data, expected_response.data, 24) == 0) { |
649 | 0 | ret = 0; |
650 | 0 | } |
651 | |
|
652 | 0 | return ret; |
653 | 0 | } |
654 | | |
655 | | int ntlmv2_verify_nt_response(struct ntlm_buffer *nt_response, |
656 | | struct ntlm_key *ntlmv2_key, |
657 | | uint8_t server_chal[8]) |
658 | 0 | { |
659 | 0 | union wire_ntlm_response *nt_resp = NULL; |
660 | 0 | struct ntlm_buffer key = { ntlmv2_key->data, ntlmv2_key->length }; |
661 | 0 | uint8_t proof[16]; |
662 | 0 | struct ntlm_buffer nt_proof = { proof, 16 }; |
663 | 0 | struct ntlm_buffer payload; |
664 | 0 | int ret; |
665 | |
|
666 | 0 | if (nt_response->length < 24) return EINVAL; |
667 | | |
668 | 0 | nt_resp = (union wire_ntlm_response *)nt_response->data; |
669 | |
|
670 | 0 | payload.length = nt_response->length - sizeof(nt_resp->v2.resp) + 8; |
671 | 0 | payload.data = malloc(payload.length); |
672 | 0 | if (!payload.data) return ENOMEM; |
673 | 0 | memcpy(payload.data, server_chal, 8); |
674 | 0 | memcpy(&payload.data[8], nt_resp->v2.cli_chal, payload.length - 8); |
675 | |
|
676 | 0 | ret = HMAC_MD5(&key, &payload, &nt_proof); |
677 | |
|
678 | 0 | if (ret) goto done; |
679 | | |
680 | 0 | ret = EINVAL; |
681 | 0 | if (memcmp(nt_resp->v2.resp, proof, 16) == 0) { |
682 | 0 | ret = 0; |
683 | 0 | } |
684 | |
|
685 | 0 | done: |
686 | 0 | safefree(payload.data); |
687 | 0 | return ret; |
688 | 0 | } |
689 | | |
690 | | int ntlmv2_verify_lm_response(struct ntlm_buffer *lm_response, |
691 | | struct ntlm_key *ntlmv2_key, |
692 | | uint8_t server_chal[8]) |
693 | 0 | { |
694 | 0 | struct ntlm_buffer key = { ntlmv2_key->data, ntlmv2_key->length }; |
695 | 0 | union wire_ntlm_response *lm_resp = NULL; |
696 | 0 | uint8_t payload_buf[16]; |
697 | 0 | struct ntlm_buffer payload = { payload_buf, 16 }; |
698 | 0 | uint8_t proof[16]; |
699 | 0 | struct ntlm_buffer lm_proof = { proof, 16 }; |
700 | 0 | int ret; |
701 | |
|
702 | 0 | if (lm_response->length != 24) return EINVAL; |
703 | | |
704 | | /* now caluclate the LM Proof */ |
705 | 0 | lm_resp = (union wire_ntlm_response *)lm_response->data; |
706 | |
|
707 | 0 | memcpy(payload.data, server_chal, 8); |
708 | 0 | memcpy(&payload.data[8], lm_resp->v2.cli_chal, 8); |
709 | 0 | ret = HMAC_MD5(&key, &payload, &lm_proof); |
710 | |
|
711 | 0 | if (ret) return ret; |
712 | | |
713 | 0 | if (memcmp(lm_resp->v2.resp, proof, 16) == 0) return 0; |
714 | | |
715 | 0 | return EINVAL; |
716 | 0 | } |
717 | | |
718 | | static int ntlmv2_sign(struct ntlm_key *sign_key, uint32_t seq_num, |
719 | | struct ntlm_rc4_handle *handle, bool keyex, |
720 | | struct ntlm_buffer *message, |
721 | | struct ntlm_buffer *signature) |
722 | 0 | { |
723 | 0 | struct ntlm_buffer key = { sign_key->data, sign_key->length }; |
724 | 0 | union wire_msg_signature *msg_sig; |
725 | 0 | uint32_t le_seq; |
726 | 0 | uint8_t le8seq[8]; |
727 | 0 | struct ntlm_buffer seq = { le8seq, 4 }; |
728 | 0 | struct ntlm_buffer *data[2]; |
729 | 0 | struct ntlm_iov iov; |
730 | 0 | uint8_t hmac_sig[NTLM_SIGNATURE_SIZE]; |
731 | 0 | struct ntlm_buffer hmac = { hmac_sig, NTLM_SIGNATURE_SIZE }; |
732 | 0 | struct ntlm_buffer rc4buf; |
733 | 0 | struct ntlm_buffer rc4res; |
734 | 0 | int ret; |
735 | |
|
736 | 0 | msg_sig = (union wire_msg_signature *)signature->data; |
737 | 0 | if (signature->length != NTLM_SIGNATURE_SIZE) { |
738 | 0 | return EINVAL; |
739 | 0 | } |
740 | | |
741 | 0 | le_seq = htole32(seq_num); |
742 | 0 | memcpy(seq.data, &le_seq, 4); |
743 | 0 | data[0] = &seq; |
744 | 0 | data[1] = message; |
745 | 0 | iov.data = data; |
746 | 0 | iov.num = 2; |
747 | |
|
748 | 0 | ret = HMAC_MD5_IOV(&key, &iov, &hmac); |
749 | 0 | if (ret) return ret; |
750 | | |
751 | | /* put version */ |
752 | 0 | msg_sig->v2.version = htole32(NTLMSSP_MESSAGE_SIGNATURE_VERSION); |
753 | | |
754 | | /* put actual MAC */ |
755 | 0 | if (keyex) { |
756 | | /* encrypt truncated hmac */ |
757 | 0 | rc4buf.data = hmac.data; |
758 | 0 | rc4buf.length = 8; |
759 | | /* and put it in the middle of the output signature */ |
760 | 0 | rc4res.data = (uint8_t *)&msg_sig->v2.checksum; |
761 | 0 | rc4res.length = 8; |
762 | 0 | ret = RC4_UPDATE(handle, &rc4buf, &rc4res); |
763 | 0 | if (ret) return ret; |
764 | 0 | } else { |
765 | 0 | memcpy(&msg_sig->v2.checksum, hmac.data, 8); |
766 | 0 | } |
767 | | |
768 | | /* put used seq_num */ |
769 | 0 | msg_sig->v2.seq_num = le_seq; |
770 | |
|
771 | 0 | return 0; |
772 | 0 | } |
773 | | |
774 | | static int ntlmv1_sign(struct ntlm_rc4_handle *handle, |
775 | | uint32_t random_pad, uint32_t seq_num, |
776 | | struct ntlm_buffer *message, |
777 | | struct ntlm_buffer *signature) |
778 | 0 | { |
779 | 0 | union wire_msg_signature *msg_sig; |
780 | 0 | uint32_t rc4buf[3]; |
781 | 0 | struct ntlm_buffer payload; |
782 | 0 | struct ntlm_buffer result; |
783 | 0 | int ret; |
784 | |
|
785 | 0 | msg_sig = (union wire_msg_signature *)signature->data; |
786 | 0 | if (signature->length != NTLM_SIGNATURE_SIZE) { |
787 | 0 | return EINVAL; |
788 | 0 | } |
789 | | |
790 | 0 | rc4buf[0] = random_pad; |
791 | 0 | rc4buf[1] = htole32(CRC32(0, message)); |
792 | 0 | rc4buf[2] = htole32(seq_num); |
793 | |
|
794 | 0 | payload.data = (uint8_t *)rc4buf; |
795 | 0 | payload.length = 12; |
796 | 0 | result.data = (uint8_t *)&msg_sig->v1.random_pad; |
797 | 0 | result.length = 12; |
798 | 0 | ret = RC4_UPDATE(handle, &payload, &result); |
799 | 0 | if (ret) return ret; |
800 | | |
801 | 0 | msg_sig->v1.version = htole32(NTLMSSP_MESSAGE_SIGNATURE_VERSION); |
802 | 0 | msg_sig->v1.random_pad = 0; |
803 | |
|
804 | 0 | return 0; |
805 | 0 | } |
806 | | |
807 | | int ntlm_sign(uint32_t flags, int direction, |
808 | | struct ntlm_signseal_state *state, |
809 | | struct ntlm_buffer *message, |
810 | | struct ntlm_buffer *signature) |
811 | 0 | { |
812 | 0 | struct ntlm_signseal_handle *h; |
813 | 0 | int ret; |
814 | |
|
815 | 0 | if (direction == NTLM_SEND || !state->ext_sec) { |
816 | 0 | h = &state->send; |
817 | 0 | } else { |
818 | 0 | h = &state->recv; |
819 | 0 | } |
820 | |
|
821 | 0 | if (flags & NTLMSSP_NEGOTIATE_SIGN) { |
822 | 0 | if (state->ext_sec) { |
823 | 0 | if (state->datagram) { |
824 | 0 | ret = ntlm_seal_regen(h); |
825 | 0 | if (ret) return ret; |
826 | 0 | } |
827 | | |
828 | 0 | ret = ntlmv2_sign(&h->sign_key, h->seq_num, h->seal_handle, |
829 | 0 | (flags & NTLMSSP_NEGOTIATE_KEY_EXCH), |
830 | 0 | message, signature); |
831 | 0 | } else { |
832 | 0 | ret = ntlmv1_sign(h->seal_handle, 0, h->seq_num, |
833 | 0 | message, signature); |
834 | 0 | } |
835 | 0 | if (ret) return ret; |
836 | | |
837 | 0 | if (!state->datagram) { |
838 | 0 | h->seq_num++; |
839 | 0 | } |
840 | 0 | return 0; |
841 | |
|
842 | 0 | } else if (flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) { |
843 | 0 | uint32_t sig_ver = htole32(NTLMSSP_MESSAGE_SIGNATURE_VERSION); |
844 | 0 | memcpy(signature->data, &sig_ver, 4); |
845 | 0 | memset(&signature->data[4], 0, 12); |
846 | 0 | return 0; |
847 | 0 | } |
848 | | |
849 | 0 | return ENOTSUP; |
850 | 0 | } |
851 | | |
852 | | int ntlm_seal(uint32_t flags, |
853 | | struct ntlm_signseal_state *state, |
854 | | struct ntlm_buffer *message, |
855 | | struct ntlm_buffer *output, |
856 | | struct ntlm_buffer *signature) |
857 | 0 | { |
858 | 0 | struct ntlm_signseal_handle *h; |
859 | 0 | int ret; |
860 | |
|
861 | 0 | h = &state->send; |
862 | |
|
863 | 0 | if (h->seal_handle == NULL) { |
864 | 0 | return EINVAL; |
865 | 0 | } |
866 | | |
867 | 0 | ret = RC4_UPDATE(h->seal_handle, message, output); |
868 | 0 | if (ret) return ret; |
869 | | |
870 | 0 | if (state->ext_sec) { |
871 | 0 | if (state->datagram) { |
872 | 0 | ret = ntlm_seal_regen(h); |
873 | 0 | if (ret) return ret; |
874 | 0 | } |
875 | 0 | ret = ntlmv2_sign(&h->sign_key, h->seq_num, h->seal_handle, |
876 | 0 | (flags & NTLMSSP_NEGOTIATE_KEY_EXCH), |
877 | 0 | message, signature); |
878 | 0 | } else { |
879 | 0 | ret = ntlmv1_sign(h->seal_handle, 0, h->seq_num, message, signature); |
880 | 0 | } |
881 | 0 | if (ret) return ret; |
882 | | |
883 | 0 | if (!state->datagram) { |
884 | 0 | h->seq_num++; |
885 | 0 | } |
886 | 0 | return 0; |
887 | 0 | } |
888 | | |
889 | | int ntlm_unseal(uint32_t flags, |
890 | | struct ntlm_signseal_state *state, |
891 | | struct ntlm_buffer *message, |
892 | | struct ntlm_buffer *output, |
893 | | struct ntlm_buffer *signature) |
894 | 0 | { |
895 | 0 | struct ntlm_signseal_handle *h; |
896 | 0 | int ret; |
897 | |
|
898 | 0 | if (!state->ext_sec) { |
899 | 0 | h = &state->send; |
900 | 0 | } else { |
901 | 0 | h = &state->recv; |
902 | 0 | } |
903 | |
|
904 | 0 | if (h->seal_handle == NULL) { |
905 | 0 | return EINVAL; |
906 | 0 | } |
907 | | |
908 | 0 | ret = RC4_UPDATE(h->seal_handle, message, output); |
909 | 0 | if (ret) return ret; |
910 | | |
911 | 0 | if (state->ext_sec) { |
912 | 0 | if (state->datagram) { |
913 | 0 | ret = ntlm_seal_regen(h); |
914 | 0 | if (ret) return ret; |
915 | 0 | } |
916 | 0 | ret = ntlmv2_sign(&h->sign_key, h->seq_num, h->seal_handle, |
917 | 0 | (flags & NTLMSSP_NEGOTIATE_KEY_EXCH), |
918 | 0 | output, signature); |
919 | 0 | } else { |
920 | 0 | ret = ntlmv1_sign(h->seal_handle, 0, h->seq_num, output, signature); |
921 | 0 | } |
922 | 0 | if (ret) return ret; |
923 | | |
924 | 0 | if (!state->datagram) { |
925 | 0 | h->seq_num++; |
926 | 0 | } |
927 | 0 | return 0; |
928 | 0 | } |
929 | | |
930 | | int ntlm_mic(struct ntlm_key *exported_session_key, |
931 | | struct ntlm_buffer *negotiate_message, |
932 | | struct ntlm_buffer *challenge_message, |
933 | | struct ntlm_buffer *authenticate_message, |
934 | | struct ntlm_buffer *mic) |
935 | 0 | { |
936 | 0 | struct ntlm_buffer key = { exported_session_key->data, |
937 | 0 | exported_session_key->length }; |
938 | 0 | struct ntlm_buffer *data[3] = { negotiate_message, |
939 | 0 | challenge_message, |
940 | 0 | authenticate_message }; |
941 | 0 | struct ntlm_iov iov; |
942 | |
|
943 | 0 | if (negotiate_message->length == 0) { |
944 | | /* connectionless case */ |
945 | 0 | iov.data = &data[1]; |
946 | 0 | iov.num = 2; |
947 | 0 | } else { |
948 | 0 | iov.data = data; |
949 | 0 | iov.num = 3; |
950 | 0 | } |
951 | |
|
952 | 0 | return HMAC_MD5_IOV(&key, &iov, mic); |
953 | 0 | } |
954 | | |
955 | | int ntlm_verify_mic(struct ntlm_key *key, |
956 | | struct ntlm_buffer *negotiate_message, |
957 | | struct ntlm_buffer *challenge_message, |
958 | | struct ntlm_buffer *authenticate_message, |
959 | | struct ntlm_buffer *mic) |
960 | 0 | { |
961 | 0 | uint8_t micbuf[NTLM_SIGNATURE_SIZE]; |
962 | 0 | struct ntlm_buffer check_mic = { micbuf, NTLM_SIGNATURE_SIZE }; |
963 | 0 | struct wire_auth_msg *msg; |
964 | 0 | size_t payload_offs; |
965 | 0 | uint32_t flags; |
966 | 0 | int ret; |
967 | |
|
968 | 0 | msg = (struct wire_auth_msg *)authenticate_message->data; |
969 | 0 | payload_offs = offsetof(struct wire_auth_msg, payload); |
970 | | |
971 | | /* flags must be checked as they may push the payload further down */ |
972 | 0 | flags = le32toh(msg->neg_flags); |
973 | 0 | if ((flags & NTLMSSP_NEGOTIATE_VERSION) == 0) { |
974 | 0 | struct wire_version zver = {0}; |
975 | | /* mic is at payload_offs right now, but this offset may |
976 | | * need to be reduced if the sender completely omitted |
977 | | * the version struct, as some older clients do */ |
978 | 0 | if (memcmp(&msg->version, &zver, |
979 | 0 | sizeof(struct wire_version)) != 0) { |
980 | | /* version struct is not all zeros, this indicates the actual |
981 | | * struct was omitted and payload is shifted down */ |
982 | 0 | payload_offs -= sizeof(struct wire_version); |
983 | 0 | } |
984 | 0 | } |
985 | |
|
986 | 0 | if (payload_offs + NTLM_SIGNATURE_SIZE > authenticate_message->length) { |
987 | 0 | return EINVAL; |
988 | 0 | } |
989 | | |
990 | | /* payload_offs now points at the MIC buffer, clear it off in order |
991 | | * to be able to calculate the original chcksum */ |
992 | 0 | memset(&authenticate_message->data[payload_offs], 0, NTLM_SIGNATURE_SIZE); |
993 | |
|
994 | 0 | ret = ntlm_mic(key, negotiate_message, challenge_message, |
995 | 0 | authenticate_message, &check_mic); |
996 | 0 | if (ret) return ret; |
997 | | |
998 | 0 | if (memcmp(mic->data, check_mic.data, NTLM_SIGNATURE_SIZE) != 0) { |
999 | 0 | return EACCES; |
1000 | 0 | } |
1001 | | |
1002 | 0 | return 0; |
1003 | 0 | } |
1004 | | |
1005 | | int ntlm_hash_channel_bindings(struct ntlm_buffer *unhashed, |
1006 | | struct ntlm_buffer *signature) |
1007 | 0 | { |
1008 | 0 | struct ntlm_buffer input; |
1009 | 0 | uint32_t ulen; |
1010 | 0 | int ret; |
1011 | | |
1012 | | /* The channel bindings are calculated according to RFC4121, 4.1.1.2, |
1013 | | * with a all initiator and acceptor fields zeroed, so we need 4 zeroed |
1014 | | * 32bit fields, and one little endian length field to include in the |
1015 | | * MD5 calculation */ |
1016 | 0 | input.length = sizeof(uint32_t) * 5 + unhashed->length; |
1017 | 0 | input.data = malloc(input.length); |
1018 | 0 | if (!input.data) return EINVAL; |
1019 | | |
1020 | 0 | memset(input.data, 0, sizeof(uint32_t) * 4); |
1021 | 0 | ulen = unhashed->length; |
1022 | 0 | ulen = htole32(ulen); |
1023 | 0 | memcpy(&input.data[sizeof(uint32_t) * 4], &ulen, sizeof(uint32_t)); |
1024 | 0 | memcpy(&input.data[sizeof(uint32_t) * 5], unhashed->data, unhashed->length); |
1025 | |
|
1026 | 0 | ret = MD5_HASH(&input, signature); |
1027 | |
|
1028 | 0 | safefree(input.data); |
1029 | 0 | return ret; |
1030 | 0 | } |
1031 | | |
1032 | | int ntlm_verify_channel_bindings(struct ntlm_buffer *unhashed, |
1033 | | struct ntlm_buffer *signature) |
1034 | 0 | { |
1035 | 0 | uint8_t cbbuf[16]; |
1036 | 0 | struct ntlm_buffer cb = { cbbuf, 16 }; |
1037 | 0 | int ret; |
1038 | |
|
1039 | 0 | if (signature->length != 16) return EINVAL; |
1040 | | |
1041 | 0 | ret = ntlm_hash_channel_bindings(unhashed, &cb); |
1042 | 0 | if (ret) return ret; |
1043 | | |
1044 | 0 | if (memcmp(cb.data, signature->data, 16) != 0) return EACCES; |
1045 | | |
1046 | 0 | return 0; |
1047 | 0 | } |