diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 87e8ec240ef..8a7e99c2f0e 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -134,10 +134,11 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType, 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); @@ -402,6 +403,32 @@ static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType, 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) @@ -2033,6 +2060,145 @@ static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType, 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) @@ -2120,6 +2286,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, 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)); } @@ -2306,7 +2475,9 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags, 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. @@ -2316,9 +2487,9 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags, * 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 @@ -2328,6 +2499,7 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags, */ struct AsnDecodeSequenceItem { + BYTE tag; DWORD offset; CryptDecodeObjectExFunc decodeFunc; DWORD minSize; @@ -2337,6 +2509,114 @@ struct AsnDecodeSequenceItem 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. @@ -2363,72 +2643,19 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - DWORD i, bytesNeeded = 0, minSize = 0; - const BYTE *ptr; + DWORD i; - ptr = pbEncoded + 1 + lenBytes; - for (i = 0; ret && i < cItem; i++) - { - DWORD nextItemLen; - - minSize += items[i].minSize; - if (cbEncoded - (ptr - pbEncoded) != 0) - { - if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), - &nextItemLen))) - { - BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]); - - if (items[i].decodeFunc) - { - 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); - 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()); - } - else - bytesNeeded += items[i].minSize; - } - } - 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; - } + 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, @@ -2441,69 +2668,10 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, if (startingPointer) nextData = (BYTE *)startingPointer; else - nextData = (BYTE *)pvStructInfo + minSize; - memset(pvStructInfo, 0, minSize); - ptr = pbEncoded + 1 + lenBytes; - for (i = 0; ret && i < cItem; i++) - { - if (cbEncoded - (ptr - pbEncoded) != 0) - { - DWORD nextItemLen; - BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]); - - CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), - &nextItemLen); - if (items[i].hasPointer) - { - TRACE("Setting next pointer to %p\n", nextData); - *(BYTE **)((BYTE *)pvStructInfo + - items[i].pointerOffset) = nextData; - } - if (items[i].decodeFunc) - { - TRACE("decoding item %ld, offset %ld (%p)\n", - i, items[i].offset, - (BYTE *)pvStructInfo + items[i].offset); - 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; - 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); - } - } - ptr += 1 + nextItemLenBytes + nextItemLen; - } - else if (items[i].optional && - GetLastError() == CRYPT_E_ASN1_BADTAG) - { - SetLastError(NOERROR); - ret = TRUE; - } - } - else if (!items[i].optional) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - } + nextData = (BYTE *)pvStructInfo + structSize; + memset(pvStructInfo, 0, structSize); + ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, + pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData); } } } @@ -2790,14 +2958,14 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType, __TRY { struct AsnDecodeSequenceItem items[] = { - { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned), + { 0, offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned), CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 }, - { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm), - CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), - FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO, - SignatureAlgorithm.pszObjId), 0 }, - { offsetof(CERT_SIGNED_CONTENT_INFO, Signature), + { ASN_SEQUENCEOF, offsetof(CERT_SIGNED_CONTENT_INFO, + SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId, + sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, + offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm.pszObjId), 0 }, + { ASN_BITSTRING, offsetof(CERT_SIGNED_CONTENT_INFO, Signature), CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 }, }; @@ -2817,29 +2985,21 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType, return ret; } +/* Internal function */ static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { BOOL ret; + DWORD dataLen; - if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR)) + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { - DWORD dataLen; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - - ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER, - pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo); - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; + ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER, + pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo); } return ret; } @@ -2851,9 +3011,9 @@ static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType, BOOL ret; struct AsnDecodeSequenceItem items[] = { - { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore), + { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore), CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, - { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter), + { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter), CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, }; @@ -2863,29 +3023,21 @@ static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType, return ret; } +/* Internal function */ static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { BOOL ret; + DWORD dataLen; - if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR | 3)) + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { - DWORD dataLen; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) - { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - - ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, - X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo); - } - } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; + ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, + X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo); } return ret; } @@ -2902,34 +3054,39 @@ static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType, __TRY { struct AsnDecodeSequenceItem items[] = { - { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion, - sizeof(DWORD), TRUE, FALSE, 0, 0 }, - { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal, - sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO, - SerialNumber.pbData), 0 }, - { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId, - sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO, - SignatureAlgorithm.pszObjId), 0 }, - { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob, + { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CERT_INFO, dwVersion), + CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 }, + { ASN_INTEGER, offsetof(CERT_INFO, SerialNumber), + CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, + TRUE, offsetof(CERT_INFO, SerialNumber.pbData), 0 }, + { ASN_SEQUENCEOF, offsetof(CERT_INFO, SignatureAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CERT_INFO, SignatureAlgorithm.pszObjId), 0 }, + { 0, offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO, Issuer.pbData) }, - { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity, - sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 }, - { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob, + { ASN_SEQUENCEOF, offsetof(CERT_INFO, NotBefore), + CRYPT_AsnDecodeValidity, sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, + FALSE, 0 }, + { 0, offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO, Subject.pbData) }, - { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo, - sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO, + /* jil FIXME: shouldn't this have an internal version, which expects + * the pbData to be set? + */ + { ASN_SEQUENCEOF, offsetof(CERT_INFO, SubjectPublicKeyInfo), + CRYPT_AsnDecodePubKeyInfo, sizeof(CERT_PUBLIC_KEY_INFO), FALSE, + TRUE, offsetof(CERT_INFO, SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 }, - { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal, - sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO, - IssuerUniqueId.pbData), 0 }, - { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal, - sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO, - SubjectUniqueId.pbData), 0 }, - { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeCertExtensions, - sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO, - rgExtension), 0 }, + { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, + offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 }, + { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, + offsetof(CERT_INFO, SubjectUniqueId.pbData), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR | 3, offsetof(CERT_INFO, cExtension), + CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE, + offsetof(CERT_INFO, rgExtension), 0 }, }; ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, @@ -2951,14 +3108,14 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType, { BOOL ret; struct AsnDecodeSequenceItem items[] = { - { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal, - sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY, - SerialNumber.pbData), 0 }, - { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime, + { ASN_INTEGER, offsetof(CRL_ENTRY, SerialNumber), + CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, + offsetof(CRL_ENTRY, SerialNumber.pbData), 0 }, + { 0, offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, - { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal, - sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY, - rgExtension), 0 }, + { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension), + CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE, + offsetof(CRL_ENTRY, rgExtension), 0 }, }; PCRL_ENTRY entry = (PCRL_ENTRY)pvStructInfo; @@ -2971,12 +3128,7 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType, return ret; } -typedef struct _WINE_CRL_ENTRIES { - DWORD cCRLEntry; - PCRL_ENTRY rgCRLEntry; -} WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES; - -/* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has +/* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has * been set prior to calling. */ static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType, @@ -2987,14 +3139,14 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType, struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE, offsetof(CRL_ENTRY, SerialNumber.pbData) }; - PWINE_CRL_ENTRIES entries = (PWINE_CRL_ENTRIES)pvStructInfo; + struct GenericArray *entries = (struct GenericArray *)pvStructInfo; TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo); ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, - entries ? entries->rgCRLEntry : NULL); + entries ? entries->rgItems : NULL); TRACE("Returning %d (%08lx)\n", ret, GetLastError()); return ret; } @@ -3011,24 +3163,24 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType, __TRY { struct AsnDecodeSequenceItem items[] = { - { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion, - sizeof(DWORD), TRUE, FALSE, 0, 0 }, - { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId, - sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO, - SignatureAlgorithm.pszObjId), 0 }, - { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob, + { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CRL_INFO, dwVersion), + CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 }, + { ASN_SEQUENCEOF, offsetof(CRL_INFO, SignatureAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CRL_INFO, SignatureAlgorithm.pszObjId), 0 }, + { 0, offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO, Issuer.pbData) }, - { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime, + { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, - { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime, + { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), TRUE, FALSE, 0 }, - { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries, - sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO, - rgCRLEntry), 0 }, + { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry), + CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CRL_INFO, rgCRLEntry), 0 }, /* Note that the extensions are ignored by MS, so I'll ignore them too */ - { offsetof(CRL_INFO, cExtension), NULL, + { 0, offsetof(CRL_INFO, cExtension), NULL, sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 }, }; @@ -3079,13 +3231,14 @@ static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { struct AsnDecodeSequenceItem items[] = { - { offsetof(CERT_EXTENSION, pszObjId), CRYPT_AsnDecodeOidWrapper, - sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_EXTENSION, pszObjId), 0 }, - { offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool, + { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId), + CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, + offsetof(CERT_EXTENSION, pszObjId), 0 }, + { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 }, - { offsetof(CERT_EXTENSION, Value), CRYPT_AsnDecodeOctetsInternal, - sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, offsetof(CERT_EXTENSION, - Value.pbData) }, + { ASN_OCTETSTRING, offsetof(CERT_EXTENSION, Value), + CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, + offsetof(CERT_EXTENSION, Value.pbData) }, }; BOOL ret = TRUE; PCERT_EXTENSION ext = (PCERT_EXTENSION)pvStructInfo; @@ -3394,9 +3547,10 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType, __TRY { struct AsnDecodeSequenceItem items[] = { - { offsetof(CERT_RDN_ATTR, pszObjId), CRYPT_AsnDecodeOidWrapper, - sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_RDN_ATTR, pszObjId), 0 }, - { offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeNameValue, + { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId), + CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, + offsetof(CERT_RDN_ATTR, pszObjId), 0 }, + { 0, offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeNameValue, sizeof(CERT_NAME_VALUE), FALSE, TRUE, offsetof(CERT_RDN_ATTR, Value.pbData), 0 }, }; @@ -3514,10 +3668,10 @@ static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo; BOOL ret = TRUE; struct AsnDecodeSequenceItem items[] = { - { offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), + { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 }, - { offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters), + { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters), CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 }, }; @@ -3545,11 +3699,11 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, __TRY { struct AsnDecodeSequenceItem items[] = { - { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm), + { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm), CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm.pszObjId) }, - { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey), + { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey), CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) }, }; @@ -3578,11 +3732,6 @@ static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, SetLastError(CRYPT_E_ASN1_CORRUPT); return FALSE; } - if (pbEncoded[0] != ASN_BOOL) - { - SetLastError(CRYPT_E_ASN1_BADTAG); - return FALSE; - } if (GET_LEN_BYTES(pbEncoded[1]) > 1) { SetLastError(CRYPT_E_ASN1_CORRUPT); @@ -3696,6 +3845,8 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, entry->u.pwszURL[i] = (WCHAR)pbEncoded[1 + lenBytes + i]; entry->u.pwszURL[i] = 0; + TRACE("URL is %p (%s)\n", entry->u.pwszURL, + debugstr_w(entry->u.pwszURL)); break; } case 7: /* iPAddress */ @@ -3714,6 +3865,26 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, + offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; + PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + if (info) + TRACE("info->rgAltEntry is %p\n", info->rgAltEntry); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL); + return ret; +} + static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -3753,6 +3924,9 @@ static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType, { BOOL ret = TRUE; + TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + if (cbEncoded) { if (pbEncoded[0] == ASN_INTEGER) @@ -3801,11 +3975,11 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType, __TRY { struct AsnDecodeSequenceItem items[] = { - { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), CRYPT_AsnDecodeBool, - sizeof(BOOL), TRUE, FALSE, 0, 0 }, - { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fPathLenConstraint), - CRYPT_AsnDecodePathLenConstraint, sizeof(struct PATH_LEN_CONSTRAINT), - TRUE, FALSE, 0, 0 }, + { ASN_BOOL, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), + CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 }, + { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, + fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint, + sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 }, }; ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, @@ -3838,11 +4012,11 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType, __TRY { struct AsnDecodeSequenceItem items[] = { - { offsetof(struct DECODED_RSA_PUB_KEY, modulus), + { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus), CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData), 0 }, - { offsetof(struct DECODED_RSA_PUB_KEY, pubexp), + { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp), CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 }, }; struct DECODED_RSA_PUB_KEY *decodedKey = NULL; @@ -3900,52 +4074,43 @@ static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { BOOL ret; + DWORD bytesNeeded, dataLen; TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo); - if (pbEncoded[0] == ASN_OCTETSTRING) + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { - DWORD bytesNeeded, dataLen; - - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + bytesNeeded = sizeof(CRYPT_DATA_BLOB); + else + bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB); + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) { - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - bytesNeeded = sizeof(CRYPT_DATA_BLOB); - else - bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB); - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - SetLastError(ERROR_MORE_DATA); - *pcbStructInfo = bytesNeeded; - ret = FALSE; - } - else - { - CRYPT_DATA_BLOB *blob; - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + SetLastError(ERROR_MORE_DATA); + *pcbStructInfo = bytesNeeded; + ret = FALSE; + } + else + { + CRYPT_DATA_BLOB *blob; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - blob = (CRYPT_DATA_BLOB *)pvStructInfo; - blob->cbData = dataLen; - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes; - else - { - assert(blob->pbData); - if (blob->cbData) - memcpy(blob->pbData, pbEncoded + 1 + lenBytes, - blob->cbData); - } + blob = (CRYPT_DATA_BLOB *)pvStructInfo; + blob->cbData = dataLen; + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes; + else + { + assert(blob->pbData); + if (blob->cbData) + memcpy(blob->pbData, pbEncoded + 1 + lenBytes, + blob->cbData); } } } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } return ret; } @@ -3962,7 +4127,17 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, { DWORD bytesNeeded; - if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType, + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else if (pbEncoded[0] != ASN_OCTETSTRING) + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType, lpszStructType, pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) { @@ -3983,11 +4158,6 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, &bytesNeeded); } } - else - { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; - } } __EXCEPT(page_fault) { @@ -4830,6 +5000,57 @@ static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + struct AsnDecodeSequenceItem items[] = { + { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_DIST_POINT, + DistPointName), CRYPT_AsnDecodeAltNameInternal, + sizeof(CRL_DIST_POINT_NAME), TRUE, TRUE, offsetof(CRL_DIST_POINT, + DistPointName.u.FullName.rgAltEntry), 0 }, + { ASN_CONTEXT | 1, offsetof(CRL_DIST_POINT, ReasonFlags), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, + offsetof(CRL_DIST_POINT, ReasonFlags.pbData), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR | 2, offsetof(CRL_DIST_POINT, CRLIssuer), + CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, TRUE, + offsetof(CRL_DIST_POINT, CRLIssuer.rgAltEntry), 0 }, + }; + BOOL ret; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeDistPoint, sizeof(CRL_DIST_POINT), TRUE, + offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) }; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT(page_fault) + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -4927,6 +5148,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)PKCS_UTC_TIME: decodeFunc = CRYPT_AsnDecodeUtcTime; break; + case (WORD)X509_CRL_DIST_POINTS: + decodeFunc = CRYPT_AsnDecodeCRLDistPoints; + break; default: FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); } diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 45132ca1aa1..1849d3a1dfe 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -1379,14 +1379,15 @@ static void test_decodeBasicConstraints(DWORD dwEncoding) ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2, constraints2[i].encoded, constraints2[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize); - ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError()); + ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i, + GetLastError()); if (buf) { CERT_BASIC_CONSTRAINTS2_INFO *info = (CERT_BASIC_CONSTRAINTS2_INFO *)buf; ok(!memcmp(info, &constraints2[i].info, sizeof(*info)), - "Unexpected value\n"); + "Unexpected value for item %ld\n", i); LocalFree(buf); } } @@ -2222,6 +2223,227 @@ static void test_decodeCert(DWORD dwEncoding) } } +static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 }; +static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15, + 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, + 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 }; +static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02, + 0x00, 0x03 }; +static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13, + 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, + 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 }; +static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0, + 0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, + 0x2e, 0x6f, 0x72, 0x67 }; +static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE | + CRL_REASON_AFFILIATION_CHANGED; + +static void test_encodeCRLDistPoints(DWORD dwEncoding) +{ + CRL_DIST_POINTS_INFO info = { 0 }; + CRL_DIST_POINT point = { { 0 } }; + CERT_ALT_NAME_ENTRY entry = { 0 }; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + + /* Test with an empty info */ + ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), + "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n", + GetLastError()); + /* Test with one empty dist point */ + info.cDistPoint = 1; + info.rgDistPoint = &point; + ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (buf) + { + ok(size == sizeof(emptyDistPoint), "Expected size %d, got %ld\n", + sizeof(emptyDistPoint), size); + ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n"); + LocalFree(buf); + } + /* A dist point with an invalid name */ + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; + entry.dwAltNameChoice = CERT_ALT_NAME_URL; + entry.pwszURL = (LPWSTR)nihongoURL; + point.DistPointName.FullName.cAltEntry = 1; + point.DistPointName.FullName.rgAltEntry = &entry; + ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING, + "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError()); + /* The first invalid character is at index 7 */ + ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7, + "Expected invalid char at index 7, got %ld\n", + GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size)); + /* A dist point with (just) a valid name */ + entry.pwszURL = (LPWSTR)url; + ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (buf) + { + ok(size == sizeof(distPointWithUrl), "Expected size %d, got %ld\n", + sizeof(distPointWithUrl), size); + ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n"); + LocalFree(buf); + } + /* A dist point with (just) reason flags */ + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME; + point.ReasonFlags.cbData = sizeof(crlReason); + point.ReasonFlags.pbData = (LPBYTE)&crlReason; + ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (buf) + { + ok(size == sizeof(distPointWithReason), "Expected size %d, got %ld\n", + sizeof(distPointWithReason), size); + ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n"); + LocalFree(buf); + } + /* A dist point with just an issuer */ + point.ReasonFlags.cbData = 0; + point.CRLIssuer.cAltEntry = 1; + point.CRLIssuer.rgAltEntry = &entry; + ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (buf) + { + ok(size == sizeof(distPointWithIssuer), "Expected size %d, got %ld\n", + sizeof(distPointWithIssuer), size); + ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n"); + LocalFree(buf); + } + /* A dist point with both a name and an issuer */ + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; + ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (buf) + { + ok(size == sizeof(distPointWithUrlAndIssuer), + "Expected size %d, got %ld\n", sizeof(distPointWithUrlAndIssuer), + size); + ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeCRLDistPoints(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + PCRL_DIST_POINTS_INFO info; + PCRL_DIST_POINT point; + PCERT_ALT_NAME_ENTRY entry; + + ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, + emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&buf, &size); + if (ret) + { + info = (PCRL_DIST_POINTS_INFO)buf; + ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), + "Expected size at least %d, got %ld\n", + sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size); + ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n", + info->cDistPoint); + point = info->rgDistPoint; + ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME, + "Expected CRL_DIST_POINT_NO_NAME, got %ld\n", + point->DistPointName.dwDistPointNameChoice); + ok(point->ReasonFlags.cbData == 0, "Expected no reason\n"); + ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n"); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, + distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&buf, &size); + if (ret) + { + info = (PCRL_DIST_POINTS_INFO)buf; + ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), + "Expected size at least %d, got %ld\n", + sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size); + ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n", + info->cDistPoint); + point = info->rgDistPoint; + ok(point->DistPointName.dwDistPointNameChoice == + CRL_DIST_POINT_FULL_NAME, + "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n", + point->DistPointName.dwDistPointNameChoice); + ok(point->DistPointName.FullName.cAltEntry == 1, + "Expected 1 name entry, got %ld\n", + point->DistPointName.FullName.cAltEntry); + entry = point->DistPointName.FullName.rgAltEntry; + ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL, + "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice); + ok(!lstrcmpW(entry->pwszURL, url), "Unexpected name\n"); + ok(point->ReasonFlags.cbData == 0, "Expected no reason\n"); + ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n"); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, + distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG, + NULL, (BYTE *)&buf, &size); + if (ret) + { + info = (PCRL_DIST_POINTS_INFO)buf; + ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), + "Expected size at least %d, got %ld\n", + sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size); + ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n", + info->cDistPoint); + point = info->rgDistPoint; + ok(point->DistPointName.dwDistPointNameChoice == + CRL_DIST_POINT_NO_NAME, + "Expected CRL_DIST_POINT_NO_NAME, got %ld\n", + point->DistPointName.dwDistPointNameChoice); + ok(point->ReasonFlags.cbData == sizeof(crlReason), + "Expected reason length\n"); + ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)), + "Unexpected reason\n"); + ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n"); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, + distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (ret) + { + info = (PCRL_DIST_POINTS_INFO)buf; + ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), + "Expected size at least %d, got %ld\n", + sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size); + ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n", + info->cDistPoint); + point = info->rgDistPoint; + ok(point->DistPointName.dwDistPointNameChoice == + CRL_DIST_POINT_FULL_NAME, + "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n", + point->DistPointName.dwDistPointNameChoice); + ok(point->DistPointName.FullName.cAltEntry == 1, + "Expected 1 name entry, got %ld\n", + point->DistPointName.FullName.cAltEntry); + entry = point->DistPointName.FullName.rgAltEntry; + ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL, + "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice); + ok(!lstrcmpW(entry->pwszURL, url), "Unexpected name\n"); + ok(point->ReasonFlags.cbData == 0, "Expected no reason\n"); + ok(point->CRLIssuer.cAltEntry == 1, + "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry); + entry = point->CRLIssuer.rgAltEntry; + ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL, + "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice); + ok(!lstrcmpW(entry->pwszURL, url), "Unexpected name\n"); + LocalFree(buf); + } +} + static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a }; @@ -2594,6 +2816,8 @@ START_TEST(encode) test_decodeCertToBeSigned(encodings[i]); test_encodeCert(encodings[i]); test_decodeCert(encodings[i]); + test_encodeCRLDistPoints(encodings[i]); + test_decodeCRLDistPoints(encodings[i]); test_encodeCRLToBeSigned(encodings[i]); test_decodeCRLToBeSigned(encodings[i]); }