diff options
author | Günther Deschner <gd@samba.org> | 2019-09-17 22:37:06 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2019-10-07 08:13:44 +0000 |
commit | f988756599c2f7253989f2ca1dea2975dd89e6ea (patch) | |
tree | 0a4055eb76762a2423a5808fecca720ca2dfbfbd /auth | |
parent | 709d54d68a9c2cb3cda91d9ab63228a7adbaceb4 (diff) | |
download | samba-f988756599c2f7253989f2ca1dea2975dd89e6ea.tar.gz |
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 <metze@samba.org>
Pair-Programmed-With: Guenther Deschner <gd@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Diffstat (limited to 'auth')
-rw-r--r-- | auth/gensec/schannel.c | 47 |
1 files changed, 30 insertions, 17 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,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 */ |