Merge branch 'release/1.4.2'

This commit is contained in:
Zaripov Emil 2025-11-27 15:50:00 +03:00
commit 73f1af565c
6 changed files with 191 additions and 8 deletions

View file

@ -2,7 +2,7 @@ CMAKE_MINIMUM_REQUIRED (VERSION 3.0)
SET (CMAKE_C_COMPILER "gcc") SET (CMAKE_C_COMPILER "gcc")
PROJECT (ervu-sign-module VERSION 1.4.1 LANGUAGES C) PROJECT (ervu-sign-module VERSION 1.4.2 LANGUAGES C)
IF (CMAKE_VERBOSE) IF (CMAKE_VERBOSE)
SET (CMAKE_VERBOSE_MAKEFILE 1) SET (CMAKE_VERBOSE_MAKEFILE 1)

View file

@ -120,6 +120,7 @@ $ /opt/cprocsp/bin/amd64/curl -v http://127.0.0.1/msg/verify_detached \
| `CERT_TRUST_REVOCATION_STATUS_UNKNOWN` | Неизвестен статус отзыва сертификата или одного из сертификатов в цепочке (проблема с CRL) | | `CERT_TRUST_REVOCATION_STATUS_UNKNOWN` | Неизвестен статус отзыва сертификата или одного из сертификатов в цепочке (проблема с CRL) |
| `CERT_TRUST_IS_UNTRUSTED_ROOT` | Сертификат или цепочка сертификатов основана на ненадежном корневом сертификате | | `CERT_TRUST_IS_UNTRUSTED_ROOT` | Сертификат или цепочка сертификатов основана на ненадежном корневом сертификате |
| `CERT_TRUST_IS_NOT_TIME_VALID` | Этот сертификат или один из сертификатов в цепочке сертификатов является недопустимым по времени | | `CERT_TRUST_IS_NOT_TIME_VALID` | Этот сертификат или один из сертификатов в цепочке сертификатов является недопустимым по времени |
| `CERT_TRUST_IS_PARTIAL_CHAIN` | Цепочка сертификатов не полная |
## Сборка из исходников ## Сборка из исходников

View file

@ -37,6 +37,7 @@ capi_function_list_init(library_t *lib, capi_function_list_t *fl)
LIBRARY_RESOLVE(fl->CertFindExtension, lib, "CertFindExtension"); LIBRARY_RESOLVE(fl->CertFindExtension, lib, "CertFindExtension");
LIBRARY_RESOLVE(fl->CryptDecodeObjectEx, lib, "CryptDecodeObjectEx"); LIBRARY_RESOLVE(fl->CryptDecodeObjectEx, lib, "CryptDecodeObjectEx");
LIBRARY_RESOLVE(fl->LocalFree, lib, "LocalFree"); LIBRARY_RESOLVE(fl->LocalFree, lib, "LocalFree");
LIBRARY_RESOLVE(fl->FileTimeToSystemTime, lib, "FileTimeToSystemTime");
#ifdef UNICODE #ifdef UNICODE
LIBRARY_RESOLVE(fl->CryptSignHash, lib, "CryptSignHashW"); LIBRARY_RESOLVE(fl->CryptSignHash, lib, "CryptSignHashW");

View file

