Merge branch 'develop' into feature/8714_list_of_esia_certs

This commit is contained in:
Наиля Алашкова 2024-11-25 13:11:28 +03:00
commit afd73dfcaf
10 changed files with 500 additions and 10 deletions

View file

@ -0,0 +1,76 @@
Подписание (в автоматическом режиме) запросов в ЕСИА ключом ЭП.
Должно быть выполнено тестирование со следующими вариантами статуса сертификата ключа проверки ЭП:
1. Действительный сертификат компонента ervu-sign-module, изготовленный Удостоверяющим центром запрос в ЕСИА должен быть успешно отправлен:
1.1. Установить сертификат в систему, согласно "Инструкции по установке".
1.2. Открыть приложение - запрос в ЕСИА должен быть успешно отправлен.
2. Проверка статуса сертификата не может быть выполнена, так как в Системе отсутствует CRL, соответствующий Удостоверяющему центру запрос в ЕСИА не должен быть отправлен:
2.1. Удалить CRL, соответствующий Удостоверяющему центру, изготовившему сертификат компонента ervu-sign-module, выполнив команду от имени ervu:
/opt/cprocsp/bin/amd64/certmgr -delete -crl -store ucache -dn uc_fk@roskazna.ru
/opt/cprocsp/bin/amd64/certmgr -delete -crl -store uca -dn uc_fk@roskazna.ru
2.2. Отключить доступ к УЦ (например, прописав в /etc/hosts недоступный ip-адрес для хоста УЦ, указанного в свойствах сертификата):
Пример /etc/hosts:
127.0.0.1 crl.roskazna.ru
2.3. Перезапустить сервис подписания ervu-sign-module, чтобы сбросить кэш:
systemctl restart ervu-sign-module
2.4. Открыть приложение - запрос в ЕСИА не должен быть отправлен. Пользователю отобразится ошибка.
В логах ЛК РП должно быть следующее:
Caused by: java.lang.RuntimeException: 500 500 Internal Server Error
at ru.micord.ervu.security.esia.service.EsiaAuthService.errorHandler(EsiaAuthService.java:351) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.signMap(EsiaAuthService.java:340) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.generateAuthCodeUrl(EsiaAuthService.java:101) ~[classes/:1.10.0-SNAPSHOT]
В логах ervu-sign-module должно быть следующее:
WARN: The certificate is not trusted. CERT_TRUST_STATUS: '0x00000040'
ERROR: get_cert_chain exit with error
ERROR: sign_hash_data exit with error. Last error code: 0x00000000
ERROR: cryptopro_sign exit with error
ERROR: sign_content exit with error
ERROR: response status: '500 Internal Server Error'
CERT_TRUST_STATUS = 0x00000040 (CERT_TRUST_REVOCATION_STATUS_UNKNOWN) означает, что статус отзыва сертификата или одного из сертификатов в цепочке сертификатов неизвестен.
2.5. Восстановить доступ к УЦ. Все CRL будут автоматически установлены при следующих запросах на подпись.
3. Сертификат действителен, но выдан УЦ, корневой сертификат которого не установлен в системе запрос в ЕСИА не должен быть отправлен:
3.1. Получить цепочку сертификатов и SHA1 отпечаток корневого сертификата УЦ, выполнив команду от имени ervu:
/opt/cprocsp/bin/amd64/certmgr -list -thumbprint 0f948ba2b4866bf92e77f768a01add655daa5748 -chain
Результатом команды будет цепочка сертификатов с перечнем их свойств, из которого необходимо получить значение поля "SHA1 отпечаток" для одного из корневых сертификатов.
3.2. Из Системы удалить корневой сертификат Удостоверяющего центра, выполнив команду от имени root. Например, удалить сертификат Минцифры России, выполнив команду от имени root:
/opt/cprocsp/bin/amd64/certmgr -delete -store mRoot -thumbprint 2f0cb09be3550ef17ec4f29c90abd18bfcaad63a
3.3. Открыть приложение - запрос в ЕСИА не должен быть отправлен. Пользователю отобразится ошибка.
В логах ЛК РП должно быть следующее:
Caused by: java.lang.RuntimeException: 500 500 Internal Server Error
at ru.micord.ervu.security.esia.service.EsiaAuthService.errorHandler(EsiaAuthService.java:351) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.signMap(EsiaAuthService.java:340) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.generateAuthCodeUrl(EsiaAuthService.java:101) ~[classes/:1.10.0-SNAPSHOT]
В логах ervu-sign-module должно быть следующее:
WARN: The certificate is not trusted. CERT_TRUST_STATUS: '0x00000020'
ERROR: get_cert_chain exit with error
ERROR: sign_hash_data exit with error. Last error code: 0x80092004
ERROR: cryptopro_sign exit with error
ERROR: sign_content exit with error
ERROR: response status: '500 Internal Server Error'
CERT_TRUST_STATUS = 0x00000020 (CERT_TRUST_IS_UNTRUSTED_ROOT) означает, что сертификат или цепочка сертификатов основана на ненадежном корневом сертификате.
3.4. Восстановить все корневые сертификаты, которые были удалены, выполнив для каждого команду от имени root. Для восстановления сертификата Минцифры России выполните команду от имени root:
/opt/cprocsp/bin/amd64/certmgr -install -store mRoot -file guc2022.crt
Сертификат Минцифры России доступен по ссылке: http://reestr-pki.ru/cdp/guc2022.crt

View file

@ -0,0 +1,74 @@
Подписание (в автоматическом режиме) запросов в ЕСИА ключом ЭП.
Должно быть выполнено тестирование со следующими вариантами статуса сертификата ключа проверки ЭП:
1. Действительный сертификат компонента ervu-sign-module, изготовленный Удостоверяющим центром запрос в ЕСИА должен быть успешно отправлен:
1.1. Установить сертификат в систему, согласно "Инструкции по установке".
1.2. Открыть приложение - запрос в ЕСИА должен быть успешно отправлен.
2. Проверка статуса сертификата не может быть выполнена, так как в Системе отсутствует CRL, соответствующий Удостоверяющему центру запрос в ЕСИА не должен быть отправлен:
2.1. Удалить CRL, соответствующий Удостоверяющему центру, изготовившему сертификат компонента ervu-sign-module:
sudo -u ervu /opt/cprocsp/bin/amd64/certmgr -delete -crl -store ucache -all
sudo -u ervu /opt/cprocsp/bin/amd64/certmgr -delete -crl -store uca -all
2.2. Отключить доступ к УЦ (например, прописав в /etc/hosts недоступный ip-адрес для хоста УЦ, указанного в свойствах сертификата):
Пример /etc/hosts:
127.0.0.1 testgost2012.cryptopro.ru
2.3. Перезапустить сервис подписания ervu-sign-module, чтобы сбросить кэш:
sudo systemctl restart ervu-sign-module
2.4. Открыть приложение - запрос в ЕСИА не должен быть отправлен. Пользователю отобразится ошибка.
В логах ЛК РП должно быть следующее:
Caused by: java.lang.RuntimeException: 500 500 Internal Server Error
at ru.micord.ervu.security.esia.service.EsiaAuthService.errorHandler(EsiaAuthService.java:351) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.signMap(EsiaAuthService.java:340) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.generateAuthCodeUrl(EsiaAuthService.java:101) ~[classes/:1.10.0-SNAPSHOT]
В логах ervu-sign-module должно быть следующее:
WARN: The certificate is not trusted. CERT_TRUST_STATUS: '0x00000040'
ERROR: get_cert_chain exit with error
ERROR: sign_hash_data exit with error. Last error code: 0x00000000
ERROR: cryptopro_sign exit with error
ERROR: sign_content exit with error
ERROR: response status: '500 Internal Server Error'
CERT_TRUST_STATUS = 0x00000040 (CERT_TRUST_REVOCATION_STATUS_UNKNOWN) означает, что статус отзыва сертификата или одного из сертификатов в цепочке сертификатов неизвестен.
2.5. Восстановить доступ к УЦ. Все CRL будут автоматически установлены при следующих запросах на подпись.
3. Сертификат действителен, но выдан УЦ, корневой сертификат которого не установлен в системе запрос в ЕСИА не должен быть отправлен:
3.1. Получить цепочку сертификатов и SHA1 отпечаток корневого сертификата УЦ:
sudo -u ervu /opt/cprocsp/bin/amd64/certmgr -list -thumbprint 1f5ab193354a7701e4964711163c6b46d4a361e0 -chain
Результатом команды будет цепочка сертификатов с перечнем их свойств, из которого необходимо получить значение поля "SHA1 отпечаток" для одного из корневых сертификатов.
3.2. Из Системы удалить корневой сертификат Удостоверяющего центра. Например, удалить сертификат Тестового УЦ ООО Крипто-Про, выполнив команду:
sudo /opt/cprocsp/bin/amd64/certmgr -delete -store mRoot -thumbprint 41dcbff2ae102339bcedd0d5100ffb8e6018353d
3.3. Открыть приложение - запрос в ЕСИА не должен быть отправлен. Пользователю отобразится ошибка.
В логах ЛК РП должно быть следующее:
Caused by: java.lang.RuntimeException: 500 500 Internal Server Error
at ru.micord.ervu.security.esia.service.EsiaAuthService.errorHandler(EsiaAuthService.java:351) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.signMap(EsiaAuthService.java:340) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.generateAuthCodeUrl(EsiaAuthService.java:101) ~[classes/:1.10.0-SNAPSHOT]
В логах ervu-sign-module должно быть следующее:
WARN: The certificate is not trusted. CERT_TRUST_STATUS: '0x00000020'
ERROR: get_cert_chain exit with error
ERROR: sign_hash_data exit with error. Last error code: 0x80092004
ERROR: cryptopro_sign exit with error
ERROR: sign_content exit with error
ERROR: response status: '500 Internal Server Error'
CERT_TRUST_STATUS = 0x00000020 (CERT_TRUST_IS_UNTRUSTED_ROOT) означает, что сертификат или цепочка сертификатов основана на ненадежном корневом сертификате.
3.4. Восстановить все корневые сертификаты, которые были удалены, выполнив для каждого команду от имени root. Для восстановления сертификата Тестового УЦ ООО Крипто-Про выполните команду:
sudo /opt/cprocsp/bin/amd64/certmgr -install -store mRoot -file ~/work/ervu/certs/lkrp-mnsv93/testgost2012\(10\).crt

