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:
parent
bb17583239
commit
f04b102484
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue