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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Stalker4  
#1 Оставлено : 19 февраля 2013 г. 19:02:45(UTC)
Stalker4

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2013(UTC)
Сообщений: 30
Украина

Сказал(а) «Спасибо»: 1 раз
Hi All,

В описании структур CERT_RDN_ATTR и CERT_RDN говориться что они обе могут быть массивами.
Мне честно говоря не понятно, зачем эти обе структуры могут быть
массивами.

Скажем делаю я запрос на получение сертификата и указываю в начальных данных
только владельца сертификата (cSubject).
Код:
var
  rdnSubjectAttr :CERT_RDN_ATTR;
  CertRDN        :CERT_RDN;

 rdnSubjectAttr.pszObjId     := szOID_COMMON_NAME;
 rdnSubjectAttr.dwValueType  := CERT_RDN_PRINTABLE_STRING;
 rdnSubjectAttr.Value.cbData := Length(cSubject);
 rdnSubjectAttr.Value.pbData := PBYTE(cSubject);

 CertRDN.cRDNAttr  := 1;
 CertRDN.rgRDNAttr := @rdnSubjectAttr;

Тут вроде бы все понятно.

Теперь же в запросе я хочу указать владельца сертификата (szOID_COMMON_NAME)
и его организацию (szOID_ORGANIZATION_NAME).

Возникает вопрос, кто должен быть массивом CERT_RDN_ATTR или CERT_RDN ?
Ведь я могу взять две переменные типа CERT_RDN_ATTR и поместить их в
массив CERT_RDN (CertRDN :array[0..1] of CERT_RDN), а могу вроде бы сделать и
по другому создать массив типа CERT_RDN_ATTR
(rdn_attr :array[0..1] of CERT_RDN_ATTR) и уже ссылку на этот массив
поместить в CertRDN.
Как правильнее ?
Offline Юрий  
#2 Оставлено : 20 февраля 2013 г. 9:09:30(UTC)
Юрий

Статус: Активный участник

Группы: Участники
Зарегистрирован: 22.01.2008(UTC)
Сообщений: 671
Мужчина
Российская Федерация
Откуда: Йошкар-Ола

Сказал «Спасибо»: 3 раз
Поблагодарили: 93 раз в 67 постах
Действительно оба эти структуры могут быть массивами так как с точки зрения ASN.1 (в который они в конечном итоге и кодируются) они обе являются "последовательностями" (SET и SEQUENCE).

Вот только в CERT_RDN_ATTR хранит описание для одного OBJECT ID для "distinguished name", а CERT_RDN - общий массив всех этих CERT_RDN_ATTR. Ниже приведено описание из RFC5280:

Name ::= CHOICE { -- only one possibility for now --
rdnSequence RDNSequence }

RDNSequence ::= SEQUENCE OF RelativeDistinguishedName

RelativeDistinguishedName ::=
SET SIZE (1..MAX) OF AttributeTypeAndValue

AttributeTypeAndValue ::= SEQUENCE {
type AttributeType,
value AttributeValue }

AttributeType ::= OBJECT IDENTIFIER

AttributeValue ::= ANY -- DEFINED BY AttributeType
С уважением,
Юрий Строжевский
Offline Stalker4  
#3 Оставлено : 20 февраля 2013 г. 12:57:05(UTC)
Stalker4

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2013(UTC)
Сообщений: 30
Украина

Сказал(а) «Спасибо»: 1 раз
Автор: Юрий Перейти к цитате
Действительно оба эти структуры могут быть массивами так как с точки зрения ASN.1 (в который они в конечном итоге и кодируются) они обе являются "последовательностями" (SET и SEQUENCE).

Вот только в CERT_RDN_ATTR хранит описание для одного OBJECT ID для "distinguished name", а CERT_RDN - общий массив всех этих CERT_RDN_ATTR. Ниже приведено описание из RFC5280:

То есть я правильно предположил, что если в запросе на получения сертификата я хочу указать не только владельца сертификата, но и его организацию, то я должен создавать массив для CERT_RDN ?

Цитата:

var
rdnSubjectAttr :CERT_RDN_ATTR;
rdnOrganizAttr :CERT_RDN_ATTR;
cSubject :String;
cOrganization :String;
CertRDN :array[0..1] of CERT_RDN;
CertNameInfo :CERT_NAME_INFO;

begin

cSubject := 'Stalker'; // Название владельца

rdnSubjectAttr.pszObjId := szOID_COMMON_NAME;
rdnSubjectAttr.dwValueType := CERT_RDN_PRINTABLE_STRING;
rdnSubjectAttr.Value.cbData := Length(cSubject);
rdnSubjectAttr.Value.pbData := PBYTE(cSubject);

cOrganization := 'MIAC'; // Организация владельца

rdnOrganizAttr.pszObjId := szOID_ORGANIZATION_NAME;
rdnOrganizAttr.dwValueType := CERT_RDN_PRINTABLE_STRING;
rdnOrganizAttr.Value.cbData := Length(cSubject);
rdnOrganizAttr.Value.pbData := PBYTE(cSubject);

CertRDN[0].cRDNAttr := 1;
CertRDN[0].rgRDNAttr := @rdnSubjectAttr;

CertRDN[1].cRDNAttr := 1;
CertRDN[1].rgRDNAttr := @rdnOrganizAttr;

CertNameInfo.cRDN := 2;
CertNameInfo.rgRDN := @CertRDN[0];

Ну а потом, структуру CertNameInfo передаю в CryptEncodeObject.

Offline Юрий  
#4 Оставлено : 20 февраля 2013 г. 14:16:02(UTC)
Юрий

Статус: Активный участник

Группы: Участники
Зарегистрирован: 22.01.2008(UTC)
Сообщений: 671
Мужчина
Российская Федерация
Откуда: Йошкар-Ола

Сказал «Спасибо»: 3 раз
Поблагодарили: 93 раз в 67 постах
Нужно как-то вот так:


CERT_RDN_ATTR rdn_attr[5];

rdn_attr[0].pszObjId = "2.5.4.6"; // countryName
rdn_attr[0].dwValueType = CERT_RDN_PRINTABLE_STRING;

rdn_attr[0].Value.cbData = 2;
rdn_attr[0].Value.pbData = ( BYTE* ) "RU";

rdn_attr[1].pszObjId = "2.5.4.13"; // description
rdn_attr[1].dwValueType = CERT_RDN_UTF8_STRING;

WCHAR* description = L"Юрий Строжевский, статья 'Использование сертификатов', корневой удостоверяющий центр №1";
rdn_attr[1].Value.cbData = wcslen( description ) * sizeof( WCHAR );
rdn_attr[1].Value.pbData = ( BYTE* ) description;

rdn_attr[2].pszObjId = "2.5.4.11"; // organizationUnit
rdn_attr[2].dwValueType = CERT_RDN_UTF8_STRING;

WCHAR* organizationUnit = L"Подразделение сертификации";
rdn_attr[2].Value.cbData = wcslen( organizationUnit ) * sizeof( WCHAR );
rdn_attr[2].Value.pbData = ( BYTE* ) organizationUnit;

rdn_attr[3].pszObjId = "2.5.4.10"; // organizationName
rdn_attr[3].dwValueType = CERT_RDN_UTF8_STRING;

WCHAR* organizationName = L"Организация сертификации";
rdn_attr[3].Value.cbData = wcslen( organizationName ) * sizeof( WCHAR );
rdn_attr[3].Value.pbData = ( BYTE* ) organizationName;

rdn_attr[4].pszObjId = "2.5.4.12"; // title
rdn_attr[4].dwValueType = CERT_RDN_UTF8_STRING;

WCHAR* organizationTitle = L"Корневой удостоверяющий центр №1";
rdn_attr[4].Value.cbData = wcslen( organizationTitle ) * sizeof( WCHAR );
rdn_attr[4].Value.pbData = ( BYTE* ) organizationTitle;

CERT_RDN cert_rdn;

cert_rdn.cRDNAttr = 5;
cert_rdn.rgRDNAttr = rdn_attr;

CERT_NAME_INFO name_info;

name_info.cRDN = 1;
name_info.rgRDN = &cert_rdn;

if( Encode( X509_ASN_ENCODING, X509_NAME, &name_info, &( TBS_blob[ 3 ].pbData ), &( TBS_blob[ 3 ].cbData ) ) )
return 1;
С уважением,
Юрий Строжевский
thanks 1 пользователь поблагодарил Юрий за этот пост.
Stalker4 оставлено 27.02.2013(UTC)
Offline Stalker4  
#5 Оставлено : 20 февраля 2013 г. 14:36:26(UTC)
Stalker4

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2013(UTC)
Сообщений: 30
Украина

Сказал(а) «Спасибо»: 1 раз
Ага, значит я предположил не правильно. Массивом должен быть CERT_RDN_ATTR, а не CERT_RDN.
Цитата:

var
rdnAttr :array[0..1] of CERT_RDN_ATTR;
cSubject :String;
cOrganization :String;
CertRDN :CERT_RDN;
CertNameInfo :CERT_NAME_INFO;

begin

cSubject := 'Stalker'; // Название владельца

rdnAttr[0].pszObjId := szOID_COMMON_NAME;
rdnAttr[0].dwValueType := CERT_RDN_PRINTABLE_STRING;
rdnAttr[0].Value.cbData := Length(cSubject);
rdnAttr[0].Value.pbData := PBYTE(cSubject);

cOrganization := 'MIAC'; // Организация владельца

rdnAttr[1].pszObjId := szOID_ORGANIZATION_NAME;
rdnAttr[1].dwValueType := CERT_RDN_PRINTABLE_STRING;
rdnAttr[1].Value.cbData := Length(cSubject);
rdnAttr[1].Value.pbData := PBYTE(cSubject);

CertRDN.cRDNAttr := 2;
CertRDN.rgRDNAttr := @rdnAttr;

CertNameInfo.cRDN := 1;
CertNameInfo.rgRDN := CertRDN;


P.S. А тег форума code похоже глючит, когда я заключил в него вышеуказанный код, то он часть куда куда то дел.
Offline Aqel  
#6 Оставлено : 10 января 2022 г. 19:33:00(UTC)
Aqel

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

Группы: Участники
Зарегистрирован: 07.11.2018(UTC)
Сообщений: 6
Мужчина
Российская Федерация
Откуда: Пермь

Сказал «Спасибо»: 1 раз
Помогите разобраться, исходя из выше показанного собираю по крупицам код запроса на Delphi, вот что получилось...
Цитата:

var
rdn: CERT_RDN;
CertRDN: array [1 .. 5] of CERT_RDN_ATTR;
begin
CertRDN[1].pszObjId := '2.5.4.6'; // Страна
CertRDN[1].dwValueType := CERT_RDN_PRINTABLE_STRING;
CertRDN[1].Value.cbData := 2;
CertRDN[1].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit6.Text) + 1));
CertRDN[2].pszObjId := '2.5.4.13'; // Инфо
CertRDN[2].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[2].Value.cbData := length(LabeledEdit1.Text);
CertRDN[2].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit1.Text) + 1));
CertRDN[3].pszObjId := '2.5.4.11'; // Подразделение
CertRDN[3].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[3].Value.cbData := length(LabeledEdit3.Text);
CertRDN[3].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit3.Text) + 1));
CertRDN[4].pszObjId := '2.5.4.10'; // Организация
CertRDN[4].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[4].Value.cbData := length(LabeledEdit2.Text);
CertRDN[4].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit2.Text) + 1));
CertRDN[5].pszObjId := '2.5.4.12'; // Корневой удостоверяющий центр
CertRDN[5].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[5].Value.cbData := length(LabeledEdit5.Text);
CertRDN[5].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit5.Text) + 1));
rdn.cRDNAttr := 5;
rdn.rgRDNAttr := CertRDN[..];
name_info.cRDN := 1;
name_info.rgRDN := @rdn;
...


Возникает ошибка в строке: rdn.rgRDNAttr := CertRDN[..];
...как мне прописать ?
Всё намного проще, чем есть на самом деле...
Offline Андрей *  
#7 Оставлено : 10 января 2022 г. 20:03:47(UTC)
Андрей *

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

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 10,869
Мужчина
Российская Федерация

Сказал «Спасибо»: 404 раз
Поблагодарили: 1649 раз в 1263 постах
почему по крупицам, если это пример выше (9 лет назад)

1. Нумерации с 0
2. В тексте сообщения с ошибкой - что именно не понятно?
3. В MSDN описано и в подключенных модулях Delphi ... типы.

наводка:
чем отличается:
rdn.rgRDNAttr := CertRDN[..];
от
name_info.rgRDN := @rdn;

и
почему cRDN := 1; ?

Отредактировано пользователем 10 января 2022 г. 20:04:36(UTC)  | Причина: Не указана

Техническую поддержку оказываем тут
Наша база знаний
Offline Андрей *  
#8 Оставлено : 10 января 2022 г. 20:08:17(UTC)
Андрей *

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

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 10,869
Мужчина
Российская Федерация

Сказал «Спасибо»: 404 раз
Поблагодарили: 1649 раз в 1263 постах
Техническую поддержку оказываем тут
Наша база знаний
Offline Андрей *  
#9 Оставлено : 10 января 2022 г. 20:09:05(UTC)
Андрей *

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

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 10,869
Мужчина
Российская Федерация

Сказал «Спасибо»: 404 раз
Поблагодарили: 1649 раз в 1263 постах
Цитата:
CertRDN[5].pszObjId := '2.5.4.12'; // Корневой удостоверяющий центр


Кто это придумал?
Это OID для кодирования Должности.
Техническую поддержку оказываем тут
Наша база знаний
Offline two_oceans  
#10 Оставлено : 10 января 2022 г. 22:24:50(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,429
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 95 раз
Поблагодарили: 342 раз в 322 постах
Aqel написал:
исходя из выше показанного собираю по крупицам код запроса на Delphi
Добрый день. Коллега, обратите внимание на префиксы названий полей. Они самодокументируют формат и наталкивают на мысль что должно быть в поле.
dw - целое беззнаковое (4 байта)
cb - количество байт
cch - количество символов
pb - указатель на буфер
psz - указатель на строковый буфер, оканчивающийся 0 (PChar/PAnsiChar)
c - количество элементов

