Как проверить статус отзыва сертификата x509 в c ++ с помощью wincrypt.h? - PullRequest
0 голосов
/ 25 апреля 2020

Я пытаюсь проверить состояние отзыва сертификата X509 в программе на c ++ с использованием wincrypt.h. К сожалению, я не могу найти исчерпывающий пример. В c# код будет следующим:

X509Certificate2 certificate = new X509Certificate2();
//Create X509Certificate2 object from .cer file.
byte[] rawData = ReadFile(@"C:\Users\z002m76a\Desktop\cert.pem");
certificate.Import(rawData);

X509Chain ch = new X509Chain();
ch.ChainPolicy.RevocationMode = X509RevocationMode.Online;
ch.Build(certificate);

Console.WriteLine("Chain revocation flag: {0}", ch.ChainPolicy.RevocationFlag);

Ответы [ 2 ]

0 голосов
/ 28 апреля 2020

Основываясь на отличном комментарии @ crypt32, я создал следующую программу на С ++. Вероятно, это не самый красивый код на С ++ в мире (мой С ++ довольно ржавый), но, похоже, он работает

// ValidationCheckCPP.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>

#include <windows.h>
#include <wincrypt.h>
#include "ValidationCheckCPP.h"

int main()
{
    char keyFile[] = "C:\\Users\\z002m76a\\Desktop\\2698514447.crt";

    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = FALSE;

    HANDLE hKeyFile;
    hKeyFile = CreateFile(keyFile, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hKeyFile) {

        BYTE lp[65536];
        DWORD flags;
        DWORD bytes;

        if (ReadFile(hKeyFile, lp, GetFileSize(hKeyFile, NULL), &bytes, NULL) && bytes > 0) {

            BYTE* p;
            p = lp + bytes;
            if (CryptStringToBinary((char*)lp, p - lp, CRYPT_STRING_BASE64_ANY, p, &bytes, NULL, &flags) && bytes > 0) {

                PCCERT_CONTEXT  pCertContext;
                pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, p, bytes);

                if (pCertContext)
                {
                    printf("Certificate loaded");

                    CERT_ENHKEY_USAGE EnhkeyUsage;
                    EnhkeyUsage.cUsageIdentifier = 0;
                    EnhkeyUsage.rgpszUsageIdentifier = NULL;

                    CERT_USAGE_MATCH CertUsage;
                    CertUsage.dwType = USAGE_MATCH_TYPE_AND;
                    CertUsage.Usage = EnhkeyUsage;

                    CERT_CHAIN_PARA ChainPara;
                    ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
                    ChainPara.RequestedUsage = CertUsage;

                    PCCERT_CHAIN_CONTEXT pChainContext;

                    if (CertGetCertificateChain(
                        NULL,                  // use the default chain engine
                        pCertContext,          // pointer to the end certificate
                        NULL,                  // use the default time
                        NULL,                  // search no additional stores
                        &ChainPara,
                        CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
                        NULL,                  // currently reserved
                        &pChainContext))       // return a pointer to the chain created
                    {
                        printf("Chain built with %d certificates.\n", pChainContext->rgpChain[0]->cElement);

                        CERT_CHAIN_POLICY_PARA ChainPolicy = { 0 };
                        ChainPolicy.cbSize = sizeof(ChainPolicy);

                        CERT_CHAIN_POLICY_STATUS PolicyStatus = { 0 };
                        PolicyStatus.cbSize = sizeof(PolicyStatus);

                        CertVerifyCertificateChainPolicy(
                            CERT_CHAIN_POLICY_BASE,
                            pChainContext,          // pointer to the chain    
                            &ChainPolicy,
                            &PolicyStatus);

                        CERT_REVOCATION_STATUS revocationStatus;
                        revocationStatus.cbSize = sizeof(CERT_REVOCATION_STATUS);

                        PCERT_CONTEXT* pCerts = new PCERT_CONTEXT[pChainContext->cChain];

                        for (DWORD i = 0; i < pChainContext->cChain; i++) {
                            pCerts[i] = (PCERT_CONTEXT)(pChainContext->rgpChain[i]->rgpElement[0]->pCertContext);
                        }

                        // CERT_VERIFY_REV_CHAIN_FLAG
                        // Verification of the chain of certificates is done assuming each certificate except the first certificate is the issuer of the certificate that precedes it.If dwRevType is not CERT_CONTEXT_REVOCATION_TYPE, no assumptions are made about the order of the contexts.
                        // CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION
                        // Prevents the revocation handler from accessing any network - based resources for revocation checking.
                        // CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG
                        // When set, dwUrlRetrievalTimeout is the cumulative time - out across all URL wire retrievals.
                        // CERT_VERIFY_REV_SERVER_OCSP_FLAG
                        // When set, this function only uses online certificate status protocol(OCSP) for revocation checking.If the certificate does not have any OCSP AIA URLs, the dwError member of the pRevStatus parameter is set to CRYPT_E_NOT_IN_REVOCATION_DATABASE.
                        DWORD revocationCheckType = CERT_VERIFY_REV_CHAIN_FLAG;

                        BOOL bRc = CertVerifyRevocation(
                            X509_ASN_ENCODING,
                            CERT_CONTEXT_REVOCATION_TYPE,
                            pChainContext->cChain,
                            (void**)pCerts,
                            revocationCheckType,
                            NULL,
                            &revocationStatus);

                        printf("The size of the chain context is %d. \n", pChainContext->cbSize);
                        printf("%d simple chains found.\n", pChainContext->cChain);
                        printf("\nError status for the chain:\n");

                        switch (pChainContext->TrustStatus.dwErrorStatus)
                        {
                        case CERT_TRUST_NO_ERROR:
                            printf("No error found for this certificate or chain.\n");
                            break;
                        case CERT_TRUST_IS_NOT_TIME_VALID:
                            printf("This certificate or one of the certificates in the certificate chain is not time-valid.\n");
                            break;
                        case CERT_TRUST_IS_REVOKED:
                            printf("Trust for this certificate or one of the certificates in the certificate chain has been revoked.\n");
                            break;
                        case CERT_TRUST_IS_NOT_SIGNATURE_VALID:
                            printf("The certificate or one of the certificates in the certificate chain does not have a valid signature.\n");
                            break;
                        case CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
                            printf("The certificate or certificate chain is not valid in its proposed usage.\n");
                            break;
                        case CERT_TRUST_IS_UNTRUSTED_ROOT:
                            printf("The certificate or certificate chain is based on an untrusted root.\n");
                            break;
                        case CERT_TRUST_REVOCATION_STATUS_UNKNOWN:
                            printf("The revocation status of the certificate or one of the certificates in the certificate chain is unknown.\n");
                            break;
                        case CERT_TRUST_IS_CYCLIC:
                            printf("One of the certificates in the chain was issued by a certification authority that the original certificate had certified.\n");
                            break;
                        case CERT_TRUST_IS_PARTIAL_CHAIN:
                            printf("The certificate chain is not complete.\n");
                            break;
                        case CERT_TRUST_CTL_IS_NOT_TIME_VALID:
                            printf("A CTL used to create this chain was not time-valid.\n");
                            break;
                        case CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID:
                            printf("A CTL used to create this chain did not have a valid signature.\n");
                            break;
                        case CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE:
                            printf("A CTL used to create this chain is not valid for this usage.\n");
                        }

                        printf("Info status for the chain:\n");
                        switch (pChainContext->TrustStatus.dwInfoStatus)
                        {
                        case 0:
                            printf("No information status reported.\n");
                            break;
                        case CERT_TRUST_HAS_EXACT_MATCH_ISSUER:
                            printf("An exact match issuer certificate has been found for this certificate.\n");
                            break;
                        case CERT_TRUST_HAS_KEY_MATCH_ISSUER:
                            printf("A key match issuer certificate has been found for this certificate.\n");
                            break;
                        case CERT_TRUST_HAS_NAME_MATCH_ISSUER:
                            printf("A name match issuer certificate has been found for this certificate.\n");
                            break;
                        case CERT_TRUST_IS_SELF_SIGNED:
                            printf("This certificate is self-signed.\n");
                            break;
                        case CERT_TRUST_IS_COMPLEX_CHAIN:
                            printf("The certificate chain created is a complex chain.\n");
                            break;
                        } // end switch
                    }

                    CertFreeCertificateContext(pCertContext);
                }
                else {
                    printf("Could not convert certificate to internal form\n");
                }
            }
            else {
                printf("Failed to convert from PEM\n");
            }
        }
        else {
            printf("Failed to read key file: %s\n", keyFile);
        }
    }
    else {
        printf("Failed to open key file: %s\n", keyFile);
    }

    CloseHandle(hKeyFile);

    return 0;
}
0 голосов
/ 26 апреля 2020

В C ++ вы используете функцию CertGetCertificateChain . Наряду с результатом вызова функция возвращает указатель на CERT_CHAIN_CONTEXT (через ppChainContext член). Эта структура CERT_CHAIN_CONTEXT хранит указатель на структуру CERT_SIMPLE_CHAIN (rgpChain член), которая представляет массив элементов цепочки (это то, что X509Chain.ChainElements представляет в. NET). По сути, вам нужно проверить самый первый элемент в rgpChain, который является указателем на структуру CERT_SIMPLE_CHAIN. И проверьте TrustStatus член на наличие флагов статуса отзыва (два флага).

...