crypt32: Copy the CRL_INFO structure instead of recalculating it.

Steam calls CertGetCertificateChain() on a certificate with a 20 MB CRL, which
can take over 400 ms to parse each time. Avoid parsing it more often than we
need to.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-07-15 11:25:17 -05:00 committed by Alexandre Julliard
parent 1c501c6587
commit bdcddf024f

View file

@ -38,6 +38,108 @@ static void CRL_free(context_t *context)
static const context_vtbl_t crl_vtbl;
static char *copy_string(char *p, char **dst, const char *src)
{
size_t size = strlen(src) + 1;
*dst = memcpy(p, src, size);
return p + size;
}
static char *copy_blob(char *p, DATA_BLOB *dst, const DATA_BLOB *src)
{
size_t size = src->cbData;
dst->cbData = size;
dst->pbData = memcpy(p, src->pbData, size);
return p + size;
}
static char *copy_extension(char *p, CERT_EXTENSION *dst, const CERT_EXTENSION *src)
{
p = copy_string(p, &dst->pszObjId, src->pszObjId);
dst->fCritical = src->fCritical;
return copy_blob(p, &dst->Value, &src->Value);
}
static CRL_INFO *clone_crl_info(const CRL_INFO *src)
{
size_t size = sizeof(CRL_INFO);
CRL_INFO *dst;
DWORD i, j;
char *p;
if (src->SignatureAlgorithm.pszObjId)
size += strlen(src->SignatureAlgorithm.pszObjId) + 1;
size += src->SignatureAlgorithm.Parameters.cbData;
size += src->Issuer.cbData;
for (i = 0; i < src->cCRLEntry; ++i)
{
const CRL_ENTRY *entry = &src->rgCRLEntry[i];
size += sizeof(CRL_ENTRY);
size += entry->SerialNumber.cbData;
for (j = 0; j < entry->cExtension; ++j)
{
const CERT_EXTENSION *ext = &entry->rgExtension[j];
size += sizeof(CERT_EXTENSION);
size += strlen(ext->pszObjId) + 1;
size += ext->Value.cbData;
}
}
for (j = 0; j < src->cExtension; ++j)
{
const CERT_EXTENSION *ext = &src->rgExtension[j];
size += sizeof(CERT_EXTENSION);
size += strlen(ext->pszObjId) + 1;
size += ext->Value.cbData;
}
if (!(dst = LocalAlloc(LPTR, size)))
return NULL;
p = (char *)(dst + 1);
dst->dwVersion = src->dwVersion;
if (src->SignatureAlgorithm.pszObjId)
p = copy_string(p, &dst->SignatureAlgorithm.pszObjId, src->SignatureAlgorithm.pszObjId);
p = copy_blob(p, &dst->SignatureAlgorithm.Parameters, &src->SignatureAlgorithm.Parameters);
p = copy_blob(p, &dst->Issuer, &src->Issuer);
dst->ThisUpdate = src->ThisUpdate;
dst->NextUpdate = src->NextUpdate;
dst->cCRLEntry = src->cCRLEntry;
dst->rgCRLEntry = (CRL_ENTRY *)p;
p += src->cCRLEntry * sizeof(CRL_ENTRY);
dst->cExtension = src->cExtension;
dst->rgExtension = (CERT_EXTENSION *)p;
p += src->cExtension * sizeof(CERT_EXTENSION);
for (i = 0; i < src->cCRLEntry; ++i)
{
const CRL_ENTRY *src_entry = &src->rgCRLEntry[i];
CRL_ENTRY *dst_entry = &dst->rgCRLEntry[i];
p = copy_blob(p, &dst_entry->SerialNumber, &src_entry->SerialNumber);
dst_entry->RevocationDate = src_entry->RevocationDate;
dst_entry->cExtension = src_entry->cExtension;
dst_entry->rgExtension = (CERT_EXTENSION *)p;
p += src_entry->cExtension * sizeof(CERT_EXTENSION);
for (j = 0; j < src_entry->cExtension; ++j)
p = copy_extension(p, &dst_entry->rgExtension[j], &src_entry->rgExtension[j]);
}
for (j = 0; j < src->cExtension; ++j)
p = copy_extension(p, &dst->rgExtension[j], &src->rgExtension[j]);
assert(p - (char *)dst == size);
return dst;
}
static context_t *CRL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link)
{
crl_t *dst;
@ -47,8 +149,6 @@ static context_t *CRL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL
return NULL;
}else {
const crl_t *src = (const crl_t*)context;
DWORD size = 0;
BOOL res;
if (!(dst = (crl_t *)Context_CreateDataContext(sizeof(CRL_CONTEXT), &crl_vtbl, store)))
return NULL;
@ -60,11 +160,8 @@ static context_t *CRL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL
memcpy(dst->ctx.pbCrlEncoded, src->ctx.pbCrlEncoded, src->ctx.cbCrlEncoded);
dst->ctx.cbCrlEncoded = src->ctx.cbCrlEncoded;
/* FIXME: We don't need to decode the object here, we could just clone dst info. */
res = CryptDecodeObjectEx(dst->ctx.dwCertEncodingType, X509_CERT_CRL_TO_BE_SIGNED,
dst->ctx.pbCrlEncoded, dst->ctx.cbCrlEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
&dst->ctx.pCrlInfo, &size);
if(!res) {
if (!(dst->ctx.pCrlInfo = clone_crl_info(src->ctx.pCrlInfo)))
{
CertFreeCRLContext(&dst->ctx);
return NULL;
}