Что не так понятно для программиста на Дельфи: в идеале вся структура передаваемая в CryptoApi должна быть в одном куске памяти. Все что связано указателями в структуре - должно идти друг за другом в какой-то области памяти. Без этого иногда работает, иногда нет, иногда на ровном месте выдает ошибку обращения к памяти. Где-то в глубине кода есть IsBadReadPtr с указанием на основную структуру, но размером по сумме размеров всех элементов. Когда такой вызов вылетит за пределы динамического куска памяти основной структуры - что-то может быть проигнорировано или может быть выдана ошибка проверки параметров структуры.

Чтобы добиться расположения структуры в одном куске памяти StrAlloc не в кассу, так как для каждой строчки создается отдельный буфер в отдельном куске памяти. Более того, rdn и name_info также лучше бы расположить вместе. Хотя конечно для глобальных переменных в 99% случаев это не спровоцирует ошибку - сегмент данных-то большой, Дельфи объявляет достаточно много глобальных переменных, чтобы IsBadReadPtr не вылетел за пределы.
В примере выше (9 лет назад) переменные объявлены последовательно и статически (если принять? что на той версии Дельфи string = shortstring), то есть идут друг за другом (в стэке если локальные, в сегменте данных, если глобальные), что формально удовлетворяет требование о расположении последовательно в одном куске памяти.

Однако если выделять динамические буферы под структуры и элементы или передавать структуру между процедурами, то там уже совсем другая история. Для избегания ошибки можно объявить свою "мегаструктуру" и ее заполнять, так можно передавать структуру (по ссылке!) между процедурами, не нарушая последовательность элементов.
Автор: Андрей * Перейти к цитате
1. Нумерации с 0
Сработает и без этого, так как массив выше объявлен с нумерацией от 1. Хотя по общепринятым нормам соглашусь, что MSDN нумерует с нуля.
Автор: Андрей * Перейти к цитате
и почему name_info.cRDN := 1; ?
Как я понимаю, это количество субъектов. На первый взгляд все верно, субъект один, а у этого субъекта RDN из 5 компонентов.

Отредактировано пользователем 10 января 2022 г. 22:47:16(UTC)  | Причина: Не указана

thanks 2 пользователей поблагодарили two_oceans за этот пост.
Андрей * оставлено 10.01.2022(UTC), Aqel оставлено 11.01.2022(UTC)
Offline Aqel  
#11 Оставлено : 11 января 2022 г. 17:31:19(UTC)
Aqel

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

Группы: Участники
Зарегистрирован: 07.11.2018(UTC)
Сообщений: 6
Мужчина
Российская Федерация
Откуда: Пермь

