From: Benoît Legat <benoit.legat@gmail.com> --- dlls/crypt32/pfx.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/dlls/crypt32/pfx.c b/dlls/crypt32/pfx.c index 5ece0bc9080..bc245497d4c 100644 --- a/dlls/crypt32/pfx.c +++ b/dlls/crypt32/pfx.c @@ -446,8 +446,14 @@ BOOL WINAPI PFXExportCertStoreEx( HCERTSTORE store, CRYPT_DATA_BLOB *pfx, const params.key_blob_size = key_blob ? key_blob_size : 0; params.password = password; - if (!pfx->pbData) + /* GnuTLS encrypts the private key with a random salt, so the output + * size can vary between calls. Do a single export into a temporary + * buffer and then handle the size query / copy on the Windows side. */ { + DWORD alloc_size; + BYTE *tmp; + + /* Get an estimate of the required size. */ pfx_size = 0; params.pfx_data = NULL; params.pfx_size = &pfx_size; @@ -456,31 +462,50 @@ BOOL WINAPI PFXExportCertStoreEx( HCERTSTORE store, CRYPT_DATA_BLOB *pfx, const { WARN( "unix export_cert_store failed %08lx\n", (DWORD)status ); SetLastError( RtlNtStatusToDosError( status ) ); + goto done; } - else + + /* Allocate with extra room for size variation. */ + alloc_size = pfx_size + 256; + tmp = CryptMemAlloc( alloc_size ); + if (!tmp) { - pfx->cbData = pfx_size; - ret = TRUE; + SetLastError( ERROR_OUTOFMEMORY ); + goto done; } - } - else - { - pfx_size = pfx->cbData; - params.pfx_data = pfx->pbData; + + pfx_size = alloc_size; + params.pfx_data = tmp; params.pfx_size = &pfx_size; status = CRYPT32_CALL( export_cert_store, ¶ms ); if (status) { WARN( "unix export_cert_store failed %08lx\n", (DWORD)status ); SetLastError( RtlNtStatusToDosError( status ) ); + CryptMemFree( tmp ); + goto done; + } + + if (!pfx->pbData) + { + pfx->cbData = pfx_size; + ret = TRUE; + } + else if (pfx->cbData < pfx_size) + { + pfx->cbData = pfx_size; + SetLastError( ERROR_MORE_DATA ); } else { + memcpy( pfx->pbData, tmp, pfx_size ); pfx->cbData = pfx_size; ret = TRUE; } + CryptMemFree( tmp ); } +done: CryptMemFree( key_blob ); CertFreeCertificateContext( cert ); return ret; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10532