From 687e29b9125633f9fa3c08ed26b94153f8d0cfe4 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Tue, 18 Jan 2011 19:17:46 -0800 Subject: [PATCH] crypt32: Fix memory leaks when encoding fails. --- dlls/crypt32/encode.c | 264 ++++++++++++++++++++++++++---------------- 1 file changed, 167 insertions(+), 97 deletions(-) diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index f10c92e26b4..a1db6d93763 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -127,6 +127,14 @@ BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags, const CRYPT_ENCODE_PARA *pEncodePara return ret; } +static void CRYPT_FreeSpace(const CRYPT_ENCODE_PARA *pEncodePara, LPVOID pv) +{ + if (pEncodePara && pEncodePara->pfnFree) + pEncodePara->pfnFree(pv); + else + LocalFree(pv); +} + BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded) { DWORD bytesNeeded, significantBytes = 0; @@ -201,21 +209,26 @@ BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCE; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCE; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < cItem; i++) { ret = items[i].encodeFunc(dwCertEncodingType, NULL, items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, - NULL, pbEncoded, &items[i].size); + NULL, out, &items[i].size); /* Some functions propagate their errors through the size */ if (!ret) *pcbEncoded = items[i].size; - pbEncoded += items[i].size; + out += items[i].size; } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -243,18 +256,23 @@ BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType, else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag; - CRYPT_EncodeLen(len, pbEncoded, &dataLen); - pbEncoded += dataLen; + out = pbEncoded; + *out++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag; + CRYPT_EncodeLen(len, out, &dataLen); + out += dataLen; ret = item->encodeFunc(dwCertEncodingType, lpszStructType, item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, - pbEncoded, &len); + out, &len); if (!ret) { /* Some functions propagate their errors through the size */ *pcbEncoded = len; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -607,20 +625,24 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; i < info->cCRLEntry; i++) { DWORD size = dataLen; - ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, - &size); - pbEncoded += size; + ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], out, &size); + out += size; dataLen -= size; } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -764,20 +786,25 @@ static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; i < exts->cExtension; i++) { DWORD size = dataLen; ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], - pbEncoded, &size); - pbEncoded += size; + out, &size); + out += size; dataLen -= size; } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -1399,26 +1426,30 @@ static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, - &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < info->cRDN; i++) { size = bytesNeeded; ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue, - pbEncoded, &size); + out, &size); if (ret) { - pbEncoded += size; + out += size; bytesNeeded -= size; } else *pcbEncoded = size; } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -1532,20 +1563,25 @@ static BOOL WINAPI CRYPT_AsnEncodeCTLEntries(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < entries->cEntry; i++) { DWORD size = dataLen; ret = CRYPT_AsnEncodeCTLEntry(&entries->rgEntry[i], - pbEncoded, &size); - pbEncoded += size; + out, &size); + out += size; dataLen -= size; } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -1682,21 +1718,26 @@ static BOOL WINAPI CRYPT_AsnEncodeSMIMECapabilities(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; i < capabilities->cCapability; i++) { DWORD size = dataLen; ret = CRYPT_AsnEncodeSMIMECapability(dwCertEncodingType, NULL, &capabilities->rgCapability[i], 0, NULL, - pbEncoded, &size); - pbEncoded += size; + out, &size); + out += size; dataLen -= size; } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -1737,20 +1778,25 @@ static BOOL WINAPI CRYPT_AsnEncodeNoticeNumbers(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCE; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCE; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; i < noticeRef->cNoticeNumbers; i++) { DWORD size = dataLen; ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, - ¬iceRef->rgNoticeNumbers[i], 0, NULL, pbEncoded, &size); - pbEncoded += size; + ¬iceRef->rgNoticeNumbers[i], 0, NULL, out, &size); + out += size; dataLen -= size; } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -1972,14 +2018,6 @@ static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value, return ret; } -static void CRYPT_FreeSpace(const CRYPT_ENCODE_PARA *pEncodePara, LPVOID pv) -{ - if (pEncodePara && pEncodePara->pfnFree) - pEncodePara->pfnFree(pv); - else - LocalFree(pv); -} - static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value, DWORD dwFlags, const CRYPT_ENCODE_PARA *pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -2271,24 +2309,27 @@ static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, - &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < info->cRDN; i++) { size = bytesNeeded; ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, - &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded, - &size); + &info->rgRDN[i], CRYPT_AsnEncodeNameValue, out, &size); if (ret) { - pbEncoded += size; + out += size; bytesNeeded -= size; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -2540,23 +2581,28 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < info->cAltEntry; i++) { DWORD len = dataLen; ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType, - NULL, &info->rgAltEntry[i], 0, NULL, pbEncoded, &len); + NULL, &info->rgAltEntry[i], 0, NULL, out, &len); if (ret) { - pbEncoded += len; + out += len; dataLen -= len; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -2674,20 +2720,25 @@ static BOOL WINAPI CRYPT_AsnEncodeAuthorityInfoAccess(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; i < info->cAccDescr; i++) { DWORD size = dataLen; ret = CRYPT_AsnEncodeAccessDescription( - &info->rgAccDescr[i], pbEncoded, &size); - pbEncoded += size; + &info->rgAccDescr[i], out, &size); + out += size; dataLen -= size; } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -2819,12 +2870,14 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicyQualifiers(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, - &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < info->cPolicyQualifier; i++) { items[0].pvStructInfo = @@ -2834,14 +2887,15 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicyQualifiers(DWORD dwCertEncodingType, size = bytesNeeded; ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, sizeof(items) / sizeof(items[0]), - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded, - &size); + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, out, &size); if (ret) { - pbEncoded += size; + out += size; bytesNeeded -= size; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -2900,24 +2954,28 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicies(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, - &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < info->cPolicyInfo; i++) { size = bytesNeeded; ret = CRYPT_AsnEncodeCertPolicy(dwCertEncodingType, &info->rgPolicyInfo[i], - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pbEncoded, &size); + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, out, &size); if (ret) { - pbEncoded += size; + out += size; bytesNeeded -= size; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -2979,24 +3037,28 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicyMappings(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, - &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < info->cPolicyMapping; i++) { size = bytesNeeded; ret = CRYPT_AsnEncodeCertPolicyMapping( dwCertEncodingType, &info->rgPolicyMapping[i], - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pbEncoded, &size); + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, out, &size); if (ret) { - pbEncoded += size; + out += size; bytesNeeded -= size; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -3729,23 +3791,28 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < info->cDistPoint; i++) { DWORD len = dataLen; ret = CRYPT_AsnEncodeDistPoint( - &info->rgDistPoint[i], pbEncoded, &len); + &info->rgDistPoint[i], out, &len); if (ret) { - pbEncoded += len; + out += len; dataLen -= len; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } } @@ -3791,25 +3858,28 @@ static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, bytesNeeded))) { + BYTE *out; + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_SEQUENCEOF; - CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, - &lenBytes); - pbEncoded += lenBytes; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, out, &lenBytes); + out += lenBytes; for (i = 0; ret && i < usage->cUsageIdentifier; i++) { size = bytesNeeded; ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, usage->rgpszUsageIdentifier[i], - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded, - &size); + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, out, &size); if (ret) { - pbEncoded += size; + out += size; bytesNeeded -= size; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); } } }