1 /*
2 Unix SMB/CIFS implementation.
3 SMB2 signing
4
5 Copyright (C) Stefan Metzmacher 2009
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include <gnutls/gnutls.h>
24 #include <gnutls/crypto.h>
25 #define SMB2_SIGNING_KEY_GNUTLS_TYPES 1
26 #include "../libcli/smb/smb_common.h"
27 #include "../lib/crypto/crypto.h"
28 #include "lib/util/iov_buf.h"
29
30 #ifndef HAVE_GNUTLS_AES_CMAC
31 #include "lib/crypto/aes.h"
32 #include "lib/crypto/aes_cmac_128.h"
33 #endif
34
35 #include "lib/crypto/gnutls_helpers.h"
36
smb2_signing_key_destructor(struct smb2_signing_key * key)37 int smb2_signing_key_destructor(struct smb2_signing_key *key)
38 {
39 if (key->hmac_hnd != NULL) {
40 gnutls_hmac_deinit(key->hmac_hnd, NULL);
41 key->hmac_hnd = NULL;
42 }
43
44 if (key->cipher_hnd != NULL) {
45 gnutls_aead_cipher_deinit(key->cipher_hnd);
46 key->cipher_hnd = NULL;
47 }
48
49 return 0;
50 }
51
smb2_signing_key_valid(const struct smb2_signing_key * key)52 bool smb2_signing_key_valid(const struct smb2_signing_key *key)
53 {
54 if (key == NULL) {
55 return false;
56 }
57
58 if (key->blob.length == 0 || key->blob.data == NULL) {
59 return false;
60 }
61
62 return true;
63 }
64
smb2_signing_sign_pdu(struct smb2_signing_key * signing_key,enum protocol_types protocol,struct iovec * vector,int count)65 NTSTATUS smb2_signing_sign_pdu(struct smb2_signing_key *signing_key,
66 enum protocol_types protocol,
67 struct iovec *vector,
68 int count)
69 {
70 uint8_t *hdr;
71 uint64_t session_id;
72 uint8_t res[16];
73 int i;
74
75 if (count < 2) {
76 return NT_STATUS_INVALID_PARAMETER;
77 }
78
79 if (vector[0].iov_len != SMB2_HDR_BODY) {
80 return NT_STATUS_INVALID_PARAMETER;
81 }
82
83 hdr = (uint8_t *)vector[0].iov_base;
84
85 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
86 if (session_id == 0) {
87 /*
88 * do not sign messages with a zero session_id.
89 * See MS-SMB2 3.2.4.1.1
90 */
91 return NT_STATUS_OK;
92 }
93
94 if (!smb2_signing_key_valid(signing_key)) {
95 DBG_WARNING("No signing key for SMB2 signing\n");
96 return NT_STATUS_ACCESS_DENIED;
97 }
98
99 memset(hdr + SMB2_HDR_SIGNATURE, 0, 16);
100
101 SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
102
103 if (protocol >= PROTOCOL_SMB2_24) {
104 #ifdef HAVE_GNUTLS_AES_CMAC
105 gnutls_datum_t key = {
106 .data = signing_key->blob.data,
107 .size = MIN(signing_key->blob.length, 16),
108 };
109 int rc;
110
111 if (signing_key->hmac_hnd == NULL) {
112 rc = gnutls_hmac_init(&signing_key->hmac_hnd,
113 GNUTLS_MAC_AES_CMAC_128,
114 key.data,
115 key.size);
116 if (rc < 0) {
117 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
118 }
119 }
120
121 for (i = 0; i < count; i++) {
122 rc = gnutls_hmac(signing_key->hmac_hnd,
123 vector[i].iov_base,
124 vector[i].iov_len);
125 if (rc < 0) {
126 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
127 }
128 }
129 gnutls_hmac_output(signing_key->hmac_hnd, res);
130 #else /* NOT HAVE_GNUTLS_AES_CMAC */
131 struct aes_cmac_128_context ctx;
132 uint8_t key[AES_BLOCK_SIZE] = {0};
133
134 memcpy(key,
135 signing_key->blob.data,
136 MIN(signing_key->blob.length, 16));
137
138 aes_cmac_128_init(&ctx, key);
139 for (i=0; i < count; i++) {
140 aes_cmac_128_update(&ctx,
141 (const uint8_t *)vector[i].iov_base,
142 vector[i].iov_len);
143 }
144 aes_cmac_128_final(&ctx, res);
145
146 ZERO_ARRAY(key);
147 #endif /* HAVE_GNUTLS_AES_CMAC */
148 } else {
149 uint8_t digest[gnutls_hmac_get_len(GNUTLS_MAC_SHA256)];
150 int rc;
151
152 if (signing_key->hmac_hnd == NULL) {
153 rc = gnutls_hmac_init(&signing_key->hmac_hnd,
154 GNUTLS_MAC_SHA256,
155 signing_key->blob.data,
156 MIN(signing_key->blob.length, 16));
157 if (rc < 0) {
158 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
159 }
160 }
161
162 for (i = 0; i < count; i++) {
163 rc = gnutls_hmac(signing_key->hmac_hnd,
164 vector[i].iov_base,
165 vector[i].iov_len);
166 if (rc < 0) {
167 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
168 }
169 }
170 gnutls_hmac_output(signing_key->hmac_hnd, digest);
171 memcpy(res, digest, sizeof(res));
172 }
173 DEBUG(5,("signed SMB2 message\n"));
174
175 memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16);
176
177 return NT_STATUS_OK;
178 }
179
smb2_signing_check_pdu(struct smb2_signing_key * signing_key,enum protocol_types protocol,const struct iovec * vector,int count)180 NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
181 enum protocol_types protocol,
182 const struct iovec *vector,
183 int count)
184 {
185 const uint8_t *hdr;
186 const uint8_t *sig;
187 uint64_t session_id;
188 uint8_t res[16];
189 static const uint8_t zero_sig[16] = { 0, };
190 int i;
191
192 SMB_ASSERT(count >= 2);
193 SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
194
195 hdr = (const uint8_t *)vector[0].iov_base;
196
197 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
198 if (session_id == 0) {
199 /*
200 * do not sign messages with a zero session_id.
201 * See MS-SMB2 3.2.4.1.1
202 */
203 return NT_STATUS_OK;
204 }
205
206 if (!smb2_signing_key_valid(signing_key)) {
207 /* we don't have the session key yet */
208 return NT_STATUS_OK;
209 }
210
211 sig = hdr+SMB2_HDR_SIGNATURE;
212
213 if (protocol >= PROTOCOL_SMB2_24) {
214 #ifdef HAVE_GNUTLS_AES_CMAC
215 gnutls_datum_t key = {
216 .data = signing_key->blob.data,
217 .size = MIN(signing_key->blob.length, 16),
218 };
219 int rc;
220
221 if (signing_key->hmac_hnd == NULL) {
222 rc = gnutls_hmac_init(&signing_key->hmac_hnd,
223 GNUTLS_MAC_AES_CMAC_128,
224 key.data,
225 key.size);
226 if (rc < 0) {
227 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
228 }
229 }
230
231 rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE);
232 if (rc < 0) {
233 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
234 }
235
236 rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16);
237 if (rc < 0) {
238 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
239 }
240
241 for (i = 1; i < count; i++) {
242 rc = gnutls_hmac(signing_key->hmac_hnd,
243 vector[i].iov_base,
244 vector[i].iov_len);
245 if (rc < 0) {
246 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
247 }
248 }
249 gnutls_hmac_output(signing_key->hmac_hnd, res);
250 #else /* NOT HAVE_GNUTLS_AES_CMAC */
251 struct aes_cmac_128_context ctx;
252 uint8_t key[AES_BLOCK_SIZE] = {0};
253
254 memcpy(key,
255 signing_key->blob.data,
256 MIN(signing_key->blob.length, 16));
257
258 aes_cmac_128_init(&ctx, key);
259 aes_cmac_128_update(&ctx, hdr, SMB2_HDR_SIGNATURE);
260 aes_cmac_128_update(&ctx, zero_sig, 16);
261 for (i=1; i < count; i++) {
262 aes_cmac_128_update(&ctx,
263 (const uint8_t *)vector[i].iov_base,
264 vector[i].iov_len);
265 }
266 aes_cmac_128_final(&ctx, res);
267
268 ZERO_ARRAY(key);
269 #endif
270 } else {
271 uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
272 int rc;
273
274 if (signing_key->hmac_hnd == NULL) {
275 rc = gnutls_hmac_init(&signing_key->hmac_hnd,
276 GNUTLS_MAC_SHA256,
277 signing_key->blob.data,
278 MIN(signing_key->blob.length, 16));
279 if (rc < 0) {
280 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
281 }
282 }
283
284 rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE);
285 if (rc < 0) {
286 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
287 }
288 rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16);
289 if (rc < 0) {
290 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
291 }
292
293 for (i = 1; i < count; i++) {
294 rc = gnutls_hmac(signing_key->hmac_hnd,
295 vector[i].iov_base,
296 vector[i].iov_len);
297 if (rc < 0) {
298 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
299 }
300 }
301 gnutls_hmac_output(signing_key->hmac_hnd, digest);
302 memcpy(res, digest, 16);
303 ZERO_ARRAY(digest);
304 }
305
306 if (memcmp_const_time(res, sig, 16) != 0) {
307 DEBUG(0,("Bad SMB2 signature for message\n"));
308 dump_data(0, sig, 16);
309 dump_data(0, res, 16);
310 return NT_STATUS_ACCESS_DENIED;
311 }
312
313 return NT_STATUS_OK;
314 }
315
smb2_key_derivation(const uint8_t * KI,size_t KI_len,const uint8_t * Label,size_t Label_len,const uint8_t * Context,size_t Context_len,uint8_t KO[16])316 NTSTATUS smb2_key_derivation(const uint8_t *KI, size_t KI_len,
317 const uint8_t *Label, size_t Label_len,
318 const uint8_t *Context, size_t Context_len,
319 uint8_t KO[16])
320 {
321 gnutls_hmac_hd_t hmac_hnd = NULL;
322 uint8_t buf[4];
323 static const uint8_t zero = 0;
324 uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
325 uint32_t i = 1;
326 uint32_t L = 128;
327 int rc;
328
329 /*
330 * a simplified version of
331 * "NIST Special Publication 800-108" section 5.1
332 * using hmac-sha256.
333 */
334 rc = gnutls_hmac_init(&hmac_hnd,
335 GNUTLS_MAC_SHA256,
336 KI,
337 KI_len);
338 if (rc < 0) {
339 return gnutls_error_to_ntstatus(rc,
340 NT_STATUS_HMAC_NOT_SUPPORTED);
341 }
342
343 RSIVAL(buf, 0, i);
344 rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
345 if (rc < 0) {
346 return gnutls_error_to_ntstatus(rc,
347 NT_STATUS_HMAC_NOT_SUPPORTED);
348 }
349 rc = gnutls_hmac(hmac_hnd, Label, Label_len);
350 if (rc < 0) {
351 gnutls_hmac_deinit(hmac_hnd, NULL);
352 return gnutls_error_to_ntstatus(rc,
353 NT_STATUS_HMAC_NOT_SUPPORTED);
354 }
355 rc = gnutls_hmac(hmac_hnd, &zero, 1);
356 if (rc < 0) {
357 gnutls_hmac_deinit(hmac_hnd, NULL);
358 return gnutls_error_to_ntstatus(rc,
359 NT_STATUS_HMAC_NOT_SUPPORTED);
360 }
361 rc = gnutls_hmac(hmac_hnd, Context, Context_len);
362 if (rc < 0) {
363 gnutls_hmac_deinit(hmac_hnd, NULL);
364 return gnutls_error_to_ntstatus(rc,
365 NT_STATUS_HMAC_NOT_SUPPORTED);
366 }
367 RSIVAL(buf, 0, L);
368 rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
369 if (rc < 0) {
370 gnutls_hmac_deinit(hmac_hnd, NULL);
371 return gnutls_error_to_ntstatus(rc,
372 NT_STATUS_HMAC_NOT_SUPPORTED);
373 }
374
375 gnutls_hmac_deinit(hmac_hnd, digest);
376
377 memcpy(KO, digest, 16);
378
379 ZERO_ARRAY(digest);
380
381 return NT_STATUS_OK;
382 }
383
smb2_signing_encrypt_pdu(struct smb2_signing_key * encryption_key,uint16_t cipher_id,struct iovec * vector,int count)384 NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
385 uint16_t cipher_id,
386 struct iovec *vector,
387 int count)
388 {
389 uint8_t *tf;
390 size_t a_total;
391 ssize_t m_total;
392 uint32_t iv_size = 0;
393 uint32_t key_size = 0;
394 size_t tag_size = 0;
395 uint8_t _key[16] = {0};
396 gnutls_cipher_algorithm_t algo = 0;
397 gnutls_datum_t key;
398 gnutls_datum_t iv;
399 NTSTATUS status;
400 int rc;
401
402 if (count < 1) {
403 return NT_STATUS_INVALID_PARAMETER;
404 }
405
406 if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
407 return NT_STATUS_INVALID_PARAMETER;
408 }
409
410 tf = (uint8_t *)vector[0].iov_base;
411
412 if (!smb2_signing_key_valid(encryption_key)) {
413 DBG_WARNING("No encryption key for SMB2 signing\n");
414 return NT_STATUS_ACCESS_DENIED;
415 }
416
417 a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
418
419 m_total = iov_buflen(&vector[1], count-1);
420 if (m_total == -1) {
421 return NT_STATUS_BUFFER_TOO_SMALL;
422 }
423
424 SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
425 SIVAL(tf, SMB2_TF_MSG_SIZE, m_total);
426
427 switch (cipher_id) {
428 case SMB2_ENCRYPTION_AES128_CCM:
429 algo = GNUTLS_CIPHER_AES_128_CCM;
430 iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
431 break;
432 case SMB2_ENCRYPTION_AES128_GCM:
433 algo = GNUTLS_CIPHER_AES_128_GCM;
434 iv_size = gnutls_cipher_get_iv_size(algo);
435 break;
436 default:
437 return NT_STATUS_INVALID_PARAMETER;
438 }
439
440 key_size = gnutls_cipher_get_key_size(algo);
441 tag_size = gnutls_cipher_get_tag_size(algo);
442
443 if (key_size > sizeof(_key)) {
444 return NT_STATUS_BUFFER_TOO_SMALL;
445 }
446
447 key = (gnutls_datum_t) {
448 .data = _key,
449 .size = key_size,
450 };
451
452 memcpy(key.data,
453 encryption_key->blob.data,
454 MIN(encryption_key->blob.length, key.size));
455
456 iv = (gnutls_datum_t) {
457 .data = tf + SMB2_TF_NONCE,
458 .size = iv_size,
459 };
460
461 if (encryption_key->cipher_hnd == NULL) {
462 rc = gnutls_aead_cipher_init(&encryption_key->cipher_hnd,
463 algo,
464 &key);
465 if (rc < 0) {
466 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
467 goto out;
468 }
469 }
470
471 memset(tf + SMB2_TF_NONCE + iv_size,
472 0,
473 16 - iv_size);
474
475 #if defined(HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2)
476 {
477 uint8_t tag[tag_size];
478 giovec_t auth_iov[1];
479
480 auth_iov[0] = (giovec_t) {
481 .iov_base = tf + SMB2_TF_NONCE,
482 .iov_len = a_total,
483 };
484
485 rc = gnutls_aead_cipher_encryptv2(encryption_key->cipher_hnd,
486 iv.data,
487 iv.size,
488 auth_iov,
489 1,
490 &vector[1],
491 count - 1,
492 tag,
493 &tag_size);
494 if (rc < 0) {
495 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
496 goto out;
497 }
498
499 memcpy(tf + SMB2_TF_SIGNATURE, tag, tag_size);
500 }
501 #else /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
502 {
503 size_t ptext_size = m_total;
504 uint8_t *ptext = NULL;
505 size_t ctext_size = m_total + tag_size;
506 uint8_t *ctext = NULL;
507 size_t len = 0;
508 int i;
509
510 ptext = talloc_size(talloc_tos(), ptext_size);
511 if (ptext == NULL) {
512 status = NT_STATUS_NO_MEMORY;
513 goto out;
514 }
515
516 ctext = talloc_size(talloc_tos(), ctext_size);
517 if (ctext == NULL) {
518 status = NT_STATUS_NO_MEMORY;
519 goto out;
520 }
521
522 for (i = 1; i < count; i++) {
523 memcpy(ptext + len,
524 vector[i].iov_base,
525 vector[i].iov_len);
526
527 len += vector[i].iov_len;
528 if (len > ptext_size) {
529 TALLOC_FREE(ptext);
530 TALLOC_FREE(ctext);
531 status = NT_STATUS_INTERNAL_ERROR;
532 goto out;
533 }
534 }
535
536 rc = gnutls_aead_cipher_encrypt(encryption_key->cipher_hnd,
537 iv.data,
538 iv.size,
539 tf + SMB2_TF_NONCE,
540 a_total,
541 tag_size,
542 ptext,
543 ptext_size,
544 ctext,
545 &ctext_size);
546 if (rc < 0 || ctext_size != m_total + tag_size) {
547 TALLOC_FREE(ptext);
548 TALLOC_FREE(ctext);
549 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
550 goto out;
551 }
552
553 len = 0;
554 for (i = 1; i < count; i++) {
555 memcpy(vector[i].iov_base,
556 ctext + len,
557 vector[i].iov_len);
558
559 len += vector[i].iov_len;
560 }
561
562 memcpy(tf + SMB2_TF_SIGNATURE, ctext + m_total, tag_size);
563
564 TALLOC_FREE(ptext);
565 TALLOC_FREE(ctext);
566 }
567 #endif /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
568
569 DBG_INFO("Enencrypted SMB2 message\n");
570
571 status = NT_STATUS_OK;
572 out:
573 ZERO_ARRAY(_key);
574
575 return status;
576 }
577
smb2_signing_decrypt_pdu(struct smb2_signing_key * decryption_key,uint16_t cipher_id,struct iovec * vector,int count)578 NTSTATUS smb2_signing_decrypt_pdu(struct smb2_signing_key *decryption_key,
579 uint16_t cipher_id,
580 struct iovec *vector,
581 int count)
582 {
583 uint8_t *tf;
584 uint16_t flags;
585 size_t a_total;
586 ssize_t m_total;
587 uint32_t msg_size = 0;
588 uint32_t iv_size = 0;
589 uint32_t key_size = 0;
590 size_t tag_size = 0;
591 uint8_t _key[16] = {0};
592 gnutls_cipher_algorithm_t algo = 0;
593 gnutls_datum_t key;
594 gnutls_datum_t iv;
595 NTSTATUS status;
596 int rc;
597
598 if (count < 1) {
599 return NT_STATUS_INVALID_PARAMETER;
600 }
601
602 if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
603 return NT_STATUS_INVALID_PARAMETER;
604 }
605
606 tf = (uint8_t *)vector[0].iov_base;
607
608 if (!smb2_signing_key_valid(decryption_key)) {
609 DBG_WARNING("No decryption key for SMB2 signing\n");
610 return NT_STATUS_ACCESS_DENIED;
611 }
612
613 a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
614
615 m_total = iov_buflen(&vector[1], count-1);
616 if (m_total == -1) {
617 return NT_STATUS_BUFFER_TOO_SMALL;
618 }
619
620 flags = SVAL(tf, SMB2_TF_FLAGS);
621 msg_size = IVAL(tf, SMB2_TF_MSG_SIZE);
622
623 if (flags != SMB2_TF_FLAGS_ENCRYPTED) {
624 return NT_STATUS_ACCESS_DENIED;
625 }
626
627 if (msg_size != m_total) {
628 return NT_STATUS_INTERNAL_ERROR;
629 }
630
631 switch (cipher_id) {
632 case SMB2_ENCRYPTION_AES128_CCM:
633 algo = GNUTLS_CIPHER_AES_128_CCM;
634 iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
635 break;
636 case SMB2_ENCRYPTION_AES128_GCM:
637 algo = GNUTLS_CIPHER_AES_128_GCM;
638 iv_size = gnutls_cipher_get_iv_size(algo);
639 break;
640 default:
641 return NT_STATUS_INVALID_PARAMETER;
642 }
643
644 key_size = gnutls_cipher_get_key_size(algo);
645 tag_size = gnutls_cipher_get_tag_size(algo);
646
647 if (key_size > sizeof(_key)) {
648 return NT_STATUS_BUFFER_TOO_SMALL;
649 }
650
651 key = (gnutls_datum_t) {
652 .data = _key,
653 .size = key_size,
654 };
655
656 memcpy(key.data,
657 decryption_key->blob.data,
658 MIN(decryption_key->blob.length, key.size));
659
660 iv = (gnutls_datum_t) {
661 .data = tf + SMB2_TF_NONCE,
662 .size = iv_size,
663 };
664
665 if (decryption_key->cipher_hnd == NULL) {
666 rc = gnutls_aead_cipher_init(&decryption_key->cipher_hnd,
667 algo,
668 &key);
669 if (rc < 0) {
670 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
671 goto out;
672 }
673 }
674
675 /* gnutls_aead_cipher_encryptv2() has a bug in version 3.6.10 */
676 #if defined(HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2)
677 {
678 giovec_t auth_iov[1];
679
680 auth_iov[0] = (giovec_t) {
681 .iov_base = tf + SMB2_TF_NONCE,
682 .iov_len = a_total,
683 };
684
685 rc = gnutls_aead_cipher_decryptv2(decryption_key->cipher_hnd,
686 iv.data,
687 iv.size,
688 auth_iov,
689 1,
690 &vector[1],
691 count - 1,
692 tf + SMB2_TF_SIGNATURE,
693 tag_size);
694 if (rc < 0) {
695 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
696 goto out;
697 }
698 }
699 #else /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
700 {
701 size_t ctext_size = m_total + tag_size;
702 uint8_t *ctext = NULL;
703 size_t ptext_size = m_total;
704 uint8_t *ptext = NULL;
705 size_t len = 0;
706 int i;
707
708 /* GnuTLS doesn't have a iovec API for decryption yet */
709
710 ptext = talloc_size(talloc_tos(), ptext_size);
711 if (ptext == NULL) {
712 status = NT_STATUS_NO_MEMORY;
713 goto out;
714 }
715
716 ctext = talloc_size(talloc_tos(), ctext_size);
717 if (ctext == NULL) {
718 TALLOC_FREE(ptext);
719 status = NT_STATUS_NO_MEMORY;
720 goto out;
721 }
722
723
724 for (i = 1; i < count; i++) {
725 memcpy(ctext + len,
726 vector[i].iov_base,
727 vector[i].iov_len);
728
729 len += vector[i].iov_len;
730 }
731 if (len != m_total) {
732 TALLOC_FREE(ptext);
733 TALLOC_FREE(ctext);
734 status = NT_STATUS_INTERNAL_ERROR;
735 goto out;
736 }
737
738 memcpy(ctext + len,
739 tf + SMB2_TF_SIGNATURE,
740 tag_size);
741
742 /* This function will verify the tag */
743 rc = gnutls_aead_cipher_decrypt(decryption_key->cipher_hnd,
744 iv.data,
745 iv.size,
746 tf + SMB2_TF_NONCE,
747 a_total,
748 tag_size,
749 ctext,
750 ctext_size,
751 ptext,
752 &ptext_size);
753 if (rc < 0 || ptext_size != m_total) {
754 TALLOC_FREE(ptext);
755 TALLOC_FREE(ctext);
756 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
757 goto out;
758 }
759
760 len = 0;
761 for (i = 1; i < count; i++) {
762 memcpy(vector[i].iov_base,
763 ptext + len,
764 vector[i].iov_len);
765
766 len += vector[i].iov_len;
767 }
768
769 TALLOC_FREE(ptext);
770 TALLOC_FREE(ctext);
771 }
772 #endif /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
773
774 DBG_INFO("Decrypted SMB2 message\n");
775
776 status = NT_STATUS_OK;
777 out:
778 ZERO_ARRAY(_key);
779
780 return status;
781 }
782