From 279d31dfa642126ce7670292390e02b2e33ea36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Tue, 17 Sep 2019 22:37:06 +0200 Subject: [PATCH 133/187] auth/gensec: fix AES schannel seal and unseal Workaround bug present in gnutls 3.6.8: gnutls_cipher_decrypt() uses an optimization internally that breaks decryption when processing buffers with their length not being a multiple of the blocksize. Signed-off-by: Stefan Metzmacher Pair-Programmed-With: Guenther Deschner Reviewed-by: Andreas Schneider (cherry picked from commit f988756599c2f7253989f2ca1dea2975dd89e6ea) --- auth/gensec/schannel.c | 47 +++++++++++++++++++++++++++--------------- selftest/knownfail | 1 - 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/auth/gensec/schannel.c b/auth/gensec/schannel.c index 9f2611e5f04..ea2a8b201ce 100644 --- a/auth/gensec/schannel.c +++ b/auth/gensec/schannel.c @@ -306,11 +306,6 @@ static NTSTATUS netsec_do_seal(struct schannel_state *state, return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); } - /* - * Looks like we have to reuse the initial IV which is - * cryptographically wrong! - */ - gnutls_cipher_set_iv(cipher_hnd, iv.data, iv.size); rc = gnutls_cipher_encrypt(cipher_hnd, data, length); @@ -319,26 +314,44 @@ static NTSTATUS netsec_do_seal(struct schannel_state *state, return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); } } else { - rc = gnutls_cipher_decrypt(cipher_hnd, - confounder, - 8); - if (rc < 0) { - gnutls_cipher_deinit(cipher_hnd); - return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); - } /* - * Looks like we have to reuse the initial IV which is - * cryptographically wrong! + * Workaround bug present in gnutls 3.6.8: + * + * gnutls_cipher_decrypt() uses an optimization + * internally that breaks decryption when processing + * buffers with their length not being a multiple + * of the blocksize. */ - gnutls_cipher_set_iv(cipher_hnd, iv.data, iv.size); + + uint8_t tmp[16] = { 0, }; + uint32_t tmp_dlength = MIN(length, sizeof(tmp) - 8); + + memcpy(tmp, confounder, 8); + memcpy(tmp + 8, data, tmp_dlength); + rc = gnutls_cipher_decrypt(cipher_hnd, - data, - length); + tmp, + 8 + tmp_dlength); if (rc < 0) { + ZERO_STRUCT(tmp); gnutls_cipher_deinit(cipher_hnd); return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); } + + memcpy(confounder, tmp, 8); + memcpy(data, tmp + 8, tmp_dlength); + ZERO_STRUCT(tmp); + + if (length > tmp_dlength) { + rc = gnutls_cipher_decrypt(cipher_hnd, + data + tmp_dlength, + length - tmp_dlength); + if (rc < 0) { + gnutls_cipher_deinit(cipher_hnd); + return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); + } + } } gnutls_cipher_deinit(cipher_hnd); #else /* NOT HAVE_GNUTLS_AES_CFB8 */ diff --git a/selftest/knownfail b/selftest/knownfail index 95db97a44e0..7b54b77a708 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -374,4 +374,3 @@ ^samba.tests.ntlmdisabled.python\(ktest\).python2.ntlmdisabled.NtlmDisabledTests.test_samr_change_password\(ktest\) ^samba.tests.ntlmdisabled.python\(ad_dc_no_ntlm\).python3.ntlmdisabled.NtlmDisabledTests.test_ntlm_connection\(ad_dc_no_ntlm\) ^samba.tests.ntlmdisabled.python\(ad_dc_no_ntlm\).python2.ntlmdisabled.NtlmDisabledTests.test_ntlm_connection\(ad_dc_no_ntlm\) -^samba.unittests.schannel.torture_schannel_seal_aes -- 2.23.0