From 92821ebd49abfaf7435295c83c9e2bb3604c2f1e Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Fri, 4 Mar 2022 13:57:15 +0100 Subject: [PATCH] crypt32: Add support for encoding OCSP requests. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/crypt32/encode.c | 192 ++++++++++++++++++++++++++++++++++++ dlls/crypt32/tests/encode.c | 85 ++++++++++++++++ 2 files changed, 277 insertions(+) diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 7668d0ddb2c..a506f197be1 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -4472,6 +4472,195 @@ BOOL CRYPT_AsnEncodePKCSEnvelopedData(const CRYPT_ENVELOPED_DATA *envelopedData, ARRAY_SIZE(items), 0, NULL, pvData, pcbData); } +static BOOL WINAPI CRYPT_AsnEncodeCertId(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const OCSP_CERT_ID *id = pvStructInfo; + struct AsnEncodeSequenceItem items[] = { + { &id->HashAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 }, + { &id->IssuerNameHash, CRYPT_AsnEncodeOctets, 0 }, + { &id->IssuerKeyHash, CRYPT_AsnEncodeOctets, 0 }, + { &id->SerialNumber, CRYPT_AsnEncodeInteger, 0 }, + }; + + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + ARRAY_SIZE(items), dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnEncodeOCSPRequestEntry(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const OCSP_REQUEST_ENTRY *info = pvStructInfo; + struct AsnEncodeSequenceItem items[] = { + { &info->CertId, CRYPT_AsnEncodeCertId, 0 }, + }; + + if (info->cExtension) + { + FIXME("extensions not supported\n"); + SetLastError(E_INVALIDARG); + ret = FALSE; + } + else + { + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + ARRAY_SIZE(items), dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +struct ocsp_request_list +{ + DWORD count; + OCSP_REQUEST_ENTRY *entry; +}; + +static BOOL WINAPI CRYPT_AsnEncodeOCSPRequestEntries(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + DWORD bytesNeeded, dataLen, lenBytes, i; + const struct ocsp_request_list *list = pvStructInfo; + + ret = TRUE; + for (i = 0, dataLen = 0; ret && i < list->count; i++) + { + DWORD size; + ret = CRYPT_AsnEncodeOCSPRequestEntry(dwCertEncodingType, lpszStructType, &list->entry[i], + dwFlags, pEncodePara, NULL, &size); + if (ret) + dataLen += size; + } + if (ret) + { + CRYPT_EncodeLen(dataLen, NULL, &lenBytes); + bytesNeeded = 1 + lenBytes + dataLen; + if (!pbEncoded) + *pcbEncoded = bytesNeeded; + else + { + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pbEncoded, pcbEncoded, bytesNeeded))) + { + BYTE *out; + + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + out = pbEncoded; + *out++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(dataLen, out, &lenBytes); + out += lenBytes; + for (i = 0; i < list->count; i++) + { + DWORD size = dataLen; + + ret = CRYPT_AsnEncodeOCSPRequestEntry(dwCertEncodingType, lpszStructType, + &list->entry[i], dwFlags, pEncodePara, out, &size); + out += size; + dataLen -= size; + } + + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pEncodePara, pbEncoded); + } + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnEncodeOCSPRequest(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const OCSP_REQUEST_INFO *info = pvStructInfo; + + if (info->dwVersion != OCSP_REQUEST_V1) + { + FIXME("version %lu not supported\n", info->dwVersion); + SetLastError(E_INVALIDARG); + ret = FALSE; + } + else + { + if (info->cExtension) + { + FIXME("extensions not supported\n"); + SetLastError(E_INVALIDARG); + ret = FALSE; + } + else + { + struct AsnConstructedItem name; + struct AsnEncodeSequenceItem items[2]; + DWORD count = 1; + + name.tag = 1; + name.pvStructInfo = info->pRequestorName; + name.encodeFunc = CRYPT_AsnEncodeAltNameEntry; + items[0].pvStructInfo = &name; + items[0].encodeFunc = CRYPT_AsnEncodeConstructed; + + if (info->cRequestEntry) + { + items[1].pvStructInfo = &info->cRequestEntry; + items[1].encodeFunc = CRYPT_AsnEncodeOCSPRequestEntries; + count++; + } + + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + count, dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, LPCSTR lpszStructType) { @@ -4612,6 +4801,9 @@ static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, case LOWORD(CNG_RSA_PUBLIC_KEY_BLOB): encodeFunc = CRYPT_AsnEncodeRsaPubKey_Bcrypt; break; + case LOWORD(OCSP_REQUEST): + encodeFunc = CRYPT_AsnEncodeOCSPRequest; + break; default: FIXME("Unimplemented encoder for lpszStructType OID %d\n", LOWORD(lpszStructType)); } diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 3ba6b2680a7..9d12223c54c 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -8633,6 +8633,90 @@ static void testPortPublicKeyInfo(void) ok(ret,"CryptAcquireContextA failed\n"); } +static void test_encodeOCSPRequestInfo(DWORD dwEncoding) +{ + static const BYTE expected[] = + {0x30, 0x68, 0xa1, 0x17, 0x82, 0x15, 0x2a, 0x2e, 0x63, 0x6d, 0x2e, 0x73, 0x74, 0x65, 0x61, 0x6d, + 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4d, 0x30, 0x4b, 0x30, + 0x49, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0xe4, 0xe3, + 0x95, 0xa2, 0x29, 0xd3, 0xd4, 0xc1, 0xc3, 0x1f, 0xf0, 0x98 ,0x0c, 0x0b, 0x4e, 0xc0, 0x09, 0x8a, + 0xab, 0xd8, 0x04, 0x14, 0xb7, 0x6b, 0xa2, 0xea, 0xa8, 0xaa, 0x84, 0x8c, 0x79, 0xea, 0xb4, 0xda, + 0x0f, 0x98, 0xb2, 0xc5, 0x95, 0x76, 0xb9, 0xf4, 0x02, 0x10, 0xb1, 0xc1, 0x87, 0x54, 0x54, 0xac, + 0x1e, 0x55, 0x40, 0xfb, 0xef, 0xd9, 0x6d, 0x8f, 0x49, 0x08}; + static const BYTE expected2[] = + {0x30, 0x81, 0xb6, 0xa1, 0x17, 0x82, 0x15, 0x2a, 0x2e, 0x63, 0x6d, 0x2e, 0x73, 0x74, 0x65, 0x61, + 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x81, 0x9a, 0x30, + 0x4b, 0x30, 0x49, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, + 0xe4, 0xe3, 0x95, 0xa2, 0x29, 0xd3, 0xd4, 0xc1, 0xc3, 0x1f, 0xf0, 0x98, 0x0c, 0x0b, 0x4e, 0xc0, + 0x09, 0x8a, 0xab, 0xd8, 0x04, 0x14, 0xb7, 0x6b, 0xa2, 0xea, 0xa8, 0xaa, 0x84, 0x8c, 0x79, 0xea, + 0xb4, 0xda, 0x0f, 0x98, 0xb2, 0xc5, 0x95, 0x76, 0xb9, 0xf4, 0x02, 0x10, 0xb1, 0xc1, 0x87, 0x54, + 0x54, 0xac, 0x1e, 0x55, 0x40, 0xfb, 0xef, 0xd9, 0x6d, 0x8f, 0x49, 0x08, 0x30, 0x4b, 0x30, 0x49, + 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0xe4, 0xe3, 0x95, + 0xa2, 0x29, 0xd3, 0xd4, 0xc1, 0xc3, 0x1f, 0xf0, 0x98, 0x0c, 0x0b, 0x4e, 0xc0, 0x09, 0x8a, 0xab, + 0xd8, 0x04, 0x14, 0xb7, 0x6b, 0xa2, 0xea, 0xa8, 0xaa, 0x84, 0x8c, 0x79, 0xea, 0xb4, 0xda, 0x0f, + 0x98, 0xb2, 0xc5, 0x95, 0x76, 0xb9, 0xf4, 0x02, 0x10, 0xb1, 0xc1, 0x87, 0x54, 0x54, 0xac, 0x1e, + 0x55, 0x40, 0xfb, 0xef, 0xd9, 0x6d, 0x8f, 0x49, 0x08}; + static const BYTE issuer_name[] = + {0xe4, 0xe3 ,0x95, 0xa2, 0x29, 0xd3, 0xd4, 0xc1, 0xc3, 0x1f, 0xf0, 0x98, 0x0c, 0x0b, 0x4e, 0xc0, + 0x09, 0x8a, 0xab, 0xd8}; + static const BYTE issuer_key[] = + {0xb7, 0x6b, 0xa2, 0xea, 0xa8, 0xaa, 0x84, 0x8c, 0x79, 0xea, 0xb4, 0xda, 0x0f, 0x98, 0xb2, 0xc5, + 0x95, 0x76, 0xb9, 0xf4}; + static const BYTE serial[] = + {0x08, 0x49, 0x8f, 0x6d, 0xd9, 0xef, 0xfb, 0x40, 0x55, 0x1e, 0xac, 0x54, 0x54, 0x87, 0xc1, 0xb1}; + OCSP_REQUEST_ENTRY entry[2]; + CERT_ALT_NAME_ENTRY name; + OCSP_REQUEST_INFO info; + DWORD size; + BYTE *buf; + BOOL ret; + + memset(&entry, 0, sizeof(entry)); + entry[0].CertId.HashAlgorithm.pszObjId = (char *)szOID_OIWSEC_sha1; + entry[0].CertId.IssuerNameHash.cbData = sizeof(issuer_name); + entry[0].CertId.IssuerNameHash.pbData = (BYTE *)issuer_name; + entry[0].CertId.IssuerKeyHash.cbData = sizeof(issuer_key); + entry[0].CertId.IssuerKeyHash.pbData = (BYTE *)issuer_key; + entry[0].CertId.SerialNumber.cbData = sizeof(serial); + entry[0].CertId.SerialNumber.pbData = (BYTE *)serial; + + name.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME; + name.pwszDNSName = (WCHAR *)L"*.cm.steampowered.com"; + + info.dwVersion = OCSP_REQUEST_V1; + info.pRequestorName = &name; + info.cRequestEntry = 1; + info.rgRequestEntry = entry; + info.cExtension = 0; + info.rgExtension = NULL; + + size = 0; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, OCSP_REQUEST, &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "got %08lx\n", GetLastError()); + ok(size == sizeof(expected), "got %lu\n", size); + ok(!memcmp(buf, expected, sizeof(expected)), "unexpected value\n"); + LocalFree(buf); + + /* two entries */ + entry[1].CertId.HashAlgorithm.pszObjId = (char *)szOID_OIWSEC_sha1; + entry[1].CertId.IssuerNameHash.cbData = sizeof(issuer_name); + entry[1].CertId.IssuerNameHash.pbData = (BYTE *)issuer_name; + entry[1].CertId.IssuerKeyHash.cbData = sizeof(issuer_key); + entry[1].CertId.IssuerKeyHash.pbData = (BYTE *)issuer_key; + entry[1].CertId.SerialNumber.cbData = sizeof(serial); + entry[1].CertId.SerialNumber.pbData = (BYTE *)serial; + info.cRequestEntry = 2; + + size = 0; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, OCSP_REQUEST, &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "got %08lx\n", GetLastError()); + ok(size == sizeof(expected2), "got %lu\n", size); + ok(!memcmp(buf, expected2, sizeof(expected2)), "unexpected value\n"); + LocalFree(buf); +} + START_TEST(encode) { static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING, @@ -8726,6 +8810,7 @@ START_TEST(encode) test_encodeCertPolicyConstraints(encodings[i]); test_decodeCertPolicyConstraints(encodings[i]); test_decodeRsaPrivateKey(encodings[i]); + test_encodeOCSPRequestInfo(encodings[i]); } testPortPublicKeyInfo(); }