From f988756599c2f7253989f2ca1dea2975dd89e6ea 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] 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 --- auth/gensec/schannel.c | 49 ++++++++++++++++++++++++++---------------- selftest/knownfail | 1 - 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/auth/gensec/schannel.c b/auth/gensec/schannel.c index b5e6289ef3f..0cdae141ead 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,25 +314,43 @@ static NTSTATUS netsec_do_seal(struct schannel_state *state, return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); } } else { + + /* + * 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. + */ + + 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, - confounder, - 8); + 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); } - /* - * 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_decrypt(cipher_hnd, - data, - length); - if (rc < 0) { - 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); diff --git a/selftest/knownfail b/selftest/knownfail index 6d229192e01..82259dcfe90 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -375,4 +375,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