Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/crypt32/decode.c | 243 ++++++++++++++++++++++++++++++++++++
dlls/crypt32/tests/encode.c | 58 +++++++++
2 files changed, 301 insertions(+)
diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c
index be36d3ef7b8..762d1b54661 100644
--- a/dlls/crypt32/decode.c
+++ b/dlls/crypt32/decode.c
@@ -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));
}
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c
index c4417a27e2c..b6325efd518 100644
--- a/dlls/crypt32/tests/encode.c
+++ b/dlls/crypt32/tests/encode.c
@@ -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();
}
--
2.30.2