Сказал «Спасибо»: 1 раз
Вот переделал, всё компилится (код без проверки ошибок), но данные сохраняемые в запросе: NUL и в конце что то кодирование...
Цитата:
var
nameAttr: CERT_RDN_ATTR;
nameString: PChar;
rdn: CERT_RDN;
nameInfo: CERT_NAME_INFO;
certReqInfo: CERT_REQUEST_INFO;
subjNameBlob: CERT_NAME_BLOB;
encNameLen: DWORD;
encName: PBYTE;
prov: HCRYPTPROV;
pubKeyInfoLen: DWORD;
pubKeyInfo: PCERT_PUBLIC_KEY_INFO;
encCertReqLen: DWORD;
params: CRYPT_OBJID_BLOB;
sigAlg: CRYPT_ALGORITHM_IDENTIFIER;
signedEncCertReq: PBYTE;
cont: PChar;
err: string;
encType: DWORD;
f: file;
CertRDN: array [0 .. 5] of CERT_RDN_ATTR;
begin
encType := PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;
{nameString := StrAlloc(length(LabeledEdit1.Text) + 1);
StrPCopy(nameString, LabeledEdit1.Text);
nameAttr.pszObjId := '2.5.4.3';
nameAttr.dwValueType := CERT_RDN_UTF8_STRING; // CERT_RDN_PRINTABLE_STRING
nameAttr.Value.cbData := length(LabeledEdit1.Text);
nameAttr.Value.pbData := PBYTE(nameString);
rdn.cRDNAttr := 1;
rdn.rgRDNAttr := @nameAttr;
nameInfo.cRDN := 1;
nameInfo.rgRDN := @rdn; }
CertRDN[0].pszObjId := '2.5.4.3'; // Имя
CertRDN[0].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[0].Value.cbData := length(LabeledEdit1.Text);
CertRDN[0].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit1.Text) + 1));
CertRDN[1].pszObjId := '2.5.4.6'; // Страна
CertRDN[1].dwValueType := CERT_RDN_PRINTABLE_STRING;
CertRDN[1].Value.cbData := 2;
CertRDN[1].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit6.Text) + 1));
CertRDN[2].pszObjId := '2.5.4.13'; // Инфо
CertRDN[2].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[2].Value.cbData := length(LabeledEdit1.Text);
CertRDN[2].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit1.Text) + 1));
CertRDN[3].pszObjId := '2.5.4.11'; // Подразделение
CertRDN[3].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[3].Value.cbData := length(LabeledEdit3.Text);
CertRDN[3].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit3.Text) + 1));
CertRDN[4].pszObjId := '2.5.4.10'; // Организация
CertRDN[4].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[4].Value.cbData := length(LabeledEdit2.Text);
CertRDN[4].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit2.Text) + 1));
CertRDN[5].pszObjId := '2.5.4.7'; // Город
CertRDN[5].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[5].Value.cbData := length(LabeledEdit5.Text);
CertRDN[5].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit5.Text) + 1));
rdn.cRDNAttr := 6;
rdn.rgRDNAttr := @CertRDN;
nameInfo.cRDN := 6;
nameInfo.rgRDN := @rdn;
GetMem(encName, encNameLen);
subjNameBlob.cbData := encNameLen;
subjNameBlob.pbData := encName;
certReqInfo.Subject := subjNameBlob;
certReqInfo.cAttribute := 0;
certReqInfo.rgAttribute := nil;
certReqInfo.dwVersion := CERT_REQUEST_V1;
GetMem(pubKeyInfo, pubKeyInfoLen);
certReqInfo.SubjectPublicKeyInfo := pubKeyInfo^;
FillChar(params, sizeof(params), 0);
sigAlg.pszObjId := szOID_OIWSEC_sha1RSASign;
sigAlg.Parameters := params;
GetMem(signedEncCertReq, encCertReqLen);
if SaveDialog1.Execute then
begin
AssignFile(f, SaveDialog1.FileName);
Rewrite(f, 1);
BlockWrite(f, signedEncCertReq^, encCertReqLen);
CloseFile(f);
end;
StrDispose(StrAlloc(length(LabeledEdit1.Text) + 1));
FreeMem(encName, encNameLen);
FreeMem(pubKeyInfo, pubKeyInfoLen);
FreeMem(signedEncCertReq, encCertReqLen);
...
Всё намного проще, чем есть на самом деле...
Offline two_oceans  
#12 Оставлено : 13 января 2022 г. 13:41:25(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,429
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 95 раз
Поблагодарили: 342 раз в 322 постах
Многобукв. А если серьезно, то меня терзают сомнения после чтения справки там они говоря не о массиве структур, а о массиве указателей на структуры. Возможно придется объявить новый массив x заполнить указателями на соответствующие элементы certRDN и передать указатель на массив указателей?
Offline Aqel  
#13 Оставлено : 18 января 2022 г. 17:07:11(UTC)
Aqel

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

Группы: Участники
Зарегистрирован: 07.11.2018(UTC)
Сообщений: 6
Мужчина
Российская Федерация
Откуда: Пермь

Сказал «Спасибо»: 1 раз
two_oceans
Букв то не много (мне вот нужны все эти параметры), а вот как с указателями это оформить?
Всё намного проще, чем есть на самом деле...
Offline two_oceans  
#14 Оставлено : 19 января 2022 г. 6:07:54(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,429
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 95 раз
Поблагодарили: 342 раз в 322 постах
Автор: Aqel Перейти к цитате
two_oceans
Букв то не много (мне вот нужны все эти параметры), а вот как с указателями это оформить?
Если принять предположение из сообщения выше, что это массивы указателей, то как-то так:
Код:
var ...
CertRDNPtr:array[0..5]of pointer; // по идее pCERT_RDN_ATTR, но обобщенно подойдет pointer
rdnptr:array[0..0]of pointer; // по идее pCERT_RDN, но обобщенно подойдет pointer
...
CertRDN[0].pszObjId := '2.5.4.3'; // Имя
CertRDN[0].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[0].Value.cbData := length(LabeledEdit1.Text);
CertRDN[0].Value.pbData := PBYTE(StrAlloc(length(LabeledEdit1.Text) + 1));
CertRDNPtr[0]:=@(CertRDN[0]); // повторить для каждого элемента
...
rdn.rgRDNAttr := @CertRDNPtr;
rdnptr[0]:= @rdn;
nameInfo.rgRDN := @rdnptr;
...
Кстати, 1) в закомментированном фрагменте кроме StrAlloc были ещё и вызовы StrPCopy, а потом их нет - в структуру CertRDN[0] данные вообще попадают? Не пробовали вывести содержимое? 2) Что-то я вообще не уловил где потом nameInfo в процитированном коде используется? Хотел попробовать воспроизвести задачу, но приведенного фрагмента кода явно недостаточно.

Отредактировано пользователем 19 января 2022 г. 6:09:10(UTC)  | Причина: Не указана

Offline Aqel  
#15 Оставлено : 19 января 2022 г. 20:11:43(UTC)
Aqel

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

Группы: Участники
Зарегистрирован: 07.11.2018(UTC)
Сообщений: 6
Мужчина
Российская Федерация
Откуда: Пермь

Сказал «Спасибо»: 1 раз
Вот весь код кнопки:
Цитата:
procedure TForm1.Button3Click(Sender: TObject);
var
nameAttr: CERT_RDN_ATTR;
nameString: PChar;
rdn: CERT_RDN;
nameInfo: CERT_NAME_INFO;
certReqInfo: CERT_REQUEST_INFO;
subjNameBlob: CERT_NAME_BLOB;
encNameLen: DWORD;
encName: PBYTE;
prov: HCRYPTPROV;
pubKeyInfoLen: DWORD;
pubKeyInfo: PCERT_PUBLIC_KEY_INFO;
encCertReqLen: DWORD;
params: CRYPT_OBJID_BLOB;
sigAlg: CRYPT_ALGORITHM_IDENTIFIER;
signedEncCertReq: PBYTE;
cont: PChar;
err: string;
encType: DWORD;
f: file;
CertRDN: array [0 .. 5] of CERT_RDN_ATTR;
CertRDNPtr: array [0 .. 5] of pointer;
rdnptr: array [0 .. 0] of pointer;
begin
encType := PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;

{ nameString := StrAlloc(length(LabeledEdit1.Text) + 1);
StrPCopy(nameString, LabeledEdit1.Text);
nameAttr.pszObjId := '2.5.4.3';
nameAttr.dwValueType := CERT_RDN_UTF8_STRING; // CERT_RDN_PRINTABLE_STRING
nameAttr.Value.cbData := length(LabeledEdit1.Text);
nameAttr.Value.pbData := PBYTE(nameString);
rdn.cRDNAttr := 1;
rdn.rgRDNAttr := @nameAttr;
nameInfo.cRDN := 1;
nameInfo.rgRDN := @rdn; }

nameString := StrAlloc(length(LabeledEdit1.Text) + 1);
StrPCopy(nameString, LabeledEdit1.Text);
CertRDN[0].pszObjId := '2.5.4.3'; // Имя
CertRDN[0].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[0].Value.cbData := length(LabeledEdit1.Text);
CertRDN[0].Value.pbData := PBYTE(nameString);
CertRDNPtr[0] := @(CertRDN[0]);

nameString := StrAlloc(length(LabeledEdit6.Text) + 1);
StrPCopy(nameString, LabeledEdit6.Text);
CertRDN[1].pszObjId := '2.5.4.6'; // Страна
CertRDN[1].dwValueType := CERT_RDN_PRINTABLE_STRING;
CertRDN[1].Value.cbData := 2;
CertRDN[1].Value.pbData := PBYTE(nameString);
CertRDNPtr[1] := @(CertRDN[1]);

nameString := StrAlloc(length(LabeledEdit5.Text) + 1);
StrPCopy(nameString, LabeledEdit5.Text);
CertRDN[2].pszObjId := '2.5.4.7'; // Город
CertRDN[2].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[2].Value.cbData := length(LabeledEdit5.Text);
CertRDN[2].Value.pbData := PBYTE(nameString);
CertRDNPtr[2] := @(CertRDN[2]);

nameString := StrAlloc(length(LabeledEdit2.Text) + 1);
StrPCopy(nameString, LabeledEdit2.Text);
CertRDN[3].pszObjId := '2.5.4.10'; // Организация
CertRDN[3].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[3].Value.cbData := length(LabeledEdit2.Text);
CertRDN[3].Value.pbData := PBYTE(nameString);
CertRDNPtr[3] := @(CertRDN[3]);

nameString := StrAlloc(length(LabeledEdit3.Text) + 1);
StrPCopy(nameString, LabeledEdit3.Text);
CertRDN[4].pszObjId := '2.5.4.11'; // Подразделение
CertRDN[4].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[4].Value.cbData := length(LabeledEdit3.Text);
CertRDN[4].Value.pbData := PBYTE(nameString);
CertRDNPtr[4] := @(CertRDN[4]);

nameString := StrAlloc(length(LabeledEdit1.Text) + 1);
StrPCopy(nameString, LabeledEdit1.Text);
CertRDN[5].pszObjId := '2.5.4.13'; // Инфо
CertRDN[5].dwValueType := CERT_RDN_UTF8_STRING;
CertRDN[5].Value.cbData := length(LabeledEdit1.Text);
CertRDN[5].Value.pbData := PBYTE(nameString);
CertRDNPtr[5] := @(CertRDN[5]);

rdn.rgRDNAttr := @CertRDNPtr;
rdnptr[0] := @rdn;
nameInfo.rgRDN := @rdnptr;

