Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50024 Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/crypt32/cert.c | 251 +++++++++++++-------------------- dlls/crypt32/crypt32_private.h | 8 -- dlls/crypt32/serialize.c | 187 +++++++++++++++++++++++- 3 files changed, 279 insertions(+), 167 deletions(-)
diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c index c0bec721fd..aad8fa047b 100644 --- a/dlls/crypt32/cert.c +++ b/dlls/crypt32/cert.c @@ -434,6 +434,84 @@ void CRYPT_ConvertKeyContext(const struct store_CERT_KEY_CONTEXT *src, CERT_KEY_ dst->dwKeySpec = src->dwKeySpec; }
+/* + * Fix offsets in a continuous block of memory of CRYPT_KEY_PROV_INFO with + * its associated data. + */ +static void fix_KeyProvInfoProperty(CRYPT_KEY_PROV_INFO *info) +{ + BYTE *data; + DWORD i; + + data = (BYTE *)(info + 1) + sizeof(CRYPT_KEY_PROV_PARAM) * info->cProvParam; + + if (info->pwszContainerName) + { + info->pwszContainerName = (LPWSTR)data; + data += (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR); + } + + if (info->pwszProvName) + { + info->pwszProvName = (LPWSTR)data; + data += (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR); + } + + info->rgProvParam = info->cProvParam ? (CRYPT_KEY_PROV_PARAM *)(info + 1) : NULL; + + for (i = 0; i < info->cProvParam; i++) + { + info->rgProvParam[i].pbData = info->rgProvParam[i].cbData ? data : NULL; + data += info->rgProvParam[i].cbData; + } +} + +/* + * Copy to a continuous block of memory of CRYPT_KEY_PROV_INFO with + * its associated data. + */ +static void copy_KeyProvInfoProperty(const CRYPT_KEY_PROV_INFO *from, CRYPT_KEY_PROV_INFO *to) +{ + BYTE *data; + DWORD i; + + data = (BYTE *)(to + 1) + sizeof(CRYPT_KEY_PROV_PARAM) * from->cProvParam; + + if (from->pwszContainerName) + { + to->pwszContainerName = (LPWSTR)data; + lstrcpyW((LPWSTR)data, from->pwszContainerName); + data += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR); + } + else + to->pwszContainerName = NULL; + + if (from->pwszProvName) + { + to->pwszProvName = (LPWSTR)data; + lstrcpyW((LPWSTR)data, from->pwszProvName); + data += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR); + } + else + to->pwszProvName = NULL; + + to->dwProvType = from->dwProvType; + to->dwFlags = from->dwFlags; + to->cProvParam = from->cProvParam; + to->rgProvParam = from->cProvParam ? (CRYPT_KEY_PROV_PARAM *)(to + 1) : NULL; + to->dwKeySpec = from->dwKeySpec; + + for (i = 0; i < from->cProvParam; i++) + { + to->rgProvParam[i].dwParam = from->rgProvParam[i].dwParam; + to->rgProvParam[i].dwFlags = from->rgProvParam[i].dwFlags; + to->rgProvParam[i].cbData = from->rgProvParam[i].cbData; + to->rgProvParam[i].pbData = from->rgProvParam[i].cbData ? data : NULL; + memcpy(data, from->rgProvParam[i].pbData, from->rgProvParam[i].cbData); + data += from->rgProvParam[i].cbData; + } +} + static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId, void *pvData, DWORD *pcbData) { @@ -535,87 +613,6 @@ static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId, return ret; }
-/* 64-bit compatible layout, so that 64-bit crypt32 is able to read - * the structure saved by 32-bit crypt32. - */ -typedef struct -{ - ULONG64 pwszContainerName; - ULONG64 pwszProvName; - DWORD dwProvType; - DWORD dwFlags; - DWORD cProvParam; - ULONG64 rgProvParam; - DWORD dwKeySpec; -} store_CRYPT_KEY_PROV_INFO; - -typedef struct -{ - DWORD dwParam; - ULONG64 pbData; - DWORD cbData; - DWORD dwFlags; -} store_CRYPT_KEY_PROV_PARAM; - -void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO buf) -{ - CRYPT_KEY_PROV_INFO info; - store_CRYPT_KEY_PROV_INFO *store = (store_CRYPT_KEY_PROV_INFO *)buf; - BYTE *p = (BYTE *)(store + 1); - - if (store->pwszContainerName) - { - info.pwszContainerName = (LPWSTR)((BYTE *)store + store->pwszContainerName); - p += (lstrlenW(info.pwszContainerName) + 1) * sizeof(WCHAR); - } - else - info.pwszContainerName = NULL; - - if (store->pwszProvName) - { - info.pwszProvName = (LPWSTR)((BYTE *)store + store->pwszProvName); - p += (lstrlenW(info.pwszProvName) + 1) * sizeof(WCHAR); - } - else - info.pwszProvName = NULL; - - info.dwProvType = store->dwProvType; - info.dwFlags = store->dwFlags; - info.dwKeySpec = store->dwKeySpec; - info.cProvParam = store->cProvParam; - - if (info.cProvParam) - { - DWORD i; - - info.rgProvParam = (CRYPT_KEY_PROV_PARAM *)p; - - for (i = 0; i < store->cProvParam; i++) - { - CRYPT_KEY_PROV_PARAM param; - store_CRYPT_KEY_PROV_PARAM *store_param; - - store_param = (store_CRYPT_KEY_PROV_PARAM *)p; - p += sizeof(*store_param); - - param.dwParam = store_param[i].dwParam; - param.dwFlags = store_param[i].dwFlags; - param.cbData = store_param[i].cbData; - param.pbData = param.cbData ? p : NULL; - p += store_param[i].cbData; - - memcpy(&info.rgProvParam[i], ¶m, sizeof(param)); - } - } - else - info.rgProvParam = NULL; - - TRACE("%s,%s,%u,%08x,%u,%p,%u\n", debugstr_w(info.pwszContainerName), debugstr_w(info.pwszProvName), - info.dwProvType, info.dwFlags, info.cProvParam, info.rgProvParam, info.dwKeySpec); - - *buf = info; -} - BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, DWORD dwPropId, void *pvData, DWORD *pcbData) { @@ -649,10 +646,9 @@ BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, break; } case CERT_KEY_PROV_INFO_PROP_ID: - ret = CertContext_GetProperty(cert, dwPropId, pvData, - pcbData); + ret = CertContext_GetProperty(cert, dwPropId, pvData, pcbData); if (ret && pvData) - CRYPT_FixKeyProvInfoPointers(pvData); + fix_KeyProvInfoProperty(pvData); break; default: ret = CertContext_GetProperty(cert, dwPropId, pvData, @@ -663,69 +659,14 @@ BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, return ret; }
-/* Copies key provider info from from into to, where to is assumed to be a - * contiguous buffer of memory large enough for from and all its associated - * data, but whose pointers are uninitialized. - * Upon return, to contains a contiguous copy of from, packed in the following - * order: - * - store_CRYPT_KEY_PROV_INFO - * - pwszContainerName - * - pwszProvName - * - store_CRYPT_KEY_PROV_PARAM[0] - * - store_CRYPT_KEY_PROV_PARAM[0].data - * - ... +/* + * Create a continuous block of memory for CRYPT_KEY_PROV_INFO with + * its associated data, and add it to the certificate properties. */ -static void CRYPT_CopyKeyProvInfo(store_CRYPT_KEY_PROV_INFO *to, const CRYPT_KEY_PROV_INFO *from) +static BOOL CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST *properties, const CRYPT_KEY_PROV_INFO *info) { - DWORD i; - BYTE *p; - store_CRYPT_KEY_PROV_PARAM *param; - - p = (BYTE *)(to + 1); - - if (from->pwszContainerName) - { - to->pwszContainerName = p - (BYTE *)to; - lstrcpyW((LPWSTR)p, from->pwszContainerName); - p += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR); - } - else - to->pwszContainerName = 0; - - if (from->pwszProvName) - { - to->pwszProvName = p - (BYTE *)to; - lstrcpyW((LPWSTR)p, from->pwszProvName); - p += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR); - } - else - to->pwszProvName = 0; - - to->dwProvType = from->dwProvType; - to->dwFlags = from->dwFlags; - to->cProvParam = from->cProvParam; - to->rgProvParam = 0; - to->dwKeySpec = from->dwKeySpec; - - for (i = 0; i < to->cProvParam; i++) - { - param = (store_CRYPT_KEY_PROV_PARAM *)p; - p += sizeof(*param); - - param->dwParam = from->rgProvParam[i].dwParam; - param->pbData = 0; - param->cbData = from->rgProvParam[i].cbData; - param->dwFlags = from->rgProvParam[i].dwFlags; - memcpy(p, from->rgProvParam[i].pbData, from->rgProvParam[i].cbData); - p += from->rgProvParam[i].cbData; - } -} - -static BOOL CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST *properties, - const CRYPT_KEY_PROV_INFO *info) -{ - BYTE *buf; - DWORD size = sizeof(store_CRYPT_KEY_PROV_INFO), i; + CRYPT_KEY_PROV_INFO *prop; + DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i; BOOL ret;
if (info->pwszContainerName) @@ -734,18 +675,20 @@ static BOOL CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST *properties size += (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
for (i = 0; i < info->cProvParam; i++) - size += sizeof(store_CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData; + size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
- buf = CryptMemAlloc(size); - if (buf) + prop = HeapAlloc(GetProcessHeap(), 0, size); + if (!prop) { - CRYPT_CopyKeyProvInfo((store_CRYPT_KEY_PROV_INFO *)buf, info); - ret = ContextPropertyList_SetProperty(properties, - CERT_KEY_PROV_INFO_PROP_ID, buf, size); - CryptMemFree(buf); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; } - else - ret = FALSE; + + copy_KeyProvInfoProperty(info, prop); + + ret = ContextPropertyList_SetProperty(properties, CERT_KEY_PROV_INFO_PROP_ID, (const BYTE *)prop, size); + HeapFree(GetProcessHeap(), 0, prop); + return ret; }
diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index a4664ed85a..30cf4334de 100644 --- a/dlls/crypt32/crypt32_private.h +++ b/dlls/crypt32/crypt32_private.h @@ -370,14 +370,6 @@ BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) DECLSPEC_H BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob, HCERTSTORE store) DECLSPEC_HIDDEN;
-/* Fixes up the pointers in info, where info is assumed to be a - * CRYPT_KEY_PROV_INFO, followed by its container name, provider name, and any - * provider parameters, in a contiguous buffer, but where info's pointers are - * assumed to be invalid. Upon return, info's pointers point to the - * appropriate memory locations. - */ -void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info) DECLSPEC_HIDDEN; - struct store_CERT_KEY_CONTEXT { DWORD cbSize; diff --git a/dlls/crypt32/serialize.c b/dlls/crypt32/serialize.c index d5153deb10..8fa24370b6 100644 --- a/dlls/crypt32/serialize.c +++ b/dlls/crypt32/serialize.c @@ -36,6 +36,86 @@ typedef struct _WINE_CERT_PROP_HEADER DWORD cb; } WINE_CERT_PROP_HEADER;
+struct store_CRYPT_KEY_PROV_INFO +{ + DWORD pwszContainerName; + DWORD pwszProvName; + DWORD dwProvType; + DWORD dwFlags; + DWORD cProvParam; + DWORD rgProvParam; + DWORD dwKeySpec; +}; + +struct store_CRYPT_KEY_PROV_PARAM +{ + DWORD dwParam; + DWORD pbData; + DWORD cbData; + DWORD dwFlags; +}; + +static DWORD serialize_KeyProvInfoProperty(const CRYPT_KEY_PROV_INFO *info, struct store_CRYPT_KEY_PROV_INFO **ret) +{ + struct store_CRYPT_KEY_PROV_INFO *store; + struct store_CRYPT_KEY_PROV_PARAM *param; + DWORD size = sizeof(struct store_CRYPT_KEY_PROV_INFO), i; + BYTE *data; + + if (info->pwszContainerName) + size += (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR); + if (info->pwszProvName) + size += (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR); + + for (i = 0; i < info->cProvParam; i++) + size += sizeof(struct store_CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData; + + if (!ret) return size; + + store = HeapAlloc(GetProcessHeap(), 0, size); + if (!store) return 0; + + param = (struct store_CRYPT_KEY_PROV_PARAM *)(store + 1); + data = (BYTE *)param + sizeof(struct store_CRYPT_KEY_PROV_PARAM) * info->cProvParam; + + if (info->pwszContainerName) + { + store->pwszContainerName = data - (BYTE *)store; + lstrcpyW((LPWSTR)data, info->pwszContainerName); + data += (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR); + } + else + store->pwszContainerName = 0; + + if (info->pwszProvName) + { + store->pwszProvName = data - (BYTE *)store; + lstrcpyW((LPWSTR)data, info->pwszProvName); + data += (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR); + } + else + store->pwszProvName = 0; + + store->dwProvType = info->dwProvType; + store->dwFlags = info->dwFlags; + store->cProvParam = info->cProvParam; + store->rgProvParam = info->cProvParam ? (BYTE *)param - (BYTE *)store : 0; + store->dwKeySpec = info->dwKeySpec; + + for (i = 0; i < info->cProvParam; i++) + { + param[i].dwParam = info->rgProvParam[i].dwParam; + param[i].dwFlags = info->rgProvParam[i].dwFlags; + param[i].cbData = info->rgProvParam[i].cbData; + param[i].pbData = param[i].cbData ? data - (BYTE *)store : 0; + memcpy(data, info->rgProvParam[i].pbData, info->rgProvParam[i].cbData); + data += info->rgProvParam[i].cbData; + } + + *ret = store; + return size; +} + static BOOL CRYPT_SerializeStoreElement(const void *context, const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID, const WINE_CONTEXT_INTERFACE *contextInterface, DWORD dwFlags, BOOL omitHashes, @@ -60,7 +140,16 @@ static BOOL CRYPT_SerializeStoreElement(const void *context,
ret = contextInterface->getProp(context, prop, NULL, &propSize); if (ret) + { + if (prop == CERT_KEY_PROV_INFO_PROP_ID) + { + BYTE *info = CryptMemAlloc(propSize); + contextInterface->getProp(context, prop, info, &propSize); + propSize = serialize_KeyProvInfoProperty((const CRYPT_KEY_PROV_INFO *)info, NULL); + CryptMemFree(info); + } bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize; + } } } while (ret && prop != 0);
@@ -106,6 +195,14 @@ static BOOL CRYPT_SerializeStoreElement(const void *context, &propSize); if (ret) { + if (prop == CERT_KEY_PROV_INFO_PROP_ID) + { + struct store_CRYPT_KEY_PROV_INFO *store; + propSize = serialize_KeyProvInfoProperty((const CRYPT_KEY_PROV_INFO *)buf, &store); + CryptMemFree(buf); + buf = (BYTE *)store; + } + hdr = (WINE_CERT_PROP_HEADER*)pbElement; hdr->propID = prop; hdr->unknown = 1; @@ -215,6 +312,83 @@ static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf, return ret; }
+static DWORD read_serialized_KeyProvInfoProperty(const struct store_CRYPT_KEY_PROV_INFO *store, CRYPT_KEY_PROV_INFO **ret) +{ + const struct store_CRYPT_KEY_PROV_PARAM *param; + CRYPT_KEY_PROV_INFO *info; + DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i; + const BYTE *base; + BYTE *data; + + base = (const BYTE *)store; + param = (const struct store_CRYPT_KEY_PROV_PARAM *)(base + store->rgProvParam); + + if (store->pwszContainerName) + size += (lstrlenW((LPCWSTR)(base + store->pwszContainerName)) + 1) * sizeof(WCHAR); + if (store->pwszProvName) + size += (lstrlenW((LPCWSTR)(base + store->pwszProvName)) + 1) * sizeof(WCHAR); + + for (i = 0; i < store->cProvParam; i++) + size += sizeof(CRYPT_KEY_PROV_PARAM) + param[i].cbData; + + info = HeapAlloc(GetProcessHeap(), 0, size); + if (!info) + { + SetLastError(ERROR_OUTOFMEMORY); + return 0; + } + + data = (BYTE *)(info + 1) + sizeof(CRYPT_KEY_PROV_PARAM) * store->cProvParam; + + if (store->pwszContainerName) + { + info->pwszContainerName = (LPWSTR)data; + lstrcpyW(info->pwszContainerName, (LPCWSTR)((const BYTE *)store + store->pwszContainerName)); + data += (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR); + } + else + info->pwszContainerName = NULL; + + if (store->pwszProvName) + { + info->pwszProvName = (LPWSTR)data; + lstrcpyW(info->pwszProvName, (LPCWSTR)((const BYTE *)store + store->pwszProvName)); + data += (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR); + } + else + info->pwszProvName = NULL; + + info->dwProvType = store->dwProvType; + info->dwFlags = store->dwFlags; + info->dwKeySpec = store->dwKeySpec; + info->cProvParam = store->cProvParam; + + if (info->cProvParam) + { + DWORD i; + + info->rgProvParam = (CRYPT_KEY_PROV_PARAM *)(info + 1); + + for (i = 0; i < info->cProvParam; i++) + { + info->rgProvParam[i].dwParam = param[i].dwParam; + info->rgProvParam[i].dwFlags = param[i].dwFlags; + info->rgProvParam[i].cbData = param[i].cbData; + info->rgProvParam[i].pbData = param[i].cbData ? data : NULL; + memcpy(info->rgProvParam[i].pbData, base + param[i].pbData, param[i].cbData); + data += param[i].cbData; + } + } + else + info->rgProvParam = NULL; + + TRACE("%s,%s,%u,%08x,%u,%p,%u\n", debugstr_w(info->pwszContainerName), debugstr_w(info->pwszProvName), + info->dwProvType, info->dwFlags, info->cProvParam, info->rgProvParam, info->dwKeySpec); + + *ret = info; + return size; +} + static BOOL CRYPT_ReadContextProp( const WINE_CONTEXT_INTERFACE *contextInterface, const void *context, const WINE_CERT_PROP_HEADER *hdr, const BYTE *pbElement, DWORD cbElement) @@ -269,12 +443,15 @@ static BOOL CRYPT_ReadContextProp( break; case CERT_KEY_PROV_INFO_PROP_ID: { - PCRYPT_KEY_PROV_INFO info = - (PCRYPT_KEY_PROV_INFO)pbElement; + CRYPT_KEY_PROV_INFO *info;
- CRYPT_FixKeyProvInfoPointers(info); - ret = contextInterface->setProp(context, - hdr->propID, 0, pbElement); + if (read_serialized_KeyProvInfoProperty((const struct store_CRYPT_KEY_PROV_INFO *)pbElement, &info)) + { + ret = contextInterface->setProp(context, hdr->propID, 0, info); + CryptMemFree(info); + } + else + ret = FALSE; break; } case CERT_KEY_CONTEXT_PROP_ID: