From a3c7e63cfc59e6161c68a11d6d63d294f538d0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B0=D0=B8=D0=BB=D1=8F=20=D0=90=D0=BB=D0=B0=D1=88?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2=D0=B0?= Date: Mon, 25 Nov 2024 13:06:44 +0300 Subject: [PATCH 1/2] =?UTF-8?q?SUPPORT-8703.=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B0=20=D1=86=D0=B5=D0=BF=D0=BE=D1=87=D0=BA=D0=B8?= =?UTF-8?q?=20=D1=81=D0=B5=D1=80=D1=82=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ПМИ (прод ЕСИА + mnsv126).txt | 76 +++++++++++++++++ docs/ПМИ (тест ЕСИА + mnsv93).txt | 74 ++++++++++++++++ docs/ПМИ.txt | 114 +++++++++++++++++++++++++ entrypoint.sh | 7 ++ src/utils/capi.c | 3 + src/utils/capi.h | 28 ++++++ src/utils/cryptopro.c | 132 +++++++++++++++++++++++++++++ Инструкция по установке.md | 46 +++++++++- 8 files changed, 478 insertions(+), 2 deletions(-) create mode 100644 docs/ПМИ (прод ЕСИА + mnsv126).txt create mode 100644 docs/ПМИ (тест ЕСИА + mnsv93).txt create mode 100644 docs/ПМИ.txt diff --git a/docs/ПМИ (прод ЕСИА + mnsv126).txt b/docs/ПМИ (прод ЕСИА + mnsv126).txt new file mode 100644 index 0000000..eb7853b --- /dev/null +++ b/docs/ПМИ (прод ЕСИА + mnsv126).txt @@ -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 diff --git a/docs/ПМИ (тест ЕСИА + mnsv93).txt b/docs/ПМИ (тест ЕСИА + mnsv93).txt new file mode 100644 index 0000000..916d6f7 --- /dev/null +++ b/docs/ПМИ (тест ЕСИА + mnsv93).txt @@ -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 diff --git a/docs/ПМИ.txt b/docs/ПМИ.txt new file mode 100644 index 0000000..414474a --- /dev/null +++ b/docs/ПМИ.txt @@ -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 -chain + где - это SHA1 отпечаток сертификата компонента ervu-sign-module. + + Результатом команды будет цепочка сертификатов с перечнем их свойств, из которого необходимо получить значение поля "SHA1 отпечаток". + + 1.3.2. Из Системы удалить корневой сертификат Удостоверяющего центра, выполнив команду от имени root: + /opt/cprocsp/bin/amd64/certmgr -delete -store mRoot -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 .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 -chain + где - это SHA1 отпечаток сертификата ЕСИА. + + Результатом команды будет цепочка сертификатов с перечнем их свойств, из которого необходимо получить значение поля "SHA1 отпечаток". + + 2.3.2. Из Системы удалить корневой сертификат Удостоверяющего центра, выполнив команду от имени root: + /opt/cprocsp/bin/amd64/certmgr -delete -store mRoot -thumbprint + где - это SHA1 отпечаток корневой сертификата УЦ, полученный на предыдущем шаге. + + 2.3.3. Выполнить вход через ЕСИА - обработка ответа от ЕСИА должна завершиться ошибкой. + + 2.3.4. Восстановить все корневые сертификаты, которые были удалены, выполнив для каждого команду от имени root: + /opt/cprocsp/bin/amd64/certmgr -install -store mRoot -file .crt \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index 3c491b8..f8ef189 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -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 diff --git a/src/utils/capi.c b/src/utils/capi.c index 8cba246..c6458e7 100644 --- a/src/utils/capi.c +++ b/src/utils/capi.c @@ -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"); diff --git a/src/utils/capi.h b/src/utils/capi.h index 555ffb9..71fe5c4 100644 --- a/src/utils/capi.h +++ b/src/utils/capi.h @@ -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; diff --git a/src/utils/cryptopro.c b/src/utils/cryptopro.c index b93b91f..ae93f49 100644 --- a/src/utils/cryptopro.c +++ b/src/utils/cryptopro.c @@ -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, @@ -425,6 +553,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"); diff --git a/Инструкция по установке.md b/Инструкция по установке.md index 2f1391d..5ad3274 100644 --- a/Инструкция по установке.md +++ b/Инструкция по установке.md @@ -58,11 +58,32 @@ chown -R ervu:ervu /var/opt/cprocsp/keys/ervu/key_cont.000/ Получить следующие значения: - Поле "SHA1 отпечаток": это значение нужно будет указать в конфигурационном файле модуля подписания в качестве настройки \ - Поле "Ссылка на ключ": убедиться, что значение равно "Есть" (иначе необходимо проверить выполнение предыдущих шагов) +- Поля "URL сертификата УЦ": по ссылкам, указанным в этом значении, скачать сертификаты УЦ и установить их (описано далее) +- Поля "URL списка отзыва": по ссылкам, указанным в этом значении, скачать CRL и установить их (описано далее) -4. (опционально) Сделать тестовую подпись с помощью установленного контейнера и полученных значений \ и \: +4. Установить сертификаты УЦ (поля "URL сертификата УЦ" в свойствах сертификата). Для каждого сертификата выполнить команду от имени **root**: +``` bash +/opt/cprocsp/bin/amd64/certmgr -install -store mRoot -file .cer +``` + +5. В случае отсутствия доступа к УЦ, установить CRL (поле "URL списка отзыва" в свойствах сертификата). Для каждого CRL выполнить команду от имени **ervu**: +``` bash +/opt/cprocsp/bin/amd64/certmgr -install -store uCA -crl -file .crl +``` + +6. Проверить цепочку сертификатов (команда выполняется от имени **ervu**): +``` bash +/opt/cprocsp/bin/amd64/certmgr -list -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. (опционально) Сделать тестовую подпись с помощью установленного контейнера и полученных значений \ и \: ``` bash touch test.txt -/opt/cprocsp/bin/amd64/cryptcp -signf -thumbprint ./test.txt +/opt/cprocsp/bin/amd64/cryptcp -signf -thumbprint -errchain ./test.txt rm -f test.txt test.txt.sgn ``` @@ -91,6 +112,27 @@ rm -f test.txt test.txt.sgn - Поле "SHA1 отпечаток": это значение нужно будет указать в конфигурационном файле модуля подписания в качестве настройки \. - Поле "Алгоритм подписи": проверить, что значение совпадает с настройками ИС в ЕСИА. - Поле "Истекает": проверить, что срок действия сертификата не истёк. +- Поля "URL сертификата УЦ": по ссылкам, указанным в этом значении, скачать сертификаты УЦ и установить их (описано далее) +- Поля "URL списка отзыва": по ссылкам, указанным в этом значении, скачать CRL и установить их (описано далее) + +4. Установить сертификаты УЦ (поля "URL сертификата УЦ" в свойствах сертификата). Для каждого сертификата выполнить команду от имени **root**: +``` bash +/opt/cprocsp/bin/amd64/certmgr -install -store mRoot -file .cer +``` + +5. В случае отсутствия доступа к УЦ, установить CRL (поле "URL списка отзыва" в свойствах сертификата). Для каждого CRL выполнить команду от имени **ervu**: +``` bash +/opt/cprocsp/bin/amd64/certmgr -install -store uCA -crl -file .crl +``` + +6. Проверить цепочку сертификатов (команда выполняется от имени **ervu**): +``` bash +/opt/cprocsp/bin/amd64/certmgr -list -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 From a6b1c503251602dbfb0be87718a88aae724ea83d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B0=D0=B8=D0=BB=D1=8F=20=D0=90=D0=BB=D0=B0=D1=88?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2=D0=B0?= Date: Mon, 25 Nov 2024 13:09:51 +0300 Subject: [PATCH 2/2] =?UTF-8?q?SUPPORT-8703.=20=D0=94=D0=BE=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0=D0=BD=D0=BE=20=D0=BB=D0=BE=D0=B3=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fcgisrv/fcgi_utils.h | 28 ++++++++++++++++++++-------- src/modules/service_verify.c | 2 ++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/fcgisrv/fcgi_utils.h b/src/fcgisrv/fcgi_utils.h index bd3197c..080531b 100644 --- a/src/fcgisrv/fcgi_utils.h +++ b/src/fcgisrv/fcgi_utils.h @@ -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); } diff --git a/src/modules/service_verify.c b/src/modules/service_verify.c index fd82789..5a67ac2 100644 --- a/src/modules/service_verify.c +++ b/src/modules/service_verify.c @@ -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; }