Пример проверки цепочки и использования конечного сертификата для выполнения операций подписи штампов времени с использованием флага CPCERT_CHAIN_POLICY_SIGNATURE в функции CertVerifyCertificateChainPolicy.

C++ Copy Code
    // Параметры для CertVerifyCertificateChainPolicy. 
    CERT_CHAIN_POLICY_PARA para = { sizeof(para) };

    // Помимо флагов, разрешенных в CERT_CHAIN_POLICY_PARA,
    // можно потребовать не проверять конечный сертификат, установив флаг
    // CPPRIVATEKEY_USAGE_PERIOD_CERT_CHAIN_POLICY_SKIP_END_CERT_FLAG,
    // тогда для проверки передавать время проверки в pvExtraPolicyPara 
    // нет необходимости. Будет проверена корректность построения самой
    // цепочки: закрытые ключи соответствующих сертификатов цепочки 
    // (исключая конечный) были использованы для подписи объектов PKI 
    // таких как CRL, CTL, выпущенный конечный сертификат или 
    // промежуточного ЦС, если это сертификат ЦС.    
    // 
    // Выставляем необходимые флаги
    para.dwFlags = dwFlags; 

    // Указываем дополнительные параметры с указанием времени проверки 
    // срока действия закрытого ключа конечного сертификата.
    //
    // Эту структуру можно не передавать, если необходимо проверить 
    // допустимость использования закрытого ключа в 
    // данный момент времени, или если указан флаг SKIP_END_CERT.  
    CPSIGNATURE_EXTRA_CERT_CHAIN_POLICY_PARA extraPara
        = { sizeof(extraPara) };    
    extraPara.pPrivateKeyUsedTime = &eeCertVerifyTime;
    para.pvExtraPolicyPara = &extraPara;


    // Готовим структуру для получения дополнительного статуса 
    // проверки цепочки. В ней будут указаны только специфичные коды
    // ошибок для расширенной проверки. Стандартные коды ошибок 
    // проверки цепочки возвращаются в status.dwError. Если pvExtraPolicyStatus
    // не задан, проверка завершается после первой ошибкb при проверке 
    // и в в status.dwError возвращаются только коды ошибок, определенных в 
    // заголовочных файлах Microsoft.
    CERT_CHAIN_POLICY_STATUS status = { sizeof(status) };
    CPSIGNATURE_EXTRA_CERT_CHAIN_POLICY_STATUS extraStatus
        = { sizeof(extraStatus) };
    status.pvExtraPolicyStatus = &extraStatus;

    // Зовём CertVerifyCertificateChainPolicy
    if(!::CertVerifyCertificateChainPolicy(
        CPCERT_CHAIN_POLICY_SIGNATURE, 
        pChainContext, 
        &para,
        &status)) {
            // "Цепочка не была проверена" 
            return HRESULT_FROM_WIN32(GetLastError());   
    }

    // Произошла ошибка при проверке по флагу 
    // CPCERT_CHAIN_POLICY_PRIVATEKEY_USAGE_PERIOD
    // Если задана pvExtraPolicyStatus, то можно получить больше информации
    // об ошибке
    if(status.dwError) {
        hr = HRESULT_FROM_WIN32(status.dwError);
        DoSmthIfError(L"Общая ошибка проверки цепочки:" + GetErrorMessage(hr)); 
    }

    // Ошибка произошла при проверке периода действия закрытого ключа 
    if (extraStatus.dwError & 
        (CPCERT_TRUST_PRIVATE_KEY_IS_NOT_TIME_VALID 
         | CPCERT_TRUST_PRIVATE_KEY_IS_NOT_TIME_VALID_FOR_CRL))
    {
        // Разбор детальной причины ошибки см. в примере 
        // проверки периода действия закрытого ключа 
        DoSmthIfError(L"Один из сертификатов цепочки "
            L"был использован для подписи " 
            L"вне периода действия закрытого ключа");
        if (SUCCEEDED(hr))
            hr = CERT_E_EXPIRED;
    }

    // Ошибка произошла при проверке конечного сертификата
    if (extraStatus.dwError & 
        CPCERT_TRUST_IS_NOT_VALID_BY_KEYUSAGE)
    {
        DoSmthIfError(L"В конечном сертификате отсутствую флаги " 
            L"CERT_NON_REPUDIATION_KEY_USAGE или CERT_DIGITAL_SIGNATURE_KEY_USAGE");
        if (SUCCEEDED(hr))
            hr = CERT_E_WRONG_USAGE;
    }

    return hr;