232 lines
5.6 KiB
Diff
232 lines
5.6 KiB
Diff
|
From 94b8f3071fafea18ceb59098f8611a0f2cb5a655 Mon Sep 17 00:00:00 2001
|
||
|
From: Andreas Schneider <asn@samba.org>
|
||
|
Date: Tue, 26 Feb 2019 16:43:36 +0100
|
||
|
Subject: [PATCH 125/187] libcli:smb: Support GnuTLS AES CCM and GCM in
|
||
|
smb2_signing_decrypt_pdu()
|
||
|
|
||
|
This requires GnuTLS >= 3.4.0.
|
||
|
|
||
|
Signed-off-by: Andreas Schneider <asn@samba.org>
|
||
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||
|
|
||
|
Adapted to remove Samba AES support
|
||
|
|
||
|
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
||
|
(cherry picked from commit 3d2de36d9a08354fb775a5d93a9b40012bf6966f)
|
||
|
---
|
||
|
libcli/smb/smb2_signing.c | 170 ++++++++++++++++++++++++++++----------
|
||
|
1 file changed, 125 insertions(+), 45 deletions(-)
|
||
|
|
||
|
diff --git a/libcli/smb/smb2_signing.c b/libcli/smb/smb2_signing.c
|
||
|
index 52209d9553b..1d9c99337d8 100644
|
||
|
--- a/libcli/smb/smb2_signing.c
|
||
|
+++ b/libcli/smb/smb2_signing.c
|
||
|
@@ -558,7 +558,6 @@ out:
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
-
|
||
|
NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key,
|
||
|
uint16_t cipher_id,
|
||
|
struct iovec *vector,
|
||
|
@@ -566,17 +565,20 @@ NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key,
|
||
|
{
|
||
|
uint8_t *tf;
|
||
|
uint16_t flags;
|
||
|
- uint8_t *sig_ptr = NULL;
|
||
|
- uint8_t sig[16];
|
||
|
int i;
|
||
|
size_t a_total;
|
||
|
ssize_t m_total;
|
||
|
uint32_t msg_size = 0;
|
||
|
- union {
|
||
|
- struct aes_ccm_128_context ccm;
|
||
|
- struct aes_gcm_128_context gcm;
|
||
|
- } c;
|
||
|
- uint8_t key[AES_BLOCK_SIZE];
|
||
|
+ uint32_t iv_size = 0;
|
||
|
+ uint32_t key_size = 0;
|
||
|
+ uint32_t tag_size = 0;
|
||
|
+ uint8_t _key[16] = {0};
|
||
|
+ gnutls_cipher_algorithm_t algo = 0;
|
||
|
+ gnutls_aead_cipher_hd_t cipher_hnd = NULL;
|
||
|
+ gnutls_datum_t key;
|
||
|
+ gnutls_datum_t iv;
|
||
|
+ NTSTATUS status;
|
||
|
+ int rc;
|
||
|
|
||
|
if (count < 1) {
|
||
|
return NT_STATUS_INVALID_PARAMETER;
|
||
|
@@ -612,53 +614,131 @@ NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key,
|
||
|
return NT_STATUS_INTERNAL_ERROR;
|
||
|
}
|
||
|
|
||
|
- ZERO_STRUCT(key);
|
||
|
- memcpy(key, decryption_key.data,
|
||
|
- MIN(decryption_key.length, AES_BLOCK_SIZE));
|
||
|
-
|
||
|
switch (cipher_id) {
|
||
|
case SMB2_ENCRYPTION_AES128_CCM:
|
||
|
- aes_ccm_128_init(&c.ccm, key,
|
||
|
- tf + SMB2_TF_NONCE,
|
||
|
- a_total, m_total);
|
||
|
- aes_ccm_128_update(&c.ccm, tf + SMB2_TF_NONCE, a_total);
|
||
|
- for (i=1; i < count; i++) {
|
||
|
- aes_ccm_128_crypt(&c.ccm,
|
||
|
- (uint8_t *)vector[i].iov_base,
|
||
|
- vector[i].iov_len);
|
||
|
- aes_ccm_128_update(&c.ccm,
|
||
|
- ( uint8_t *)vector[i].iov_base,
|
||
|
- vector[i].iov_len);
|
||
|
- }
|
||
|
- aes_ccm_128_digest(&c.ccm, sig);
|
||
|
+ algo = GNUTLS_CIPHER_AES_128_CCM;
|
||
|
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
|
||
|
break;
|
||
|
-
|
||
|
case SMB2_ENCRYPTION_AES128_GCM:
|
||
|
- aes_gcm_128_init(&c.gcm, key, tf + SMB2_TF_NONCE);
|
||
|
- aes_gcm_128_updateA(&c.gcm, tf + SMB2_TF_NONCE, a_total);
|
||
|
- for (i=1; i < count; i++) {
|
||
|
- aes_gcm_128_updateC(&c.gcm,
|
||
|
- (const uint8_t *)vector[i].iov_base,
|
||
|
- vector[i].iov_len);
|
||
|
- aes_gcm_128_crypt(&c.gcm,
|
||
|
- (uint8_t *)vector[i].iov_base,
|
||
|
- vector[i].iov_len);
|
||
|
- }
|
||
|
- aes_gcm_128_digest(&c.gcm, sig);
|
||
|
+ algo = GNUTLS_CIPHER_AES_128_GCM;
|
||
|
+ iv_size = gnutls_cipher_get_iv_size(algo);
|
||
|
break;
|
||
|
-
|
||
|
default:
|
||
|
- ZERO_STRUCT(key);
|
||
|
return NT_STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
- ZERO_STRUCT(key);
|
||
|
|
||
|
- sig_ptr = tf + SMB2_TF_SIGNATURE;
|
||
|
- if (memcmp(sig_ptr, sig, 16) != 0) {
|
||
|
- return NT_STATUS_ACCESS_DENIED;
|
||
|
+ key_size = gnutls_cipher_get_key_size(algo);
|
||
|
+ tag_size = gnutls_cipher_get_tag_size(algo);
|
||
|
+
|
||
|
+ if (key_size > sizeof(_key)) {
|
||
|
+ return NT_STATUS_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
- DEBUG(5,("decrypt SMB2 message\n"));
|
||
|
+ key = (gnutls_datum_t) {
|
||
|
+ .data = _key,
|
||
|
+ .size = key_size,
|
||
|
+ };
|
||
|
|
||
|
- return NT_STATUS_OK;
|
||
|
+ memcpy(key.data,
|
||
|
+ decryption_key.data,
|
||
|
+ MIN(decryption_key.length, key.size));
|
||
|
+
|
||
|
+ iv = (gnutls_datum_t) {
|
||
|
+ .data = tf + SMB2_TF_NONCE,
|
||
|
+ .size = iv_size,
|
||
|
+ };
|
||
|
+
|
||
|
+ rc = gnutls_aead_cipher_init(&cipher_hnd,
|
||
|
+ algo,
|
||
|
+ &key);
|
||
|
+ if (rc < 0) {
|
||
|
+ status = NT_STATUS_NO_MEMORY;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ {
|
||
|
+ size_t ctext_size = m_total + tag_size;
|
||
|
+ uint8_t *ctext = NULL;
|
||
|
+ size_t ptext_size = m_total;
|
||
|
+ uint8_t *ptext = NULL;
|
||
|
+ size_t len = 0;
|
||
|
+
|
||
|
+ /* GnuTLS doesn't have a iovec API for decryption yet */
|
||
|
+
|
||
|
+ ptext = talloc_size(talloc_tos(), ptext_size);
|
||
|
+ if (ptext == NULL) {
|
||
|
+ gnutls_aead_cipher_deinit(cipher_hnd);
|
||
|
+ status = NT_STATUS_NO_MEMORY;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ ctext = talloc_size(talloc_tos(), ctext_size);
|
||
|
+ if (ctext == NULL) {
|
||
|
+ TALLOC_FREE(ptext);
|
||
|
+ gnutls_aead_cipher_deinit(cipher_hnd);
|
||
|
+ status = NT_STATUS_NO_MEMORY;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+
|
||
|
+ for (i = 1; i < count; i++) {
|
||
|
+ memcpy(ctext + len,
|
||
|
+ vector[i].iov_base,
|
||
|
+ vector[i].iov_len);
|
||
|
+
|
||
|
+ len += vector[i].iov_len;
|
||
|
+ }
|
||
|
+ if (len != m_total) {
|
||
|
+ TALLOC_FREE(ptext);
|
||
|
+ TALLOC_FREE(ctext);
|
||
|
+ gnutls_aead_cipher_deinit(cipher_hnd);
|
||
|
+ status = NT_STATUS_INTERNAL_ERROR;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy(ctext + len,
|
||
|
+ tf + SMB2_TF_SIGNATURE,
|
||
|
+ tag_size);
|
||
|
+
|
||
|
+ /* This function will verify the tag */
|
||
|
+ rc = gnutls_aead_cipher_decrypt(cipher_hnd,
|
||
|
+ iv.data,
|
||
|
+ iv.size,
|
||
|
+ tf + SMB2_TF_NONCE,
|
||
|
+ a_total,
|
||
|
+ tag_size,
|
||
|
+ ctext,
|
||
|
+ ctext_size,
|
||
|
+ ptext,
|
||
|
+ &ptext_size);
|
||
|
+ if (rc < 0 || ptext_size != m_total) {
|
||
|
+ DBG_ERR("ERROR: %s\n", gnutls_strerror(rc));
|
||
|
+ TALLOC_FREE(ptext);
|
||
|
+ TALLOC_FREE(ctext);
|
||
|
+ gnutls_aead_cipher_deinit(cipher_hnd);
|
||
|
+ status = NT_STATUS_INTERNAL_ERROR;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ len = 0;
|
||
|
+ for (i = 1; i < count; i++) {
|
||
|
+ memcpy(vector[i].iov_base,
|
||
|
+ ptext + len,
|
||
|
+ vector[i].iov_len);
|
||
|
+
|
||
|
+ len += vector[i].iov_len;
|
||
|
+ }
|
||
|
+
|
||
|
+ TALLOC_FREE(ptext);
|
||
|
+ TALLOC_FREE(ctext);
|
||
|
+ }
|
||
|
+ gnutls_aead_cipher_deinit(cipher_hnd);
|
||
|
+
|
||
|
+ DBG_INFO("Decrypted SMB2 message\n");
|
||
|
+
|
||
|
+ status = NT_STATUS_OK;
|
||
|
+out:
|
||
|
+ ZERO_ARRAY(_key);
|
||
|
+
|
||
|
+ return status;
|
||
|
}
|
||
|
--
|
||
|
2.23.0
|
||
|
|