libcli/smb: no longer pass protocol to smb2_signing_{encrypt,decrypt}_pdu()
[Samba.git] / libcli / smb / smb2_signing.c
bloba4effb8b31e0c4e996914058c42d5cc27f832db8
1 /*
2 Unix SMB/CIFS implementation.
3 SMB2 signing
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/>.
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"
30 #ifndef HAVE_GNUTLS_AES_CMAC
31 #include "lib/crypto/aes.h"
32 #include "lib/crypto/aes_cmac_128.h"
33 #endif
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_10) {
44 struct smb2_signing_derivation *d = NULL;
46 SMB_ASSERT(preauth_hash.length != 0);
48 d = &ds->__signing;
49 ds->signing = d;
50 d->label = data_blob_string_const_null("SMBSigningKey");
51 d->context = preauth_hash;
53 d = &ds->__cipher_c2s;
54 ds->cipher_c2s = d;
55 d->label = data_blob_string_const_null("SMBC2SCipherKey");
56 d->context = preauth_hash;
58 d = &ds->__cipher_s2c;
59 ds->cipher_s2c = d;
60 d->label = data_blob_string_const_null("SMBS2CCipherKey");
61 d->context = preauth_hash;
63 d = &ds->__application;
64 ds->application = d;
65 d->label = data_blob_string_const_null("SMBAppKey");
66 d->context = preauth_hash;
68 } else if (protocol >= PROTOCOL_SMB2_24) {
69 struct smb2_signing_derivation *d = NULL;
71 d = &ds->__signing;
72 ds->signing = d;
73 d->label = data_blob_string_const_null("SMB2AESCMAC");
74 d->context = data_blob_string_const_null("SmbSign");
76 d = &ds->__cipher_c2s;
77 ds->cipher_c2s = d;
78 d->label = data_blob_string_const_null("SMB2AESCCM");
79 d->context = data_blob_string_const_null("ServerIn ");
81 d = &ds->__cipher_s2c;
82 ds->cipher_s2c = d;
83 d->label = data_blob_string_const_null("SMB2AESCCM");
84 d->context = data_blob_string_const_null("ServerOut");
86 d = &ds->__application;
87 ds->application = d;
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);
97 key->hmac_hnd = NULL;
100 if (key->cipher_hnd != NULL) {
101 gnutls_aead_cipher_deinit(key->cipher_hnd);
102 key->cipher_hnd = NULL;
105 return 0;
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);
115 if (dst == NULL) {
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) {
124 *_dst = dst;
125 return NT_STATUS_OK;
128 dst->blob = data_blob_talloc_zero(dst, src->blob.length);
129 if (dst->blob.length == 0) {
130 TALLOC_FREE(dst);
131 return NT_STATUS_NO_MEMORY;
133 talloc_keep_secret(dst->blob.data);
134 memcpy(dst->blob.data, src->blob.data, dst->blob.length);
136 *_dst = dst;
137 return NT_STATUS_OK;
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;
150 NTSTATUS status;
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);
160 if (key == NULL) {
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);
171 *_key = key;
172 return NT_STATUS_OK;
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
184 break;
185 case SMB2_SIGNING_MD5_SMB1:
186 SMB_ASSERT(d == NULL);
187 break;
188 case SMB2_SIGNING_HMAC_SHA256:
189 case SMB2_SIGNING_AES128_CMAC:
191 * signing keys are padded or truncated to
192 * 16 bytes.
194 * Even with master_key->length = 0,
195 * we need to use 16 zeros.
197 in_key_length = out_key_length = 16;
198 break;
199 default:
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
208 break;
209 case SMB2_ENCRYPTION_NONE:
211 * No encryption negotiated.
213 break;
214 case SMB2_ENCRYPTION_AES128_CCM:
215 case SMB2_ENCRYPTION_AES128_GCM:
217 * encryption keys are padded or truncated to
218 * 16 bytes.
220 if (master_key->length == 0) {
221 DBG_ERR("cipher_algo_id[%u] without key\n",
222 cipher_algo_id);
223 return NT_STATUS_NO_USER_SESSION_KEY;
225 in_key_length = out_key_length = 16;
226 break;
227 default:
228 DBG_ERR("cipher_algo_id[%u] not supported\n", cipher_algo_id);
229 return NT_STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG;
232 if (out_key_length == 0) {
233 *_key = key;
234 return NT_STATUS_OK;
237 key->blob = data_blob_talloc_zero(key, out_key_length);
238 if (key->blob.length == 0) {
239 TALLOC_FREE(key);
240 return NT_STATUS_NO_MEMORY;
242 talloc_keep_secret(key->blob.data);
243 memcpy(key->blob.data,
244 master_key->data,
245 MIN(key->blob.length, master_key->length));
247 if (d == NULL) {
248 *_key = key;
249 return NT_STATUS_OK;
252 status = smb2_key_derivation(key->blob.data, in_key_length,
253 d->label.data, d->label.length,
254 d->context.data, d->context.length,
255 key->blob.data, out_key_length);
256 if (!NT_STATUS_IS_OK(status)) {
257 TALLOC_FREE(key);
258 return status;
261 *_key = key;
262 return NT_STATUS_OK;
265 NTSTATUS smb2_signing_key_sign_create(TALLOC_CTX *mem_ctx,
266 uint16_t sign_algo_id,
267 const DATA_BLOB *master_key,
268 const struct smb2_signing_derivation *d,
269 struct smb2_signing_key **_key)
271 return smb2_signing_key_create(mem_ctx,
272 sign_algo_id,
273 SMB2_ENCRYPTION_INVALID_ALGO,
274 master_key,
276 _key);
279 NTSTATUS smb2_signing_key_cipher_create(TALLOC_CTX *mem_ctx,
280 uint16_t cipher_algo_id,
281 const DATA_BLOB *master_key,
282 const struct smb2_signing_derivation *d,
283 struct smb2_signing_key **_key)
285 return smb2_signing_key_create(mem_ctx,
286 SMB2_SIGNING_INVALID_ALGO,
287 cipher_algo_id,
288 master_key,
290 _key);
293 bool smb2_signing_key_valid(const struct smb2_signing_key *key)
295 if (key == NULL) {
296 return false;
299 if (key->blob.length == 0 || key->blob.data == NULL) {
300 return false;
303 return true;
306 static NTSTATUS smb2_signing_calc_signature(struct smb2_signing_key *signing_key,
307 uint16_t sign_algo_id,
308 const struct iovec *vector,
309 int count,
310 uint8_t signature[16])
312 const uint8_t *hdr = (uint8_t *)vector[0].iov_base;
313 static const uint8_t zero_sig[16] = { 0, };
314 gnutls_mac_algorithm_t hmac_algo = GNUTLS_MAC_UNKNOWN;
315 int i;
318 * We expect
319 * - SMB2 HDR
320 * - SMB2 BODY FIXED
321 * - (optional) SMB2 BODY DYN
322 * - (optional) PADDING
324 SMB_ASSERT(count >= 2);
325 SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
326 SMB_ASSERT(count <= 4);
328 switch (sign_algo_id) {
329 case SMB2_SIGNING_AES128_CMAC:
330 #ifdef HAVE_GNUTLS_AES_CMAC
331 hmac_algo = GNUTLS_MAC_AES_CMAC_128;
332 break;
333 #else /* NOT HAVE_GNUTLS_AES_CMAC */
335 struct aes_cmac_128_context ctx;
336 uint8_t key[AES_BLOCK_SIZE] = {0};
338 memcpy(key,
339 signing_key->blob.data,
340 MIN(signing_key->blob.length, 16));
342 aes_cmac_128_init(&ctx, key);
343 aes_cmac_128_update(&ctx, hdr, SMB2_HDR_SIGNATURE);
344 aes_cmac_128_update(&ctx, zero_sig, 16);
345 for (i=1; i < count; i++) {
346 aes_cmac_128_update(&ctx,
347 (const uint8_t *)vector[i].iov_base,
348 vector[i].iov_len);
350 aes_cmac_128_final(&ctx, signature);
352 ZERO_ARRAY(key);
354 return NT_STATUS_OK;
355 } break;
356 #endif
357 case SMB2_SIGNING_HMAC_SHA256:
358 hmac_algo = GNUTLS_MAC_SHA256;
359 break;
361 default:
362 return NT_STATUS_HMAC_NOT_SUPPORTED;
365 if (hmac_algo != GNUTLS_MAC_UNKNOWN) {
366 uint8_t digest[gnutls_hash_get_len(hmac_algo)];
367 gnutls_datum_t key = {
368 .data = signing_key->blob.data,
369 .size = MIN(signing_key->blob.length, 16),
371 int rc;
373 if (signing_key->hmac_hnd == NULL) {
374 rc = gnutls_hmac_init(&signing_key->hmac_hnd,
375 hmac_algo,
376 key.data,
377 key.size);
378 if (rc < 0) {
379 return gnutls_error_to_ntstatus(rc,
380 NT_STATUS_HMAC_NOT_SUPPORTED);
384 rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE);
385 if (rc < 0) {
386 return gnutls_error_to_ntstatus(rc,
387 NT_STATUS_HMAC_NOT_SUPPORTED);
389 rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16);
390 if (rc < 0) {
391 return gnutls_error_to_ntstatus(rc,
392 NT_STATUS_HMAC_NOT_SUPPORTED);
395 for (i = 1; i < count; i++) {
396 rc = gnutls_hmac(signing_key->hmac_hnd,
397 vector[i].iov_base,
398 vector[i].iov_len);
399 if (rc < 0) {
400 return gnutls_error_to_ntstatus(rc,
401 NT_STATUS_HMAC_NOT_SUPPORTED);
404 gnutls_hmac_output(signing_key->hmac_hnd, digest);
405 memcpy(signature, digest, 16);
406 ZERO_ARRAY(digest);
407 return NT_STATUS_OK;
410 return NT_STATUS_HMAC_NOT_SUPPORTED;
413 NTSTATUS smb2_signing_sign_pdu(struct smb2_signing_key *signing_key,
414 struct iovec *vector,
415 int count)
417 uint16_t sign_algo_id;
418 uint8_t *hdr;
419 uint64_t session_id;
420 uint8_t res[16];
421 NTSTATUS status;
424 * We expect
425 * - SMB2 HDR
426 * - SMB2 BODY FIXED
427 * - (optional) SMB2 BODY DYN
428 * - (optional) PADDING
430 SMB_ASSERT(count >= 2);
431 SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
432 SMB_ASSERT(count <= 4);
434 hdr = (uint8_t *)vector[0].iov_base;
436 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
437 if (session_id == 0) {
439 * do not sign messages with a zero session_id.
440 * See MS-SMB2 3.2.4.1.1
442 return NT_STATUS_OK;
445 if (!smb2_signing_key_valid(signing_key)) {
446 DBG_WARNING("No signing key for SMB2 signing\n");
447 return NT_STATUS_ACCESS_DENIED;
450 memset(hdr + SMB2_HDR_SIGNATURE, 0, 16);
452 SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
454 sign_algo_id = signing_key->sign_algo_id;
456 status = smb2_signing_calc_signature(signing_key,
457 sign_algo_id,
458 vector,
459 count,
460 res);
461 if (!NT_STATUS_IS_OK(status)) {
462 DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
463 (unsigned)sign_algo_id, nt_errstr(status));
464 return status;
467 DEBUG(5,("signed SMB2 message (sign_algo_id=%u)\n",
468 (unsigned)sign_algo_id));
470 memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16);
472 return NT_STATUS_OK;
475 NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
476 const struct iovec *vector,
477 int count)
479 uint16_t sign_algo_id;
480 const uint8_t *hdr;
481 const uint8_t *sig;
482 uint64_t session_id;
483 uint8_t res[16];
484 NTSTATUS status;
487 * We expect
488 * - SMB2 HDR
489 * - SMB2 BODY FIXED
490 * - (optional) SMB2 BODY DYN
491 * - (optional) PADDING
493 SMB_ASSERT(count >= 2);
494 SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
495 SMB_ASSERT(count <= 4);
497 hdr = (const uint8_t *)vector[0].iov_base;
499 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
500 if (session_id == 0) {
502 * do not sign messages with a zero session_id.
503 * See MS-SMB2 3.2.4.1.1
505 return NT_STATUS_OK;
508 if (!smb2_signing_key_valid(signing_key)) {
509 /* we don't have the session key yet */
510 return NT_STATUS_OK;
513 sig = hdr+SMB2_HDR_SIGNATURE;
515 sign_algo_id = signing_key->sign_algo_id;
517 status = smb2_signing_calc_signature(signing_key,
518 sign_algo_id,
519 vector,
520 count,
521 res);
522 if (!NT_STATUS_IS_OK(status)) {
523 DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
524 (unsigned)sign_algo_id, nt_errstr(status));
525 return status;
528 if (memcmp_const_time(res, sig, 16) != 0) {
529 DEBUG(0,("Bad SMB2 (sign_algo_id=%u) signature for message\n",
530 (unsigned)sign_algo_id));
531 dump_data(0, sig, 16);
532 dump_data(0, res, 16);
533 return NT_STATUS_ACCESS_DENIED;
536 return NT_STATUS_OK;
539 NTSTATUS smb2_key_derivation(const uint8_t *KI, size_t KI_len,
540 const uint8_t *Label, size_t Label_len,
541 const uint8_t *Context, size_t Context_len,
542 uint8_t *KO, size_t KO_len)
544 gnutls_hmac_hd_t hmac_hnd = NULL;
545 uint8_t buf[4];
546 static const uint8_t zero = 0;
547 const size_t digest_len = gnutls_hash_get_len(GNUTLS_MAC_SHA256);
548 uint8_t digest[digest_len];
549 uint32_t i = 1;
550 uint32_t L = KO_len * 8;
551 int rc;
553 if (KO_len > digest_len) {
554 DBG_ERR("KO_len[%zu] > digest_len[%zu]\n", KO_len, digest_len);
555 return NT_STATUS_INTERNAL_ERROR;
558 switch (KO_len) {
559 case 16:
560 case 32:
561 break;
562 default:
563 DBG_ERR("KO_len[%zu] not supported\n", KO_len);
564 return NT_STATUS_INTERNAL_ERROR;
568 * a simplified version of
569 * "NIST Special Publication 800-108" section 5.1
570 * using hmac-sha256.
572 rc = gnutls_hmac_init(&hmac_hnd,
573 GNUTLS_MAC_SHA256,
575 KI_len);
576 if (rc < 0) {
577 return gnutls_error_to_ntstatus(rc,
578 NT_STATUS_HMAC_NOT_SUPPORTED);
581 RSIVAL(buf, 0, i);
582 rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
583 if (rc < 0) {
584 return gnutls_error_to_ntstatus(rc,
585 NT_STATUS_HMAC_NOT_SUPPORTED);
587 rc = gnutls_hmac(hmac_hnd, Label, Label_len);
588 if (rc < 0) {
589 gnutls_hmac_deinit(hmac_hnd, NULL);
590 return gnutls_error_to_ntstatus(rc,
591 NT_STATUS_HMAC_NOT_SUPPORTED);
593 rc = gnutls_hmac(hmac_hnd, &zero, 1);
594 if (rc < 0) {
595 gnutls_hmac_deinit(hmac_hnd, NULL);
596 return gnutls_error_to_ntstatus(rc,
597 NT_STATUS_HMAC_NOT_SUPPORTED);
599 rc = gnutls_hmac(hmac_hnd, Context, Context_len);
600 if (rc < 0) {
601 gnutls_hmac_deinit(hmac_hnd, NULL);
602 return gnutls_error_to_ntstatus(rc,
603 NT_STATUS_HMAC_NOT_SUPPORTED);
605 RSIVAL(buf, 0, L);
606 rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
607 if (rc < 0) {
608 gnutls_hmac_deinit(hmac_hnd, NULL);
609 return gnutls_error_to_ntstatus(rc,
610 NT_STATUS_HMAC_NOT_SUPPORTED);
613 gnutls_hmac_deinit(hmac_hnd, digest);
615 memcpy(KO, digest, KO_len);
617 ZERO_ARRAY(digest);
619 return NT_STATUS_OK;
622 NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
623 struct iovec *vector,
624 int count)
626 uint16_t cipher_id;
627 uint8_t *tf;
628 size_t a_total;
629 ssize_t m_total;
630 uint32_t iv_size = 0;
631 uint32_t key_size = 0;
632 size_t tag_size = 0;
633 uint8_t _key[16] = {0};
634 gnutls_cipher_algorithm_t algo = 0;
635 gnutls_datum_t key;
636 gnutls_datum_t iv;
637 NTSTATUS status;
638 int rc;
640 if (count < 1) {
641 return NT_STATUS_INVALID_PARAMETER;
644 if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
645 return NT_STATUS_INVALID_PARAMETER;
648 tf = (uint8_t *)vector[0].iov_base;
650 if (!smb2_signing_key_valid(encryption_key)) {
651 DBG_WARNING("No encryption key for SMB2 signing\n");
652 return NT_STATUS_ACCESS_DENIED;
654 cipher_id = encryption_key->cipher_algo_id;
656 a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
658 m_total = iov_buflen(&vector[1], count-1);
659 if (m_total == -1) {
660 return NT_STATUS_BUFFER_TOO_SMALL;
663 SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
664 SIVAL(tf, SMB2_TF_MSG_SIZE, m_total);
666 switch (cipher_id) {
667 case SMB2_ENCRYPTION_AES128_CCM:
668 algo = GNUTLS_CIPHER_AES_128_CCM;
669 iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
670 break;
671 case SMB2_ENCRYPTION_AES128_GCM:
672 algo = GNUTLS_CIPHER_AES_128_GCM;
673 iv_size = gnutls_cipher_get_iv_size(algo);
674 break;
675 default:
676 return NT_STATUS_INVALID_PARAMETER;
679 key_size = gnutls_cipher_get_key_size(algo);
680 tag_size = gnutls_cipher_get_tag_size(algo);
682 if (key_size > sizeof(_key)) {
683 return NT_STATUS_BUFFER_TOO_SMALL;
686 key = (gnutls_datum_t) {
687 .data = _key,
688 .size = key_size,
691 memcpy(key.data,
692 encryption_key->blob.data,
693 MIN(encryption_key->blob.length, key.size));
695 iv = (gnutls_datum_t) {
696 .data = tf + SMB2_TF_NONCE,
697 .size = iv_size,
700 if (encryption_key->cipher_hnd == NULL) {
701 rc = gnutls_aead_cipher_init(&encryption_key->cipher_hnd,
702 algo,
703 &key);
704 if (rc < 0) {
705 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
706 goto out;
710 memset(tf + SMB2_TF_NONCE + iv_size,
712 16 - iv_size);
714 #if defined(HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2)
716 uint8_t tag[tag_size];
717 giovec_t auth_iov[1];
719 auth_iov[0] = (giovec_t) {
720 .iov_base = tf + SMB2_TF_NONCE,
721 .iov_len = a_total,
724 rc = gnutls_aead_cipher_encryptv2(encryption_key->cipher_hnd,
725 iv.data,
726 iv.size,
727 auth_iov,
729 &vector[1],
730 count - 1,
731 tag,
732 &tag_size);
733 if (rc < 0) {
734 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
735 goto out;
738 memcpy(tf + SMB2_TF_SIGNATURE, tag, tag_size);
740 #else /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
742 size_t ptext_size = m_total;
743 uint8_t *ptext = NULL;
744 size_t ctext_size = m_total + tag_size;
745 uint8_t *ctext = NULL;
746 size_t len = 0;
747 int i;
748 TALLOC_CTX *tmp_ctx = NULL;
751 * If we come from python bindings, we don't have a stackframe
752 * around, so use the NULL context.
754 * This is fine as we make sure we free the memory.
756 if (talloc_stackframe_exists()) {
757 tmp_ctx = talloc_tos();
760 ptext = talloc_size(tmp_ctx, ptext_size);
761 if (ptext == NULL) {
762 status = NT_STATUS_NO_MEMORY;
763 goto out;
766 ctext = talloc_size(tmp_ctx, ctext_size);
767 if (ctext == NULL) {
768 TALLOC_FREE(ptext);
769 status = NT_STATUS_NO_MEMORY;
770 goto out;
773 for (i = 1; i < count; i++) {
774 memcpy(ptext + len,
775 vector[i].iov_base,
776 vector[i].iov_len);
778 len += vector[i].iov_len;
779 if (len > ptext_size) {
780 TALLOC_FREE(ptext);
781 TALLOC_FREE(ctext);
782 status = NT_STATUS_INTERNAL_ERROR;
783 goto out;
787 rc = gnutls_aead_cipher_encrypt(encryption_key->cipher_hnd,
788 iv.data,
789 iv.size,
790 tf + SMB2_TF_NONCE,
791 a_total,
792 tag_size,
793 ptext,
794 ptext_size,
795 ctext,
796 &ctext_size);
797 if (rc < 0 || ctext_size != m_total + tag_size) {
798 TALLOC_FREE(ptext);
799 TALLOC_FREE(ctext);
800 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
801 goto out;
804 len = 0;
805 for (i = 1; i < count; i++) {
806 memcpy(vector[i].iov_base,
807 ctext + len,
808 vector[i].iov_len);
810 len += vector[i].iov_len;
813 memcpy(tf + SMB2_TF_SIGNATURE, ctext + m_total, tag_size);
815 TALLOC_FREE(ptext);
816 TALLOC_FREE(ctext);
818 #endif /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
820 DBG_INFO("Encrypted SMB2 message\n");
822 status = NT_STATUS_OK;
823 out:
824 ZERO_ARRAY(_key);
826 return status;
829 NTSTATUS smb2_signing_decrypt_pdu(struct smb2_signing_key *decryption_key,
830 struct iovec *vector,
831 int count)
833 uint16_t cipher_id;
834 uint8_t *tf;
835 uint16_t flags;
836 size_t a_total;
837 ssize_t m_total;
838 uint32_t msg_size = 0;
839 uint32_t iv_size = 0;
840 uint32_t key_size = 0;
841 size_t tag_size = 0;
842 uint8_t _key[16] = {0};
843 gnutls_cipher_algorithm_t algo = 0;
844 gnutls_datum_t key;
845 gnutls_datum_t iv;
846 NTSTATUS status;
847 int rc;
849 if (count < 1) {
850 return NT_STATUS_INVALID_PARAMETER;
853 if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
854 return NT_STATUS_INVALID_PARAMETER;
857 tf = (uint8_t *)vector[0].iov_base;
859 if (!smb2_signing_key_valid(decryption_key)) {
860 DBG_WARNING("No decryption key for SMB2 signing\n");
861 return NT_STATUS_ACCESS_DENIED;
863 cipher_id = decryption_key->cipher_algo_id;
865 a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
867 m_total = iov_buflen(&vector[1], count-1);
868 if (m_total == -1) {
869 return NT_STATUS_BUFFER_TOO_SMALL;
872 flags = SVAL(tf, SMB2_TF_FLAGS);
873 msg_size = IVAL(tf, SMB2_TF_MSG_SIZE);
875 if (flags != SMB2_TF_FLAGS_ENCRYPTED) {
876 return NT_STATUS_ACCESS_DENIED;
879 if (msg_size != m_total) {
880 return NT_STATUS_INTERNAL_ERROR;
883 switch (cipher_id) {
884 case SMB2_ENCRYPTION_AES128_CCM:
885 algo = GNUTLS_CIPHER_AES_128_CCM;
886 iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
887 break;
888 case SMB2_ENCRYPTION_AES128_GCM:
889 algo = GNUTLS_CIPHER_AES_128_GCM;
890 iv_size = gnutls_cipher_get_iv_size(algo);
891 break;
892 default:
893 return NT_STATUS_INVALID_PARAMETER;
896 key_size = gnutls_cipher_get_key_size(algo);
897 tag_size = gnutls_cipher_get_tag_size(algo);
899 if (key_size > sizeof(_key)) {
900 return NT_STATUS_BUFFER_TOO_SMALL;
903 key = (gnutls_datum_t) {
904 .data = _key,
905 .size = key_size,
908 memcpy(key.data,
909 decryption_key->blob.data,
910 MIN(decryption_key->blob.length, key.size));
912 iv = (gnutls_datum_t) {
913 .data = tf + SMB2_TF_NONCE,
914 .size = iv_size,
917 if (decryption_key->cipher_hnd == NULL) {
918 rc = gnutls_aead_cipher_init(&decryption_key->cipher_hnd,
919 algo,
920 &key);
921 if (rc < 0) {
922 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
923 goto out;
927 /* gnutls_aead_cipher_encryptv2() has a bug in version 3.6.10 */
928 #if defined(HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2)
930 giovec_t auth_iov[1];
932 auth_iov[0] = (giovec_t) {
933 .iov_base = tf + SMB2_TF_NONCE,
934 .iov_len = a_total,
937 rc = gnutls_aead_cipher_decryptv2(decryption_key->cipher_hnd,
938 iv.data,
939 iv.size,
940 auth_iov,
942 &vector[1],
943 count - 1,
944 tf + SMB2_TF_SIGNATURE,
945 tag_size);
946 if (rc < 0) {
947 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
948 goto out;
951 #else /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
953 size_t ctext_size = m_total + tag_size;
954 uint8_t *ctext = NULL;
955 size_t ptext_size = m_total;
956 uint8_t *ptext = NULL;
957 size_t len = 0;
958 int i;
959 TALLOC_CTX *tmp_ctx = NULL;
962 * If we come from python bindings, we don't have a stackframe
963 * around, so use the NULL context.
965 * This is fine as we make sure we free the memory.
967 if (talloc_stackframe_exists()) {
968 tmp_ctx = talloc_tos();
971 /* GnuTLS doesn't have a iovec API for decryption yet */
973 ptext = talloc_size(tmp_ctx, ptext_size);
974 if (ptext == NULL) {
975 status = NT_STATUS_NO_MEMORY;
976 goto out;
979 ctext = talloc_size(tmp_ctx, ctext_size);
980 if (ctext == NULL) {
981 TALLOC_FREE(ptext);
982 status = NT_STATUS_NO_MEMORY;
983 goto out;
987 for (i = 1; i < count; i++) {
988 memcpy(ctext + len,
989 vector[i].iov_base,
990 vector[i].iov_len);
992 len += vector[i].iov_len;
994 if (len != m_total) {
995 TALLOC_FREE(ptext);
996 TALLOC_FREE(ctext);
997 status = NT_STATUS_INTERNAL_ERROR;
998 goto out;
1001 memcpy(ctext + len,
1002 tf + SMB2_TF_SIGNATURE,
1003 tag_size);
1005 /* This function will verify the tag */
1006 rc = gnutls_aead_cipher_decrypt(decryption_key->cipher_hnd,
1007 iv.data,
1008 iv.size,
1009 tf + SMB2_TF_NONCE,
1010 a_total,
1011 tag_size,
1012 ctext,
1013 ctext_size,
1014 ptext,
1015 &ptext_size);
1016 if (rc < 0 || ptext_size != m_total) {
1017 TALLOC_FREE(ptext);
1018 TALLOC_FREE(ctext);
1019 status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
1020 goto out;
1023 len = 0;
1024 for (i = 1; i < count; i++) {
1025 memcpy(vector[i].iov_base,
1026 ptext + len,
1027 vector[i].iov_len);
1029 len += vector[i].iov_len;
1032 TALLOC_FREE(ptext);
1033 TALLOC_FREE(ctext);
1035 #endif /* HAVE_GNUTLS_AEAD_CIPHER_ENCRYPTV2 */
1037 DBG_INFO("Decrypted SMB2 message\n");
1039 status = NT_STATUS_OK;
1040 out:
1041 ZERO_ARRAY(_key);
1043 return status;