crypt32: Add partial support for decoding OCSP_BASIC_RESPONSE_INFO structures.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2022-03-25 14:18:07 +01:00 committed by Alexandre Julliard
parent bb17583239
commit f04b102484
2 changed files with 301 additions and 0 deletions

View File

@ -6287,6 +6287,246 @@ static BOOL WINAPI CRYPT_AsnDecodeOCSPBasicSignedResponse(DWORD dwCertEncodingTy
return ret;
}
static BOOL CRYPT_AsnDecodeOCSPHashAlgorithm(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
DWORD dataLen;
BOOL ret;
if (!cbEncoded)
{
SetLastError(CRYPT_E_ASN1_EOD);
return FALSE;
}
if (pbEncoded[0] != ASN_SEQUENCEOF)
{
SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
{
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
DWORD bytesDecoded;
if (dataLen)
{
ret = CRYPT_AsnDecodeAlgorithmId(pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, dwFlags,
pvStructInfo, pcbStructInfo, &bytesDecoded);
if (ret) *pcbDecoded = bytesDecoded + lenBytes + 1;
}
}
return ret;
}
static BOOL CRYPT_AsnDecodeOCSPNextUpdate(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
DWORD dataLen;
BOOL ret;
if (!cbEncoded)
{
SetLastError(CRYPT_E_ASN1_EOD);
return FALSE;
}
if (pbEncoded[0] != (ASN_CONTEXT | ASN_CONSTRUCTOR))
{
SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
{
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
DWORD bytesDecoded;
if (dataLen)
{
ret = CRYPT_AsnDecodeGeneralizedTime(pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, dwFlags,
pvStructInfo, pcbStructInfo, &bytesDecoded);
if (ret) *pcbDecoded = bytesDecoded + lenBytes + 1;
}
}
return ret;
}
static BOOL CRYPT_AsnDecodeOCSPBasicResponseEntry(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
{
struct AsnDecodeSequenceItem items[] = {
{ ASN_SEQUENCEOF, offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.HashAlgorithm.pszObjId),
CRYPT_AsnDecodeOCSPHashAlgorithm, sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE,
offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.HashAlgorithm.pszObjId), 0 },
{ ASN_OCTETSTRING, offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.IssuerNameHash),
CRYPT_AsnDecodeOctets, sizeof(CRYPT_HASH_BLOB), FALSE, TRUE,
offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.IssuerNameHash.pbData), 0 },
{ ASN_OCTETSTRING, offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.IssuerKeyHash),
CRYPT_AsnDecodeOctets, sizeof(CRYPT_HASH_BLOB), FALSE, TRUE,
offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.IssuerKeyHash.pbData), 0 },
{ ASN_INTEGER, offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.SerialNumber),
CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE,
offsetof(OCSP_BASIC_RESPONSE_ENTRY, CertId.SerialNumber.pbData), 0 },
{ ASN_CONTEXT, offsetof(OCSP_BASIC_RESPONSE_ENTRY, dwCertStatus),
CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE,
0, 0 },
/* FIXME: pRevokedInfo */
{ ASN_GENERALTIME, offsetof(OCSP_BASIC_RESPONSE_ENTRY, ThisUpdate),
CRYPT_AsnDecodeGeneralizedTime, sizeof(FILETIME), FALSE, FALSE,
0, 0 },
{ ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(OCSP_BASIC_RESPONSE_ENTRY, NextUpdate),
CRYPT_AsnDecodeOCSPNextUpdate, sizeof(FILETIME), TRUE, FALSE,
0, 0 },
{ ASN_CONTEXT | ASN_CONSTRUCTOR /* FIXME */, offsetof(OCSP_BASIC_RESPONSE_ENTRY, cExtension),
CRYPT_AsnDecodeCertExtensions, FINALMEMBERSIZE(OCSP_BASIC_RESPONSE_ENTRY, cExtension),
TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_ENTRY, rgExtension), 0 },
};
return CRYPT_AsnDecodeSequence(items, ARRAY_SIZE(items),
pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo,
pcbStructInfo, pcbDecoded, NULL);
}
static BOOL CRYPT_AsnDecodeOCSPBasicResponseEntriesArray(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
offsetof(OCSP_BASIC_RESPONSE_INFO, cResponseEntry), offsetof(OCSP_BASIC_RESPONSE_INFO, rgResponseEntry),
MEMBERSIZE(OCSP_BASIC_RESPONSE_INFO, cResponseEntry, cExtension),
CRYPT_AsnDecodeOCSPBasicResponseEntry, sizeof(OCSP_BASIC_RESPONSE_ENTRY),
FALSE, 0 };
return CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded,
dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded);
}
static BOOL CRYPT_AsnDecodeResponderID(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
{
OCSP_BASIC_RESPONSE_INFO *info = pvStructInfo;
BYTE tag = pbEncoded[0] & ~3, choice = pbEncoded[0] & 3;
DWORD decodedLen, dataLen, lenBytes, bytesNeeded = sizeof(*info), len;
CERT_NAME_BLOB *blob;
if (tag != (ASN_CONTEXT | ASN_CONSTRUCTOR))
{
WARN("Unexpected tag %02x\n", tag);
SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
if (choice > 2)
{
WARN("Unexpected choice %02x\n", choice);
SetLastError(CRYPT_E_ASN1_CORRUPT);
return FALSE;
}
if (pvStructInfo && *pcbStructInfo >= bytesNeeded)
info->dwResponderIdChoice = choice;
if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
return FALSE;
lenBytes = GET_LEN_BYTES(pbEncoded[1]);
cbEncoded -= 1 + lenBytes;
decodedLen = 1 + lenBytes;
if (dataLen > cbEncoded)
{
SetLastError(CRYPT_E_ASN1_EOD);
return FALSE;
}
pbEncoded += 1 + lenBytes;
if (pbEncoded[0] != ASN_OCTETSTRING)
{
WARN("Unexpected tag %02x\n", pbEncoded[0]);
SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
if (!CRYPT_GetLen(pbEncoded, cbEncoded, &len))
return FALSE;
lenBytes = GET_LEN_BYTES(pbEncoded[1]);
decodedLen += 1 + lenBytes + len;
cbEncoded -= 1 + lenBytes;
if (len > cbEncoded)
{
SetLastError(CRYPT_E_ASN1_EOD);
return FALSE;
}
pbEncoded += 1 + lenBytes;
if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) bytesNeeded += len;
if (pvStructInfo && *pcbStructInfo >= bytesNeeded)
{
blob = &info->u.ByNameResponderId;
blob->cbData = len;
if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
blob->pbData = (BYTE *)pbEncoded;
else if (blob->cbData)
{
blob->pbData = (BYTE *)(info + 1);
memcpy(blob->pbData, pbEncoded, blob->cbData);
}
}
if (pcbDecoded)
*pcbDecoded = decodedLen;
if (!pvStructInfo)
{
*pcbStructInfo = bytesNeeded;
return TRUE;
}
if (*pcbStructInfo < bytesNeeded)
{
SetLastError(ERROR_MORE_DATA);
*pcbStructInfo = bytesNeeded;
return FALSE;
}
*pcbStructInfo = bytesNeeded;
return TRUE;
}
static BOOL WINAPI CRYPT_AsnDecodeOCSPBasicResponse(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
CRYPT_DECODE_PARA *pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
struct AsnDecodeSequenceItem items[] = {
{ 0, 0,
CRYPT_AsnDecodeResponderID, offsetof(OCSP_BASIC_RESPONSE_INFO, ProducedAt), FALSE, TRUE,
offsetof(OCSP_BASIC_RESPONSE_INFO, u.ByNameResponderId.pbData), 0 },
{ ASN_GENERALTIME, offsetof(OCSP_BASIC_RESPONSE_INFO, ProducedAt),
CRYPT_AsnDecodeGeneralizedTime, sizeof(FILETIME), FALSE, FALSE,
0, 0 },
{ ASN_SEQUENCEOF, offsetof(OCSP_BASIC_RESPONSE_INFO, cResponseEntry),
CRYPT_AsnDecodeOCSPBasicResponseEntriesArray, MEMBERSIZE(OCSP_BASIC_RESPONSE_INFO, cResponseEntry, cExtension),
TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_INFO, rgResponseEntry) },
{ ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(OCSP_BASIC_RESPONSE_INFO, cExtension),
CRYPT_AsnDecodeCertExtensions, FINALMEMBERSIZE(OCSP_BASIC_RESPONSE_INFO, cExtension),
TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_INFO, rgExtension), 0 },
};
BOOL ret;
__TRY
{
ret = CRYPT_AsnDecodeSequence(items, ARRAY_SIZE(items),
pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
pcbStructInfo, NULL, NULL);
}
__EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType,
LPCSTR lpszStructType)
{
@ -6441,6 +6681,9 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType,
case LOWORD(OCSP_BASIC_SIGNED_RESPONSE):
decodeFunc = CRYPT_AsnDecodeOCSPBasicSignedResponse;
break;
case LOWORD(OCSP_BASIC_RESPONSE):
decodeFunc = CRYPT_AsnDecodeOCSPBasicResponse;
break;
default:
FIXME("Unimplemented decoder for lpszStructType OID %d\n", LOWORD(lpszStructType));
}