114
docs/ПМИ.txt Normal file
View file

@ -0,0 +1,114 @@
1. Подписание (в автоматическом режиме) запросов в ЕСИА ключом ЭП.
Должно быть выполнено тестирование со следующими вариантами статуса сертификата ключа проверки ЭП:
1.1. Действительный сертификат компонента ervu-sign-module, изготовленный Удостоверяющим центром запрос в ЕСИА должен быть успешно отправлен:
1.1.1. Установить сертификат в систему, согласно "Инструкции по установке".
1.1.2. Открыть приложение - запрос в ЕСИА должен быть успешно отправлен.
1.2. Проверка статуса сертификата не может быть выполнена, так как в Системе отсутствует CRL, соответствующий Удостоверяющему центру запрос в ЕСИА не должен быть отправлен:
1.2.1. Удалить CRL, соответствующий Удостоверяющему центру, изготовившему сертификат компонента ervu-sign-module:
/opt/cprocsp/bin/amd64/certmgr -delete -crl -store ucache -all
/opt/cprocsp/bin/amd64/certmgr -delete -crl -store uca -all
1.2.2. Отключить доступ к УЦ.
1.2.3. Перезапустить сервис подписания ervu-sign-module, чтобы сбросить кэш.
1.2.4. Открыть приложение - запрос в ЕСИА не должен быть отправлен. Пользователю отобразится ошибка.
В логах ЛК РП должно быть следующее:
Caused by: java.lang.RuntimeException: 500 500 Internal Server Error
at ru.micord.ervu.security.esia.service.EsiaAuthService.errorHandler(EsiaAuthService.java:351) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.signMap(EsiaAuthService.java:340) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.generateAuthCodeUrl(EsiaAuthService.java:101) ~[classes/:1.10.0-SNAPSHOT]
В логах ervu-sign-module должно быть следующее:
WARN: The certificate is not trusted. CERT_TRUST_STATUS: '0x00000040'
ERROR: get_cert_chain exit with error
ERROR: sign_hash_data exit with error. Last error code: 0x00000000
ERROR: cryptopro_sign exit with error
ERROR: sign_content exit with error
ERROR: response status: '500 Internal Server Error'
CERT_TRUST_STATUS = 0x00000040 (CERT_TRUST_REVOCATION_STATUS_UNKNOWN) означает, что статус отзыва сертификата или одного из сертификатов в цепочке сертификатов неизвестен.
1.2.5. Восстановить доступ к УЦ. Все CRL будут автоматически установлены при следующих запросах на подпись.
1.3. Сертификат действителен, но выдан УЦ, корневой сертификат которого не установлен в системе запрос в ЕСИА не должен быть отправлен:
1.3.1. Получить цепочку сертификатов и SHA1 отпечаток корневого сертификата УЦ:
/opt/cprocsp/bin/amd64/certmgr -list -thumbprint <sign_cert_thumbprint> -chain
где <sign_cert_thumbprint> - это SHA1 отпечаток сертификата компонента ervu-sign-module.
Результатом команды будет цепочка сертификатов с перечнем их свойств, из которого необходимо получить значение поля "SHA1 отпечаток".
1.3.2. Из Системы удалить корневой сертификат Удостоверяющего центра, выполнив команду от имени root:
/opt/cprocsp/bin/amd64/certmgr -delete -store mRoot -thumbprint <root_cert_thumbprint>
где <root_cert_thumbprint> - это SHA1 отпечаток корневого сертификата УЦ, полученный на предыдущем шаге.
1.3.3. Открыть приложение - запрос в ЕСИА не должен быть отправлен. Пользователю отобразится ошибка.
В логах ЛК РП должно быть следующее:
Caused by: java.lang.RuntimeException: 500 500 Internal Server Error
at ru.micord.ervu.security.esia.service.EsiaAuthService.errorHandler(EsiaAuthService.java:351) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.signMap(EsiaAuthService.java:340) ~[classes/:1.10.0-SNAPSHOT]
at ru.micord.ervu.security.esia.service.EsiaAuthService.generateAuthCodeUrl(EsiaAuthService.java:101) ~[classes/:1.10.0-SNAPSHOT]
В логах ervu-sign-module должно быть следующее:
WARN: The certificate is not trusted. CERT_TRUST_STATUS: '0x00000020'
ERROR: get_cert_chain exit with error
ERROR: sign_hash_data exit with error. Last error code: 0x80092004
ERROR: cryptopro_sign exit with error
ERROR: sign_content exit with error
ERROR: response status: '500 Internal Server Error'
CERT_TRUST_STATUS = 0x00000020 (CERT_TRUST_IS_UNTRUSTED_ROOT) означает, что сертификат или цепочка сертификатов основана на ненадежном корневом сертификате.
1.3.4. Восстановить все корневые сертификаты, которые были удалены, выполнив для каждого команду от имени root:
/opt/cprocsp/bin/amd64/certmgr -install -store mRoot -file <root_cert>.crt
2. Проверка ЭП маркера доступа, полученного от ЕСИА.
Должно быть выполнено тестирование со следующими вариантами статуса сертификата ключа проверки ЭП:
2.1. Действительный сертификат ЕСИА ответ ЕСИА должен быть принят:
2.1.1. Установить сертификат ЕСИА в систему, согласно "Инструкции по установке".
2.1.2. Выполнить вход через ЕСИА - ответ ЕСИА должен быть принят.
2.2. Проверка статуса сертификата не может быть выполнена, так как в Системе отсутствует CRL, соответствующий Удостоверяющему центру, изготовившему сертификат ЕСИА - ответ ЕСИА не должен быть принят:
2.2.1. Удалить CRL, соответствующий Удостоверяющему центру, изготовившему сертификат ЕСИА:
/opt/cprocsp/bin/amd64/certmgr -delete -crl -store ucache
/opt/cprocsp/bin/amd64/certmgr -delete -crl -store uCA
2.2.2. Отключить доступ к УЦ.
2.2.3. Перезапустить сервис подписания ervu-sign-module, чтобы сбросить кэш.
2.2.4. Выполнить вход через ЕСИА - ответ ЕСИА должен быть отклонен с ошибкой.
2.2.5. Восстановить доступ к УЦ. Все CRL будут автоматически установлены при следующих запросах на проверку ЭП маркера доступа, полученного от ЕСИА.
2.3. Сертификат действителен, но выдан УЦ, корневой сертификат которого не установлен в системе ответ ЕСИА не должен быть принят:
2.3.1. Получить цепочку сертификатов и SHA1 отпечаток корневого сертификата УЦ:
/opt/cprocsp/bin/amd64/certmgr -list -thumbprint <esia_cert_thumbprint> -chain
где <esia_cert_thumbprint> - это SHA1 отпечаток сертификата ЕСИА.
Результатом команды будет цепочка сертификатов с перечнем их свойств, из которого необходимо получить значение поля "SHA1 отпечаток".
2.3.2. Из Системы удалить корневой сертификат Удостоверяющего центра, выполнив команду от имени root:
/opt/cprocsp/bin/amd64/certmgr -delete -store mRoot -thumbprint <root_esia_cert_thumbprint>
где <root_esia_cert_thumbprint> - это SHA1 отпечаток корневой сертификата УЦ, полученный на предыдущем шаге.
2.3.3. Выполнить вход через ЕСИА - обработка ответа от ЕСИА должна завершиться ошибкой.
2.3.4. Восстановить все корневые сертификаты, которые были удалены, выполнив для каждого команду от имени root:
/opt/cprocsp/bin/amd64/certmgr -install -store mRoot -file <root_esia_cert>.crt

