The example provided by @Rufus Buschart is quite lovely. If checking OCSP in his example, simply change revocationCheckType
to CERT_VERIFY_REV_SERVER_OCSP_FLAG
.
Here I'd like to provide an example using another api CertOpenServerOcspResponse()
// after construct the PCCERT_CHAIN_CONTEXT ppChainContext, which can be the same as @Rufus
// If async operation is required, change second parameter 0 to 1 (available since Win8.1, but not announced on official documentations)
HCERT_SERVER_OCSP_RESPONSE hServerOcspResponse = CertOpenServerOcspResponse(ppChainContext, 0, nullptr);
PCCERT_SERVER_OCSP_RESPONSE_CONTEXT recvdResponseCtx = CertGetServerOcspResponseContext(hServerOcspResponse, 0, nullptr);
if (recvdResponseCtx == nullptr)
{
printf("Receive OCSP server response failed\n");
showStrError("CertGetServerOcspResponseContext"); // show the description about GetLastError()
return 1;
}
POCSP_RESPONSE_INFO pocspResponseInfo = nullptr;
DWORD ocspResponseSize = 0; // X509_SEQUENCE_OF_ANY
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_RESPONSE, recvdResponseCtx->pbEncodedOcspResponse, recvdResponseCtx->cbEncodedOcspResponse, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspResponseInfo, &ocspResponseSize);
if (!ret)
{
printf("Error decode ocsp response info from CERT_SERVER_OCSP_RESPONSE_CONTEXT.\n");
showStrError("DecodeOcspServerResponse");
return 1;
}
if (pocspResponseInfo->dwStatus != OCSP_SUCCESSFUL_RESPONSE)
{
printf("Unsuccessfully ocsp response. The status value is %d, which means %s\n", pocspResponseInfo->dwStatus, "OCSP_MALFORMED_REQUEST_RESPONSE if it is 1");
return 1;
}
if (strcmp(szOID_PKIX_OCSP_BASIC_SIGNED_RESPONSE, pocspResponseInfo->pszObjId))
{
printf("Ocsp response info is %s\n, but it should be %s\n", pocspResponseInfo->pszObjId, szOID_PKIX_OCSP_BASIC_SIGNED_RESPONSE);
return 1;
}
POCSP_BASIC_SIGNED_RESPONSE_INFO pocspBasicSignedResponseInfo = nullptr;
DWORD ocspBasicSignedResponseSize = 0;
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_BASIC_SIGNED_RESPONSE, pocspResponseInfo->Value.pbData, pocspResponseInfo->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspBasicSignedResponseInfo, &ocspBasicSignedResponseSize);
if (!ret)
{
showStrError("DecodeOCSP_BASIC_SIGNED_RESPONSE");
return 1;
}
POCSP_BASIC_RESPONSE_INFO pocspBasicResponseInfo = nullptr;
DWORD ocspBasicResponseSize = 0;
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_BASIC_RESPONSE, pocspBasicSignedResponseInfo->ToBeSigned.pbData, pocspBasicSignedResponseInfo->ToBeSigned.cbData, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspBasicResponseInfo, &ocspBasicResponseSize);
if (!ret)
{
showStrError("DecodeOCSP_BASIC_RESPONSE");
return 1;
}
DWORD certStatus = pocspBasicResponseInfo->rgResponseEntry->dwCertStatus;
printf("cert status is %d", certStatus); // good:0, revoked:1, unknown:2
return 0;
The showStrError()
is modified from WinCrypt examples as below:
void showStrError(const char* lpszFunction)
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
printf("%s failed with error %d: %ws\n", lpszFunction, dw, (LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}