@ -266,6 +266,12 @@ DECLARE_FN(WINADVAPI,
LOCAL_FREE, LOCAL_FREE,
(HLOCAL hMem)); (HLOCAL hMem));
DECLARE_FN(WINADVAPI,
BOOL,
FILE_TIME_TO_SYSTEM_TIME,
(CONST FILETIME *lpFileTime,
LPSYSTEMTIME lpSystemTime));
#ifdef UNICODE #ifdef UNICODE
#define CRYPT_SIGN_HASH_FN CRYPT_SIGN_HASH_W_FN #define CRYPT_SIGN_HASH_FN CRYPT_SIGN_HASH_W_FN
#define CRYPT_VERIFY_SIGNATURE_FN CRYPT_VERIFY_SIGNATURE_W_FN #define CRYPT_VERIFY_SIGNATURE_FN CRYPT_VERIFY_SIGNATURE_W_FN
@ -308,6 +314,7 @@ typedef struct {
CERT_FIND_EXTENSION_FN CertFindExtension; CERT_FIND_EXTENSION_FN CertFindExtension;
CRYPT_DECODE_OBJECT_EX_FN CryptDecodeObjectEx; CRYPT_DECODE_OBJECT_EX_FN CryptDecodeObjectEx;
LOCAL_FREE_FN LocalFree; LOCAL_FREE_FN LocalFree;
FILE_TIME_TO_SYSTEM_TIME_FN FileTimeToSystemTime;
} capi_function_list_t; } capi_function_list_t;

View file