View File

@ -8948,6 +8948,63 @@ static void test_decodeOCSPBasicSignedResponseInfo(DWORD dwEncoding)
LocalFree(info);
}
static void test_decodeOCSPBasicResponseInfo(DWORD dwEncoding)
{
static const BYTE resp_id[] = {
0xb7, 0x6b, 0xa2, 0xea, 0xa8, 0xaa, 0x84, 0x8c, 0x79, 0xea, 0xb4, 0xda, 0x0f, 0x98, 0xb2, 0xc5,
0x95, 0x76, 0xb9, 0xf4};
static const BYTE name_hash[] = {
0xe4, 0xe3, 0x95, 0xa2, 0x29, 0xd3, 0xd4, 0xc1, 0xc3, 0x1f, 0xf0, 0x98, 0x0c, 0x0b, 0x4e, 0xc0,
0x09, 0x8a, 0xab, 0xd8};
static const BYTE key_hash[] = {
0xb7, 0x6b, 0xa2, 0xea, 0xa8, 0xaa, 0x84, 0x8c, 0x79, 0xea, 0xb4, 0xda, 0x0f, 0x98, 0xb2, 0xc5,
0x95, 0x76, 0xb9, 0xf4};
static const BYTE serial[] = {
0xb1, 0xc1, 0x87, 0x54, 0x54, 0xac, 0x1e, 0x55, 0x40, 0xfb, 0xef, 0xd9, 0x6d, 0x8f, 0x49, 0x08};
OCSP_BASIC_RESPONSE_INFO *info;
OCSP_BASIC_RESPONSE_ENTRY *entry;
DWORD size;
BOOL ret;
size = 0;
ret = pCryptDecodeObjectEx(dwEncoding, OCSP_BASIC_RESPONSE, ocsp_to_be_signed,
sizeof(ocsp_to_be_signed), CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
ok(ret, "got %08lx\n", GetLastError());
ok(!info->dwVersion, "got %lu\n", info->dwVersion);
ok(info->dwResponderIdChoice == 2, "got %lu\n", info->dwResponderIdChoice);
ok(info->ByKeyResponderId.cbData == sizeof(resp_id), "got %lu\n", info->ByKeyResponderId.cbData);
ok(!memcmp(info->ByKeyResponderId.pbData, resp_id, sizeof(resp_id)), "wrong data\n");
ok(info->ProducedAt.dwLowDateTime == 3438583808, "got %lu\n", info->ProducedAt.dwLowDateTime);
ok(info->ProducedAt.dwHighDateTime == 30946477, "got %lu\n", info->ProducedAt.dwHighDateTime);
ok(info->cResponseEntry == 1, "got %lu\n", info->cResponseEntry);
ok(info->rgResponseEntry != NULL, "got %p\n", info->rgResponseEntry);
entry = info->rgResponseEntry;
ok(!strcmp(entry->CertId.HashAlgorithm.pszObjId, szOID_OIWSEC_sha1), "got '%s'\n", entry->CertId.HashAlgorithm.pszObjId);
ok(entry->CertId.HashAlgorithm.Parameters.cbData == 2, "got %lu\n", entry->CertId.HashAlgorithm.Parameters.cbData);
ok(entry->CertId.HashAlgorithm.Parameters.pbData[0] == 5, "got 0x%02x\n", entry->CertId.HashAlgorithm.Parameters.pbData[0]);
ok(!entry->CertId.HashAlgorithm.Parameters.pbData[1], "got 0x%02x\n", entry->CertId.HashAlgorithm.Parameters.pbData[1]);
ok(entry->CertId.IssuerNameHash.cbData == 20, "got %lu\n", entry->CertId.IssuerNameHash.cbData);
ok(!memcmp(entry->CertId.IssuerNameHash.pbData, name_hash, sizeof(name_hash)), "wrong data\n");
ok(entry->CertId.IssuerKeyHash.cbData == 20, "got %lu\n", entry->CertId.IssuerKeyHash.cbData);
ok(!memcmp(entry->CertId.IssuerKeyHash.pbData, key_hash, sizeof(key_hash)), "wrong data\n");
ok(entry->CertId.SerialNumber.cbData == 16, "got %lu\n", entry->CertId.SerialNumber.cbData);
ok(!memcmp(entry->CertId.SerialNumber.pbData, serial, sizeof(serial)), "wrong data\n");
ok(entry->dwCertStatus == 0, "got %lu\n", entry->dwCertStatus);
ok(entry->pRevokedInfo == NULL, "got %p\n", entry->pRevokedInfo);
ok(entry->ThisUpdate.dwLowDateTime == 2558518400, "got %lu\n", entry->ThisUpdate.dwLowDateTime);
ok(entry->ThisUpdate.dwHighDateTime == 30946475, "got %lu\n", entry->ThisUpdate.dwHighDateTime);
ok(entry->NextUpdate.dwLowDateTime == 2014369408, "got %lu\n", entry->NextUpdate.dwLowDateTime);
ok(entry->NextUpdate.dwHighDateTime == 30947877, "got %lu\n", entry->NextUpdate.dwHighDateTime);
ok(!entry->cExtension, "got %lu\n", entry->cExtension);
ok(entry->rgExtension == NULL, "got %p\n", entry->rgExtension);
ok(!info->cExtension, "got %lu\n", info->cExtension);
ok(info->rgExtension == NULL, "got %p\n", info->rgExtension);
LocalFree(info);
}
START_TEST(encode)
{
static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
@ -9044,6 +9101,7 @@ START_TEST(encode)
test_encodeOCSPRequestInfo(encodings[i]);
test_decodeOCSPResponseInfo(encodings[i]);
test_decodeOCSPBasicSignedResponseInfo(encodings[i]);
test_decodeOCSPBasicResponseInfo(encodings[i]);
}
testPortPublicKeyInfo();
}