Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Сергей Акулов  
#1 Оставлено : 1 ноября 2021 г. 21:23:02(UTC)
Сергей Акулов

Статус: Новичок

Группы: Участники
Зарегистрирован: 01.11.2021(UTC)
Сообщений: 3
Российская Федерация

Сказал(а) «Спасибо»: 1 раз
Здравствуйте!
Понимаю, что для большинства это покажется глупым вопросом, но я уткнулся в тупик, даже не знаю что и где читать.

Появилась задача написать so-библиотеку для последующего встраивания в другой продукт.
Библиотека должна уметь 2 вещи, для начала:
1) Имитировать команду certmgr -list (перечислить список доступных сертификатов)
2) Подписывать

Для начала я открыл это:
http://cpdn.cryptopro.ru...sp_trunk/html/Titul.html
в одной из веток было сказано, что надо использовать libcapilite20, который находится в пакете devel

Скачал последнюю доступную версию CSP 5 https://www.cryptopro.ru...2266/linux-amd64_deb.tgz
Поставил все пакеты )
Подключил flash-накопитель и открыл интерфейс cp-tools
Подтянулся контейнер, импортировал сертификат в "Личные"

Выполнил последовательно 2 команды:
1) csptestf -absorb -certs -autoprov
2) csptest -keyset -enum_cont -fqcn -verifyc
Судя по их выводу сертификат успешно подтянулся, и затем, после выполнения команды certmgr -list я получал детальную информацию об имеющемся сертификату.

Далее я начал смотреть примеры из папки samples в opt/cprocsp/src/../..
А также просматривать документацию по первой ссылке, а точнее уже другой раздел - http://cpdn.cryptopro.ru...te_trunk/html/Titul.html
и документацию Microsoft Docs по CryptoAPI

Понял, что для первой задачи необходимо:
1) CertEnumSystemStore - и передать туда
а) CERT_SYSTEM_STORE_CURRENT_USER так как я правильно понимаю, что "Личные" доступны для текущего пользователя ? (было бы странно, если нет)
б) NULL - так написано в Microsoft Docs
в) ссылку на функцию, которая будет выводить данные
2) вызвать функцию CertOpenSystemStoreA и передать туда 0, потому что первый параметр по документации по сути выпилен и наименование хранилища, полученного первой функцией

3) В результате второго пункта мы получаем контекст первого сертификата и в цикле можем пройтись по всем сертификатам хранилища методом CertEnumCertificatesInStore

По примерам написал на C небольшой файл - по сути почти пример из Microsoft Docs
Собрал его командой: gcc -g -Wall -o p1 p1.c -DUNIX -DHAVE_LIMITS_H -DHAVE_STDIN_H -I/opt/cprocsp/include -I/opt/cprocsp/include/cpcsp -I/opt/cprocsp/include/capilite -DSIZEOF_VOID_P=8 -L/opt/cprocsp/lib/amd64 -lrdrsup -lcapi20 -lpthread -lcapi10

Предварительно добавив символьные ссылки на пути к библиотекам в систему

Запустил полученный файл и получил список хранилищ, в том числе хранилище "My", которое ведь и есть "Личные" ?
Но, по какой-то причине не было выведено ни одного сертификата

код вывода сертификатов проще некуда:
HCERTSTORE hSystemStore = NULL;
PCCERT_CONTEXT pCertContext = NULL;

if ((hSystemStore = CertOpenSystemStoreA(0, pwszSystemStore)))
{
printf("The %S system store opened.\n", pwszSystemStore);

while ((pCertContext = CertEnumCertificatesInStore(
hSystemStore,
pCertContext)))
{
if (CertGetNameString(
pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
pszNameString,
128))
{
printf("\nCertificate for %s \n", pszNameString);
}
else
fprintf(stderr, "CertGetName failed. \n");
}
}
else
{
printf("The %S system store did not open.\n", pwszSystemStore);
exit(1);
}

if (!CertCloseStore(hSystemStore, 0))
{
printf("Unable to close the %S system store.\n", pwszSystemStore);
exit(1);
}
else
{
printf("The %S system store closed.\n", pwszSystemStore);
}

И теперь вопрос. Что я делаю не так? Что я не сделал ? Куда мне вообще смотреть ))
Offline Андрей Русев  
#2 Оставлено : 2 ноября 2021 г. 22:57:11(UTC)
Андрей Русев

Статус: Сотрудник

Группы: Администраторы, Участники
Зарегистрирован: 16.04.2008(UTC)
Сообщений: 931

Сказал(а) «Спасибо»: 4 раз
Поблагодарили: 254 раз в 195 постах
Здравствуйте.
Для сборки нужна минимальная установка вместе с пакетом lsb-cprocsp-devel:
Код:
./install.sh lsb-cprocsp-devel

Сразу после этого, не настраивая никаких ссылок, можно собирать, скажем, примеры.
См. /opt/cprocsp/src/readme.unix
Код:
cd /opt/cprocsp/src/samples/CSP
eval `/opt/cprocsp/src/samples/setenv.sh --64`; make -f Makefile.unix

Перечислять хранилища не нужно, так как у них фиксированные имена - используйте CertOpenSystemStoreA(0, "My")).
См. /opt/cprocsp/src/samples/CSP/CryptMsgSign/
Официальная техподдержка. Официальная база знаний.
Offline Сергей Акулов  
#3 Оставлено : 3 ноября 2021 г. 18:38:41(UTC)
Сергей Акулов

Статус: Новичок

Группы: Участники
Зарегистрирован: 01.11.2021(UTC)
Сообщений: 3
Российская Федерация

Сказал(а) «Спасибо»: 1 раз
Пакет lsb-cprocsp-devel поставил в самом начале
Согласно вашему сообщению пытаюсь кодом ниже вывести личные сертификаты, не перечисляя хранилище:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CSP_WinDef.h"
#include "CSP_WinCrypt.h"
#include "WinCryptEx.h"

int main(void)
{
HCERTSTORE hSystemStore = NULL;
PCCERT_CONTEXT pCertContext = NULL;
LPWSTR pszNameString = NULL;

if ((hSystemStore = CertOpenSystemStoreW(0, "MY")))
{
printf("My certificate store has opened.");

while ((pCertContext = CertEnumCertificatesInStore(
hSystemStore,
pCertContext)))
{
if (CertGetNameStringW(
pCertContext,
CERT_NAME_FRIENDLY_DISPLAY_TYPE,
0,
NULL,
pszNameString,
256))
{
char buffer[500];
wcstombs(buffer, pszNameString, 500);
printf("\nCertificate %s \n", buffer);
}
}
}
else
{
printf("My certificate store did not open.");
exit(1);
}

if (!CertCloseStore(hSystemStore, 0))
{
printf("Unable to close My certificate store.\n");
exit(1);
}
else
{
printf("My certificate store closed.\n");
}
}

Получаю вот такой вывод:

My certificate store has opened.
My certificate store closed.

Код не заходит даже в тело while при перечислении сертификатов, не просто в if, на получении имени

А вот что говорит менеджер сертификатов:
certmgr -list -store My

Certmgr 1.1 (c) "Crypto-Pro", 2007-2021.
Program for managing certificates, CRLs and stores.
WARNING: Legacy parameter: "-store My"
=============================================================================
1-------
Issuer : E=support@cryptopro.ru, C=RU, L=Moscow, O=CRYPTO-PRO LLC, CN=CRYPTO-PRO Test Center 2
Subject : ОГРН=0000000000000, ИНН=000000000000, СНИЛС=00000000000, C=RU, T=Тест, OU=Тест, O=Тест, E=test@test.com, SN=Тест, G=Тест Тест, CN="ООО ""Тест"""
Serial : 0x12005A227A275D66CBDEA062BF0001005A227A
SHA1 Thumbprint : 628e2adc42c1c3e339a2ffce56a49d69b47b4ae8
SubjKeyID : f8832024a66ae88d8a86df025512248dc34ca182
Signature Algorithm : ГОСТ Р 34.11/34.10-2001
PublicKey Algorithm : ГОСТ Р 34.10-2012 256 бит (512 bits)
Not valid before : 27/10/2021 10:31:22 UTC
Not valid after : 27/01/2022 10:41:22 UTC
PrivateKey Link : Yes
Container : HDIMAGE\\rnd-9-F7.000\2795
Provider Name : Crypto-Pro GOST R 34.10-2012 KC1 CSP
Provider Info : Provider Type: 80, Key Spec: 2, Flags: 0x0
CA cert URL : http://testca.cryptopro....Test%20Center%202(1).crt
OCSP URL : http://testca.cryptopro.ru/ocsp/ocsp.srf
CDP : http://testca.cryptopro....Test%20Center%202(1).crl
Extended Key Usage : 1.3.6.1.5.5.7.3.2 Проверка подлинности клиента
1.3.6.1.5.5.7.3.4 Защищенная электронная почта
=============================================================================

