SUPPORT-8703. Добавлена проверка цепочки сертификатов
This commit is contained in:
parent
4fa45a1f5e
commit
5ce934287f
4 changed files with 183 additions and 2 deletions
|
|
@ -28,6 +28,9 @@ capi_function_list_init(library_t *lib, capi_function_list_t *fl)
|
|||
LIBRARY_RESOLVE(fl->GetLastError, lib, "GetLastError");
|
||||
LIBRARY_RESOLVE(fl->CryptImportPublicKeyInfo, lib, "CryptImportPublicKeyInfo");
|
||||
LIBRARY_RESOLVE(fl->CryptDestroyKey, lib, "CryptDestroyKey");
|
||||
LIBRARY_RESOLVE(fl->CertGetCertificateChain, lib, "CertGetCertificateChain");
|
||||
LIBRARY_RESOLVE(fl->CertVerifyCertificateChainPolicy, lib, "CertVerifyCertificateChainPolicy");
|
||||
LIBRARY_RESOLVE(fl->CertFreeCertificateChain, lib, "CertFreeCertificateChain");
|
||||
|
||||
#ifdef UNICODE
|
||||
LIBRARY_RESOLVE(fl->CryptSignHash, lib, "CryptSignHashW");
|
||||
|
|
|
|||
|
|
@ -175,6 +175,31 @@ DECLARE_FN(WINADVAPI,
|
|||
CRYPT_DESTROY_KEY,
|
||||
(HCRYPTKEY hKey));
|
||||
|
||||
DECLARE_FN(WINADVAPI,
|
||||
BOOL,
|
||||
CERT_GET_CERTIFICATE_CHAIN,
|
||||
(HCERTCHAINENGINE hChainEngine,
|
||||
PCCERT_CONTEXT pCertContext,
|
||||
LPFILETIME pTime,
|
||||
HCERTSTORE hAdditionalStore,
|
||||
PCERT_CHAIN_PARA pChainPara,
|
||||
DWORD dwFlags,
|
||||
LPVOID pvReserved,
|
||||
PCCERT_CHAIN_CONTEXT* ppChainContext));
|
||||
|
||||
DECLARE_FN(WINADVAPI,
|
||||
BOOL,
|
||||
CERT_VERIFY_CERTIFICATE_CHAIN_POLICY,
|
||||
(LPCSTR pszPolicyOID,
|
||||
PCCERT_CHAIN_CONTEXT pChainContext,
|
||||
PCERT_CHAIN_POLICY_PARA pPolicyPara,
|
||||
PCERT_CHAIN_POLICY_STATUS pPolicyStatus));
|
||||
|
||||
DECLARE_FN(WINADVAPI,
|
||||
VOID,
|
||||
CERT_FREE_CERTIFICATE_CHAIN,
|
||||
(PCCERT_CHAIN_CONTEXT pChainContext));
|
||||
|
||||
#ifdef UNICODE
|
||||
#define CRYPT_SIGN_HASH_FN CRYPT_SIGN_HASH_W_FN
|
||||
#define CRYPT_VERIFY_SIGNATURE_FN CRYPT_VERIFY_SIGNATURE_W_FN
|
||||
|
|
@ -205,6 +230,9 @@ typedef struct {
|
|||
CRYPT_ACQUIRE_CONTEXT_FN CryptAcquireContext;
|
||||
CRYPT_IMPORT_PUBLIC_KEY_INFO_FN CryptImportPublicKeyInfo;
|
||||
CRYPT_DESTROY_KEY_FN CryptDestroyKey;
|
||||
CERT_GET_CERTIFICATE_CHAIN_FN CertGetCertificateChain;
|
||||
CERT_VERIFY_CERTIFICATE_CHAIN_POLICY_FN CertVerifyCertificateChainPolicy;
|
||||
CERT_FREE_CERTIFICATE_CHAIN_FN CertFreeCertificateChain;
|
||||
|
||||
} capi_function_list_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,127 @@ error:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static PCCERT_CHAIN_CONTEXT
|
||||
get_cert_chain(PCCERT_CONTEXT certificate)
|
||||
{
|
||||
LOG_TRACE("get_cert_chain enter");
|
||||
|
||||
CERT_CHAIN_PARA chain_para = {0};
|
||||
chain_para.cbSize = sizeof(CERT_CHAIN_PARA);
|
||||
|
||||
PCCERT_CHAIN_CONTEXT chain_ctx = NULL;
|
||||
|
||||
|
||||
if (!cp_function_list.CertGetCertificateChain(NULL,
|
||||
certificate,
|
||||
NULL,
|
||||
NULL,
|
||||
&chain_para,
|
||||
(CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_END_CERT),
|
||||
NULL,
|
||||
&chain_ctx)) {
|
||||
LOG_ERROR("CertGetCertificateChain() failed");
|
||||
LOG_ERROR("get_cert_chain exit with error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_TRACE("get_cert_chain exit");
|
||||
return chain_ctx;
|
||||
}
|
||||
|
||||
static const char*
|
||||
get_cert_chain_policy_status_error_desc(DWORD err)
|
||||
{
|
||||
// TODO-8703
|
||||
switch(err) {
|
||||
case CERT_E_UNTRUSTEDROOT:
|
||||
return "CERT_E_UNTRUSTEDROOT";
|
||||
case CERT_E_CHAINING:
|
||||
return "CERT_E_CHAINING";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
static bool
|
||||
check_cert_chain_policy(PCCERT_CHAIN_CONTEXT chain_ctx)
|
||||
{
|
||||
LOG_TRACE("check_cert_chain_policy enter");
|
||||
|
||||
CERT_CHAIN_POLICY_PARA policy_para = {0};
|
||||
policy_para.cbSize = sizeof(policy_para);
|
||||
|
||||
CERT_CHAIN_POLICY_STATUS status = {0};
|
||||
status.cbSize = sizeof(status);
|
||||
|
||||
CPSIGNATURE_EXTRA_CERT_CHAIN_POLICY_STATUS extraStatus = {0};
|
||||
extraStatus.cbSize = sizeof(extraStatus);
|
||||
|
||||
status.pvExtraPolicyStatus = &extraStatus;
|
||||
|
||||
if (!cp_function_list.CertVerifyCertificateChainPolicy(
|
||||
CERT_CHAIN_POLICY_BASE,
|
||||
// TODO-8703: CPCERT_CHAIN_POLICY_SIGNATURE
|
||||
chain_ctx,
|
||||
&policy_para,
|
||||
&status)) {
|
||||
LOG_ERROR("CertVerifyCertificateChainPolicy() failed");
|
||||
LOG_ERROR("check_cert_chain_policy exit with error");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (status.dwError != 0) {
|
||||
LOG_WARN("The certificate chain cannot be validated. "
|
||||
"CertVerifyCertificateChainPolicy status: %s('0x%08x')",
|
||||
get_cert_chain_policy_status_error_desc(status.dwError), status.dwError);
|
||||
LOG_TRACE("check_cert_chain_policy exit");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_TRACE("check_cert_chain_policy exit");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
free_cert_chain(PCCERT_CHAIN_CONTEXT chain_ctx)
|
||||
{
|
||||
LOG_TRACE("free_cert_chain enter");
|
||||
|
||||
if (chain_ctx) {
|
||||
cp_function_list.CertFreeCertificateChain(chain_ctx);
|
||||
}
|
||||
|
||||
LOG_TRACE("free_cert_chain exit");
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_cert_chain(PCCERT_CONTEXT certificate)
|
||||
{
|
||||
bool is_verified = false;
|
||||
|
||||
LOG_TRACE("verify_cert_chain enter");
|
||||
|
||||
PCCERT_CHAIN_CONTEXT chain_ctx = get_cert_chain(certificate);
|
||||
if (chain_ctx == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!check_cert_chain_policy(chain_ctx)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
is_verified = true;
|
||||
|
||||
exit:
|
||||
free_cert_chain(chain_ctx);
|
||||
|
||||
LOG_DEBUG("cert_chain: %s", is_verified ? "verified" : "failed");
|
||||
|
||||
LOG_DEBUG("verify_cert_chain exit");
|
||||
return is_verified;
|
||||
}
|
||||
|
||||
static int
|
||||
sign_hash_data(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t *sign)
|
||||
{
|
||||
|
|
@ -101,6 +222,10 @@ sign_hash_data(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t
|
|||
goto exit;
|
||||
}
|
||||
|
||||
if (!verify_cert_chain(pSignerCert)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!cp_function_list.CryptAcquireCertificatePrivateKey(
|
||||
pSignerCert,
|
||||
CRYPT_ACQUIRE_SILENT_FLAG,
|
||||
|
|
@ -425,6 +550,10 @@ cryptopro_verify(const str_t* cert_thumbprint, const str_t* alg, const str_t* da
|
|||
goto exit;
|
||||
}
|
||||
|
||||
if (!verify_cert_chain(certificate)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!cp_function_list.CryptAcquireContext(&hCryptProv, NULL, CP_KC1_GR3410_2001_PROV,
|
||||
PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT)) {
|
||||
LOG_ERROR("CryptAcquireContext() failed");
|
||||
|
|
|
|||
|
|
@ -58,11 +58,32 @@ chown -R ervu:ervu /var/opt/cprocsp/keys/ervu/key_cont.000/
|
|||
Получить следующие значения:
|
||||
- Поле "SHA1 отпечаток": это значение нужно будет указать в конфигурационном файле модуля подписания в качестве настройки \<sign_cert_thumbprint\>
|
||||
- Поле "Ссылка на ключ": убедиться, что значение равно "Есть" (иначе необходимо проверить выполнение предыдущих шагов)
|
||||
- Поля "URL сертификата УЦ": по ссылкам, указанным в этом значении, скачать сертификаты УЦ и установить их (описано далее)
|
||||
- Поля "URL списка отзыва": по ссылкам, указанным в этом значении, скачать CRL и установить их (описано далее)
|
||||
|
||||
4. (опционально) Сделать тестовую подпись с помощью установленного контейнера и полученных значений \<sign_cert_thumbprint\> и \<sign_cert_password\>:
|
||||
4. Установить сертификаты УЦ (поля "URL сертификата УЦ" в свойствах сертификата). Для каждого сертификата выполнить команду от имени **root**:
|
||||
``` bash
|
||||
/opt/cprocsp/bin/amd64/certmgr -install -store uRoot -file <sign_ca_cert>.cer
|
||||
```
|
||||
|
||||
5. Установить CRL (поле "URL списка отзыва" в свойствах сертификата). Для каждого CRL выполнить команду от имени **ervu**:
|
||||
``` bash
|
||||
/opt/cprocsp/bin/amd64/certmgr -install -store uCA -crl -file <sign_ca_crl>.crl
|
||||
```
|
||||
|
||||
6. Проверить цепочку сертификатов (команда выполняется от имени **ervu**):
|
||||
``` bash
|
||||
/opt/cprocsp/bin/amd64/certmgr -list -thumbprint <sign_cert_thumbprint> -chain
|
||||
```
|
||||
|
||||
Результатом команды должна быть строка "Цепочка сертификатов: Успешно проверена."
|
||||
|
||||
Подробнее о проверке цепочки сертификатов здесь: https://www.altlinux.org/%D0%9A%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D0%9F%D1%80%D0%BE#%D0%9F%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0_%D1%86%D0%B5%D0%BF%D0%BE%D1%87%D0%BA%D0%B8_%D1%81%D0%B5%D1%80%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D0%B2
|
||||
|
||||
7. (опционально) Сделать тестовую подпись с помощью установленного контейнера и полученных значений \<sign_cert_thumbprint\> и \<sign_cert_password\>:
|
||||
``` bash
|
||||
touch test.txt
|
||||
/opt/cprocsp/bin/amd64/cryptcp -signf -thumbprint <sign_cert_thumbprint> ./test.txt
|
||||
/opt/cprocsp/bin/amd64/cryptcp -signf -thumbprint <sign_cert_thumbprint> -errchain ./test.txt
|
||||
rm -f test.txt test.txt.sgn
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue