mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
libcli:smb: Support GnuTLS AES CCM and GCM in smb2_signing_encrypt_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>
This commit is contained in:
parent
10058bcfa1
commit
f43da2adf6
@ -392,15 +392,19 @@ NTSTATUS smb2_signing_encrypt_pdu(DATA_BLOB encryption_key,
|
||||
int count)
|
||||
{
|
||||
uint8_t *tf;
|
||||
uint8_t sig[16];
|
||||
int i;
|
||||
size_t a_total;
|
||||
ssize_t m_total;
|
||||
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;
|
||||
@ -428,58 +432,133 @@ NTSTATUS smb2_signing_encrypt_pdu(DATA_BLOB encryption_key,
|
||||
SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
|
||||
SIVAL(tf, SMB2_TF_MSG_SIZE, m_total);
|
||||
|
||||
ZERO_STRUCT(key);
|
||||
memcpy(key, encryption_key.data,
|
||||
MIN(encryption_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);
|
||||
memset(tf + SMB2_TF_NONCE + AES_CCM_128_NONCE_SIZE, 0,
|
||||
16 - AES_CCM_128_NONCE_SIZE);
|
||||
aes_ccm_128_update(&c.ccm, tf + SMB2_TF_NONCE, a_total);
|
||||
for (i=1; i < count; i++) {
|
||||
aes_ccm_128_update(&c.ccm,
|
||||
(const uint8_t *)vector[i].iov_base,
|
||||
vector[i].iov_len);
|
||||
aes_ccm_128_crypt(&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);
|
||||
memset(tf + SMB2_TF_NONCE + AES_GCM_128_IV_SIZE, 0,
|
||||
16 - AES_GCM_128_IV_SIZE);
|
||||
aes_gcm_128_updateA(&c.gcm, tf + SMB2_TF_NONCE, a_total);
|
||||
for (i=1; i < count; i++) {
|
||||
aes_gcm_128_crypt(&c.gcm,
|
||||
(uint8_t *)vector[i].iov_base,
|
||||
vector[i].iov_len);
|
||||
aes_gcm_128_updateC(&c.gcm,
|
||||
(const 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);
|
||||
|
||||
memcpy(tf + SMB2_TF_SIGNATURE, sig, 16);
|
||||
key_size = gnutls_cipher_get_key_size(algo);
|
||||
tag_size = gnutls_cipher_get_tag_size(algo);
|
||||
|
||||
DEBUG(5,("encrypt SMB2 message\n"));
|
||||
if (key_size > sizeof(_key)) {
|
||||
return NT_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
key = (gnutls_datum_t) {
|
||||
.data = _key,
|
||||
.size = key_size,
|
||||
};
|
||||
|
||||
memcpy(key.data,
|
||||
encryption_key.data,
|
||||
MIN(encryption_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;
|
||||
}
|
||||
|
||||
memset(tf + SMB2_TF_NONCE + iv_size,
|
||||
0,
|
||||
16 - iv_size);
|
||||
|
||||
{
|
||||
size_t ptext_size = m_total;
|
||||
uint8_t *ptext = NULL;
|
||||
size_t ctext_size = m_total + tag_size;
|
||||
uint8_t *ctext = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
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) {
|
||||
gnutls_aead_cipher_deinit(cipher_hnd);
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 1; i < count; i++) {
|
||||
memcpy(ptext + len,
|
||||
vector[i].iov_base,
|
||||
vector[i].iov_len);
|
||||
|
||||
len += vector[i].iov_len;
|
||||
if (len > ptext_size) {
|
||||
TALLOC_FREE(ptext);
|
||||
TALLOC_FREE(ctext);
|
||||
gnutls_aead_cipher_deinit(cipher_hnd);
|
||||
status = NT_STATUS_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = gnutls_aead_cipher_encrypt(cipher_hnd,
|
||||
iv.data,
|
||||
iv.size,
|
||||
tf + SMB2_TF_NONCE,
|
||||
a_total,
|
||||
tag_size,
|
||||
ptext,
|
||||
ptext_size,
|
||||
ctext,
|
||||
&ctext_size);
|
||||
if (rc < 0 || ctext_size != m_total + tag_size) {
|
||||
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,
|
||||
ctext + len,
|
||||
vector[i].iov_len);
|
||||
|
||||
len += vector[i].iov_len;
|
||||
}
|
||||
|
||||
memcpy(tf + SMB2_TF_SIGNATURE, ctext + m_total, tag_size);
|
||||
|
||||
TALLOC_FREE(ptext);
|
||||
TALLOC_FREE(ctext);
|
||||
}
|
||||
gnutls_aead_cipher_deinit(cipher_hnd);
|
||||
|
||||
DBG_INFO("Enencrypted SMB2 message\n");
|
||||
|
||||
status = NT_STATUS_OK;
|
||||
out:
|
||||
ZERO_ARRAY(_key);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS smb2_signing_decrypt_pdu(DATA_BLOB decryption_key,
|
||||
uint16_t cipher_id,
|
||||
struct iovec *vector,
|
||||
|
Loading…
Reference in New Issue
Block a user