View file

@ -7,4 +7,11 @@ if [ ! -d /var/opt/cprocsp/keys/ervu ];
fi
/opt/cprocsp/bin/amd64/csptest -absorb -certs -autoprov
set +e
cd /home/ervu/cacerts
echo o | /opt/cprocsp/bin/amd64/certmgr -install -store uRoot -file testgost2012_10.crt
echo o | /opt/cprocsp/bin/amd64/certmgr -install -store uRoot -thumbprint 67aea9fc8041cfafafbb77c4837038f05e727501 -file testroot.p7b
set -e
/opt/ervu-sign-module/ervu-sign-module

View file

@ -146,17 +146,29 @@ typedef fcgi_handler_status_t (*fcgi_request_handler_pt)(const FCGX_Request* req
typedef fcgi_request_handler_pt (*FCGI_REQUEST_FINALIZE_HANDLER)(int rc);
static inline void
fcgi_print_log(const FCGX_Request* request, const char* status)
{
const char* uri = fcgi_request_get_param(request, FCGI_PARAM_NAME_REQUEST_URI, NULL);
uri = uri != NULL ? uri : "nil";
const char* method = fcgi_request_get_param(request, FCGI_PARAM_NAME_REQUEST_METHOD, NULL);
method = method != NULL ? method : "nil";
LOG_INFO("%s %s, '%s'", method, uri, status);
}
static inline fcgi_handler_status_t
fcgi_200_ok_handler(const FCGX_Request* request, void* ctx __attribute__((unused)))
{
LOG_INFO("response status: '200 OK'");
LOG_DEBUG("response status: '200 OK'");
return FCGI_CHECK_PRINTF_STATUS(request, FCGI_200_RESPONSE_FORMAT, 200);
}
static inline fcgi_handler_status_t
fcgi_400_bad_request_handler(const FCGX_Request* request, void* ctx __attribute__((unused)))
{
LOG_INFO("response status: '400 Bad Request'");
fcgi_print_log(request, "400 Bad Request");
return FCGI_CHECK_PRINTF_STATUS(request, FCGI_400_RESPONSE_FORMAT, 400);
}
@ -164,7 +176,7 @@ fcgi_400_bad_request_handler(const FCGX_Request* request, void* ctx __attribute_
static inline fcgi_handler_status_t
fcgi_401_unauthorized_handler(const FCGX_Request* request, void* ctx __attribute__((unused)))
{
LOG_INFO("response status: '401 Unauthorized'");
fcgi_print_log(request, "401 Unauthorized");
return FCGI_CHECK_PRINTF_STATUS(request, FCGI_401_RESPONSE_FORMAT, 401);
}
@ -172,7 +184,7 @@ fcgi_401_unauthorized_handler(const FCGX_Request* request, void* ctx __attribute
static inline fcgi_handler_status_t
fcgi_404_not_found_handler(const FCGX_Request* request, void* ctx __attribute__((unused)))
{
LOG_INFO("response status: '404 Not Found'");
fcgi_print_log(request, "404 Not Found");
return FCGI_CHECK_PRINTF_STATUS(request, FCGI_404_RESPONSE_FORMAT, 404);
}
@ -180,7 +192,7 @@ fcgi_404_not_found_handler(const FCGX_Request* request, void* ctx __attribute__(
static inline fcgi_handler_status_t
fcgi_405_method_not_allowed_handler(const FCGX_Request* request, void* ctx __attribute__((unused)))
{
LOG_INFO("response status: '405 Method Not Allowed'");
fcgi_print_log(request, "405 Method Not Allowed");
return FCGI_CHECK_PRINTF_STATUS(request, FCGI_405_RESPONSE_FORMAT, 405);
}
@ -188,7 +200,7 @@ fcgi_405_method_not_allowed_handler(const FCGX_Request* request, void* ctx __att
static inline fcgi_handler_status_t
fcgi_406_not_acceptable_handler(const FCGX_Request* request, void* ctx __attribute__((unused)))
{
LOG_INFO("response status: '406 Not Acceptable'");
fcgi_print_log(request, "406 Not Acceptable");
return FCGI_CHECK_PRINTF_STATUS(request, FCGI_406_RESPONSE_FORMAT, 406);
}
@ -196,7 +208,7 @@ fcgi_406_not_acceptable_handler(const FCGX_Request* request, void* ctx __attribu
static inline fcgi_handler_status_t
fcgi_413_request_entity_too_large_handler(const FCGX_Request* request, void* ctx __attribute__((unused)))
{
LOG_INFO("response status: '413 Request Entity Too Large'");
fcgi_print_log(request, "413 Request Entity Too Large'");
return FCGI_CHECK_PRINTF_STATUS(request, FCGI_413_RESPONSE_FORMAT, 413);
}
@ -204,7 +216,7 @@ fcgi_413_request_entity_too_large_handler(const FCGX_Request* request, void* ctx
static inline fcgi_handler_status_t
fcgi_500_internal_server_error_handler(const FCGX_Request* request, void* ctx __attribute__((unused)))
{
LOG_ERROR("response status: '500 Internal Server Error'");
fcgi_print_log(request, "500 Internal Server Error");
return FCGI_CHECK_PRINTF_STATUS(request, FCGI_500_RESPONSE_FORMAT, 500);
}

View file

@ -188,6 +188,8 @@ fcgi_401_bad_signature_handler(const FCGX_Request* request, void *ctx)
return HANDLER_ERROR;
}
fcgi_print_log(request, "401 Unauthorized");
return HANDLER_SUCCESS;
}

View file

@ -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");

View file

@ -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;

View file

@ -79,6 +79,130 @@ error:
return -1;
}
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 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_CHAIN_EXCLUDE_ROOT),
NULL,
&chain_ctx)) {
LOG_ERROR("CertGetCertificateChain() failed");
goto error;
}
if (chain_ctx->TrustStatus.dwErrorStatus) {
LOG_WARN("The certificate is not trusted. CERT_TRUST_STATUS: '0x%08x'",
chain_ctx->TrustStatus.dwErrorStatus);
goto error;
}
LOG_TRACE("get_cert_chain exit");
return chain_ctx;
error:
free_cert_chain(chain_ctx);
LOG_ERROR("get_cert_chain exit with error");
return NULL;
}
static bool
check_cert_chain_policy(PCCERT_CHAIN_CONTEXT chain_ctx)
{
LOG_TRACE("check_cert_chain_policy enter");
bool is_valid = false;
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(
CPCERT_CHAIN_POLICY_SIGNATURE,
chain_ctx,
&policy_para,
&status)) {
LOG_ERROR("CertVerifyCertificateChainPolicy() failed. Error code: 0x%08x",
cp_function_list.GetLastError());
goto exit;
}
if (status.dwError != 0) {
LOG_WARN("The certificate chain cannot be validated. "
"CERT_CHAIN_POLICY_STATUS: '0x%08x'", status.dwError);
goto exit;
}
if (extraStatus.dwError != 0) {
LOG_WARN("The certificate chain cannot be validated. "
"CPSIGNATURE_EXTRA_CERT_CHAIN_POLICY_STATUS: '0x%08x'", extraStatus.dwError);
goto exit;
}
is_valid = true;
exit:
LOG_TRACE("check_cert_chain_policy exit");
return is_valid;
}
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 +225,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,
@ -429,6 +557,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");

View file

@ -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 mRoot -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
```
@ -91,6 +112,27 @@ rm -f test.txt test.txt.sgn
- Поле "SHA1 отпечаток": это значение нужно будет указать в конфигурационном файле модуля подписания в качестве настройки \<esia_cert_thumbprint\>.
- Поле "Алгоритм подписи": проверить, что значение совпадает с настройками ИС в ЕСИА.
- Поле "Истекает": проверить, что срок действия сертификата не истёк.
- Поля "URL сертификата УЦ": по ссылкам, указанным в этом значении, скачать сертификаты УЦ и установить их (описано далее)
- Поля "URL списка отзыва": по ссылкам, указанным в этом значении, скачать CRL и установить их (описано далее)
4. Установить сертификаты УЦ (поля "URL сертификата УЦ" в свойствах сертификата). Для каждого сертификата выполнить команду от имени **root**:
``` bash
/opt/cprocsp/bin/amd64/certmgr -install -store mRoot -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 <esia_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
### Установка и настройка nginx