crypt32: Split the import_cert_store function to move memory allocations to the PE side.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-10-31 17:08:59 +01:00
parent 677107378e
commit f18ccfef7b
3 changed files with 116 additions and 71 deletions

View File

@ -460,11 +460,17 @@ void init_empty_store(void) DECLSPEC_HIDDEN;
/* Unix interface */ /* Unix interface */
struct cert_store_data;
struct unix_funcs struct unix_funcs
{ {
BOOL (WINAPI *enum_root_certs)( void *buffer, SIZE_T size, SIZE_T *needed ); BOOL (WINAPI *enum_root_certs)( void *buffer, SIZE_T size, SIZE_T *needed );
BOOL (WINAPI *import_cert_store)( CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags, BOOL (WINAPI *open_cert_store)( CRYPT_DATA_BLOB *pfx, const WCHAR *password,
void **key_ret, void ***chain_ret, DWORD *count_ret ); struct cert_store_data **data_ret );
NTSTATUS (WINAPI *import_store_key)( struct cert_store_data *data, void *buf, DWORD *buf_size );
NTSTATUS (WINAPI *import_store_cert)( struct cert_store_data *data, unsigned int index,
void *buf, DWORD *buf_size );
void (WINAPI *close_cert_store)( struct cert_store_data *data );
}; };
extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN; extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN;

View File

@ -17,7 +17,10 @@
*/ */
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "wincrypt.h" #include "wincrypt.h"
@ -29,13 +32,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(crypt); WINE_DEFAULT_DEBUG_CHANNEL(crypt);
static HCRYPTPROV import_key( void *key, DWORD flags ) static HCRYPTPROV import_key( struct cert_store_data *data, DWORD flags )
{ {
HCRYPTPROV prov = 0; HCRYPTPROV prov = 0;
HCRYPTKEY cryptkey; HCRYPTKEY cryptkey;
DWORD size, acquire_flags; DWORD size, acquire_flags;
void *key;
if (unix_funcs->import_store_key( data, NULL, &size ) != STATUS_BUFFER_TOO_SMALL) return 0;
size = HeapSize( GetProcessHeap(), 0, key );
acquire_flags = (flags & CRYPT_MACHINE_KEYSET) | CRYPT_NEWKEYSET; acquire_flags = (flags & CRYPT_MACHINE_KEYSET) | CRYPT_NEWKEYSET;
if (!CryptAcquireContextW( &prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL, acquire_flags )) if (!CryptAcquireContextW( &prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL, acquire_flags ))
{ {
@ -49,13 +54,17 @@ static HCRYPTPROV import_key( void *key, DWORD flags )
} }
} }
if (!CryptImportKey( prov, key, size, 0, flags & CRYPT_EXPORTABLE, &cryptkey )) key = malloc( size );
if (unix_funcs->import_store_key( data, key, &size ) ||
!CryptImportKey( prov, key, size, 0, flags & CRYPT_EXPORTABLE, &cryptkey ))
{ {
WARN( "CryptImportKey failed %08x\n", GetLastError() ); WARN( "CryptImportKey failed %08x\n", GetLastError() );
CryptReleaseContext( prov, 0 ); CryptReleaseContext( prov, 0 );
free( key );
return 0; return 0;
} }
CryptDestroyKey( cryptkey ); CryptDestroyKey( cryptkey );
free( key );
return prov; return prov;
} }
@ -132,10 +141,10 @@ static BOOL set_key_prov_info( const void *ctx, HCRYPTPROV prov )
HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags ) HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags )
{ {
void *key, **chain; DWORD i = 0, size;
DWORD i, chain_len = 0;
HCERTSTORE store = NULL; HCERTSTORE store = NULL;
HCRYPTPROV prov = 0; HCRYPTPROV prov = 0;
struct cert_store_data *data = NULL;
if (!pfx) if (!pfx)
{ {
@ -147,15 +156,14 @@ HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor
FIXME( "flags %08x not supported\n", flags ); FIXME( "flags %08x not supported\n", flags );
return NULL; return NULL;
} }
if (!unix_funcs->import_cert_store) if (!unix_funcs->open_cert_store)
{ {
FIXME( "(%p, %p, %08x)\n", pfx, password, flags ); FIXME( "(%p, %p, %08x)\n", pfx, password, flags );
return NULL; return NULL;
} }
if (!unix_funcs->import_cert_store( pfx, password, flags, &key, &chain, &chain_len )) return NULL; if (!unix_funcs->open_cert_store( pfx, password, &data )) return NULL;
prov = import_key( key, flags ); prov = import_key( data, flags );
heap_free( key );
if (!prov) goto error; if (!prov) goto error;
if (!(store = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL ))) if (!(store = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL )))
@ -164,14 +172,17 @@ HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor
goto error; goto error;
} }
if (chain_len > 1) FIXME( "handle certificate chain\n" ); for (;;)
for (i = 0; i < chain_len; i++)
{ {
const void *ctx; const void *ctx = NULL;
size_t size = HeapSize( GetProcessHeap(), 0, chain[i] ); void *cert;
if (!(ctx = CertCreateContext( CERT_STORE_CERTIFICATE_CONTEXT, X509_ASN_ENCODING, if (unix_funcs->import_store_cert( data, i, NULL, &size ) != STATUS_BUFFER_TOO_SMALL) break;
chain[i], size, 0, NULL ))) cert = malloc( size );
if (!unix_funcs->import_store_cert( data, i++, cert, &size ))
ctx = CertCreateContext( CERT_STORE_CERTIFICATE_CONTEXT, X509_ASN_ENCODING, cert, size, 0, NULL );
free( cert );
if (!ctx)
{ {
WARN( "CertCreateContext failed %08x\n", GetLastError() ); WARN( "CertCreateContext failed %08x\n", GetLastError() );
goto error; goto error;
@ -199,15 +210,13 @@ HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor
} }
CertFreeCertificateContext( ctx ); CertFreeCertificateContext( ctx );
} }
while (chain_len) heap_free( chain[--chain_len] ); unix_funcs->close_cert_store( data );
heap_free( chain );
return store; return store;
error: error:
CryptReleaseContext( prov, 0 ); CryptReleaseContext( prov, 0 );
CertCloseStore( store, 0 ); CertCloseStore( store, 0 );
while (chain_len) heap_free( chain[--chain_len] ); if (data) unix_funcs->close_cert_store( data );
heap_free( chain );
return NULL; return NULL;
} }

