[PATCH] crypt32: Add partial support for decoding OCSP_BASIC_RESPONSE_INFO structures.

Hans Leidekker hans at codeweavers.com
Fri Mar 25 08:18:07 CDT 2022


Signed-off-by: Hans Leidekker <hans at 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




More information about the wine-devel mailing list