Отредактировано пользователем 3 ноября 2021 г. 18:40:11(UTC)  | Причина: Не указана

Offline Андрей Русев  
#4 Оставлено : 3 ноября 2021 г. 19:21:32(UTC)
Андрей Русев

Статус: Сотрудник

Группы: Администраторы, Участники
Зарегистрирован: 16.04.2008(UTC)
Сообщений: 931

Сказал(а) «Спасибо»: 4 раз
Поблагодарили: 254 раз в 195 постах
Настоятельно рекомендую всегда собирать с флагами -Wall -Werror.
Вы с ошибкой переписали мой вариант CertOpenSystemStoreA(0, "My")) в виде CertOpenSystemStoreW(0, "My")).
Под pszNameString не выделена память. Вместо wcstombs, можно просто сделать printf("\nCertificate %S \n", pszNameString);
Но у нас тут не курсы программирования.
Официальная техподдержка. Официальная база знаний.
thanks 1 пользователь поблагодарил Андрей Русев за этот пост.
Сергей Акулов оставлено 03.11.2021(UTC)
Offline Сергей Акулов  
#5 Оставлено : 3 ноября 2021 г. 20:28:54(UTC)
Сергей Акулов

Статус: Новичок

Группы: Участники
Зарегистрирован: 01.11.2021(UTC)
Сообщений: 3
Российская Федерация

Сказал(а) «Спасибо»: 1 раз
Подумал, что с W тоже подойдет.
Понимаю, что тут не курсы )
Я уже 3 года пишу на java, а тут очень срочная задача с КриптоПро, и так получилось, что некому и некогда, а я решил, что смогу оживить универские знания по плюсам, но, видимо, погорячился. Даже банальное выделение памяти забыл как писать через malloc )
Привык, что за тебя все делает Garbage Collector ) Что уж тут.

В любом случае, спасибо

Переписал код так (пока что):
и он что то да вывел. правда с вопросительными знаками вместо наименования сертификата, но с этим уж как-нибудь справлюсь, надеюсь..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CSP_WinDef.h"
#include "CSP_WinCrypt.h"
#include "WinCryptEx.h"

int main(void)
{
HCERTSTORE hSystemStore = NULL;
PCCERT_CONTEXT pCertContext = NULL;
TCHAR *pszNameString = (TCHAR*) malloc(128 * sizeof(TCHAR));

if ((hSystemStore = CertOpenSystemStoreA(0, "MY")))
{
printf("My certificate store has opened.\n");

while ((pCertContext = CertEnumCertificatesInStore(
hSystemStore,
pCertContext)))
{
printf("hi");

if (CertGetNameStringA(
pCertContext,
CERT_NAME_FRIENDLY_DISPLAY_TYPE,
0,
NULL,
pszNameString,
128))
{
printf("\nCertificate %s \n", pszNameString);
}
}
}
else
{
printf("My certificate store did not open.");
free(pszNameString);
exit(1);
}

if (!CertCloseStore(hSystemStore, 0))
{
printf("Unable to close My certificate store.\n");
free(pszNameString);
exit(1);
}
else
{
printf("My certificate store closed.\n");
}
free(pszNameString);

}

Вот вывод:
My certificate store has opened.
hi
Certificate ��� "����"
My certificate store closed.

Спасибо еще раз.
Offline Андрей Русев  
#6 Оставлено : 3 ноября 2021 г. 22:15:35(UTC)
Андрей Русев

Статус: Сотрудник

Группы: Администраторы, Участники
Зарегистрирован: 16.04.2008(UTC)
Сообщений: 931

