From: Haoyang Chen chenhaoyang@kylinos.cn
--- dlls/bcrypt/Makefile.in | 2 +- dlls/bcrypt/gnutls.c | 197 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 197 insertions(+), 2 deletions(-)
diff --git a/dlls/bcrypt/Makefile.in b/dlls/bcrypt/Makefile.in index a672ac8a3c9..a0ddbd08630 100644 --- a/dlls/bcrypt/Makefile.in +++ b/dlls/bcrypt/Makefile.in @@ -3,7 +3,7 @@ IMPORTLIB = bcrypt IMPORTS = $(TOMCRYPT_PE_LIBS) advapi32 EXTRAINCL = $(TOMCRYPT_PE_CFLAGS) UNIXLIB = bcrypt.so -UNIX_CFLAGS = $(GNUTLS_CFLAGS) +UNIX_CFLAGS = $(GNUTLS_CFLAGS) $(GMP_CFLAGS)
SOURCES = \ bcrypt_main.c \ diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 3e9efb677df..4620a570f9f 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -46,6 +46,10 @@
#include "bcrypt_internal.h"
+#ifdef HAVE_GMP_H +#include <gmp.h> +#endif + #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); @@ -189,6 +193,20 @@ MAKE_FUNCPTR(gnutls_pubkey_deinit); MAKE_FUNCPTR(gnutls_pubkey_encrypt_data); MAKE_FUNCPTR(gnutls_pubkey_import_privkey); MAKE_FUNCPTR(gnutls_pubkey_init); +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +static void *libgmp_handle; + +MAKE_FUNCPTR(mpz_init); +MAKE_FUNCPTR(mpz_clear); +MAKE_FUNCPTR(mpz_cmp); +MAKE_FUNCPTR(mpz_sizeinbase); +MAKE_FUNCPTR(mpz_import); +MAKE_FUNCPTR(mpz_export); +MAKE_FUNCPTR(mpz_mod); +MAKE_FUNCPTR(mpz_sub_ui); +MAKE_FUNCPTR(mpz_mul); +MAKE_FUNCPTR(mpz_invert); +#endif #undef MAKE_FUNCPTR
static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size) @@ -458,6 +476,36 @@ static NTSTATUS gnutls_process_attach( void *args )
#undef LOAD_FUNCPTR_OPT
+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +#define LOAD_FUNCPTR_STR(f) #f +#define LOAD_FUNCPTR(f) \ + if (!(p##f = dlsym( libgmp_handle, LOAD_FUNCPTR_STR(f) ))) \ + { \ + ERR( "failed to load %s\n", LOAD_FUNCPTR_STR(f) ); \ + goto fail; \ + } + + if ((libgmp_handle = dlopen( SONAME_LIBGMP, RTLD_NOW ))) + { + LOAD_FUNCPTR(mpz_init); + LOAD_FUNCPTR(mpz_clear); + LOAD_FUNCPTR(mpz_cmp); + LOAD_FUNCPTR(mpz_sizeinbase); + LOAD_FUNCPTR(mpz_import); + LOAD_FUNCPTR(mpz_export); + LOAD_FUNCPTR(mpz_mod); + LOAD_FUNCPTR(mpz_sub_ui); + LOAD_FUNCPTR(mpz_mul); + LOAD_FUNCPTR(mpz_invert); + } + else + { + ERR_(winediag)( "failed to load libgmp, no support for parameter completion for asymmetric algorithms.\n" ); + goto fail; + } +#undef LOAD_FUNCPTR +#undef LOAD_FUNCPTR_STR +#endif if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS) { pgnutls_perror( ret ); @@ -477,6 +525,13 @@ static NTSTATUS gnutls_process_attach( void *args ) fail: dlclose( libgnutls_handle ); libgnutls_handle = NULL; +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + if (libgmp_handle) + { + dlclose( libgmp_handle ); + libgmp_handle = NULL; + } +#endif return STATUS_DLL_NOT_FOUND; }
@@ -488,6 +543,10 @@ static NTSTATUS gnutls_process_detach( void *args ) dlclose( libgnutls_handle ); libgnutls_handle = NULL; } +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + dlclose( libgmp_handle ); + libgmp_handle = NULL; +#endif return STATUS_SUCCESS; }
@@ -1481,12 +1540,133 @@ static NTSTATUS key_export_rsa( struct key *key, ULONG flags, UCHAR *buf, ULONG return STATUS_SUCCESS; }
+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +typedef struct { + gnutls_datum_t d; + gnutls_datum_t u; + gnutls_datum_t dp; + gnutls_datum_t dq; +} rsa_crt_params_t; + +static BOOL calculate_rsa_crt_params(const unsigned char* n_data, size_t n_len, + const unsigned char* e_data, size_t e_len, + const unsigned char* p_data, size_t p_len, + const unsigned char* q_data, size_t q_len, + rsa_crt_params_t* params) +{ + mpz_t n, e, p, q, phi_n, d, p_minus_1, q_minus_1, dp, dq, u, n_calc; + BOOL ret = FALSE; + size_t size; + + if(!n_data || !e_data || !p_data || !q_data || !params) return ret; + + pmpz_init(n); + pmpz_init(e); + pmpz_init(p); + pmpz_init(q); + pmpz_init(phi_n); + pmpz_init(d); + pmpz_init(p_minus_1); + pmpz_init(q_minus_1); + pmpz_init(dp); + pmpz_init(dq); + pmpz_init(u); + + pmpz_import(n, n_len, 1, sizeof(unsigned char), 0, 0, n_data); + pmpz_import(e, e_len, 1, sizeof(unsigned char), 0, 0, e_data); + pmpz_import(p, p_len, 1, sizeof(unsigned char), 0, 0, p_data); + pmpz_import(q, q_len, 1, sizeof(unsigned char), 0, 0, q_data); + + pmpz_init(n_calc); + pmpz_mul(n_calc, p, q); + if (pmpz_cmp(n, n_calc) != 0) + { + ERR("n != p * q input data is inconsistent.\n"); + pmpz_clear(n_calc); + goto done; + } + pmpz_clear(n_calc); + + pmpz_sub_ui(p_minus_1, p, 1); + pmpz_sub_ui(q_minus_1, q, 1); + pmpz_mul(phi_n, p_minus_1, q_minus_1); + + if (pmpz_invert(d, e, phi_n) == 0) + { + ERR("inverse does not exist (e and φ(n) are not coprime).\n"); + goto done; + } + + pmpz_mod(dp, d, p_minus_1); + + pmpz_mod(dq, d, q_minus_1); + + if (pmpz_invert(u, q, p) == 0) + { + ERR("inverse does not exist (q and p are not coprime - they should be primes!).\n"); + goto done; + } + + size = (pmpz_sizeinbase(d, 2) + 7) / 8; + params->d.data = malloc(size); + if (!params->d.data) goto done; + pmpz_export(params->d.data, &size, 1, sizeof(unsigned char), 0, 0, d); + params->d.size = size; + + size = (pmpz_sizeinbase(dp, 2) + 7) / 8; + params->dp.data = malloc(size); + if (!params->dp.data) goto done; + pmpz_export(params->dp.data, &size, 1, sizeof(unsigned char), 0, 0, dp); + params->dp.size = size; + + size = (pmpz_sizeinbase(dq, 2) + 7) / 8; + params->dq.data = malloc(size); + if (!params->dq.data) goto done; + pmpz_export(params->dq.data, &size, 1, sizeof(unsigned char), 0, 0, dq); + params->dq.size = size; + + size = (pmpz_sizeinbase(u, 2) + 7) / 8; + params->u.data = malloc(size); + if (!params->u.data) goto done; + pmpz_export(params->u.data, &size, 1, sizeof(unsigned char), 0, 0, u); + params->u.size = size; + + ret = TRUE; + +done: + if (!ret) + { + free(params->d.data); + free(params->dp.data); + free(params->dq.data); + free(params->u.data); + } + + pmpz_clear(n); + pmpz_clear(e); + pmpz_clear(p); + pmpz_clear(q); + pmpz_clear(phi_n); + pmpz_clear(d); + pmpz_clear(p_minus_1); + pmpz_clear(q_minus_1); + pmpz_clear(dp); + pmpz_clear(dq); + pmpz_clear(u); + + return ret; +} +#endif + static NTSTATUS key_import_rsa( struct key *key, UCHAR *buf, ULONG len ) { BCRYPT_RSAKEY_BLOB *rsa_blob = (BCRYPT_RSAKEY_BLOB *)buf; gnutls_datum_t m, e, p, q; gnutls_privkey_t handle; int ret; +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + rsa_crt_params_t crt_params = {0}; +#endif
if ((ret = pgnutls_privkey_init( &handle ))) { @@ -1503,7 +1683,22 @@ static NTSTATUS key_import_rsa( struct key *key, UCHAR *buf, ULONG len ) q.data = p.data + p.size; q.size = rsa_blob->cbPrime2;
- if ((ret = pgnutls_privkey_import_rsa_raw( handle, &m, &e, NULL, &p, &q, NULL, NULL, NULL ))) +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + if (calculate_rsa_crt_params(m.data, m.size, e.data, e.size, p.data, p.size, q.data, q.size, &crt_params)) + { + + ret = pgnutls_privkey_import_rsa_raw( handle, &m, &e, &crt_params.d, &p, &q, + &crt_params.u, &crt_params.dp, &crt_params.dq ); + + free(crt_params.d.data); + free(crt_params.u.data); + free(crt_params.dp.data); + free(crt_params.dq.data); + } else +#endif + ret = pgnutls_privkey_import_rsa_raw( handle, &m, &e, NULL, &p, &q, NULL, NULL, NULL ); + + if (ret) { pgnutls_perror( ret ); pgnutls_privkey_deinit( handle );