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 #include "lib/crypto/gnutls_helpers.h"
32 void smb2_signing_derivations_fill_const_stack(struct smb2_signing_derivations
*ds
,
33 enum protocol_types protocol
,
34 const DATA_BLOB preauth_hash
)
36 *ds
= (struct smb2_signing_derivations
) { .signing
= NULL
, };
38 if (protocol
>= PROTOCOL_SMB3_11
) {
39 struct smb2_signing_derivation
*d
= NULL
;
41 SMB_ASSERT(preauth_hash
.length
!= 0);
45 d
->label
= data_blob_string_const_null("SMBSigningKey");
46 d
->context
= preauth_hash
;
48 d
= &ds
->__cipher_c2s
;
50 d
->label
= data_blob_string_const_null("SMBC2SCipherKey");
51 d
->context
= preauth_hash
;
53 d
= &ds
->__cipher_s2c
;
55 d
->label
= data_blob_string_const_null("SMBS2CCipherKey");
56 d
->context
= preauth_hash
;
58 d
= &ds
->__application
;
60 d
->label
= data_blob_string_const_null("SMBAppKey");
61 d
->context
= preauth_hash
;
63 } else if (protocol
>= PROTOCOL_SMB3_00
) {
64 struct smb2_signing_derivation
*d
= NULL
;
68 d
->label
= data_blob_string_const_null("SMB2AESCMAC");
69 d
->context
= data_blob_string_const_null("SmbSign");
71 d
= &ds
->__cipher_c2s
;
73 d
->label
= data_blob_string_const_null("SMB2AESCCM");
74 d
->context
= data_blob_string_const_null("ServerIn ");
76 d
= &ds
->__cipher_s2c
;
78 d
->label
= data_blob_string_const_null("SMB2AESCCM");
79 d
->context
= data_blob_string_const_null("ServerOut");
81 d
= &ds
->__application
;
83 d
->label
= data_blob_string_const_null("SMB2APP");
84 d
->context
= data_blob_string_const_null("SmbRpc");
88 static int smb2_signing_key_destructor(struct smb2_signing_key
*key
)
90 if (key
->hmac_hnd
!= NULL
) {
91 gnutls_hmac_deinit(key
->hmac_hnd
, NULL
);
95 if (key
->cipher_hnd
!= NULL
) {
96 gnutls_aead_cipher_deinit(key
->cipher_hnd
);
97 key
->cipher_hnd
= NULL
;
103 NTSTATUS
smb2_signing_key_copy(TALLOC_CTX
*mem_ctx
,
104 const struct smb2_signing_key
*src
,
105 struct smb2_signing_key
**_dst
)
107 struct smb2_signing_key
*dst
= NULL
;
109 dst
= talloc_zero(mem_ctx
, struct smb2_signing_key
);
111 return NT_STATUS_NO_MEMORY
;
113 talloc_set_destructor(dst
, smb2_signing_key_destructor
);
115 dst
->sign_algo_id
= src
->sign_algo_id
;
116 dst
->cipher_algo_id
= src
->cipher_algo_id
;
118 if (src
->blob
.length
== 0) {
123 dst
->blob
= data_blob_talloc_zero(dst
, src
->blob
.length
);
124 if (dst
->blob
.length
== 0) {
126 return NT_STATUS_NO_MEMORY
;
128 talloc_keep_secret(dst
->blob
.data
);
129 memcpy(dst
->blob
.data
, src
->blob
.data
, dst
->blob
.length
);
135 static NTSTATUS
smb2_signing_key_create(TALLOC_CTX
*mem_ctx
,
136 uint16_t sign_algo_id
,
137 uint16_t cipher_algo_id
,
138 const DATA_BLOB
*master_key
,
139 const struct smb2_signing_derivation
*d
,
140 struct smb2_signing_key
**_key
)
142 struct smb2_signing_key
*key
= NULL
;
143 size_t in_key_length
= 16;
144 size_t out_key_length
= 16;
147 if (sign_algo_id
!= SMB2_SIGNING_INVALID_ALGO
) {
148 SMB_ASSERT(cipher_algo_id
== SMB2_ENCRYPTION_INVALID_ALGO
);
150 if (cipher_algo_id
!= SMB2_ENCRYPTION_INVALID_ALGO
) {
151 SMB_ASSERT(sign_algo_id
== SMB2_SIGNING_INVALID_ALGO
);
154 key
= talloc_zero(mem_ctx
, struct smb2_signing_key
);
156 return NT_STATUS_NO_MEMORY
;
158 talloc_set_destructor(key
, smb2_signing_key_destructor
);
160 key
->sign_algo_id
= sign_algo_id
;
161 key
->cipher_algo_id
= cipher_algo_id
;
163 if (master_key
== NULL
) {
164 SMB_ASSERT(d
== NULL
);
171 * Per default use the full key.
173 in_key_length
= out_key_length
= master_key
->length
;
174 switch (sign_algo_id
) {
175 case SMB2_SIGNING_INVALID_ALGO
:
177 * This means we're processing cipher_algo_id below
180 case SMB2_SIGNING_MD5_SMB1
:
181 SMB_ASSERT(d
== NULL
);
183 case SMB2_SIGNING_HMAC_SHA256
:
184 case SMB2_SIGNING_AES128_CMAC
:
185 case SMB2_SIGNING_AES128_GMAC
:
187 * signing keys are padded or truncated to
190 * Even with master_key->length = 0,
191 * we need to use 16 zeros.
193 in_key_length
= out_key_length
= 16;
196 DBG_ERR("sign_algo_id[%u] not supported\n", sign_algo_id
);
197 return NT_STATUS_HMAC_NOT_SUPPORTED
;
199 switch (cipher_algo_id
) {
200 case SMB2_ENCRYPTION_INVALID_ALGO
:
202 * This means we're processing sign_algo_id above
205 case SMB2_ENCRYPTION_NONE
:
207 * No encryption negotiated.
210 case SMB2_ENCRYPTION_AES128_CCM
:
211 case SMB2_ENCRYPTION_AES128_GCM
:
213 * encryption keys are padded or truncated to
216 if (master_key
->length
== 0) {
217 DBG_ERR("cipher_algo_id[%u] without key\n",
219 return NT_STATUS_NO_USER_SESSION_KEY
;
221 in_key_length
= out_key_length
= 16;
223 case SMB2_ENCRYPTION_AES256_CCM
:
224 case SMB2_ENCRYPTION_AES256_GCM
:
226 * AES256 uses the available input and
227 * generated a 32 byte encryption key.
229 if (master_key
->length
== 0) {
230 DBG_ERR("cipher_algo_id[%u] without key\n",
232 return NT_STATUS_NO_USER_SESSION_KEY
;
237 DBG_ERR("cipher_algo_id[%u] not supported\n", cipher_algo_id
);
238 return NT_STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG
;
241 if (out_key_length
== 0) {
246 key
->blob
= data_blob_talloc_zero(key
, out_key_length
);
247 if (key
->blob
.length
== 0) {
249 return NT_STATUS_NO_MEMORY
;
251 talloc_keep_secret(key
->blob
.data
);
252 memcpy(key
->blob
.data
,
254 MIN(key
->blob
.length
, master_key
->length
));
261 status
= samba_gnutls_sp800_108_derive_key(key
->blob
.data
,
272 if (!NT_STATUS_IS_OK(status
)) {
281 NTSTATUS
smb2_signing_key_sign_create(TALLOC_CTX
*mem_ctx
,
282 uint16_t sign_algo_id
,
283 const DATA_BLOB
*master_key
,
284 const struct smb2_signing_derivation
*d
,
285 struct smb2_signing_key
**_key
)
287 return smb2_signing_key_create(mem_ctx
,
289 SMB2_ENCRYPTION_INVALID_ALGO
,
295 NTSTATUS
smb2_signing_key_cipher_create(TALLOC_CTX
*mem_ctx
,
296 uint16_t cipher_algo_id
,
297 const DATA_BLOB
*master_key
,
298 const struct smb2_signing_derivation
*d
,
299 struct smb2_signing_key
**_key
)
301 return smb2_signing_key_create(mem_ctx
,
302 SMB2_SIGNING_INVALID_ALGO
,
309 bool smb2_signing_key_valid(const struct smb2_signing_key
*key
)
315 if (key
->blob
.length
== 0 || key
->blob
.data
== NULL
) {
322 static NTSTATUS
smb2_signing_gmac(gnutls_aead_cipher_hd_t cipher_hnd
,
323 const uint8_t *iv
, size_t iv_size
,
324 const giovec_t
*auth_iov
, uint8_t auth_iovcnt
,
325 uint8_t *tag
, size_t _tag_size
)
327 size_t tag_size
= _tag_size
;
330 rc
= gnutls_aead_cipher_encryptv2(cipher_hnd
,
332 auth_iov
, auth_iovcnt
,
336 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HMAC_NOT_SUPPORTED
);
342 static NTSTATUS
smb2_signing_calc_signature(struct smb2_signing_key
*signing_key
,
343 uint16_t sign_algo_id
,
344 const struct iovec
*vector
,
346 uint8_t signature
[16])
348 const uint8_t *hdr
= (uint8_t *)vector
[0].iov_base
;
352 static const uint8_t zero_sig
[16] = { 0, };
353 gnutls_mac_algorithm_t hmac_algo
= GNUTLS_MAC_UNKNOWN
;
360 * - (optional) SMB2 BODY DYN
361 * - (optional) PADDING
363 SMB_ASSERT(count
>= 2);
364 SMB_ASSERT(vector
[0].iov_len
== SMB2_HDR_BODY
);
365 SMB_ASSERT(count
<= 4);
367 opcode
= SVAL(hdr
, SMB2_HDR_OPCODE
);
368 flags
= IVAL(hdr
, SMB2_HDR_FLAGS
);
369 if (flags
& SMB2_HDR_FLAG_REDIRECT
) {
370 NTSTATUS pdu_status
= NT_STATUS(IVAL(hdr
, SMB2_HDR_STATUS
));
371 if (NT_STATUS_EQUAL(pdu_status
, NT_STATUS_PENDING
)) {
372 DBG_ERR("opcode[%u] NT_STATUS_PENDING\n", opcode
);
373 return NT_STATUS_INTERNAL_ERROR
;
375 if (opcode
== SMB2_OP_CANCEL
) {
376 DBG_ERR("SMB2_OP_CANCEL response should not be signed\n");
377 return NT_STATUS_INTERNAL_ERROR
;
380 msg_id
= BVAL(hdr
, SMB2_HDR_MESSAGE_ID
);
382 if (opcode
!= SMB2_OP_CANCEL
||
383 sign_algo_id
>= SMB2_SIGNING_AES128_GMAC
)
385 DBG_ERR("opcode[%u] msg_id == 0\n", opcode
);
386 return NT_STATUS_INTERNAL_ERROR
;
389 * Legacy algorithms allow MID 0
390 * for cancel requests
393 if (msg_id
== UINT64_MAX
) {
394 DBG_ERR("opcode[%u] msg_id == UINT64_MAX\n", opcode
);
395 return NT_STATUS_INTERNAL_ERROR
;
398 switch (sign_algo_id
) {
399 case SMB2_SIGNING_AES128_GMAC
: {
400 gnutls_cipher_algorithm_t algo
= GNUTLS_CIPHER_AES_128_GCM
;
401 uint32_t key_size
= gnutls_cipher_get_key_size(algo
);
402 uint32_t iv_size
= gnutls_cipher_get_iv_size(algo
);
403 size_t tag_size
= gnutls_cipher_get_tag_size(algo
);
404 gnutls_datum_t key
= {
405 .data
= signing_key
->blob
.data
,
406 .size
= MIN(signing_key
->blob
.length
, key_size
),
408 uint64_t high_bits
= 0;
409 uint8_t iv
[AES_BLOCK_SIZE
] = {0};
410 giovec_t auth_iov
[count
+1];
411 size_t auth_iovcnt
= 0;
415 high_bits
= flags
& SMB2_HDR_FLAG_REDIRECT
;
416 if (opcode
== SMB2_OP_CANCEL
) {
417 high_bits
|= SMB2_HDR_FLAG_ASYNC
;
419 SBVAL(iv
, 0, msg_id
);
420 SBVAL(iv
, 8, high_bits
);
422 if (signing_key
->cipher_hnd
== NULL
) {
423 rc
= gnutls_aead_cipher_init(&signing_key
->cipher_hnd
,
427 return gnutls_error_to_ntstatus(rc
,
428 NT_STATUS_HMAC_NOT_SUPPORTED
);
432 SMB_ASSERT(key_size
== 16);
433 SMB_ASSERT(iv_size
== 12);
434 SMB_ASSERT(tag_size
== 16);
436 auth_iov
[auth_iovcnt
++] = (giovec_t
) {
437 .iov_base
= discard_const_p(uint8_t, hdr
),
438 .iov_len
= SMB2_HDR_SIGNATURE
,
440 auth_iov
[auth_iovcnt
++] = (giovec_t
) {
441 .iov_base
= discard_const_p(uint8_t, zero_sig
),
444 for (i
=1; i
< count
; i
++) {
445 auth_iov
[auth_iovcnt
++] = (giovec_t
) {
446 .iov_base
= discard_const_p(uint8_t, vector
[i
].iov_base
),
447 .iov_len
= vector
[i
].iov_len
,
451 status
= smb2_signing_gmac(signing_key
->cipher_hnd
,
458 if (!NT_STATUS_IS_OK(status
)) {
465 case SMB2_SIGNING_AES128_CMAC
:
466 hmac_algo
= GNUTLS_MAC_AES_CMAC_128
;
468 case SMB2_SIGNING_HMAC_SHA256
:
469 hmac_algo
= GNUTLS_MAC_SHA256
;
473 return NT_STATUS_HMAC_NOT_SUPPORTED
;
476 if (hmac_algo
!= GNUTLS_MAC_UNKNOWN
) {
477 uint8_t digest
[gnutls_hmac_get_len(hmac_algo
)];
478 gnutls_datum_t key
= {
479 .data
= signing_key
->blob
.data
,
480 .size
= MIN(signing_key
->blob
.length
, 16),
484 if (signing_key
->hmac_hnd
== NULL
) {
485 rc
= gnutls_hmac_init(&signing_key
->hmac_hnd
,
490 return gnutls_error_to_ntstatus(rc
,
491 NT_STATUS_HMAC_NOT_SUPPORTED
);
495 rc
= gnutls_hmac(signing_key
->hmac_hnd
, hdr
, SMB2_HDR_SIGNATURE
);
497 return gnutls_error_to_ntstatus(rc
,
498 NT_STATUS_HMAC_NOT_SUPPORTED
);
500 rc
= gnutls_hmac(signing_key
->hmac_hnd
, zero_sig
, 16);
502 return gnutls_error_to_ntstatus(rc
,
503 NT_STATUS_HMAC_NOT_SUPPORTED
);
506 for (i
= 1; i
< count
; i
++) {
507 rc
= gnutls_hmac(signing_key
->hmac_hnd
,
511 return gnutls_error_to_ntstatus(rc
,
512 NT_STATUS_HMAC_NOT_SUPPORTED
);
515 gnutls_hmac_output(signing_key
->hmac_hnd
, digest
);
516 memcpy(signature
, digest
, 16);
521 return NT_STATUS_HMAC_NOT_SUPPORTED
;
524 NTSTATUS
smb2_signing_sign_pdu(struct smb2_signing_key
*signing_key
,
525 struct iovec
*vector
,
528 uint16_t sign_algo_id
;
538 * - (optional) SMB2 BODY DYN
539 * - (optional) PADDING
541 SMB_ASSERT(count
>= 2);
542 SMB_ASSERT(vector
[0].iov_len
== SMB2_HDR_BODY
);
543 SMB_ASSERT(count
<= 4);
545 hdr
= (uint8_t *)vector
[0].iov_base
;
547 session_id
= BVAL(hdr
, SMB2_HDR_SESSION_ID
);
548 if (session_id
== 0) {
550 * do not sign messages with a zero session_id.
551 * See MS-SMB2 3.2.4.1.1
556 if (!smb2_signing_key_valid(signing_key
)) {
557 DBG_WARNING("No signing key for SMB2 signing\n");
558 return NT_STATUS_ACCESS_DENIED
;
561 memset(hdr
+ SMB2_HDR_SIGNATURE
, 0, 16);
563 SIVAL(hdr
, SMB2_HDR_FLAGS
, IVAL(hdr
, SMB2_HDR_FLAGS
) | SMB2_HDR_FLAG_SIGNED
);
565 sign_algo_id
= signing_key
->sign_algo_id
;
567 status
= smb2_signing_calc_signature(signing_key
,
572 if (!NT_STATUS_IS_OK(status
)) {
573 DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
574 (unsigned)sign_algo_id
, nt_errstr(status
));
575 if (NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_ERROR
)) {
576 smb_panic(__location__
);
581 DEBUG(5,("signed SMB2 message (sign_algo_id=%u)\n",
582 (unsigned)sign_algo_id
));
584 memcpy(hdr
+ SMB2_HDR_SIGNATURE
, res
, 16);
589 NTSTATUS
smb2_signing_check_pdu(struct smb2_signing_key
*signing_key
,
590 const struct iovec
*vector
,
593 uint16_t sign_algo_id
;
604 * - (optional) SMB2 BODY DYN
605 * - (optional) PADDING
607 SMB_ASSERT(count
>= 2);
608 SMB_ASSERT(vector
[0].iov_len
== SMB2_HDR_BODY
);
609 SMB_ASSERT(count
<= 4);
611 hdr
= (const uint8_t *)vector
[0].iov_base
;
613 session_id
= BVAL(hdr
, SMB2_HDR_SESSION_ID
);
614 if (session_id
== 0) {
616 * do not sign messages with a zero session_id.
617 * See MS-SMB2 3.2.4.1.1
622 if (!smb2_signing_key_valid(signing_key
)) {
623 /* we don't have the session key yet */
627 sig
= hdr
+SMB2_HDR_SIGNATURE
;
629 sign_algo_id
= signing_key
->sign_algo_id
;
631 status
= smb2_signing_calc_signature(signing_key
,
636 if (!NT_STATUS_IS_OK(status
)) {
637 DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
638 (unsigned)sign_algo_id
, nt_errstr(status
));
639 if (NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_ERROR
)) {
640 status
= NT_STATUS_ACCESS_DENIED
;
645 if (!mem_equal_const_time(res
, sig
, 16)) {
646 DEBUG(0,("Bad SMB2 (sign_algo_id=%u) signature for message\n",
647 (unsigned)sign_algo_id
));
648 dump_data(0, sig
, 16);
649 dump_data(0, res
, 16);
650 return NT_STATUS_ACCESS_DENIED
;
656 NTSTATUS
smb2_signing_encrypt_pdu(struct smb2_signing_key
*encryption_key
,
657 struct iovec
*vector
,
660 bool use_encryptv2
= false;
665 uint32_t iv_size
= 0;
666 uint32_t key_size
= 0;
668 gnutls_cipher_algorithm_t algo
= 0;
675 return NT_STATUS_INVALID_PARAMETER
;
678 if (vector
[0].iov_len
!= SMB2_TF_HDR_SIZE
) {
679 return NT_STATUS_INVALID_PARAMETER
;
682 tf
= (uint8_t *)vector
[0].iov_base
;
684 if (!smb2_signing_key_valid(encryption_key
)) {
685 DBG_WARNING("No encryption key for SMB2 signing\n");
686 return NT_STATUS_ACCESS_DENIED
;
688 cipher_id
= encryption_key
->cipher_algo_id
;
690 a_total
= SMB2_TF_HDR_SIZE
- SMB2_TF_NONCE
;
692 m_total
= iov_buflen(&vector
[1], count
-1);
694 return NT_STATUS_BUFFER_TOO_SMALL
;
697 SSVAL(tf
, SMB2_TF_FLAGS
, SMB2_TF_FLAGS_ENCRYPTED
);
698 SIVAL(tf
, SMB2_TF_MSG_SIZE
, m_total
);
701 case SMB2_ENCRYPTION_AES128_CCM
:
702 algo
= GNUTLS_CIPHER_AES_128_CCM
;
703 iv_size
= SMB2_AES_128_CCM_NONCE_SIZE
;
704 #ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
705 use_encryptv2
= true;
708 case SMB2_ENCRYPTION_AES128_GCM
:
709 algo
= GNUTLS_CIPHER_AES_128_GCM
;
710 iv_size
= gnutls_cipher_get_iv_size(algo
);
711 use_encryptv2
= true;
713 case SMB2_ENCRYPTION_AES256_CCM
:
714 algo
= GNUTLS_CIPHER_AES_256_CCM
;
715 iv_size
= SMB2_AES_128_CCM_NONCE_SIZE
;
716 #ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
717 use_encryptv2
= true;
720 case SMB2_ENCRYPTION_AES256_GCM
:
721 algo
= GNUTLS_CIPHER_AES_256_GCM
;
722 iv_size
= gnutls_cipher_get_iv_size(algo
);
723 use_encryptv2
= true;
726 return NT_STATUS_INVALID_PARAMETER
;
729 key_size
= gnutls_cipher_get_key_size(algo
);
730 tag_size
= gnutls_cipher_get_tag_size(algo
);
732 if (key_size
!= encryption_key
->blob
.length
) {
733 return NT_STATUS_INTERNAL_ERROR
;
736 if (tag_size
!= 16) {
737 return NT_STATUS_INTERNAL_ERROR
;
740 key
= (gnutls_datum_t
) {
741 .data
= encryption_key
->blob
.data
,
745 iv
= (gnutls_datum_t
) {
746 .data
= tf
+ SMB2_TF_NONCE
,
750 if (encryption_key
->cipher_hnd
== NULL
) {
751 rc
= gnutls_aead_cipher_init(&encryption_key
->cipher_hnd
,
755 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
760 memset(tf
+ SMB2_TF_NONCE
+ iv_size
,
765 uint8_t tag
[tag_size
];
766 giovec_t auth_iov
[1];
768 auth_iov
[0] = (giovec_t
) {
769 .iov_base
= tf
+ SMB2_TF_NONCE
,
773 rc
= gnutls_aead_cipher_encryptv2(encryption_key
->cipher_hnd
,
783 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
787 memcpy(tf
+ SMB2_TF_SIGNATURE
, tag
, tag_size
);
790 size_t ptext_size
= m_total
;
791 uint8_t *ptext
= NULL
;
792 size_t ctext_size
= m_total
+ tag_size
;
793 uint8_t *ctext
= NULL
;
796 TALLOC_CTX
*tmp_ctx
= NULL
;
799 * If we come from python bindings, we don't have a stackframe
800 * around, so use the NULL context.
802 * This is fine as we make sure we free the memory.
804 if (talloc_stackframe_exists()) {
805 tmp_ctx
= talloc_tos();
808 ptext
= talloc_size(tmp_ctx
, ptext_size
);
810 status
= NT_STATUS_NO_MEMORY
;
814 ctext
= talloc_size(tmp_ctx
, ctext_size
);
817 status
= NT_STATUS_NO_MEMORY
;
821 for (i
= 1; i
< count
; i
++) {
822 if (vector
[i
].iov_base
!= NULL
) {
828 len
+= vector
[i
].iov_len
;
829 if (len
> ptext_size
) {
832 status
= NT_STATUS_INTERNAL_ERROR
;
837 rc
= gnutls_aead_cipher_encrypt(encryption_key
->cipher_hnd
,
847 if (rc
< 0 || ctext_size
!= m_total
+ tag_size
) {
850 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
855 for (i
= 1; i
< count
; i
++) {
856 if (vector
[i
].iov_base
!= NULL
) {
857 memcpy(vector
[i
].iov_base
,
862 len
+= vector
[i
].iov_len
;
865 memcpy(tf
+ SMB2_TF_SIGNATURE
, ctext
+ m_total
, tag_size
);
871 DBG_INFO("Encrypted SMB2 message\n");
873 status
= NT_STATUS_OK
;
878 NTSTATUS
smb2_signing_decrypt_pdu(struct smb2_signing_key
*decryption_key
,
879 struct iovec
*vector
,
882 bool use_encryptv2
= false;
888 uint32_t msg_size
= 0;
889 uint32_t iv_size
= 0;
890 uint32_t key_size
= 0;
892 gnutls_cipher_algorithm_t algo
= 0;
899 return NT_STATUS_INVALID_PARAMETER
;
902 if (vector
[0].iov_len
!= SMB2_TF_HDR_SIZE
) {
903 return NT_STATUS_INVALID_PARAMETER
;
906 tf
= (uint8_t *)vector
[0].iov_base
;
908 if (!smb2_signing_key_valid(decryption_key
)) {
909 DBG_WARNING("No decryption key for SMB2 signing\n");
910 return NT_STATUS_ACCESS_DENIED
;
912 cipher_id
= decryption_key
->cipher_algo_id
;
914 a_total
= SMB2_TF_HDR_SIZE
- SMB2_TF_NONCE
;
916 m_total
= iov_buflen(&vector
[1], count
-1);
918 return NT_STATUS_BUFFER_TOO_SMALL
;
921 flags
= SVAL(tf
, SMB2_TF_FLAGS
);
922 msg_size
= IVAL(tf
, SMB2_TF_MSG_SIZE
);
924 if (flags
!= SMB2_TF_FLAGS_ENCRYPTED
) {
925 return NT_STATUS_ACCESS_DENIED
;
928 if (msg_size
!= m_total
) {
929 return NT_STATUS_INTERNAL_ERROR
;
933 case SMB2_ENCRYPTION_AES128_CCM
:
934 algo
= GNUTLS_CIPHER_AES_128_CCM
;
935 iv_size
= SMB2_AES_128_CCM_NONCE_SIZE
;
936 #ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
937 use_encryptv2
= true;
940 case SMB2_ENCRYPTION_AES128_GCM
:
941 algo
= GNUTLS_CIPHER_AES_128_GCM
;
942 iv_size
= gnutls_cipher_get_iv_size(algo
);
943 use_encryptv2
= true;
945 case SMB2_ENCRYPTION_AES256_CCM
:
946 algo
= GNUTLS_CIPHER_AES_256_CCM
;
947 iv_size
= SMB2_AES_128_CCM_NONCE_SIZE
;
948 #ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
949 use_encryptv2
= true;
952 case SMB2_ENCRYPTION_AES256_GCM
:
953 algo
= GNUTLS_CIPHER_AES_256_GCM
;
954 iv_size
= gnutls_cipher_get_iv_size(algo
);
955 use_encryptv2
= true;
958 return NT_STATUS_INVALID_PARAMETER
;
961 key_size
= gnutls_cipher_get_key_size(algo
);
962 tag_size
= gnutls_cipher_get_tag_size(algo
);
964 if (key_size
!= decryption_key
->blob
.length
) {
965 return NT_STATUS_INTERNAL_ERROR
;
968 if (tag_size
!= 16) {
969 return NT_STATUS_INTERNAL_ERROR
;
972 key
= (gnutls_datum_t
) {
973 .data
= decryption_key
->blob
.data
,
977 iv
= (gnutls_datum_t
) {
978 .data
= tf
+ SMB2_TF_NONCE
,
982 if (decryption_key
->cipher_hnd
== NULL
) {
983 rc
= gnutls_aead_cipher_init(&decryption_key
->cipher_hnd
,
987 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
993 giovec_t auth_iov
[1];
995 auth_iov
[0] = (giovec_t
) {
996 .iov_base
= tf
+ SMB2_TF_NONCE
,
1000 rc
= gnutls_aead_cipher_decryptv2(decryption_key
->cipher_hnd
,
1007 tf
+ SMB2_TF_SIGNATURE
,
1010 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
1015 size_t ctext_size
= m_total
+ tag_size
;
1016 uint8_t *ctext
= NULL
;
1017 size_t ptext_size
= m_total
;
1018 uint8_t *ptext
= NULL
;
1021 TALLOC_CTX
*tmp_ctx
= NULL
;
1024 * If we come from python bindings, we don't have a stackframe
1025 * around, so use the NULL context.
1027 * This is fine as we make sure we free the memory.
1029 if (talloc_stackframe_exists()) {
1030 tmp_ctx
= talloc_tos();
1033 /* GnuTLS doesn't have a iovec API for decryption yet */
1035 ptext
= talloc_size(tmp_ctx
, ptext_size
);
1036 if (ptext
== NULL
) {
1037 status
= NT_STATUS_NO_MEMORY
;
1041 ctext
= talloc_size(tmp_ctx
, ctext_size
);
1042 if (ctext
== NULL
) {
1044 status
= NT_STATUS_NO_MEMORY
;
1049 for (i
= 1; i
< count
; i
++) {
1054 len
+= vector
[i
].iov_len
;
1056 if (len
!= m_total
) {
1059 status
= NT_STATUS_INTERNAL_ERROR
;
1064 tf
+ SMB2_TF_SIGNATURE
,
1067 /* This function will verify the tag */
1068 rc
= gnutls_aead_cipher_decrypt(decryption_key
->cipher_hnd
,
1081 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
1084 if (ptext_size
!= m_total
) {
1087 rc
= GNUTLS_E_SHORT_MEMORY_BUFFER
;
1088 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_INTERNAL_ERROR
);
1093 for (i
= 1; i
< count
; i
++) {
1094 memcpy(vector
[i
].iov_base
,
1098 len
+= vector
[i
].iov_len
;
1105 DBG_INFO("Decrypted SMB2 message\n");
1107 status
= NT_STATUS_OK
;