summaryrefslogtreecommitdiff
path: root/auth
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2019-09-17 22:37:06 +0200
committerAndreas Schneider <asn@cryptomilk.org>2019-10-07 08:13:44 +0000
commitf988756599c2f7253989f2ca1dea2975dd89e6ea (patch)
tree0a4055eb76762a2423a5808fecca720ca2dfbfbd /auth
parent709d54d68a9c2cb3cda91d9ab63228a7adbaceb4 (diff)
downloadsamba-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.c47
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 */