Сказал(а) «Спасибо»: 4 раз
Поблагодарили: 254 раз в 195 постах
С русскими буквами придётся потрудиться:
https://cpdn.cryptopro.r...runk/html/encodings.html
"по возможности пользоваться только widechar-вариантами функций", а затем, например, для печати надо использовать WideCharToMultiByte(CP_UTF8).
Сразу уж поясню: wide-строки предваряются буквой L. Например, Ваши "с W тоже подойдёт" должен был выглядеть так: CertOpenSystemStoreW(0, L"MY")).
Заморачиваться TCHAR-ом не имеет смысла, кроме редких случаев (все из которых подразумевают кроссплатформенный код для windows и unix).
Чтобы упростить работу с перекодировкой строк, рекомендую пользоваться нашим макросом console_w2c из reader/support.h
Дарю хорошую кроссплатформенную Си-библиотечку для конверсии (w - от wide, c - от char):

convert.h
Код:
#include "reader/support.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

wchar_t*    alloc_c2w(LPCSTR pszSource, UINT encoding);
char*	    alloc_w2c(LPCWSTR pwszSource, UINT encoding);
char*	    convert_from_to(LPCSTR pszSource, UINT inEncoding, UINT outEncoding);

#ifdef __cplusplus
}
#endif // __cplusplus

#ifdef UNICODE
#   define alloc_t2w(ptszSource, encoding) (ptszSource ? support_wcsdup(ptszSource) : NULL)
#   define alloc_w2t(pwszSource, encoding) (pwszSource ? support_wcsdup(pwszSource) : NULL)
#else /* UNICODE */
#   define alloc_t2w(ptszSource, encoding) alloc_c2w(ptszSource, encoding)
#   define alloc_w2t(pwszSource, encoding) alloc_w2c(pwszSource, encoding)
#endif /* UNICODE */

#define console_alloc_c2w(pszSource)	alloc_c2w(pszSource, CPRO_CONSOLE_CP)
#define console_alloc_w2c(pwszSource)	alloc_w2c(pwszSource, CPRO_CONSOLE_CP)
#define console_alloc_t2w(ptszSource)	alloc_t2w(ptszSource, CPRO_CONSOLE_CP)
#define console_alloc_w2t(pwszSource)	alloc_w2t(pwszSource, CPRO_CONSOLE_CP)


convert.c
Код:
#include "convert.h"
#ifdef UNIX
#include "CSP_WinError.h"
#endif // UNIX

// Выставляет LastError при ошибке. Подача NULL на вход -- не ошибка.
wchar_t* alloc_c2w(LPCSTR pszSource, UINT encoding)
{
    if (!pszSource) {
	return NULL;
    }

    int wcharsNum = MultiByteToWideChar(encoding, 0, pszSource, -1, NULL, 0);
    if (!wcharsNum) {
	return NULL;
    }

    wchar_t* pwszOut = (wchar_t *)malloc(wcharsNum * sizeof(wchar_t));
    if (!pwszOut) {
	SetLastError(ERROR_NOT_ENOUGH_MEMORY);
	return NULL;
    }

    if (!MultiByteToWideChar(encoding, 0, pszSource, -1, pwszOut, wcharsNum)) {
	free(pwszOut);
	return NULL;
    }

    return pwszOut;
}

// Выставляет LastError при ошибке. Подача NULL на вход -- не ошибка.
char* alloc_w2c(LPCWSTR pwszSource, UINT encoding)
{
    if (!pwszSource) {
	return NULL;
    }

    int charsNum = WideCharToMultiByte(encoding, 0, pwszSource, -1, 0, 0, 0, 0);
    if (!charsNum) {
	return NULL;
    }

    char* pszOut = (char *)malloc(charsNum);
    if (!pszOut) {
	SetLastError(ERROR_NOT_ENOUGH_MEMORY);
	return NULL;
    }

    if (!WideCharToMultiByte(encoding, 0, pwszSource, -1, pszOut, charsNum, 0, 0)) {
	free(pszOut);
	return NULL;
    }

    return pszOut;
}

// Выставляет LastError при ошибке. Подача NULL на вход -- не ошибка.
char* convert_from_to(LPCSTR pszSource, UINT inEncoding, UINT outEncoding)
{
    wchar_t* pwszSource = alloc_c2w(pszSource, inEncoding);
    if (!pwszSource) {
	return NULL;
    }

    char* pszOut = alloc_w2c(pwszSource, outEncoding);
    free(pwszSource);
    return pszOut;
}
Официальная техподдержка. Официальная база знаний.
thanks 1 пользователь поблагодарил Андрей Русев за этот пост.
Санчир Момолдаев оставлено 04.11.2021(UTC)
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.