/src/samba/libcli/smb/smb_signing.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | SMB Signing Code |
4 | | Copyright (C) Jeremy Allison 2003. |
5 | | Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003 |
6 | | Copyright (C) Stefan Metzmacher 2009 |
7 | | |
8 | | This program is free software; you can redistribute it and/or modify |
9 | | it under the terms of the GNU General Public License as published by |
10 | | the Free Software Foundation; either version 3 of the License, or |
11 | | (at your option) any later version. |
12 | | |
13 | | This program is distributed in the hope that it will be useful, |
14 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | GNU General Public License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | | */ |
21 | | |
22 | | #include "includes.h" |
23 | | #include "smb_common.h" |
24 | | #include "smb_signing.h" |
25 | | |
26 | | #include "lib/crypto/gnutls_helpers.h" |
27 | | #include <gnutls/gnutls.h> |
28 | | #include <gnutls/crypto.h> |
29 | | |
30 | | /* Used by the SMB1 signing functions. */ |
31 | | |
32 | | struct smb1_signing_state { |
33 | | /* is signing locally allowed */ |
34 | | bool allowed; |
35 | | |
36 | | /* is signing locally desired */ |
37 | | bool desired; |
38 | | |
39 | | /* is signing locally mandatory */ |
40 | | bool mandatory; |
41 | | |
42 | | /* is signing negotiated by the peer */ |
43 | | bool negotiated; |
44 | | |
45 | | bool active; /* Have I ever seen a validly signed packet? */ |
46 | | |
47 | | /* mac_key.length > 0 means signing is started */ |
48 | | DATA_BLOB mac_key; |
49 | | |
50 | | /* the next expected seqnum */ |
51 | | uint32_t seqnum; |
52 | | |
53 | | TALLOC_CTX *mem_ctx; |
54 | | void *(*alloc_fn)(TALLOC_CTX *mem_ctx, size_t len); |
55 | | void (*free_fn)(TALLOC_CTX *mem_ctx, void *ptr); |
56 | | }; |
57 | | |
58 | | static void smb1_signing_reset_info(struct smb1_signing_state *si) |
59 | 0 | { |
60 | 0 | si->active = false; |
61 | 0 | si->seqnum = 0; |
62 | |
|
63 | 0 | data_blob_clear(&si->mac_key); |
64 | |
|
65 | 0 | if (si->free_fn) { |
66 | 0 | si->free_fn(si->mem_ctx, si->mac_key.data); |
67 | 0 | } else { |
68 | 0 | talloc_free(si->mac_key.data); |
69 | 0 | } |
70 | 0 | si->mac_key.data = NULL; |
71 | 0 | si->mac_key.length = 0; |
72 | 0 | } |
73 | | |
74 | | struct smb1_signing_state *smb1_signing_init_ex(TALLOC_CTX *mem_ctx, |
75 | | bool allowed, |
76 | | bool desired, |
77 | | bool mandatory, |
78 | | void *(*alloc_fn)(TALLOC_CTX *, size_t), |
79 | | void (*free_fn)(TALLOC_CTX *, void *)) |
80 | 0 | { |
81 | 0 | struct smb1_signing_state *si; |
82 | |
|
83 | 0 | if (alloc_fn) { |
84 | 0 | void *p = alloc_fn(mem_ctx, sizeof(struct smb1_signing_state)); |
85 | 0 | if (p == NULL) { |
86 | 0 | return NULL; |
87 | 0 | } |
88 | 0 | memset(p, 0, sizeof(struct smb1_signing_state)); |
89 | 0 | si = (struct smb1_signing_state *)p; |
90 | 0 | si->mem_ctx = mem_ctx; |
91 | 0 | si->alloc_fn = alloc_fn; |
92 | 0 | si->free_fn = free_fn; |
93 | 0 | } else { |
94 | 0 | si = talloc_zero(mem_ctx, struct smb1_signing_state); |
95 | 0 | if (si == NULL) { |
96 | 0 | return NULL; |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | 0 | if (mandatory) { |
101 | 0 | desired = true; |
102 | 0 | } |
103 | |
|
104 | 0 | if (desired) { |
105 | 0 | allowed = true; |
106 | 0 | } |
107 | |
|
108 | 0 | si->allowed = allowed; |
109 | 0 | si->desired = desired; |
110 | 0 | si->mandatory = mandatory; |
111 | |
|
112 | 0 | return si; |
113 | 0 | } |
114 | | |
115 | | struct smb1_signing_state *smb1_signing_init(TALLOC_CTX *mem_ctx, |
116 | | bool allowed, |
117 | | bool desired, |
118 | | bool mandatory) |
119 | 0 | { |
120 | 0 | return smb1_signing_init_ex(mem_ctx, allowed, desired, mandatory, |
121 | 0 | NULL, NULL); |
122 | 0 | } |
123 | | |
124 | | static bool smb1_signing_good(struct smb1_signing_state *si, |
125 | | bool good, uint32_t seq) |
126 | 0 | { |
127 | 0 | if (good) { |
128 | 0 | if (!si->active) { |
129 | 0 | si->active = true; |
130 | 0 | } |
131 | 0 | return true; |
132 | 0 | } |
133 | | |
134 | 0 | if (!si->mandatory && !si->active) { |
135 | | /* Non-mandatory signing - just turn off if this is the first bad packet.. */ |
136 | 0 | DBG_INFO("signing negotiated but not required and peer\n" |
137 | 0 | "isn't sending correct signatures. Turning off.\n"); |
138 | 0 | smb1_signing_reset_info(si); |
139 | 0 | return true; |
140 | 0 | } |
141 | | |
142 | | /* Mandatory signing or bad packet after signing started - fail and disconnect. */ |
143 | 0 | DBG_ERR("BAD SIG: seq %u\n", (unsigned int)seq); |
144 | 0 | return false; |
145 | 0 | } |
146 | | |
147 | | static NTSTATUS smb1_signing_md5(const DATA_BLOB *mac_key, |
148 | | const uint8_t *hdr, size_t len, |
149 | | uint32_t seq_number, |
150 | | uint8_t calc_md5_mac[16]) |
151 | 0 | { |
152 | 0 | const size_t offset_end_of_sig = (HDR_SS_FIELD + 8); |
153 | 0 | uint8_t sequence_buf[8]; |
154 | 0 | gnutls_hash_hd_t hash_hnd = NULL; |
155 | 0 | int rc; |
156 | | |
157 | | /* |
158 | | * Firstly put the sequence number into the first 4 bytes. |
159 | | * and zero out the next 4 bytes. |
160 | | * |
161 | | * We do this here, to avoid modifying the packet. |
162 | | */ |
163 | |
|
164 | 0 | DBG_DEBUG("sequence number %u\n", seq_number ); |
165 | |
|
166 | 0 | SIVAL(sequence_buf, 0, seq_number); |
167 | 0 | SIVAL(sequence_buf, 4, 0); |
168 | | |
169 | | /* |
170 | | * Calculate the 16 byte MAC - but don't alter the data in the |
171 | | * incoming packet. |
172 | | * |
173 | | * This makes for a bit of fussing about, but it's not too bad. |
174 | | */ |
175 | 0 | rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5); |
176 | 0 | if (rc < 0) { |
177 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED); |
178 | 0 | } |
179 | | /* Initialise with the key. */ |
180 | 0 | rc = gnutls_hash(hash_hnd, mac_key->data, mac_key->length); |
181 | 0 | if (rc < 0) { |
182 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
183 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED); |
184 | 0 | } |
185 | | /* Copy in the first bit of the SMB header. */ |
186 | 0 | rc = gnutls_hash(hash_hnd, hdr, HDR_SS_FIELD); |
187 | 0 | if (rc < 0) { |
188 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
189 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED); |
190 | 0 | } |
191 | | /* Copy in the sequence number, instead of the signature. */ |
192 | 0 | rc = gnutls_hash(hash_hnd, sequence_buf, sizeof(sequence_buf)); |
193 | 0 | if (rc < 0) { |
194 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
195 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED); |
196 | 0 | } |
197 | | /* Copy in the rest of the packet in, skipping the signature. */ |
198 | 0 | rc = gnutls_hash(hash_hnd, hdr + offset_end_of_sig, len - offset_end_of_sig); |
199 | 0 | if (rc < 0) { |
200 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
201 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED); |
202 | 0 | } |
203 | | |
204 | 0 | gnutls_hash_deinit(hash_hnd, calc_md5_mac); |
205 | |
|
206 | 0 | return NT_STATUS_OK; |
207 | 0 | } |
208 | | |
209 | | uint32_t smb1_signing_next_seqnum(struct smb1_signing_state *si, bool oneway) |
210 | 0 | { |
211 | 0 | uint32_t seqnum; |
212 | |
|
213 | 0 | if (si->mac_key.length == 0) { |
214 | 0 | return 0; |
215 | 0 | } |
216 | | |
217 | 0 | seqnum = si->seqnum; |
218 | 0 | if (oneway) { |
219 | 0 | si->seqnum += 1; |
220 | 0 | } else { |
221 | 0 | si->seqnum += 2; |
222 | 0 | } |
223 | |
|
224 | 0 | return seqnum; |
225 | 0 | } |
226 | | |
227 | | void smb1_signing_cancel_reply(struct smb1_signing_state *si, bool oneway) |
228 | 0 | { |
229 | 0 | if (si->mac_key.length == 0) { |
230 | 0 | return; |
231 | 0 | } |
232 | | |
233 | 0 | if (oneway) { |
234 | 0 | si->seqnum -= 1; |
235 | 0 | } else { |
236 | 0 | si->seqnum -= 2; |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | | NTSTATUS smb1_signing_sign_pdu(struct smb1_signing_state *si, |
241 | | uint8_t *outhdr, size_t len, |
242 | | uint32_t seqnum) |
243 | 0 | { |
244 | 0 | uint8_t calc_md5_mac[16]; |
245 | 0 | uint8_t com; |
246 | 0 | uint8_t flags; |
247 | |
|
248 | 0 | if (si->mac_key.length == 0) { |
249 | 0 | if (!si->negotiated) { |
250 | 0 | return NT_STATUS_OK; |
251 | 0 | } |
252 | 0 | } |
253 | | |
254 | | /* JRA Paranioa test - we should be able to get rid of this... */ |
255 | 0 | if (len < (HDR_SS_FIELD + 8)) { |
256 | 0 | DBG_WARNING("Logic error. " |
257 | 0 | "Can't check signature on short packet! smb_len = %u\n", |
258 | 0 | (unsigned)len); |
259 | 0 | abort(); |
260 | 0 | } |
261 | | |
262 | 0 | com = SVAL(outhdr, HDR_COM); |
263 | 0 | flags = SVAL(outhdr, HDR_FLG); |
264 | |
|
265 | 0 | if (!(flags & FLAG_REPLY)) { |
266 | 0 | uint16_t flags2 = SVAL(outhdr, HDR_FLG2); |
267 | | /* |
268 | | * If this is a request, specify what is |
269 | | * supported or required by the client |
270 | | */ |
271 | 0 | if (si->negotiated && si->desired) { |
272 | 0 | flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; |
273 | 0 | } |
274 | 0 | if (si->negotiated && si->mandatory) { |
275 | 0 | flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED; |
276 | 0 | } |
277 | 0 | SSVAL(outhdr, HDR_FLG2, flags2); |
278 | 0 | } |
279 | |
|
280 | 0 | if (si->mac_key.length == 0) { |
281 | | /* I wonder what BSRSPYL stands for - but this is what MS |
282 | | actually sends! */ |
283 | 0 | if (com == SMBsesssetupX) { |
284 | 0 | memcpy(calc_md5_mac, "BSRSPYL ", 8); |
285 | 0 | } else { |
286 | 0 | memset(calc_md5_mac, 0, 8); |
287 | 0 | } |
288 | 0 | } else { |
289 | 0 | NTSTATUS status; |
290 | |
|
291 | 0 | status = smb1_signing_md5(&si->mac_key, |
292 | 0 | outhdr, |
293 | 0 | len, |
294 | 0 | seqnum, |
295 | 0 | calc_md5_mac); |
296 | 0 | if (!NT_STATUS_IS_OK(status)) { |
297 | 0 | return status; |
298 | 0 | } |
299 | 0 | } |
300 | | |
301 | 0 | DBG_DEBUG("sent SMB signature of\n"); |
302 | 0 | dump_data(10, calc_md5_mac, 8); |
303 | |
|
304 | 0 | memcpy(&outhdr[HDR_SS_FIELD], calc_md5_mac, 8); |
305 | | |
306 | | /* outhdr[HDR_SS_FIELD+2]=0; |
307 | | Uncomment this to test if the remote server actually verifies signatures...*/ |
308 | |
|
309 | 0 | return NT_STATUS_OK; |
310 | 0 | } |
311 | | |
312 | | bool smb1_signing_check_pdu(struct smb1_signing_state *si, |
313 | | const uint8_t *inhdr, size_t len, |
314 | | uint32_t seqnum) |
315 | 0 | { |
316 | 0 | bool good; |
317 | 0 | uint8_t calc_md5_mac[16]; |
318 | 0 | const uint8_t *reply_sent_mac; |
319 | 0 | NTSTATUS status; |
320 | |
|
321 | 0 | if (si->mac_key.length == 0) { |
322 | 0 | return true; |
323 | 0 | } |
324 | | |
325 | 0 | if (len < (HDR_SS_FIELD + 8)) { |
326 | 0 | DBG_WARNING("Can't check signature " |
327 | 0 | "on short packet! smb_len = %u\n", |
328 | 0 | (unsigned)len); |
329 | 0 | return false; |
330 | 0 | } |
331 | | |
332 | 0 | status = smb1_signing_md5(&si->mac_key, |
333 | 0 | inhdr, |
334 | 0 | len, |
335 | 0 | seqnum, |
336 | 0 | calc_md5_mac); |
337 | 0 | if (!NT_STATUS_IS_OK(status)) { |
338 | 0 | DBG_ERR("Failed to calculate signing mac: %s\n", |
339 | 0 | nt_errstr(status)); |
340 | 0 | return false; |
341 | 0 | } |
342 | | |
343 | 0 | reply_sent_mac = &inhdr[HDR_SS_FIELD]; |
344 | 0 | good = mem_equal_const_time(reply_sent_mac, calc_md5_mac, 8); |
345 | |
|
346 | 0 | if (!good) { |
347 | 0 | int i; |
348 | 0 | const int sign_range = 5; |
349 | |
|
350 | 0 | DBG_INFO("BAD SIG: wanted SMB signature of\n"); |
351 | 0 | dump_data(5, calc_md5_mac, 8); |
352 | |
|
353 | 0 | DBG_INFO("BAD SIG: got SMB signature of\n"); |
354 | 0 | dump_data(5, reply_sent_mac, 8); |
355 | |
|
356 | 0 | for (i = -sign_range; i < sign_range; i++) { |
357 | 0 | smb1_signing_md5(&si->mac_key, inhdr, len, |
358 | 0 | seqnum+i, calc_md5_mac); |
359 | 0 | if (mem_equal_const_time(reply_sent_mac, calc_md5_mac, 8)) { |
360 | 0 | DBG_ERR("out of seq. seq num %u matches. " |
361 | 0 | "We were expecting seq %u\n", |
362 | 0 | (unsigned int)seqnum+i, |
363 | 0 | (unsigned int)seqnum); |
364 | 0 | break; |
365 | 0 | } |
366 | 0 | } |
367 | 0 | } else { |
368 | 0 | DBG_DEBUG("seq %u: got good SMB signature of\n", |
369 | 0 | (unsigned int)seqnum); |
370 | 0 | dump_data(10, reply_sent_mac, 8); |
371 | 0 | } |
372 | |
|
373 | 0 | return smb1_signing_good(si, good, seqnum); |
374 | 0 | } |
375 | | |
376 | | bool smb1_signing_activate(struct smb1_signing_state *si, |
377 | | const DATA_BLOB user_session_key, |
378 | | const DATA_BLOB response) |
379 | 0 | { |
380 | 0 | size_t len; |
381 | 0 | off_t ofs; |
382 | |
|
383 | 0 | if (!user_session_key.length) { |
384 | 0 | return false; |
385 | 0 | } |
386 | | |
387 | 0 | if (!si->negotiated) { |
388 | 0 | return false; |
389 | 0 | } |
390 | | |
391 | 0 | if (si->active) { |
392 | 0 | return false; |
393 | 0 | } |
394 | | |
395 | 0 | if (si->mac_key.length > 0) { |
396 | 0 | return false; |
397 | 0 | } |
398 | | |
399 | 0 | smb1_signing_reset_info(si); |
400 | |
|
401 | 0 | len = response.length + user_session_key.length; |
402 | 0 | if (si->alloc_fn) { |
403 | 0 | si->mac_key.data = (uint8_t *)si->alloc_fn(si->mem_ctx, len); |
404 | 0 | if (si->mac_key.data == NULL) { |
405 | 0 | return false; |
406 | 0 | } |
407 | 0 | } else { |
408 | 0 | si->mac_key.data = (uint8_t *)talloc_size(si, len); |
409 | 0 | if (si->mac_key.data == NULL) { |
410 | 0 | return false; |
411 | 0 | } |
412 | 0 | } |
413 | 0 | si->mac_key.length = len; |
414 | |
|
415 | 0 | ofs = 0; |
416 | 0 | memcpy(&si->mac_key.data[ofs], user_session_key.data, user_session_key.length); |
417 | |
|
418 | 0 | DBG_DEBUG("user_session_key\n"); |
419 | 0 | dump_data(10, user_session_key.data, user_session_key.length); |
420 | |
|
421 | 0 | if (response.length) { |
422 | 0 | ofs = user_session_key.length; |
423 | 0 | memcpy(&si->mac_key.data[ofs], response.data, response.length); |
424 | 0 | DBG_DEBUG("response_data\n"); |
425 | 0 | dump_data(10, response.data, response.length); |
426 | 0 | } else { |
427 | 0 | DBG_DEBUG("NULL response_data\n"); |
428 | 0 | } |
429 | |
|
430 | 0 | dump_data_pw("smb1_signing_activate: mac key is:\n", |
431 | 0 | si->mac_key.data, si->mac_key.length); |
432 | | |
433 | | /* Initialise the sequence number */ |
434 | 0 | si->seqnum = 2; |
435 | |
|
436 | 0 | return true; |
437 | 0 | } |
438 | | |
439 | | bool smb1_signing_is_active(struct smb1_signing_state *si) |
440 | 0 | { |
441 | 0 | return si->active; |
442 | 0 | } |
443 | | |
444 | | bool smb1_signing_is_desired(struct smb1_signing_state *si) |
445 | 0 | { |
446 | 0 | return si->desired; |
447 | 0 | } |
448 | | |
449 | | bool smb1_signing_is_mandatory(struct smb1_signing_state *si) |
450 | 0 | { |
451 | 0 | return si->mandatory; |
452 | 0 | } |
453 | | |
454 | | bool smb1_signing_set_negotiated(struct smb1_signing_state *si, |
455 | | bool allowed, bool mandatory) |
456 | 0 | { |
457 | 0 | if (si->active) { |
458 | 0 | return true; |
459 | 0 | } |
460 | | |
461 | 0 | if (mandatory) { |
462 | 0 | allowed = true; |
463 | 0 | } |
464 | |
|
465 | 0 | if (!si->allowed && mandatory) { |
466 | 0 | return false; |
467 | 0 | } |
468 | | |
469 | 0 | if (si->mandatory && !allowed) { |
470 | 0 | return false; |
471 | 0 | } |
472 | | |
473 | 0 | if (si->mandatory) { |
474 | 0 | si->negotiated = true; |
475 | 0 | return true; |
476 | 0 | } |
477 | | |
478 | 0 | if (mandatory) { |
479 | 0 | si->negotiated = true; |
480 | 0 | return true; |
481 | 0 | } |
482 | | |
483 | 0 | if (!si->desired) { |
484 | 0 | si->negotiated = false; |
485 | 0 | return true; |
486 | 0 | } |
487 | | |
488 | 0 | if (si->desired && allowed) { |
489 | 0 | si->negotiated = true; |
490 | 0 | return true; |
491 | 0 | } |
492 | | |
493 | 0 | si->negotiated = false; |
494 | 0 | return true; |
495 | 0 | } |
496 | | |
497 | | bool smb1_signing_is_negotiated(struct smb1_signing_state *si) |
498 | 0 | { |
499 | 0 | return si->negotiated; |
500 | 0 | } |
501 | | |
502 | | NTSTATUS smb1_key_derivation(const uint8_t *KI, |
503 | | size_t KI_len, |
504 | | uint8_t KO[16]) |
505 | 0 | { |
506 | 0 | int rc; |
507 | 0 | static const uint8_t SSKeyHash[256] = { |
508 | 0 | 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, |
509 | 0 | 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, |
510 | 0 | 0x72, 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x55, |
511 | 0 | 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x07, |
512 | 0 | 0x6e, 0x28, 0x2e, 0x69, 0x88, 0x10, 0xb3, 0xdb, |
513 | 0 | 0x01, 0x55, 0x72, 0xfb, 0x74, 0x14, 0xfb, 0xc4, |
514 | 0 | 0xc5, 0xaf, 0x3b, 0x41, 0x65, 0x32, 0x17, 0xba, |
515 | 0 | 0xa3, 0x29, 0x08, 0xc1, 0xde, 0x16, 0x61, 0x7e, |
516 | 0 | 0x66, 0x98, 0xa4, 0x0b, 0xfe, 0x06, 0x83, 0x53, |
517 | 0 | 0x4d, 0x05, 0xdf, 0x6d, 0xa7, 0x51, 0x10, 0x73, |
518 | 0 | 0xc5, 0x50, 0xdc, 0x5e, 0xf8, 0x21, 0x46, 0xaa, |
519 | 0 | 0x96, 0x14, 0x33, 0xd7, 0x52, 0xeb, 0xaf, 0x1f, |
520 | 0 | 0xbf, 0x36, 0x6c, 0xfc, 0xb7, 0x1d, 0x21, 0x19, |
521 | 0 | 0x81, 0xd0, 0x6b, 0xfa, 0x77, 0xad, 0xbe, 0x18, |
522 | 0 | 0x78, 0xcf, 0x10, 0xbd, 0xd8, 0x78, 0xf7, 0xd3, |
523 | 0 | 0xc6, 0xdf, 0x43, 0x32, 0x19, 0xd3, 0x9b, 0xa8, |
524 | 0 | 0x4d, 0x9e, 0xaa, 0x41, 0xaf, 0xcb, 0xc6, 0xb9, |
525 | 0 | 0x34, 0xe7, 0x48, 0x25, 0xd4, 0x88, 0xc4, 0x51, |
526 | 0 | 0x60, 0x38, 0xd9, 0x62, 0xe8, 0x8d, 0x5b, 0x83, |
527 | 0 | 0x92, 0x7f, 0xb5, 0x0e, 0x1c, 0x2d, 0x06, 0x91, |
528 | 0 | 0xc3, 0x75, 0xb3, 0xcc, 0xf8, 0xf7, 0x92, 0x91, |
529 | 0 | 0x0b, 0x3d, 0xa1, 0x10, 0x5b, 0xd5, 0x0f, 0xa8, |
530 | 0 | 0x3f, 0x5d, 0x13, 0x83, 0x0a, 0x6b, 0x72, 0x93, |
531 | 0 | 0x14, 0x59, 0xd5, 0xab, 0xde, 0x26, 0x15, 0x6d, |
532 | 0 | 0x60, 0x67, 0x71, 0x06, 0x6e, 0x3d, 0x0d, 0xa7, |
533 | 0 | 0xcb, 0x70, 0xe9, 0x08, 0x5c, 0x99, 0xfa, 0x0a, |
534 | 0 | 0x5f, 0x3d, 0x44, 0xa3, 0x8b, 0xc0, 0x8d, 0xda, |
535 | 0 | 0xe2, 0x68, 0xd0, 0x0d, 0xcd, 0x7f, 0x3d, 0xf8, |
536 | 0 | 0x73, 0x7e, 0x35, 0x7f, 0x07, 0x02, 0x0a, 0xb5, |
537 | 0 | 0xe9, 0xb7, 0x87, 0xfb, 0xa1, 0xbf, 0xcb, 0x32, |
538 | 0 | 0x31, 0x66, 0x09, 0x48, 0x88, 0xcc, 0x18, 0xa3, |
539 | 0 | 0xb2, 0x1f, 0x1f, 0x1b, 0x90, 0x4e, 0xd7, 0xe1 |
540 | 0 | }; |
541 | | |
542 | | /* The callers passing down KI_len of 16 so no need to limit to 64 */ |
543 | 0 | rc = gnutls_hmac_fast(GNUTLS_MAC_MD5, |
544 | 0 | KI, |
545 | 0 | KI_len, |
546 | 0 | SSKeyHash, |
547 | 0 | sizeof(SSKeyHash), |
548 | 0 | KO); |
549 | 0 | if (rc < 0) { |
550 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED); |
551 | 0 | } |
552 | | |
553 | 0 | return NT_STATUS_OK; |
554 | 0 | } |