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: 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 | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'auth') 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,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 */ -- cgit v1.2.1