@ -5,9 +5,12 @@
#include "library.h" #include "library.h"
#include "logger.h" #include "logger.h"
#define SHA1_SIZE 20
static const char* CERT_TRUST_IS_UNTRUSTED_ROOT_ERR_CODE = "CERT_TRUST_IS_UNTRUSTED_ROOT"; static const char* CERT_TRUST_IS_UNTRUSTED_ROOT_ERR_CODE = "CERT_TRUST_IS_UNTRUSTED_ROOT";
static const char* CERT_TRUST_REVOCATION_STATUS_UNKNOWN_ERR_CODE = "CERT_TRUST_REVOCATION_STATUS_UNKNOWN"; static const char* CERT_TRUST_REVOCATION_STATUS_UNKNOWN_ERR_CODE = "CERT_TRUST_REVOCATION_STATUS_UNKNOWN";
static const char* CERT_TRUST_IS_NOT_TIME_VALID_ERR_CODE = "CERT_TRUST_IS_NOT_TIME_VALID"; static const char* CERT_TRUST_IS_NOT_TIME_VALID_ERR_CODE = "CERT_TRUST_IS_NOT_TIME_VALID";
static const char* CERT_TRUST_IS_PARTIAL_CHAIN_ERR_CODE = "CERT_TRUST_IS_PARTIAL_CHAIN";
static capi_function_list_t cp_function_list; static capi_function_list_t cp_function_list;
static library_t libcapi; static library_t libcapi;
@ -24,6 +27,10 @@ static PCCERT_CONTEXT get_signer_cert(const cryptopro_context_t *ctx, HCERTSTORE
static int set_password(PCCERT_CONTEXT cert_ctx, const str_t *password); static int set_password(PCCERT_CONTEXT cert_ctx, const str_t *password);
static bool get_subject_name(PCCERT_CONTEXT cert, /*out*/ char **subject_name);
static bool get_issuer_name(PCCERT_CONTEXT cert, /*out*/ char **issuer_name);
bool bool
cryptopro_init(const char* cp_file) cryptopro_init(const char* cp_file)
{ {
@ -128,7 +135,7 @@ print_crl_urls_from_certificate(PCCERT_CONTEXT cert)
&crl_dist_points, &crl_dist_points,
&info_size &info_size
)) { )) {
LOG_ERROR("CryptDecodeObjectEx failed. Desc: 0x%x", cp_function_list.GetLastError()); LOG_ERROR("CryptDecodeObjectEx failed. Error code: 0x%08x", cp_function_list.GetLastError());
goto error; goto error;
} }
@ -160,6 +167,169 @@ error:
return; return;
} }
static void
print_crt_urls_from_certificate(PCCERT_CONTEXT cert)
{
LOG_TRACE("print_crt_urls_from_certificate enter");
PCERT_EXTENSION extension = cp_function_list.CertFindExtension(
szOID_AUTHORITY_INFO_ACCESS,
cert->pCertInfo->cExtension,
cert->pCertInfo->rgExtension
);
if (!extension) {
LOG_WARN("Authority Info Access extension not found");
goto error;
}
DWORD info_size = 0;
PCERT_AUTHORITY_INFO_ACCESS info_access = NULL;
if (!cp_function_list.CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
X509_AUTHORITY_INFO_ACCESS,
extension->Value.pbData,
extension->Value.cbData,
CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
NULL,
&info_access,
&info_size
)) {
LOG_ERROR("CryptDecodeObjectEx failed. Error code: 0x%08x", cp_function_list.GetLastError());
goto error;
}
if (info_access && info_access->cAccDescr > 0) {
for (DWORD i = 0; i < info_access->cAccDescr; i++) {
if (strcmp(info_access->rgAccDescr[i].pszAccessMethod, szOID_PKIX_CA_ISSUERS) == 0) {
if (info_access->rgAccDescr[i].AccessLocation.dwAltNameChoice == CERT_ALT_NAME_URL) {
LOG_INFO("CA Issuers URL: %ls", info_access->rgAccDescr[i].AccessLocation._empty_union_.pwszURL);
}
}
}
}
if (info_access) {
cp_function_list.LocalFree(info_access);
}
LOG_TRACE("print_crt_urls_from_certificate exit");
return;
error:
LOG_ERROR("print_crt_urls_from_certificate exit with error");
return;
}
static char*
bin_to_hex(const BYTE *bytes, DWORD len)
{
char* hex = NULL;
hex = malloc(len * 2 + 1);
if (hex == NULL) {
LOG_ERROR("bin_to_hex exit with error: could not allocate memory for hex (%d bytes)", len * 2 + 1);
return NULL;
}
for (DWORD i = 0; i < len; i++) {
sprintf(hex + i * 2, "%02x", bytes[i]);
}
return hex;
}
static bool
get_thumbprint(PCCERT_CONTEXT cert, /*out*/ char** thumbprint)
{
LOG_TRACE("get_thumbprint enter");
BYTE sha1_hash[SHA1_SIZE];
DWORD sha1_hash_size = sizeof(sha1_hash);
if (!cp_function_list.CertGetCertificateContextProperty(
cert,
CERT_SHA1_HASH_PROP_ID,
sha1_hash,
&sha1_hash_size)) {
LOG_ERROR("CertGetCertificateContextProperty(CERT_SHA1_HASH_PROP_ID) failed. Error code: 0x%08x",
cp_function_list.GetLastError());
goto error;
}
*thumbprint = bin_to_hex(sha1_hash, sha1_hash_size);
if (*thumbprint == NULL) {
goto error;
}
LOG_DEBUG("thumbprint: '%s'", *thumbprint);
LOG_TRACE("get_thumbprint exit");
return true;
error:
LOG_ERROR("get_thumbprint exit with error");
return false;
}
static void
print_cert_time_validity(PCCERT_CONTEXT cert)
{
SYSTEMTIME st;
LOG_TRACE("print_cert_time_validity enter");
if (cp_function_list.FileTimeToSystemTime(&cert->pCertInfo->NotBefore, &st)) {
LOG_INFO("Not valid before: %02d.%02d.%04d", st.wDay, st.wMonth, st.wYear);
}
if (cp_function_list.FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &st)) {
LOG_INFO("Not valid after: %02d.%02d.%04d", st.wDay, st.wMonth, st.wYear);
}
LOG_TRACE("print_cert_time_validity exit");
}
static void
print_common_cert_info(PCCERT_CONTEXT cert)
{
char* subject = NULL;
char* issuer = NULL;
char* thumbprint = NULL;
LOG_TRACE("print_common_cert_info enter");
if (get_thumbprint(cert, &thumbprint)) {
LOG_INFO("SHA1 Hash: %s", thumbprint);
}
if (get_subject_name(cert, &subject)) {
LOG_INFO("Subject: %s", subject);
}
if (get_issuer_name(cert, &issuer)) {
LOG_INFO("Issuer: %s", issuer);
}
free(subject);
free(issuer);
free(thumbprint);
LOG_TRACE("print_common_cert_info exit");
}
static void
print_cert_info(PCCERT_CONTEXT cert)
{
LOG_INFO("=========== Certificate Info: ===========");
print_common_cert_info(cert);
print_cert_time_validity(cert);
print_crt_urls_from_certificate(cert);
print_crl_urls_from_certificate(cert);
LOG_INFO("=========================================");
}
static void static void
process_trust_status_error(PCCERT_CONTEXT cert, DWORD status, /*out*/ const char **error_code) process_trust_status_error(PCCERT_CONTEXT cert, DWORD status, /*out*/ const char **error_code)
{ {
@ -168,7 +338,6 @@ process_trust_status_error(PCCERT_CONTEXT cert, DWORD status, /*out*/ const char
switch (status) { switch (status) {
case CERT_TRUST_REVOCATION_STATUS_UNKNOWN: case CERT_TRUST_REVOCATION_STATUS_UNKNOWN:
*error_code = CERT_TRUST_REVOCATION_STATUS_UNKNOWN_ERR_CODE; *error_code = CERT_TRUST_REVOCATION_STATUS_UNKNOWN_ERR_CODE;
print_crl_urls_from_certificate(cert);
break; break;
case CERT_TRUST_IS_UNTRUSTED_ROOT: case CERT_TRUST_IS_UNTRUSTED_ROOT:
*error_code = CERT_TRUST_IS_UNTRUSTED_ROOT_ERR_CODE; *error_code = CERT_TRUST_IS_UNTRUSTED_ROOT_ERR_CODE;
@ -176,6 +345,9 @@ process_trust_status_error(PCCERT_CONTEXT cert, DWORD status, /*out*/ const char
case CERT_TRUST_IS_NOT_TIME_VALID: case CERT_TRUST_IS_NOT_TIME_VALID:
*error_code = CERT_TRUST_IS_NOT_TIME_VALID_ERR_CODE; *error_code = CERT_TRUST_IS_NOT_TIME_VALID_ERR_CODE;
break; break;
case CERT_TRUST_IS_PARTIAL_CHAIN:
*error_code = CERT_TRUST_IS_PARTIAL_CHAIN_ERR_CODE;
break;
default: default:
*error_code = NULL; *error_code = NULL;
break; break;
@ -188,6 +360,8 @@ process_trust_status_error(PCCERT_CONTEXT cert, DWORD status, /*out*/ const char
LOG_WARN("The certificate is not trusted. CERT_TRUST_STATUS: '0x%08x'", status); LOG_WARN("The certificate is not trusted. CERT_TRUST_STATUS: '0x%08x'", status);
} }
print_cert_info(cert);
LOG_TRACE("process_trust_status_error exit"); LOG_TRACE("process_trust_status_error exit");
} }

View file

@ -99,12 +99,12 @@ chown -R ervu:ervu /var/opt/cprocsp/keys/ervu/key_cont.000/
| Среда \ Алгоритм подписания | GOST3410_2012_256 | | Среда \ Алгоритм подписания | GOST3410_2012_256 |
| ----------------------------- | ----------------------------------------------------- | | ----------------------------- | ----------------------------------------------------- |
| | TESIA GOST 2012 new.cer | | | TESIA GOST 2012 new.cer |
| Тестовая | Отпечаток: e654f6114dc19bae84c5748794a4fd7797726e71 | | Тестовая | Отпечаток: b3a7890493bdd95d47c6871627b475e276962bf1 |
| | Срок действия: по 24.04.2025 | | | Срок действия: по 21.04.2026 |
| ----------------------------- | ----------------------------------------------------- | | ----------------------------- | ----------------------------------------------------- |
| | ГОСТ+ПРОД+24-25.cer | | | ГОСТ_PROD_25_26.cer |
| Продуктивная | Отпечаток: 20ad21785b9161ef46f075d4dc23c34e1e349228 | | Продуктивная | Отпечаток: 2583cca4e2aad8d8170ef73fecc592ccac46821d |
| | Срок действия: по 08.06.2025 | | | Срок действия: по 17.06.2026 |
------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------