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:
parent
677107378e
commit
f18ccfef7b
|
@ -460,11 +460,17 @@ void init_empty_store(void) DECLSPEC_HIDDEN;
|
|||
|
||||
/* Unix interface */
|
||||
|
||||
struct cert_store_data;
|
||||
|
||||
struct unix_funcs
|
||||
{
|
||||
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,
|
||||
void **key_ret, void ***chain_ret, DWORD *count_ret );
|
||||
BOOL (WINAPI *open_cert_store)( CRYPT_DATA_BLOB *pfx, const WCHAR *password,
|
||||
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;
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wincrypt.h"
|
||||
|
@ -29,13 +32,15 @@
|
|||
|
||||
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;
|
||||
HCRYPTKEY cryptkey;
|
||||
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;
|
||||
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() );
|
||||
CryptReleaseContext( prov, 0 );
|
||||
free( key );
|
||||
return 0;
|
||||
}
|
||||
CryptDestroyKey( cryptkey );
|
||||
free( key );
|
||||
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 )
|
||||
{
|
||||
void *key, **chain;
|
||||
DWORD i, chain_len = 0;
|
||||
DWORD i = 0, size;
|
||||
HCERTSTORE store = NULL;
|
||||
HCRYPTPROV prov = 0;
|
||||
struct cert_store_data *data = NULL;
|
||||
|
||||
if (!pfx)
|
||||
{
|
||||
|
@ -147,15 +156,14 @@ HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor
|
|||
FIXME( "flags %08x not supported\n", flags );
|
||||
return NULL;
|
||||
}
|
||||
if (!unix_funcs->import_cert_store)
|
||||
if (!unix_funcs->open_cert_store)
|
||||
{
|
||||
FIXME( "(%p, %p, %08x)\n", pfx, password, flags );
|
||||
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 );
|
||||
heap_free( key );
|
||||
prov = import_key( data, flags );
|
||||
if (!prov) goto error;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (chain_len > 1) FIXME( "handle certificate chain\n" );
|
||||
for (i = 0; i < chain_len; i++)
|
||||
for (;;)
|
||||
{
|
||||
const void *ctx;
|
||||
size_t size = HeapSize( GetProcessHeap(), 0, chain[i] );
|
||||
const void *ctx = NULL;
|
||||
void *cert;
|
||||
|
||||
if (!(ctx = CertCreateContext( CERT_STORE_CERTIFICATE_CONTEXT, X509_ASN_ENCODING,
|
||||
chain[i], size, 0, NULL )))
|
||||
if (unix_funcs->import_store_cert( data, i, NULL, &size ) != STATUS_BUFFER_TOO_SMALL) break;
|
||||
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() );
|
||||
goto error;
|
||||
|
@ -199,15 +210,13 @@ HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor
|
|||
}
|
||||
CertFreeCertificateContext( ctx );
|
||||
}
|
||||
while (chain_len) heap_free( chain[--chain_len] );
|
||||
heap_free( chain );
|
||||
unix_funcs->close_cert_store( data );
|
||||
return store;
|
||||
|
||||
error:
|
||||
CryptReleaseContext( prov, 0 );
|
||||
CertCloseStore( store, 0 );
|
||||
while (chain_len) heap_free( chain[--chain_len] );
|
||||
heap_free( chain );
|
||||
if (data) unix_funcs->close_cert_store( data );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -155,38 +155,37 @@ static void gnutls_uninitialize(void)
|
|||
#define RSA_MAGIC_KEY ('R' | ('S' << 8) | ('A' << 16) | ('2' << 24))
|
||||
#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;
|
||||
unsigned int bitlen;
|
||||
unsigned int bitlen = data->key_bitlen;
|
||||
gnutls_datum_t m, e, d, p, q, u, e1, e2;
|
||||
BLOBHEADER *hdr;
|
||||
RSAPUBKEY *rsakey;
|
||||
BYTE *buf, *src, *dst;
|
||||
BYTE *src, *dst;
|
||||
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);
|
||||
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->bType = PRIVATEKEYBLOB;
|
||||
|
@ -235,8 +234,6 @@ static DWORD import_key( gnutls_x509_privkey_t key, DWORD flags, void **data_ret
|
|||
else src = d.data;
|
||||
for (i = bitlen / 8 - 1; i >= 0; i--) *dst++ = src[i];
|
||||
|
||||
*data_ret = buf;
|
||||
|
||||
done:
|
||||
free( m.data );
|
||||
free( e.data );
|
||||
|
@ -246,8 +243,7 @@ done:
|
|||
free( u.data );
|
||||
free( e1.data );
|
||||
free( e2.data );
|
||||
if (!*data_ret) RtlFreeHeap( GetProcessHeap(), 0, buf );
|
||||
return size;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static char *password_to_ascii( const WCHAR *str )
|
||||
|
@ -265,16 +261,18 @@ static char *password_to_ascii( const WCHAR *str )
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI import_cert_store( CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags,
|
||||
void **key_ret, void ***chain_ret, DWORD *count_ret )
|
||||
static BOOL WINAPI open_cert_store( CRYPT_DATA_BLOB *pfx, const WCHAR *password,
|
||||
struct cert_store_data **data_ret )
|
||||
{
|
||||
gnutls_pkcs12_t p12;
|
||||
gnutls_datum_t pfx_data;
|
||||
gnutls_x509_privkey_t key;
|
||||
gnutls_x509_crt_t *chain;
|
||||
unsigned int chain_len, i;
|
||||
unsigned int chain_len;
|
||||
unsigned int bitlen;
|
||||
char *pwd = NULL;
|
||||
int ret;
|
||||
struct cert_store_data *store_data;
|
||||
|
||||
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)
|
||||
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) );
|
||||
*count_ret = chain_len;
|
||||
for (i = 0; i < chain_len; i++)
|
||||
free( pwd );
|
||||
|
||||
if (ret != GNUTLS_PK_RSA)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
if ((ret = pgnutls_x509_crt_export( chain[i], GNUTLS_X509_FMT_DER, NULL, &size )) != GNUTLS_E_SHORT_MEMORY_BUFFER)
|
||||
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;
|
||||
}
|
||||
FIXME( "key algorithm %u not supported\n", ret );
|
||||
pgnutls_pkcs12_deinit( p12 );
|
||||
return FALSE;
|
||||
}
|
||||
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;
|
||||
|
||||
error:
|
||||
|
@ -317,6 +313,34 @@ error:
|
|||
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 */
|
||||
|
||||
struct root_cert
|
||||
|
@ -649,7 +673,13 @@ NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *p
|
|||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
#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
|
||||
*(const struct unix_funcs **)ptr_out = &funcs;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue