Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Gnutls datum size might appear shorter than expected due to higher bits being zero in the random numbers. Gnutls export functions don't usually pad the data when exporting keys. bcrypt does not expect that currently. This is reproducible as random failures in some of the existing tests. Here is the testing patch which reliably reproduces this issue: https://gist.github.com/gofman/b15f91e2fb5246d13edcaf30eb6196f1.
dlls/bcrypt/gnutls.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index c065ac31fba..9e6dd4cc9a6 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -28,6 +28,7 @@ #ifdef HAVE_GNUTLS_CIPHER_INIT
#include <stdarg.h> +#include <assert.h> #include <gnutls/gnutls.h> #include <gnutls/crypto.h> #include <gnutls/abstract.h> @@ -665,11 +666,27 @@ static void CDECL key_symmetric_destroy( struct key *key ) if (key_data(key)->cipher) pgnutls_cipher_deinit( key_data(key)->cipher ); }
+static void export_gnutls_datum( UCHAR *buffer, ULONG length, gnutls_datum_t *d, ULONG *actual_length ) +{ + ULONG size = d->size; + UCHAR *src = d->data; + + assert( size <= length + 1 ); + if (size == length + 1) + { + assert(!src[0]); + ++src; + --size; + } + *actual_length = size; + memcpy( buffer, src, size ); +} + static NTSTATUS export_gnutls_pubkey_rsa( gnutls_privkey_t gnutls_key, ULONG bitlen, UCHAR **pubkey, ULONG *pubkey_len ) { BCRYPT_RSAKEY_BLOB *rsa_blob; gnutls_datum_t m, e; - UCHAR *dst, *src; + UCHAR *dst; int ret;
if ((ret = pgnutls_privkey_export_rsa_raw( gnutls_key, &m, &e, NULL, NULL, NULL, NULL, NULL, NULL ))) @@ -686,32 +703,18 @@ static NTSTATUS export_gnutls_pubkey_rsa( gnutls_privkey_t gnutls_key, ULONG bit }
dst = (UCHAR *)(rsa_blob + 1); - if (e.size == bitlen / 8 + 1 && !e.data[0]) - { - src = e.data + 1; - e.size--; - } - else src = e.data; - memcpy( dst, src, e.size ); + export_gnutls_datum( dst, bitlen / 8, &e, &rsa_blob->cbPublicExp );
- dst += e.size; - if (m.size == bitlen / 8 + 1 && !m.data[0]) - { - src = m.data + 1; - m.size--; - } - else src = m.data; - memcpy( dst, src, m.size ); + dst += rsa_blob->cbPublicExp; + export_gnutls_datum( dst, bitlen / 8, &m, &rsa_blob->cbModulus );
rsa_blob->Magic = BCRYPT_RSAPUBLIC_MAGIC; rsa_blob->BitLength = bitlen; - rsa_blob->cbPublicExp = e.size; - rsa_blob->cbModulus = m.size; rsa_blob->cbPrime1 = 0; rsa_blob->cbPrime2 = 0;
*pubkey = (UCHAR *)rsa_blob; - *pubkey_len = sizeof(*rsa_blob) + e.size + m.size; + *pubkey_len = sizeof(*rsa_blob) + rsa_blob->cbPublicExp + rsa_blob->cbModulus;
free( e.data ); free( m.data ); return STATUS_SUCCESS;