View File

@ -155,38 +155,37 @@ static void gnutls_uninitialize(void)
#define RSA_MAGIC_KEY ('R' | ('S' << 8) | ('A' << 16) | ('2' << 24)) #define RSA_MAGIC_KEY ('R' | ('S' << 8) | ('A' << 16) | ('2' << 24))
#define RSA_PUBEXP 65537 #define RSA_PUBEXP 65537
static DWORD import_key( gnutls_x509_privkey_t key, DWORD flags, void **data_ret ) struct cert_store_data
{
gnutls_pkcs12_t p12;
gnutls_x509_privkey_t key;
gnutls_x509_crt_t *chain;
unsigned int key_bitlen;
unsigned int chain_len;
};
static NTSTATUS WINAPI import_store_key( struct cert_store_data *data, void *buf, DWORD *buf_size )
{ {
int i, ret; int i, ret;
unsigned int bitlen; unsigned int bitlen = data->key_bitlen;
gnutls_datum_t m, e, d, p, q, u, e1, e2; gnutls_datum_t m, e, d, p, q, u, e1, e2;
BLOBHEADER *hdr; BLOBHEADER *hdr;
RSAPUBKEY *rsakey; RSAPUBKEY *rsakey;
BYTE *buf, *src, *dst; BYTE *src, *dst;
DWORD size; DWORD size;
*data_ret = NULL;
if ((ret = pgnutls_x509_privkey_get_pk_algorithm2( key, &bitlen )) < 0)
{
pgnutls_perror( ret );
return 0;
}
if (ret != GNUTLS_PK_RSA)
{
FIXME( "key algorithm %u not supported\n", ret );
return 0;
}
if ((ret = pgnutls_x509_privkey_export_rsa_raw2( key, &m, &e, &d, &p, &q, &u, &e1, &e2 )) < 0)
{
pgnutls_perror( ret );
return 0;
}
size = sizeof(*hdr) + sizeof(*rsakey) + (bitlen * 9 / 16); size = sizeof(*hdr) + sizeof(*rsakey) + (bitlen * 9 / 16);
if (!(buf = RtlAllocateHeap( GetProcessHeap(), 0, size ))) goto done; if (!buf || *buf_size < size)
{
*buf_size = size;
return STATUS_BUFFER_TOO_SMALL;
}
if ((ret = pgnutls_x509_privkey_export_rsa_raw2( data->key, &m, &e, &d, &p, &q, &u, &e1, &e2 )) < 0)
{
pgnutls_perror( ret );
return STATUS_INVALID_PARAMETER;
}
hdr = (BLOBHEADER *)buf; hdr = (BLOBHEADER *)buf;
hdr->bType = PRIVATEKEYBLOB; hdr->bType = PRIVATEKEYBLOB;
@ -235,8 +234,6 @@ static DWORD import_key( gnutls_x509_privkey_t key, DWORD flags, void **data_ret
else src = d.data; else src = d.data;
for (i = bitlen / 8 - 1; i >= 0; i--) *dst++ = src[i]; for (i = bitlen / 8 - 1; i >= 0; i--) *dst++ = src[i];
*data_ret = buf;
done: done:
free( m.data ); free( m.data );
free( e.data ); free( e.data );
@ -246,8 +243,7 @@ done:
free( u.data ); free( u.data );
free( e1.data ); free( e1.data );
free( e2.data ); free( e2.data );
if (!*data_ret) RtlFreeHeap( GetProcessHeap(), 0, buf ); return STATUS_SUCCESS;
return size;
} }
static char *password_to_ascii( const WCHAR *str ) static char *password_to_ascii( const WCHAR *str )
@ -265,16 +261,18 @@ static char *password_to_ascii( const WCHAR *str )
return ret; return ret;
} }
static BOOL WINAPI import_cert_store( CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags, static BOOL WINAPI open_cert_store( CRYPT_DATA_BLOB *pfx, const WCHAR *password,
void **key_ret, void ***chain_ret, DWORD *count_ret ) struct cert_store_data **data_ret )
{ {
gnutls_pkcs12_t p12; gnutls_pkcs12_t p12;
gnutls_datum_t pfx_data; gnutls_datum_t pfx_data;
gnutls_x509_privkey_t key; gnutls_x509_privkey_t key;
gnutls_x509_crt_t *chain; gnutls_x509_crt_t *chain;
unsigned int chain_len, i; unsigned int chain_len;
unsigned int bitlen;
char *pwd = NULL; char *pwd = NULL;
int ret; int ret;
struct cert_store_data *store_data;
if (password && !(pwd = password_to_ascii( password ))) return FALSE; if (password && !(pwd = password_to_ascii( password ))) return FALSE;
@ -287,27 +285,25 @@ static BOOL WINAPI import_cert_store( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor
if ((ret = pgnutls_pkcs12_simple_parse( p12, pwd ? pwd : "", &key, &chain, &chain_len, NULL, NULL, NULL, 0 )) < 0) if ((ret = pgnutls_pkcs12_simple_parse( p12, pwd ? pwd : "", &key, &chain, &chain_len, NULL, NULL, NULL, 0 )) < 0)
goto error; goto error;
if (!import_key( key, flags, key_ret )) goto error; if ((ret = pgnutls_x509_privkey_get_pk_algorithm2( key, &bitlen )) < 0)
goto error;
*chain_ret = RtlAllocateHeap( GetProcessHeap(), 0, chain_len * sizeof(*chain_ret) ); free( pwd );
*count_ret = chain_len;
for (i = 0; i < chain_len; i++) if (ret != GNUTLS_PK_RSA)
{ {
size_t size = 0; FIXME( "key algorithm %u not supported\n", ret );
pgnutls_pkcs12_deinit( p12 );
if ((ret = pgnutls_x509_crt_export( chain[i], GNUTLS_X509_FMT_DER, NULL, &size )) != GNUTLS_E_SHORT_MEMORY_BUFFER) return FALSE;
goto error;
(*chain_ret)[i] = RtlAllocateHeap( GetProcessHeap(), 0, size );
if ((ret = pgnutls_x509_crt_export( chain[i], GNUTLS_X509_FMT_DER, (*chain_ret)[i], &size )) < 0)
{
i++;
while (i) RtlFreeHeap( GetProcessHeap(), 0, (*chain_ret)[--i] );
RtlFreeHeap( GetProcessHeap(), 0, *chain_ret );
goto error;
}
} }
pgnutls_pkcs12_deinit( p12 );
store_data = malloc( sizeof(*store_data) );
store_data->p12 = p12;
store_data->key = key;
store_data->chain = chain;
store_data->key_bitlen = bitlen;
store_data->chain_len = chain_len;
*data_ret = store_data;
return TRUE; return TRUE;
error: error:
@ -317,6 +313,34 @@ error:
return FALSE; return FALSE;
} }
static NTSTATUS WINAPI import_store_cert( struct cert_store_data *data, unsigned int index,
void *buf, DWORD *buf_size )
{
size_t size = 0;
int ret;
if (index >= data->chain_len) return STATUS_NO_MORE_ENTRIES;
if ((ret = pgnutls_x509_crt_export( data->chain[index], GNUTLS_X509_FMT_DER, NULL, &size )) != GNUTLS_E_SHORT_MEMORY_BUFFER)
return STATUS_INVALID_PARAMETER;
if (!buf || *buf_size < size)
{
*buf_size = size;
return STATUS_BUFFER_TOO_SMALL;
}
if ((ret = pgnutls_x509_crt_export( data->chain[index], GNUTLS_X509_FMT_DER, buf, &size )) < 0)
return STATUS_INVALID_PARAMETER;
return STATUS_SUCCESS;
}
static void WINAPI close_cert_store( struct cert_store_data *data )
{
pgnutls_pkcs12_deinit( data->p12 );
free( data );
}
#endif /* SONAME_LIBGNUTLS */ #endif /* SONAME_LIBGNUTLS */
struct root_cert struct root_cert
@ -649,7 +673,13 @@ NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *p
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
#ifdef SONAME_LIBGNUTLS #ifdef SONAME_LIBGNUTLS
if (gnutls_initialize()) funcs.import_cert_store = import_cert_store; if (gnutls_initialize())
{
funcs.open_cert_store = open_cert_store;
funcs.import_store_key = import_store_key;
funcs.import_store_cert = import_store_cert;
funcs.close_cert_store = close_cert_store;
}
#endif #endif
*(const struct unix_funcs **)ptr_out = &funcs; *(const struct unix_funcs **)ptr_out = &funcs;
break; break;