Пример проверки цепочки сертификатов на корректность использования закрытого ключа сертификата для подписи выпущенного сертификата, базового или дельта CRL, содержащегося в цепочке, подписи CTL с использованием флага CPCERT_CHAIN_POLICY_PRIVATEKEY_USAGE_PERIOD в функции CertVerifyCertificateChainPolicy.
C++
// Параметры для 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. CPPRIVATEKEY_USAGE_PERIOD_EXTRA_CERT_CHAIN_POLICY_PARA pkupExtPara = { sizeof(pkupExtPara) }; pkupExtPara.pPrivateKeyUsedTime = &eeCertVerifyTime; para.pvExtraPolicyPara = &pkupExtPara; // Готовим структуру для получения дополнительного статуса // проверки цепочки. В ней будут указаны только специфичные коды // ошибок для расширенной проверки. Стандартные коды ошибок // проверки цепочки возвращаются в status.dwError. Если pvExtraPolicyStatus // не задан, проверка завершается после первой ошибкb при проверке // и в в status.dwError возвращаются только коды ошибок, определенных в // заголовочных файлах Microsoft. CERT_CHAIN_POLICY_STATUS status = { sizeof(status) }; CPPRIVATEKEY_USAGE_PERIOD_EXTRA_CERT_CHAIN_POLICY_STATUS pkupExtStatus = { sizeof(pkupExtStatus) }; status.pvExtraPolicyStatus = &pkupExtStatus; // Зовём CertVerifyCertificateChainPolicy if(!::CertVerifyCertificateChainPolicy( CPCERT_CHAIN_POLICY_PRIVATEKEY_USAGE_PERIOD, pChainContext, ¶, &status)) { // "Цепочка не была проверена" return HRESULT_FROM_WIN32(GetLastError()); } // Произошла ошибка при проверке по флагам BASE или BASIC_CONSTRAINTS // Если задана pvExtraPolicyStatus, то можно получить больше информации // об ошибке if(status.dwError) { hr = HRESULT_FROM_WIN32(status.dwError); DoSmthIfError(L"Общая ошибка проверки цепочки:" + GetErrorMessage(hr)); } // Ошибка произошла при проверке сертификата if (pkupExtStatus.dwError & CPCERT_TRUST_PRIVATE_KEY_IS_NOT_TIME_VALID) { // Показываем детальную информацию об ошибке // Закрытый ключ конечного сертификата не может использоваться // на указанное время проверки if ( pkupExtStatus.lChainIndex == 0 && pkupExtStatus.lElementIndex == 0) { // Сообщаем об ошибке DoSmthIfError(L"Конечный сертификат нельзя использовать на момент проверки"); if (SUCCEEDED(hr)) hr = CERT_E_EXPIRED; } // CTL был подписан сертификатом, закрытый ключ // которого не мог использоваться в момент подписи CTL else if ( pkupExtStatus.lChainIndex > 0 && pkupExtStatus.lElementIndex == 0) { // Сообщаем об ошибке и можем дополнительно // показать пользователю недопустимый сертификат DoSmthIfError(L"Сертификат был использован для подписи " L"CTL вне периода действия закрытого ключа", pChainContext->rgpChain[pkupExtStatus.lChainIndex]-> rgpElement[pkupExtStatus.lElementIndex]->pCertContext); if (SUCCEEDED(hr)) hr = CERT_E_EXPIRED; } // ЦА выпустил сертификат либо подчиненного ЦА (pkupExtStatus.lElementIndex > 1) // либо конечный сответствующий конечный сертификат (pkupExtStatus.lElementIndex == 1) // вне периода действия своего закрытого ключа else if ( pkupExtStatus.lChainIndex >=0 && pkupExtStatus.lElementIndex >= 0) { // Сообщаем об ошибке и можем дополнительно // показать пользователю недопустимый сертификат DoSmthIfError(L"Сертификат был использован для подписи " L"CTL вне периода действия закрытого ключа", pChainContext->rgpChain[pkupExtStatus.lChainIndex]-> rgpElement[pkupExtStatus.lElementIndex]->pCertContext); if (SUCCEEDED(hr)) hr = CERT_E_EXPIRED; } } // Ошибка произошла при проверке сертификата if (pkupExtStatus.dwError & CPCERT_TRUST_PRIVATE_KEY_IS_NOT_TIME_VALID_FOR_CRL) { // Показываем детальную информацию об ошибке // Закрытый ключ сертификата не должен был использоваться // для выпуска соответствующего CRL, лежащего в цепочке if ( pkupExtStatus.lChainIndex >= 0 && pkupExtStatus.lElementIndex >= 0) { // Сообщаем об ошибке DoSmthIfError(L"Сертификат был использован для подписи " L"CRL вне периода действия закрытого ключа", pChainContext->rgpChain[pkupExtStatus.lChainIndex]-> rgpElement[pkupExtStatus.lElementIndex]->pCertContext); if (SUCCEEDED(hr)) hr = CERT_E_EXPIRED; } else { DoSmthIfError(L"Один из сертификатов цепочки " L"был использован для подписи CRL " L"вне периода действия закрытого ключа"); if (SUCCEEDED(hr)) hr = CERT_E_EXPIRED; } } return hr;