Sync to Wine-0_9_4:
Juan Lang <juan_lang(a)yahoo.com>
- crypt32: Implement more implicit properties, with tests.
- crypt32: Implement CRLDistPoints encoding/decoding.
- rewrite sequence decoding to support context-specific tags, and
eliminate duplicated code
- implement encoding and decoding of CRLDistPoints
- crypt32: Decode cleanups.
- implement a helper to decode sequences of like types
- use helper functions wherever applicable when decoding
- correct "expected" vs. "got" usage in tests
- fix a few other small bugs
Alexandre Julliard <julliard(a)winehq.org>
- Take advantage of the __EXCEPT_PAGE_FAULT macro.
Modified: trunk/reactos/lib/crypt32/cert.c
Modified: trunk/reactos/lib/crypt32/encode.c
Modified: trunk/reactos/w32api/include/wincrypt.h
_____
Modified: trunk/reactos/lib/crypt32/cert.c
--- trunk/reactos/lib/crypt32/cert.c 2005-12-26 22:57:56 UTC (rev
20346)
+++ trunk/reactos/lib/crypt32/cert.c 2005-12-26 23:05:15 UTC (rev
20347)
@@ -313,14 +313,6 @@
static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE
*pbElement,
DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
-/* filter for page-fault exceptions */
-static WINE_EXCEPTION_FILTER(page_fault)
-{
- if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
- return EXCEPTION_EXECUTE_HANDLER;
- return EXCEPTION_CONTINUE_SEARCH;
-}
-
static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV
hCryptProv,
DWORD dwFlags, CertStoreType type)
{
@@ -1885,6 +1877,22 @@
return ret;
}
+static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD
dwPropId,
+ ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
+ DWORD *pcbData)
+{
+ BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen,
pvData,
+ pcbData);
+ if (ret)
+ {
+ CRYPT_DATA_BLOB blob = { *pcbData, pvData };
+
+ ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
+ 0, &blob);
+ }
+ return ret;
+}
+
static BOOL WINAPI CRYPT_GetCertificateContextProperty(
PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD
*pcbData)
{
@@ -1927,26 +1935,34 @@
switch (dwPropId)
{
case CERT_SHA1_HASH_PROP_ID:
- ret = CryptHashCertificate(0, CALG_SHA1, 0,
+ ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1,
context->cert.pbCertEncoded, context->cert.cbCertEncoded,
pvData,
pcbData);
- if (ret)
- {
- CRYPT_DATA_BLOB blob = { *pcbData, pvData };
-
- ret = CRYPT_SetCertificateContextProperty(context,
dwPropId,
- 0, &blob);
- }
break;
- case CERT_KEY_PROV_INFO_PROP_ID:
case CERT_MD5_HASH_PROP_ID:
+ ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+ context->cert.pbCertEncoded, context->cert.cbCertEncoded,
pvData,
+ pcbData);
+ break;
+ case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
+ ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+ context->cert.pCertInfo->Subject.pbData,
+ context->cert.pCertInfo->Subject.cbData,
+ pvData, pcbData);
+ break;
+ case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
+ ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+
context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
+
context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
+ pvData, pcbData);
+ break;
case CERT_SIGNATURE_HASH_PROP_ID:
- case CERT_KEY_IDENTIFIER_PROP_ID:
- case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
- case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
FIXME("implicit property %ld\n", dwPropId);
+ SetLastError(CRYPT_E_NOT_FOUND);
break;
+ default:
+ SetLastError(CRYPT_E_NOT_FOUND);
}
}
LeaveCriticalSection(&context->cs);
@@ -2108,6 +2124,7 @@
case CERT_PVK_FILE_PROP_ID:
case CERT_SIGNATURE_HASH_PROP_ID:
case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
+ case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
case CERT_ENROLLMENT_PROP_ID:
case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
@@ -2787,7 +2804,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
context = NULL;
_____
Modified: trunk/reactos/lib/crypt32/encode.c
--- trunk/reactos/lib/crypt32/encode.c 2005-12-26 22:57:56 UTC (rev
20346)
+++ trunk/reactos/lib/crypt32/encode.c 2005-12-26 23:05:15 UTC (rev
20347)
@@ -61,8 +61,8 @@
#define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
#define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
-#define ASN_FLAGS_MASK 0xf0
-#define ASN_TYPE_MASK 0x0f
+#define ASN_FLAGS_MASK 0xe0
+#define ASN_TYPE_MASK 0x1f
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
@@ -134,10 +134,11 @@
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD
*pcbStructInfo);
static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD
cbEncoded,
DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
-/* Assumes algo->Parameters.pbData is set ahead of time */
+/* Assumes algo->Parameters.pbData is set ahead of time. Internal
func. */
static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD
dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD
*pcbStructInfo);
+/* Internal function */
static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD
dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD
*pcbStructInfo);
@@ -171,14 +172,6 @@
DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
void *pvStructInfo, DWORD *pcbStructInfo);
-/* filter for page-fault exceptions */
-static WINE_EXCEPTION_FILTER(page_fault)
-{
- if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
- return EXCEPTION_EXECUTE_HANDLER;
- return EXCEPTION_CONTINUE_SEARCH;
-}
-
BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR
lpszStructType,
const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
{
@@ -311,6 +304,9 @@
ret = items[i].encodeFunc(dwCertEncodingType, NULL,
items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
NULL,
NULL, &items[i].size);
+ /* Some functions propagate their errors through the size */
+ if (!ret)
+ *pcbEncoded = items[i].size;
dataLen += items[i].size;
}
if (ret)
@@ -336,6 +332,9 @@
ret = items[i].encodeFunc(dwCertEncodingType, NULL,
items[i].pvStructInfo, dwFlags &
~CRYPT_ENCODE_ALLOC_FLAG,
NULL, pbEncoded, &items[i].size);
+ /* Some functions propagate their errors through
the size */
+ if (!ret)
+ *pcbEncoded = items[i].size;
pbEncoded += items[i].size;
}
}
@@ -381,11 +380,47 @@
ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
NULL,
pbEncoded, &len);
+ if (!ret)
+ {
+ /* Some functions propagate their errors through the
size */
+ *pcbEncoded = len;
+ }
}
}
+ else
+ {
+ /* Some functions propagate their errors through the size */
+ *pcbEncoded = len;
+ }
return ret;
}
+struct AsnEncodeTagSwappedItem
+{
+ BYTE tag;
+ const void *pvStructInfo;
+ CryptEncodeObjectExFunc encodeFunc;
+};
+
+/* Sort of a wacky hack, it encodes something using the struct
+ * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte
with the tag
+ * given in the struct AsnEncodeTagSwappedItem.
+ */
+static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret;
+ const struct AsnEncodeTagSwappedItem *item =
+ (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
+
+ ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
+ item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+ if (ret && pbEncoded)
+ *pbEncoded = item->tag;
+ return ret;
+}
+
static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
@@ -495,7 +530,7 @@
sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara,
pbEncoded,
pcbEncoded);
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -526,7 +561,7 @@
sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara,
pbEncoded,
pcbEncoded);
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -595,7 +630,7 @@
ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
dwFlags, pEncodePara, pbEncoded, pcbEncoded);
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -739,7 +774,7 @@
ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
dwFlags, pEncodePara, pbEncoded, pcbEncoded);
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -823,7 +858,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1031,7 +1066,7 @@
}
else
{
- *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
+ *pbEncoded++ = ASN_SEQUENCE;
CRYPT_EncodeLen(bytesNeeded - lenBytes - 1,
pbEncoded,
&lenBytes);
pbEncoded += lenBytes;
@@ -1140,7 +1175,7 @@
CryptMemFree(blobs[i].pbData);
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1202,7 +1237,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1339,7 +1374,6 @@
{
const CERT_ALT_NAME_INFO *info =
(const CERT_ALT_NAME_INFO *)pvStructInfo;
-
DWORD bytesNeeded, dataLen, lenBytes, i;
ret = TRUE;
@@ -1399,7 +1433,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1436,7 +1470,7 @@
ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
dwFlags, pEncodePara, pbEncoded, pcbEncoded);
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1477,7 +1511,7 @@
pcbEncoded);
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1522,7 +1556,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1593,7 +1627,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1632,7 +1666,7 @@
&newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
CryptMemFree(newBlob.pbData);
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1731,7 +1765,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1802,7 +1836,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1881,7 +1915,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1930,7 +1964,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -1960,7 +1994,7 @@
lpszStructType, pvStructInfo, dwFlags, pEncodePara,
pbEncoded,
pcbEncoded);
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -2009,7 +2043,7 @@
}
}
}
- __EXCEPT(page_fault)
+ __EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
@@ -2018,6 +2052,145 @@
return ret;
}
+static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
+ BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret = TRUE;
+ struct AsnEncodeSequenceItem items[3] = { { 0 } };
+ struct AsnConstructedItem constructed = { 0 };
+ struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
+ DWORD cItem = 0, cSwapped = 0;
+
+ switch (distPoint->DistPointName.dwDistPointNameChoice)
+ {
+ case CRL_DIST_POINT_NO_NAME:
+ /* do nothing */
+ break;
+ case CRL_DIST_POINT_FULL_NAME:
+ swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
+ swapped[cSwapped].pvStructInfo =
&distPoint->DistPointName.u.FullName;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
+ constructed.tag = 0;
+ constructed.pvStructInfo = &swapped[cSwapped];
+ constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
+ items[cItem].pvStructInfo = &constructed;
+ items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
+ cSwapped++;
+ cItem++;
+ break;
+ case CRL_DIST_POINT_ISSUER_RDN_NAME:
+ FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
+ ret = FALSE;
+ break;
+ default:
+ ret = FALSE;
+ }
+ if (ret && distPoint->ReasonFlags.cbData)
+ {
+ swapped[cSwapped].tag = ASN_CONTEXT | 1;
+ swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
+ items[cItem].pvStructInfo = &swapped[cSwapped];
+ items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
+ cSwapped++;
+ cItem++;
+ }
+ if (ret && distPoint->CRLIssuer.cAltEntry)
+ {
+ swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
+ swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
+ items[cItem].pvStructInfo = &swapped[cSwapped];
+ items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
+ cSwapped++;
+ cItem++;
+ }
+ if (ret)
+ ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem,
0, NULL,
+ pbEncoded, pcbEncoded);
+ return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD
dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret;
+
+ __TRY
+ {
+ const CRL_DIST_POINTS_INFO *info =
+ (const CRL_DIST_POINTS_INFO *)pvStructInfo;
+
+ if (!info->cDistPoint)
+ {
+ SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
+ ret = FALSE;
+ }
+ else
+ {
+ DWORD bytesNeeded, dataLen, lenBytes, i;
+
+ ret = TRUE;
+ for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
+ {
+ DWORD len;
+
+ ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i],
NULL,
+ &len);
+ if (ret)
+ dataLen += len;
+ else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
+ {
+ /* Have to propagate index of failing character */
+ *pcbEncoded = len;
+ }
+ }
+ if (ret)
+ {
+ CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
+ bytesNeeded = 1 + lenBytes + dataLen;
+ if (!pbEncoded)
+ {
+ *pcbEncoded = bytesNeeded;
+ ret = TRUE;
+ }
+ else
+ {
+ if ((ret = CRYPT_EncodeEnsureSpace(dwFlags,
pEncodePara,
+ pbEncoded, pcbEncoded, bytesNeeded)))
+ {
+ if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+ pbEncoded = *(BYTE **)pbEncoded;
+ *pbEncoded++ = ASN_SEQUENCEOF;
+ CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
+ pbEncoded += lenBytes;
+ for (i = 0; ret && i < info->cDistPoint; i++)
+ {
+ DWORD len = dataLen;
+
+ ret = CRYPT_AsnEncodeDistPoint(
+ &info->rgDistPoint[i], pbEncoded, &len);
+ if (ret)
+ {
+ pbEncoded += len;
+ dataLen -= len;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ SetLastError(STATUS_ACCESS_VIOLATION);
+ ret = FALSE;
+ }
+ __ENDTRY
+ return ret;
+}
+
BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR
lpszStructType,
const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA
pEncodePara,
void *pvEncoded, DWORD *pcbEncoded)
@@ -2105,6 +2278,9 @@
case (WORD)PKCS_UTC_TIME:
encodeFunc = CRYPT_AsnEncodeUtcTime;
break;
+ case (WORD)X509_CRL_DIST_POINTS:
+ encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
+ break;
default:
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
}
@@ -2291,7 +2467,9 @@
return ret;
}
-/* A few of the members need explanation:
+/* tag:
+ * The expected tag of the item. If tag is 0, decodeFunc is called
+ * regardless of the tag value seen.
* offset:
* A sequence is decoded into a struct. The offset member is the
* offset of this item within that struct.
@@ -2301,9 +2479,9 @@
* minSize:
* The minimum amount of space occupied after decoding. You must
set this.
* optional:
- * If true, and a decoding function fails with CRYPT_E_ASN1_BADTAG,
then
- * minSize space is filled with 0 for this member. (Any other
failure
- * results in CRYPT_AsnDecodeSequence failing.)
+ * If true, and the tag doesn't match the expected tag for this
item,
+ * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize
space is
+ * filled with 0 for this member.
* hasPointer, pointerOffset, minSize:
* If the item has dynamic data, set hasPointer to TRUE,
pointerOffset to
* the offset within the (outer) struct of the data pointer (or to
the
@@ -2313,6 +2491,7 @@
*/
struct AsnDecodeSequenceItem
{
+ BYTE tag;
DWORD offset;
CryptDecodeObjectExFunc decodeFunc;
DWORD minSize;
@@ -2322,6 +2501,114 @@
DWORD size;
};
+static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
+ struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE
*pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData)
+{
+ BOOL ret;
+ DWORD i;
+ const BYTE *ptr;
+
+ ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
+ for (i = 0, ret = TRUE; ret && i < cItem; i++)
+ {
+ if (cbEncoded - (ptr - pbEncoded) != 0)
+ {
+ DWORD nextItemLen;
+
+ if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
+ &nextItemLen)))
+ {
+ BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
+
+ if (ptr[0] == items[i].tag || !items[i].tag)
+ {
+ if (nextData && pvStructInfo &&
items[i].hasPointer)
+ {
+ TRACE("Setting next pointer to %p\n",
+ nextData);
+ *(BYTE **)((BYTE *)pvStructInfo +
+ items[i].pointerOffset) = nextData;
+ }
+ if (items[i].decodeFunc)
+ {
+ if (pvStructInfo)
+ TRACE("decoding item %ld\n", i);
+ else
+ TRACE("sizing item %ld\n", i);
+ ret = items[i].decodeFunc(dwCertEncodingType,
+ NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
+ pvStructInfo ? (BYTE *)pvStructInfo +
items[i].offset
+ : NULL, &items[i].size);
+ if (ret)
+ {
+ if (nextData && items[i].hasPointer &&
+ items[i].size > items[i].minSize)
+ {
+ nextData += items[i].size -
items[i].minSize;
+ /* align nextData to DWORD boundaries
*/
+ if (items[i].size % sizeof(DWORD))
+ nextData += sizeof(DWORD) -
items[i].size %
+ sizeof(DWORD);
+ }
+ /* Account for alignment padding */
+ if (items[i].size % sizeof(DWORD))
+ items[i].size += sizeof(DWORD) -
+ items[i].size % sizeof(DWORD);
+ ptr += 1 + nextItemLenBytes + nextItemLen;
+ }
+ else if (items[i].optional &&
+ GetLastError() == CRYPT_E_ASN1_BADTAG)
+ {
+ TRACE("skipping optional item %ld\n", i);
+ items[i].size = items[i].minSize;
+ SetLastError(NOERROR);
+ ret = TRUE;
+ }
+ else
+ TRACE("item %ld failed: %08lx\n", i,
+ GetLastError());
+ }
+ else
+ items[i].size = items[i].minSize;
+ }
+ else if (items[i].optional)
+ {
+ TRACE("skipping optional item %ld\n", i);
+ items[i].size = items[i].minSize;
+ }
+ else
+ {
+ TRACE("tag %02x doesn't match expected %02x\n",
+ ptr[0], items[i].tag);
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ ret = FALSE;
+ }
+ }
+ }
+ else if (items[i].optional)
+ {
+ TRACE("missing optional item %ld, skipping\n", i);
+ items[i].size = items[i].minSize;
+ }
+ else
+ {
+ TRACE("not enough bytes for item %ld, failing\n", i);
+ SetLastError(CRYPT_E_ASN1_CORRUPT);
+ ret = FALSE;
+ }
+ }
+ if (cbEncoded - (ptr - pbEncoded) != 0)
+ {
+ TRACE("%ld remaining bytes, failing\n", cbEncoded -
+ (ptr - pbEncoded));
+ SetLastError(CRYPT_E_ASN1_CORRUPT);
+ ret = FALSE;
+ }
+ return ret;
+}
+
/* This decodes an arbitrary sequence into a contiguous block of memory
* (basically, a struct.) Each element being decoded is described by a
struct
* AsnDecodeSequenceItem, see above.
@@ -2348,70 +2635,160 @@
if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
{
+ DWORD i;
+
+ ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
pbEncoded,
+ cbEncoded, dwFlags, NULL, NULL);
+ if (ret)
+ {
+ DWORD bytesNeeded = 0, structSize = 0;
+
+ for (i = 0; i < cItem; i++)
+ {
+ bytesNeeded += items[i].size;
+ structSize += items[i].minSize;
+ }
+ if (!pvStructInfo)
+ *pcbStructInfo = bytesNeeded;
+ else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
+ pDecodePara, pvStructInfo, pcbStructInfo,
bytesNeeded)))
+ {
+ BYTE *nextData;
+
+ if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+ pvStructInfo = *(BYTE **)pvStructInfo;
+ if (startingPointer)
+ nextData = (BYTE *)startingPointer;
+ else
+ nextData = (BYTE *)pvStructInfo + structSize;
+ memset(pvStructInfo, 0, structSize);
+ ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items,
cItem,
+ pbEncoded, cbEncoded, dwFlags, pvStructInfo,
nextData);
+ }
+ }
+ }
+ }
+ else
+ {
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ ret = FALSE;
+ }
+ TRACE("returning %d (%08lx)\n", ret, GetLastError());
+ return ret;
+}
+
+/* tag:
+ * The expected tag of the entire encoded array (usually a variant
+ * of ASN_SETOF or ASN_SEQUENCEOF.)
+ * decodeFunc:
+ * used to decode each item in the array
+ * itemSize:
+ * is the minimum size of each decoded item
+ * hasPointer:
+ * indicates whether each item has a dynamic pointer
+ * pointerOffset:
+ * indicates the offset within itemSize at which the pointer exists
+ */
+struct AsnArrayDescriptor
+{
+ BYTE tag;
+ CryptDecodeObjectExFunc decodeFunc;
+ DWORD itemSize;
+ BOOL hasPointer;
+ DWORD pointerOffset;
+};
+
+struct AsnArrayItemSize
+{
+ DWORD encodedLen;
+ DWORD size;
+};
+
+struct GenericArray
+{
+ DWORD cItems;
+ BYTE *rgItems;
+};
+
+/* Decodes an array of like types into a struct GenericArray.
+ * The layout and decoding of the array are described by a struct
+ * AsnArrayDescriptor.
+ */
+static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor
*arrayDesc,
+ const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD
*pcbStructInfo,
+ void *startingPointer)
+{
+ BOOL ret = TRUE;
+
+ TRACE("%p, %p, %ld, %08lx, %p, %p, %ld, %p\n", arrayDesc,
pbEncoded,
+ cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
+ startingPointer);
+
+ if (pbEncoded[0] == arrayDesc->tag)
+ {
+ DWORD dataLen;
+
+ if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+ {
+ DWORD bytesNeeded, cItems = 0;
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
- DWORD i, bytesNeeded = 0, minSize = 0;
- const BYTE *ptr;
+ /* There can be arbitrarily many items, but there is often
only one.
+ */
+ struct AsnArrayItemSize itemSize = { 0 }, *itemSizes =
&itemSize;
- ptr = pbEncoded + 1 + lenBytes;
- for (i = 0; ret && i < cItem; i++)
+ bytesNeeded = sizeof(struct GenericArray);
+ if (dataLen)
{
- DWORD nextItemLen;
+ const BYTE *ptr;
- minSize += items[i].minSize;
- if (cbEncoded - (ptr - pbEncoded) != 0)
+ for (ptr = pbEncoded + 1 + lenBytes; ret &&
+ ptr - pbEncoded - 1 - lenBytes < dataLen; )
{
- if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr -
pbEncoded),
- &nextItemLen)))
+ DWORD itemLenBytes, itemDataLen, size;
+
+ itemLenBytes = GET_LEN_BYTES(ptr[1]);
+ /* Each item decoded may not tolerate extraneous
bytes, so
+ * get the length of the next element and pass it
directly.
+ */
+ ret = CRYPT_GetLen(ptr, cbEncoded - (ptr -
pbEncoded),
+ &itemDataLen);
+ if (ret)
+ ret = arrayDesc->decodeFunc(X509_ASN_ENCODING,
0, ptr,
+ 1 + itemLenBytes + itemDataLen,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
NULL,
+ &size);
+ if (ret)
{
- BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
+ DWORD nextLen;
- if (items[i].decodeFunc)
+ cItems++;
+ if (itemSizes != &itemSize)
+ itemSizes = CryptMemRealloc(itemSizes,
+ cItems * sizeof(struct AsnArrayItemSize));
+ else
{
- TRACE("sizing item %ld\n", i);
- ret =
items[i].decodeFunc(dwCertEncodingType, NULL,
- ptr, 1 + nextItemLenBytes + nextItemLen,
- dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
NULL,
- &items[i].size);
+ itemSizes =
+ CryptMemAlloc(
+ cItems * sizeof(struct AsnArrayItemSize));
+ memcpy(itemSizes, &itemSize,
sizeof(itemSize));
+ }
+ if (itemSizes)
+ {
+ itemSizes[cItems - 1].encodedLen = 1 +
itemLenBytes
+ + itemDataLen;
+ itemSizes[cItems - 1].size = size;
+ bytesNeeded += size;
+ ret = CRYPT_GetLen(ptr,
+ cbEncoded - (ptr - pbEncoded), &nextLen);
if (ret)
- {
- /* Account for alignment padding */
- bytesNeeded += items[i].size;
- if (items[i].size % sizeof(DWORD))
- bytesNeeded += sizeof(DWORD) -
- items[i].size % sizeof(DWORD);
- ptr += 1 + nextItemLenBytes +
nextItemLen;
- }
- else if (items[i].optional &&
- GetLastError() == CRYPT_E_ASN1_BADTAG)
- {
- TRACE("skipping optional item %ld\n",
i);
- bytesNeeded += items[i].minSize;
- SetLastError(NOERROR);
- ret = TRUE;
- }
- else
- TRACE("item %ld failed: %08lx\n", i,
- GetLastError());
+ ptr += nextLen + 1 +
GET_LEN_BYTES(ptr[1]);
}
else
- bytesNeeded += items[i].minSize;
+ ret = FALSE;
}
}
- else if (items[i].optional)
- bytesNeeded += items[i].minSize;
- else
- {
- SetLastError(CRYPT_E_ASN1_CORRUPT);
- ret = FALSE;
- }
}
- if (cbEncoded - (ptr - pbEncoded) != 0)
- {
- TRACE("%ld remaining bytes, failing\n", cbEncoded -
- (ptr - pbEncoded));
- SetLastError(CRYPT_E_ASN1_CORRUPT);
- ret = FALSE;
- }
if (ret)
{
if (!pvStructInfo)
@@ -2419,75 +2796,49 @@
else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
pDecodePara, pvStructInfo, pcbStructInfo,
bytesNeeded)))
{
+ DWORD i;
BYTE *nextData;
+ const BYTE *ptr;
+ struct GenericArray *array;
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
pvStructInfo = *(BYTE **)pvStructInfo;
+ array = (struct GenericArray *)pvStructInfo;
+ array->cItems = cItems;
if (startingPointer)
- nextData = (BYTE *)startingPointer;
+ array->rgItems = startingPointer;
else
- nextData = (BYTE *)pvStructInfo + minSize;
- memset(pvStructInfo, 0, minSize);
- ptr = pbEncoded + 1 + lenBytes;
- for (i = 0; ret && i < cItem; i++)
+ array->rgItems = (BYTE *)array +
+ sizeof(struct GenericArray);
+ nextData = (BYTE *)array->rgItems +
+ array->cItems * arrayDesc->itemSize;
+ for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
+ i < cItems && ptr - pbEncoded - 1 - lenBytes <
+ dataLen; i++)
{
- if (cbEncoded - (ptr - pbEncoded) != 0)
+ if (arrayDesc->hasPointer)
+ *(BYTE **)(array->rgItems + i *
arrayDesc->itemSize
+ + arrayDesc->pointerOffset) = nextData;
+ ret = arrayDesc->decodeFunc(X509_ASN_ENCODING,
0, ptr,
+ itemSizes[i].encodedLen,
+ dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
+ array->rgItems + i * arrayDesc->itemSize,
+ &itemSizes[i].size);
+ if (ret)
{
- DWORD nextItemLen;
- BYTE nextItemLenBytes =
GET_LEN_BYTES(ptr[1]);
+ DWORD nextLen;
- CRYPT_GetLen(ptr, cbEncoded - (ptr -
pbEncoded),
- &nextItemLen);
- if (items[i].hasPointer)
- {
- *(BYTE **)((BYTE *)pvStructInfo +
- items[i].pointerOffset) = nextData;
- }
- if (items[i].decodeFunc)
- {
- TRACE("decoding item %ld\n", i);
- ret =
items[i].decodeFunc(dwCertEncodingType,
- NULL, ptr, 1 + nextItemLenBytes +
nextItemLen,
- dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
NULL,
- (BYTE *)pvStructInfo +
items[i].offset,
- &items[i].size);
- if (!ret)
- TRACE("item %ld failed: %08lx\n",
i,
- GetLastError());
- }
- else
- items[i].size = items[i].minSize;
+ nextData += itemSizes[i].size -
arrayDesc->itemSize;
+ ret = CRYPT_GetLen(ptr,
+ cbEncoded - (ptr - pbEncoded), &nextLen);
if (ret)
- {
- if (items[i].hasPointer &&
- items[i].size > items[i].minSize)
- {
- nextData += items[i].size -
- items[i].minSize;
- /* align nextData to DWORD
boundaries */
- if (items[i].size % sizeof(DWORD))
- {
- nextData += sizeof(DWORD) -
- items[i].size % sizeof(DWORD);
- }
[truncated at 1000 lines; 1655 more skipped]