subjNameBlob.cbData := encNameLen;
subjNameBlob.pbData := encName;
certReqInfo.Subject := subjNameBlob;
certReqInfo.cAttribute := 0;
certReqInfo.rgAttribute := nil;
certReqInfo.dwVersion := CERT_REQUEST_V1;
if length(LabeledEdit10.Text) = 0 then
cont := nil
else
begin
err := LabeledEdit10.Text;
cont := StrAlloc(length(err) + 1);
StrPCopy(cont, err);
end;
if not CryptAcquireContext(prov, cont, nil, PROV_RSA_FULL, 0) then
begin
case int64(GetLastError) of
ERROR_INVALID_PARAMETER:
err := 'ERROR_INVALID_PARAMETER';
ERROR_NOT_ENOUGH_MEMORY:
err := 'ERROR_NOT_ENOUGH_MEMORY';
NTE_BAD_FLAGS:
err := 'NTE_BAD_FLAGS';
NTE_BAD_KEYSET:
err := 'NTE_BAD_KEYSET';
NTE_BAD_KEYSET_PARAM:
err := 'NTE_BAD_KEYSET_PARAM';
NTE_BAD_PROV_TYPE:
err := 'NTE_BAD_PROV_TYPE';
NTE_BAD_SIGNATURE:
err := 'NTE_BAD_SIGNATURE';
NTE_EXISTS:
err := 'NTE_EXISTS';
NTE_KEYSET_ENTRY_BAD:
err := 'NTE_KEYSET_ENTRY_BAD';
NTE_KEYSET_NOT_DEF:
err := 'NTE_KEYSET_NOT_DEF';
NTE_NO_MEMORY:
err := 'NTE_NO_MEMORY';
NTE_PROV_DLL_NOT_FOUND:
err := 'NTE_PROV_DLL_NOT_FOUND';
NTE_PROV_TYPE_ENTRY_BAD:
err := 'NTE_PROV_TYPE_ENTRY_BAD';
NTE_PROV_TYPE_NO_MATCH:
err := 'NTE_PROV_TYPE_NO_MATCH';
NTE_PROV_TYPE_NOT_DEF:
err := 'NTE_PROV_TYPE_NOT_DEF';
NTE_PROVIDER_DLL_FAIL:
err := 'NTE_PROVIDER_DLL_FAIL';
NTE_SIGNATURE_FILE_BAD:
err := 'NTE_SIGNATURE_FILE_BAD';
else
err := 'Unknown error';
end;
MessageDlg('Ошибка создания контейнера: ' + err, mtError, [mbOK], 0);
StrDispose(nameString);
FreeMem(encName, encNameLen);
if cont <> nil then
StrDispose(cont);
exit;
end;
if not CryptExportPublicKeyInfo(prov, AT_SIGNATURE, encType, nil, pubKeyInfoLen) then
begin
MessageDlg('Ошибка экспорта открытого ключа', mtError, [mbOK], 0);
StrDispose(nameString);
FreeMem(encName, encNameLen);
if cont <> nil then
StrDispose(cont);
exit;
end;
GetMem(pubKeyInfo, pubKeyInfoLen);
if not CryptExportPublicKeyInfo(prov, AT_SIGNATURE, encType, pubKeyInfo, pubKeyInfoLen) then
begin
MessageDlg('Ошибка экспорта открытого ключа', mtError, [mbOK], 0);
StrDispose(nameString);
FreeMem(encName, encNameLen);
if cont <> nil then
StrDispose(cont);
FreeMem(pubKeyInfo, pubKeyInfoLen);
exit;
end;
certReqInfo.SubjectPublicKeyInfo := pubKeyInfo^;
FillChar(params, sizeof(params), 0);
sigAlg.pszObjId := szOID_OIWSEC_sha1RSASign;
sigAlg.Parameters := params;
if not CryptSignAndEncodeCertificate(prov, AT_SIGNATURE, encType, X509_CERT_REQUEST_TO_BE_SIGNED, @certReqInfo, @sigAlg, nil, nil, encCertReqLen) then
begin
MessageDlg('Ошибка получения длины подписанного запроса', mtError, [mbOK], 0);
StrDispose(nameString);
FreeMem(encName, encNameLen);
if cont <> nil then
StrDispose(cont);
FreeMem(pubKeyInfo, pubKeyInfoLen);
exit;
end;
GetMem(signedEncCertReq, encCertReqLen);
if not CryptSignAndEncodeCertificate(prov, AT_SIGNATURE, encType, X509_CERT_REQUEST_TO_BE_SIGNED, @certReqInfo, @sigAlg, nil, signedEncCertReq, encCertReqLen) then
begin
MessageDlg('Ошибка получения подписанного запроса', mtError, [mbOK], 0);
StrDispose(nameString);
FreeMem(encName, encNameLen);
if cont <> nil then
StrDispose(cont);
FreeMem(pubKeyInfo, pubKeyInfoLen);
FreeMem(signedEncCertReq, encCertReqLen);
exit;
end;
SaveDialog1.Title := 'Укажите файл для сохранения запроса';
SaveDialog1.Filter := 'Файл запроса|*.p10';
SaveDialog1.DefaultExt := '.p10';
if SaveDialog1.Execute then
begin
AssignFile(f, SaveDialog1.FileName);
Rewrite(f, 1);
BlockWrite(f, signedEncCertReq^, encCertReqLen);
CloseFile(f);
end;
StrDispose(nameString);
FreeMem(encName, encNameLen);
if cont <> nil then
StrDispose(cont);
FreeMem(pubKeyInfo, pubKeyInfoLen);
FreeMem(signedEncCertReq, encCertReqLen);
if not CryptReleaseContext(prov, 0) then
begin
MessageDlg('Ошибка освобождения контекста', mtError, [mbOK], 0);
end;
end;
Всё намного проще, чем есть на самом деле...
Offline two_oceans  
#16 Оставлено : 20 января 2022 г. 7:21:03(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,429
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 95 раз
Поблагодарили: 342 раз в 322 постах
Для справки - какой модуль для работы с CryptoApi используете? jwawincrypt?
Все равно в исходнике, чего-то не хватает. Как будто между строками есть еще что-то.
Код:
nameInfo.rgRDN := @rdnptr;

