2 Unix SMB/CIFS implementation.
5 Copyright (C) Stefan Metzmacher 2009
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.
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.
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/>.
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"
30 #ifndef HAVE_GNUTLS_AES_CMAC
31 #include "lib/crypto/aes.h"
32 #include "lib/crypto/aes_cmac_128.h"
35 #include "lib/crypto/gnutls_helpers.h"
37 void smb2_signing_derivations_fill_const_stack(struct smb2_signing_derivations
*ds
,
38 enum protocol_types protocol
,
39 const DATA_BLOB preauth_hash
)
41 *ds
= (struct smb2_signing_derivations
) { .signing
= NULL
, };
43 if (protocol
>= PROTOCOL_SMB3_11
) {
44 struct smb2_signing_derivation
*d
= NULL
;
46 SMB_ASSERT(preauth_hash
.length
!= 0);
50 d
->label
= data_blob_string_const_null("SMBSigningKey");
51 d
->context
= preauth_hash
;
53 d
= &ds
->__cipher_c2s
;
55 d
->label
= data_blob_string_const_null("SMBC2SCipherKey");
56 d
->context
= preauth_hash
;
58 d
= &ds
->__cipher_s2c
;
60 d
->label
= data_blob_string_const_null("SMBS2CCipherKey");
61 d
->context
= preauth_hash
;
63 d
= &ds
->__application
;
65 d
->label
= data_blob_string_const_null("SMBAppKey");
66 d
->context
= preauth_hash
;
68 } else if (protocol
>= PROTOCOL_SMB3_00
) {
69 struct smb2_signing_derivation
*d
= NULL
;
73 d
->label
= data_blob_string_const_null("SMB2AESCMAC");
74 d
->context
= data_blob_string_const_null("SmbSign");
76 d
= &ds
->__cipher_c2s
;
78 d
->label
= data_blob_string_const_null("SMB2AESCCM");
79 d
->context
= data_blob_string_const_null("ServerIn ");
81 d
= &ds
->__cipher_s2c
;
83 d
->label
= data_blob_string_const_null("SMB2AESCCM");
84 d
->context
= data_blob_string_const_null("ServerOut");
86 d
= &ds
->__application
;
88 d
->label
= data_blob_string_const_null("SMB2APP");
89 d
->context
= data_blob_string_const_null("SmbRpc");
93 static int smb2_signing_key_destructor(struct smb2_signing_key
*key
)
95 if (key
->hmac_hnd
!= NULL
) {
96 gnutls_hmac_deinit(key
->hmac_hnd
, NULL
);
100 if (key
->cipher_hnd
!= NULL
) {
101 gnutls_aead_cipher_deinit(key
->cipher_hnd
);
102 key
->cipher_hnd
= NULL
;
108 NTSTATUS
smb2_signing_key_copy(TALLOC_CTX
*mem_ctx
,
109 const struct smb2_signing_key
*src
,
110 struct smb2_signing_key
**_dst
)
112 struct smb2_signing_key
*dst
= NULL
;
114 dst
= talloc_zero(mem_ctx
, struct smb2_signing_key
);
116 return NT_STATUS_NO_MEMORY
;
118 talloc_set_destructor(dst
, smb2_signing_key_destructor
);
120 dst
->sign_algo_id
= src
->sign_algo_id
;
121 dst
->cipher_algo_id
= src
->cipher_algo_id
;
123 if (src
->blob
.length
== 0) {
128 dst
->blob
= data_blob_talloc_zero(dst
, src
->blob
.length
);
129 if (dst
->blob
.length
== 0) {
131 return NT_STATUS_NO_MEMORY
;
133 talloc_keep_secret(dst
->blob
.data
);
134 memcpy(dst
->blob
.data
, src
->blob
.data
, dst
->blob
.length
);
140 static NTSTATUS
smb2_signing_key_create(TALLOC_CTX
*mem_ctx
,
141 uint16_t sign_algo_id
,
142 uint16_t cipher_algo_id
,
143 const DATA_BLOB
*master_key
,
144 const struct smb2_signing_derivation
*d
,
145 struct smb2_signing_key
**_key
)
147 struct smb2_signing_key
*key
= NULL
;
148 size_t in_key_length
= 16;
149 size_t out_key_length
= 16;
152 if (sign_algo_id
!= SMB2_SIGNING_INVALID_ALGO
) {
153 SMB_ASSERT(cipher_algo_id
== SMB2_ENCRYPTION_INVALID_ALGO
);
155 if (cipher_algo_id
!= SMB2_ENCRYPTION_INVALID_ALGO
) {
156 SMB_ASSERT(sign_algo_id
== SMB2_SIGNING_INVALID_ALGO
);
159 key
= talloc_zero(mem_ctx
, struct smb2_signing_key
);
161 return NT_STATUS_NO_MEMORY
;
163 talloc_set_destructor(key
, smb2_signing_key_destructor
);
165 key
->sign_algo_id
= sign_algo_id
;
166 key
->cipher_algo_id
= cipher_algo_id
;
168 if (master_key
== NULL
) {
169 SMB_ASSERT(d
== NULL
);
176 * Per default use the full key.
178 in_key_length
= out_key_length
= master_key
->length
;
179 switch (sign_algo_id
) {
180 case SMB2_SIGNING_INVALID_ALGO
:
182 * This means we're processing cipher_algo_id below
185 case SMB2_SIGNING_MD5_SMB1
:
186 SMB_ASSERT(d
== NULL
);
188 case SMB2_SIGNING_HMAC_SHA256
:
189 case SMB2_SIGNING_AES128_CMAC
:
191 * signing keys are padded or truncated to
194 * Even with master_key->length = 0,
195 * we need to use 16 zeros.
197 in_key_length
= out_key_length
= 16;
200 DBG_ERR("sign_algo_id[%u] not supported\n", sign_algo_id
);
201 return NT_STATUS_HMAC_NOT_SUPPORTED
;
203 switch (cipher_algo_id
) {
204 case SMB2_ENCRYPTION_INVALID_ALGO
:
206 * This means we're processing sign_algo_id above
209 case SMB2_ENCRYPTION_NONE
:
211 * No encryption negotiated.
214 case SMB2_ENCRYPTION_AES128_CCM
:
215 case SMB2_ENCRYPTION_AES128_GCM
:
217 * encryption keys are padded or truncated to
220 if (master_key
->length
== 0) {
221 DBG_ERR("cipher_algo_id[%u] without key\n",
223 return NT_STATUS_NO_USER_SESSION_KEY
;
225 in_key_length
= out_key_length
= 16;
227 case SMB2_ENCRYPTION_AES256_CCM
:
228 case SMB2_ENCRYPTION_AES256_GCM
:
230 * AES256 uses the available input and
231 * generated a 32 byte encryption key.
233 if (master_key
->length
== 0) {
234 DBG_ERR("cipher_algo_id[%u] without key\n",
236 return NT_STATUS_NO_USER_SESSION_KEY
;
241 DBG_ERR("cipher_algo_id[%u] not supported\n", cipher_algo_id
);
242 return NT_STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG
;
245 if (out_key_length
== 0) {
250 key
->blob
= data_blob_talloc_zero(key
, out_key_length
);
251 if (key
->blob
.length
== 0) {
253 return NT_STATUS_NO_MEMORY
;
255 talloc_keep_secret(key
->blob
.data
);
256 memcpy(key
->blob
.data
,
258 MIN(key
->blob
.length
, master_key
->length
));
265 status
= smb2_key_derivation(key
->blob
.data
, in_key_length
,
266 d
->label
.data
, d
->label
.length
,
267 d
->context
.data
, d
->context
.length
,
268 key
->blob
.data
, out_key_length
);
269 if (!NT_STATUS_IS_OK(status
)) {
278 NTSTATUS
smb2_signing_key_sign_create(TALLOC_CTX
*mem_ctx
,
279 uint16_t sign_algo_id
,
280 const DATA_BLOB
*master_key
,
281 const struct smb2_signing_derivation
*d
,
282 struct smb2_signing_key
**_key
)
284 return smb2_signing_key_create(mem_ctx
,
286 SMB2_ENCRYPTION_INVALID_ALGO
,
292 NTSTATUS
smb2_signing_key_cipher_create(TALLOC_CTX
*mem_ctx
,
293 uint16_t cipher_algo_id
,
294 const DATA_BLOB
*master_key
,
295 const struct smb2_signing_derivation
*d
,
296 struct smb2_signing_key
**_key
)
298 return smb2_signing_key_create(mem_ctx
,
299 SMB2_SIGNING_INVALID_ALGO
,
306 bool smb2_signing_key_valid(const struct smb2_signing_key
*key
)
312 if (key
->blob
.length
== 0 || key
->blob
.data
== NULL
) {
319 static NTSTATUS
smb2_signing_calc_signature(struct smb2_signing_key
*signing_key
,
320 uint16_t sign_algo_id
,
321 const struct iovec
*vector
,
323 uint8_t signature
[16])
325 const uint8_t *hdr
= (uint8_t *)vector
[0].iov_base
;
326 static const uint8_t zero_sig
[16] = { 0, };
327 gnutls_mac_algorithm_t hmac_algo
= GNUTLS_MAC_UNKNOWN
;
334 * - (optional) SMB2 BODY DYN
335 * - (optional) PADDING
337 SMB_ASSERT(count
>= 2);
338 SMB_ASSERT(vector
[0].iov_len
== SMB2_HDR_BODY
);
339 SMB_ASSERT(count
<= 4);
341 switch (sign_algo_id
) {
342 case SMB2_SIGNING_AES128_CMAC
:
343 #ifdef HAVE_GNUTLS_AES_CMAC
344 hmac_algo
= GNUTLS_MAC_AES_CMAC_128
;
346 #else /* NOT HAVE_GNUTLS_AES_CMAC */
348 struct aes_cmac_128_context ctx
;
349 uint8_t key
[AES_BLOCK_SIZE
] = {0};
352 signing_key
->blob
.data
,
353 MIN(signing_key
->blob
.length
, 16));
355 aes_cmac_128_init(&ctx
, key
);
356 aes_cmac_128_update(&ctx
, hdr
, SMB2_HDR_SIGNATURE
);
357 aes_cmac_128_update(&ctx
, zero_sig
, 16);
358 for (i
=1; i
< count
; i
++) {
359 aes_cmac_128_update(&ctx
,
360 (const uint8_t *)vector
[i
].iov_base
,
363 aes_cmac_128_final(&ctx
, signature
);
370 case SMB2_SIGNING_HMAC_SHA256
:
371 hmac_algo
= GNUTLS_MAC_SHA256
;
375 return NT_STATUS_HMAC_NOT_SUPPORTED
;
378 if (hmac_algo
!= GNUTLS_MAC_UNKNOWN
) {
379 uint8_t digest
[gnutls_hash_get_len(hmac_algo
)];
380 gnutls_datum_t key
= {
381 .data
= signing_key
->blob
.data
,
382 .size
= MIN(signing_key
->blob
.length
, 16),
386 if (signing_key
->hmac_hnd
== NULL
) {
387 rc
= gnutls_hmac_init(&signing_key
->hmac_hnd
,
392 return gnutls_error_to_ntstatus(rc
,
393 NT_STATUS_HMAC_NOT_SUPPORTED
);
397 rc
= gnutls_hmac(signing_key
->hmac_hnd
, hdr
, SMB2_HDR_SIGNATURE
);
399 return gnutls_error_to_ntstatus(rc
,
400 NT_STATUS_HMAC_NOT_SUPPORTED
);
402 rc
= gnutls_hmac(signing_key
->hmac_hnd
, zero_sig
, 16);
404 return gnutls_error_to_ntstatus(rc
,
405 NT_STATUS_HMAC_NOT_SUPPORTED
);
408 for (i
= 1; i
< count
; i
++) {
409 rc
= gnutls_hmac(signing_key
->hmac_hnd
,
413 return gnutls_error_to_ntstatus(rc
,
414 NT_STATUS_HMAC_NOT_SUPPORTED
);
417 gnutls_hmac_output(signing_key
->hmac_hnd
, digest
);
418 memcpy(signature
, digest
, 16);
423 return NT_STATUS_HMAC_NOT_SUPPORTED
;
426 NTSTATUS
smb2_signing_sign_pdu(struct smb2_signing_key
*signing_key
,
427 struct iovec
*vector
,
430 uint16_t sign_algo_id
;
440 * - (optional) SMB2 BODY DYN
441 * - (optional) PADDING
443 SMB_ASSERT(count
>= 2);
444 SMB_ASSERT(vector
[0].iov_len
== SMB2_HDR_BODY
);
445 SMB_ASSERT(count
<= 4);
447 hdr
= (uint8_t *)vector
[0].iov_base
;
449 session_id
= BVAL(hdr
, SMB2_HDR_SESSION_ID
);
450 if (session_id
== 0) {
452 * do not sign messages with a zero session_id.
453 * See MS-SMB2 3.2.4.1.1
458 if (!smb2_signing_key_valid(signing_key
)) {
459 DBG_WARNING("No signing key for SMB2 signing\n");
460 return NT_STATUS_ACCESS_DENIED
;
463 memset(hdr
+ SMB2_HDR_SIGNATURE
, 0, 16);
465 SIVAL(hdr
, SMB2_HDR_FLAGS
, IVAL(hdr
, SMB2_HDR_FLAGS
) | SMB2_HDR_FLAG_SIGNED
);
467 sign_algo_id
= signing_key
->sign_algo_id
;
469 status
= smb2_signing_calc_signature(signing_key
,
474 if (!NT_STATUS_IS_OK(status
)) {
475 DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
476 (unsigned)sign_algo_id
, nt_errstr(status
));
480 DEBUG(5,("signed SMB2 message (sign_algo_id=%u)\n",
481 (unsigned)sign_algo_id
));
483 memcpy(hdr
+ SMB2_HDR_SIGNATURE
, res
, 16);
488 NTSTATUS
smb2_signing_check_pdu(struct smb2_signing_key
*signing_key
,
489 const struct iovec
*vector
,
492 uint16_t sign_algo_id
;
503 * - (optional) SMB2 BODY DYN
504 * - (optional) PADDING
506 SMB_ASSERT(count
>= 2);
507 SMB_ASSERT(vector
[0].iov_len
== SMB2_HDR_BODY
);
508 SMB_ASSERT(count
<= 4);
510 hdr
= (const uint8_t *)vector
[0].iov_base
;
512 session_id
= BVAL(hdr
, SMB2_HDR_SESSION_ID
);
513 if (session_id
== 0) {
515 * do not sign messages with a zero session_id.
516 * See MS-SMB2 3.2.4.1.1
521 if (!smb2_signing_key_valid(signing_key
)) {
522 /* we don't have the session key yet */
526 sig
= hdr
+SMB2_HDR_SIGNATURE
;
528 sign_algo_id
= signing_key
->sign_algo_id
;
530 status
= smb2_signing_calc_signature(signing_key
,
535 if (!NT_STATUS_IS_OK(status
)) {
536 DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
537 (unsigned)sign_algo_id
, nt_errstr(status
));
541 if (memcmp_const_time(res
, sig
, 16) != 0) {
542 DEBUG(0,("Bad SMB2 (sign_algo_id=%u) signature for message\n",
543 (unsigned)sign_algo_id
));
544 dump_data(0, sig
, 16);
545 dump_data(0, res
, 16);
546 return NT_STATUS_ACCESS_DENIED
;
552 NTSTATUS
smb2_key_derivation(const uint8_t *KI
, size_t KI_len
,
553 const uint8_t *Label
, size_t Label_len
,
554 const uint8_t *Context
, size_t Context_len
,
555 uint8_t *KO
, size_t KO_len
)
557 gnutls_hmac_hd_t hmac_hnd
= NULL
;
559 static const uint8_t zero
= 0;
560 const size_t digest_len
= gnutls_hash_get_len(GNUTLS_DIG_SHA256
);
561 uint8_t digest
[digest_len
];
563 uint32_t L
= KO_len
* 8;
566 if (KO_len
> digest_len
) {
567 DBG_ERR("KO_len[%zu] > digest_len[%zu]\n", KO_len
, digest_len
);
568 return NT_STATUS_INTERNAL_ERROR
;
576 DBG_ERR("KO_len[%zu] not supported\n", KO_len
);
577 return NT_STATUS_INTERNAL_ERROR
;
581 * a simplified version of
582 * "NIST Special Publication 800-108" section 5.1
585 rc
= gnutls_hmac_init(&hmac_hnd
,
590 return gnutls_error_to_ntstatus(rc
,
591 NT_STATUS_HMAC_NOT_SUPPORTED
);
595 rc
= gnutls_hmac(hmac_hnd
, buf
, sizeof(buf
));
597 return gnutls_error_to_ntstatus(rc
,
598 NT_STATUS_HMAC_NOT_SUPPORTED
);
600 rc
= gnutls_hmac(hmac_hnd
, Label
, Label_len
);
602 gnutls_hmac_deinit(hmac_hnd
, NULL
);
603 return gnutls_error_to_ntstatus(rc
,
604 NT_STATUS_HMAC_NOT_SUPPORTED
);
606 rc
= gnutls_hmac(hmac_hnd
, &zero
, 1);
608 gnutls_hmac_deinit(hmac_hnd
, NULL
);
609 return gnutls_error_to_ntstatus(rc
,
610 NT_STATUS_HMAC_NOT_SUPPORTED
);
612 rc
= gnutls_hmac(hmac_hnd
, Context
, Context_len
);
614 gnutls_hmac_deinit(hmac_hnd
, NULL
);
615 return gnutls_error_to_ntstatus(rc
,
616 NT_STATUS_HMAC_NOT_SUPPORTED
);
619 rc
= gnutls_hmac(hmac_hnd
, buf
, sizeof(buf
));
621 gnutls_hmac_deinit(hmac_hnd
, NULL
);
622 return gnutls_error_to_ntstatus(rc
,
623 NT_STATUS_HMAC_NOT_SUPPORTED
);
626 gnutls_hmac_deinit(hmac_hnd
, digest
);
628 memcpy(KO
, digest
, KO_len
);
635 NTSTATUS
smb2_signing_encrypt_pdu(struct smb2_signing_key
*encryption_key
,
636 struct iovec
*vector
,
643 uint32_t iv_size
= 0;
644 uint32_t key_size
= 0;
646 gnutls_cipher_algorithm_t algo
= 0;
653 return NT_STATUS_INVALID_PARAMETER
;
656 if (vector
[0].iov_len
!= SMB2_TF_HDR_SIZE
) {
657 return NT_STATUS_INVALID_PARAMETER
;
660 tf
= (uint8_t *)vector
[0].iov_base
;
662 if (!smb2_signing_key_valid(encryption_key
)) {
663 DBG_WARNING("No encryption key for SMB2 signing\n");
664 return NT_STATUS_ACCESS_DENIED
;
666 cipher_id
= encryption_key
->cipher_algo_id
;
668 a_total
= SMB2_TF_HDR_SIZE
- SMB2_TF_NONCE
;
670 m_total
= iov_buflen(&vector
[1], count
-1);
672 return NT_STATUS_BUFFER_TOO_SMALL
;
675 SSVAL(tf
, SMB2_TF_FLAGS
, SMB2_TF_FLAGS_ENCRYPTED
);
676 SIVAL(tf
, SMB2_TF_MSG_SIZE
, m_total
);
679 case SMB2_ENCRYPTION_AES128_CCM
:
680 algo
= GNUTLS_CIPHER_AES_128_CCM
;
681 iv_size
= SMB2_AES_128_CCM_NONCE_SIZE
;
683 case SMB2_ENCRYPTION_AES128_GCM
:
684 algo
= GNUTLS_CIPHER_AES_128_GCM
;
685 iv_size
= gnutls_cipher_get_iv_size(algo
);
687 case SMB2_ENCRYPTION_AES256_CCM
:
688 algo
= GNUTLS_CIPHER_AES_256_CCM
;
689 iv_size
= SMB2_AES_128_CCM_NONCE_SIZE
;
691 case SMB2_ENCRYPTION_AES256_GCM
:
692 algo
= GNUTLS_CIPHER_AES_256_GCM
;
693 iv_size
= gnutls_cipher_get_iv_size(algo
);
696 return NT_STATUS_INVALID_PARAMETER
;
699 key_size
= gnutls_cipher_get_key_size(algo
);
700 tag_size
= gnutls_cipher_get_tag_size(algo
);
702 if (key_size
!= encryption_key
->blob
.length
) {
703 return NT_STATUS_INTERNAL_ERROR
;
706 if (tag_size
!= 16) {
707 return NT_STATUS_INTERNAL_ERROR
;
710 key
= (gnutls_datum_t
) {
711 .data
= encryption_key
->blob
.data
,
715 iv
= (gnutls_datum_t
) {
716 .data
= tf
+ SMB2_TF_NONCE
,
720 if (encryption_key
->cipher_hnd
== NULL
) {
721 rc
= gnutls_aead_cipher_init(&encryption_key
->cipher_hnd
,
725 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
730 memset(tf
+ SMB2_TF_NONCE
+ iv_size
,
734 #if defined(HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2)
736 uint8_t tag
[tag_size
];
737 giovec_t auth_iov
[1];
739 auth_iov
[0] = (giovec_t
) {
740 .iov_base
= tf
+ SMB2_TF_NONCE
,
744 rc
= gnutls_aead_cipher_encryptv2(encryption_key
->cipher_hnd
,
754 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
758 memcpy(tf
+ SMB2_TF_SIGNATURE
, tag
, tag_size
);
760 #else /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
762 size_t ptext_size
= m_total
;
763 uint8_t *ptext
= NULL
;
764 size_t ctext_size
= m_total
+ tag_size
;
765 uint8_t *ctext
= NULL
;
768 TALLOC_CTX
*tmp_ctx
= NULL
;
771 * If we come from python bindings, we don't have a stackframe
772 * around, so use the NULL context.
774 * This is fine as we make sure we free the memory.
776 if (talloc_stackframe_exists()) {
777 tmp_ctx
= talloc_tos();
780 ptext
= talloc_size(tmp_ctx
, ptext_size
);
782 status
= NT_STATUS_NO_MEMORY
;
786 ctext
= talloc_size(tmp_ctx
, ctext_size
);
789 status
= NT_STATUS_NO_MEMORY
;
793 for (i
= 1; i
< count
; i
++) {
798 len
+= vector
[i
].iov_len
;
799 if (len
> ptext_size
) {
802 status
= NT_STATUS_INTERNAL_ERROR
;
807 rc
= gnutls_aead_cipher_encrypt(encryption_key
->cipher_hnd
,
817 if (rc
< 0 || ctext_size
!= m_total
+ tag_size
) {
820 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
825 for (i
= 1; i
< count
; i
++) {
826 memcpy(vector
[i
].iov_base
,
830 len
+= vector
[i
].iov_len
;
833 memcpy(tf
+ SMB2_TF_SIGNATURE
, ctext
+ m_total
, tag_size
);
838 #endif /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
840 DBG_INFO("Encrypted SMB2 message\n");
842 status
= NT_STATUS_OK
;
847 NTSTATUS
smb2_signing_decrypt_pdu(struct smb2_signing_key
*decryption_key
,
848 struct iovec
*vector
,
856 uint32_t msg_size
= 0;
857 uint32_t iv_size
= 0;
858 uint32_t key_size
= 0;
860 gnutls_cipher_algorithm_t algo
= 0;
867 return NT_STATUS_INVALID_PARAMETER
;
870 if (vector
[0].iov_len
!= SMB2_TF_HDR_SIZE
) {
871 return NT_STATUS_INVALID_PARAMETER
;
874 tf
= (uint8_t *)vector
[0].iov_base
;
876 if (!smb2_signing_key_valid(decryption_key
)) {
877 DBG_WARNING("No decryption key for SMB2 signing\n");
878 return NT_STATUS_ACCESS_DENIED
;
880 cipher_id
= decryption_key
->cipher_algo_id
;
882 a_total
= SMB2_TF_HDR_SIZE
- SMB2_TF_NONCE
;
884 m_total
= iov_buflen(&vector
[1], count
-1);
886 return NT_STATUS_BUFFER_TOO_SMALL
;
889 flags
= SVAL(tf
, SMB2_TF_FLAGS
);
890 msg_size
= IVAL(tf
, SMB2_TF_MSG_SIZE
);
892 if (flags
!= SMB2_TF_FLAGS_ENCRYPTED
) {
893 return NT_STATUS_ACCESS_DENIED
;
896 if (msg_size
!= m_total
) {
897 return NT_STATUS_INTERNAL_ERROR
;
901 case SMB2_ENCRYPTION_AES128_CCM
:
902 algo
= GNUTLS_CIPHER_AES_128_CCM
;
903 iv_size
= SMB2_AES_128_CCM_NONCE_SIZE
;
905 case SMB2_ENCRYPTION_AES128_GCM
:
906 algo
= GNUTLS_CIPHER_AES_128_GCM
;
907 iv_size
= gnutls_cipher_get_iv_size(algo
);
909 case SMB2_ENCRYPTION_AES256_CCM
:
910 algo
= GNUTLS_CIPHER_AES_256_CCM
;
911 iv_size
= SMB2_AES_128_CCM_NONCE_SIZE
;
913 case SMB2_ENCRYPTION_AES256_GCM
:
914 algo
= GNUTLS_CIPHER_AES_256_GCM
;
915 iv_size
= gnutls_cipher_get_iv_size(algo
);
918 return NT_STATUS_INVALID_PARAMETER
;
921 key_size
= gnutls_cipher_get_key_size(algo
);
922 tag_size
= gnutls_cipher_get_tag_size(algo
);
924 if (key_size
!= decryption_key
->blob
.length
) {
925 return NT_STATUS_INTERNAL_ERROR
;
928 if (tag_size
!= 16) {
929 return NT_STATUS_INTERNAL_ERROR
;
932 key
= (gnutls_datum_t
) {
933 .data
= decryption_key
->blob
.data
,
937 iv
= (gnutls_datum_t
) {
938 .data
= tf
+ SMB2_TF_NONCE
,
942 if (decryption_key
->cipher_hnd
== NULL
) {
943 rc
= gnutls_aead_cipher_init(&decryption_key
->cipher_hnd
,
947 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
952 /* gnutls_aead_cipher_encryptv2() has a bug in version 3.6.10 */
953 #if defined(HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2)
955 giovec_t auth_iov
[1];
957 auth_iov
[0] = (giovec_t
) {
958 .iov_base
= tf
+ SMB2_TF_NONCE
,
962 rc
= gnutls_aead_cipher_decryptv2(decryption_key
->cipher_hnd
,
969 tf
+ SMB2_TF_SIGNATURE
,
972 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
976 #else /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
978 size_t ctext_size
= m_total
+ tag_size
;
979 uint8_t *ctext
= NULL
;
980 size_t ptext_size
= m_total
;
981 uint8_t *ptext
= NULL
;
984 TALLOC_CTX
*tmp_ctx
= NULL
;
987 * If we come from python bindings, we don't have a stackframe
988 * around, so use the NULL context.
990 * This is fine as we make sure we free the memory.
992 if (talloc_stackframe_exists()) {
993 tmp_ctx
= talloc_tos();
996 /* GnuTLS doesn't have a iovec API for decryption yet */
998 ptext
= talloc_size(tmp_ctx
, ptext_size
);
1000 status
= NT_STATUS_NO_MEMORY
;
1004 ctext
= talloc_size(tmp_ctx
, ctext_size
);
1005 if (ctext
== NULL
) {
1007 status
= NT_STATUS_NO_MEMORY
;
1012 for (i
= 1; i
< count
; i
++) {
1017 len
+= vector
[i
].iov_len
;
1019 if (len
!= m_total
) {
1022 status
= NT_STATUS_INTERNAL_ERROR
;
1027 tf
+ SMB2_TF_SIGNATURE
,
1030 /* This function will verify the tag */
1031 rc
= gnutls_aead_cipher_decrypt(decryption_key
->cipher_hnd
,
1041 if (rc
< 0 || ptext_size
!= m_total
) {
1044 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
1049 for (i
= 1; i
< count
; i
++) {
1050 memcpy(vector
[i
].iov_base
,
1054 len
+= vector
[i
].iov_len
;
1060 #endif /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
1062 DBG_INFO("Decrypted SMB2 message\n");
1064 status
= NT_STATUS_OK
;