subjNameBlob.cbData := encNameLen;
subjNameBlob.pbData := encName;
UPDATE: Действительно. При попытке найти что можно сделать с CERT_NAME_INFO выдало примеры создания запроса на сертификат и CryptEncodeObject.

https://docs.microsoft.c...ng-a-certificate-request
http://citforum.ru/security/articles/delphi/

По поводу обработки ошибок (не обязательно конечно, но совет как удобно): у меня используются 2 функции, которые принимают булевый параметр и строку сообщения и возвращают этот же булевый параметр, но если он ложен, то одна функция разбирает GetLastError и пишет в лог или stderr детали ошибки, вторая просто заглушка и ничего не делает. Оборачиваю вызовы CryptoApi в эти функции и легким изменением имени функции CryptCheck_ на CryptCheck получаю лог по определенной функции. Так не потребуется громоздкое описание всех NTSTATUS для каждого вызова.

Отредактировано пользователем 20 января 2022 г. 11:09:46(UTC)  | Причина: Не указана

Offline two_oceans  
#17 Оставлено : 20 января 2022 г. 12:11:35(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,429
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 95 раз
Поблагодарили: 342 раз в 322 постах
Итак, воспроизвел пример - кодирование имени вроде как проходит нормально.
Код:
  rdn.cRDNAttr:= 6;
  rdn.rgRDNAttr := @CertRDN;
  nameInfo.cRDN := 1;
  nameInfo.rgRDN := @rdn;

  encNameLen:=0;
  if CryptCheck(CryptEncodeObject(enctype ,X509_NAME, @nameInfo, nil, encNameLen),'CryptEncodeObject GetLen') then begin
    subjNameBlob.pbData:=GetMem(encNameLen);
    if CryptCheck(CryptEncodeObject(enctype, X509_NAME, @nameInfo, subjNameBlob.pbData, encNameLen),'CryptEncodeObject GetData') then begin
      subjNameBlob.cbData := encNameLen;
      //subjNameBlob.pbData := encName;
    end;
    //FreeMem(encName);
  end;
Кодировка подошла - Юникод. Вариант с дополнительными массивами указателей CertRDNPtr rdnptr выдал ошибку доступа к памяти. Прошу прощения за то, что ввел в заблуждение. Пустой буфер после кодирования данных у меня записывался в случае преждевременного освобождения памяти encName до момента записи, так как ни subjNameBlob.pbData := encName ни certReqInfo.Subject := subjNameBlob; не создает новый буфер, а копируют указатель на буфер encName.

Далее закономерно вылезла ошибка что нужно нормальное имя контейнера. Для существующего от КриптоПро заменил AT_SIGNATURE и PROV_RSA_FULL, так как у меня AT_KEYEXCHANGE и тип провайдера 80. Пин-код запрошен через штатное окошко криптопровайдера. Следующая ошибка на алгоритме подписания запроса. Подсмотрел в существующем запросе
Код:
sigAlg.pszObjId := '1.2.643.7.1.1.3.2';
Файл test.p10 записан успешно. Победа! Дальше надо дорабатывать с атрибутами имени (не вижу региона, ФИО, СНИЛС и т.д.) и расширениями запроса (вроде того какое СКЗИ и т.п.).

Отредактировано пользователем 20 января 2022 г. 13:10:33(UTC)  | Причина: Не указана

Offline Aqel  
#18 Оставлено : 20 января 2022 г. 16:48:50(UTC)
Aqel

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

Группы: Участники
Зарегистрирован: 07.11.2018(UTC)
Сообщений: 6
Мужчина
Российская Федерация
Откуда: Пермь

Сказал «Спасибо»: 1 раз
Да JwaWinCrypt (+ ему ещё нужен JwaBaseTypes)
Всё намного проще, чем есть на самом деле...
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.