Статус: Активный участник
Группы: Участники
Зарегистрирован: 19.02.2008(UTC) Сообщений: 66 Откуда: Москва
|
Есть сертификат, выпущенный на ЦС.
В моей программе я получил контекст сертификата. Подскажите как программно получить контекст (или где про это прочитать) родительского сертификата (сертификата ЦС).
|
|
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 19.02.2008(UTC) Сообщений: 66 Откуда: Москва
|
|
|
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 19.02.2008(UTC) Сообщений: 66 Откуда: Москва
|
Пока не получается. CertGetCertificateChain возвращает True. А дальше - не понятно: 1. Chain.cChain = 1, то есть только один сертификат в цепочке, хотя сертификат ЦС установлен (цепочка простая: корневой сертификат->данный сертификат) и при просмотре с помощью аплета панели управления Certification Path валиден; 2. ChainArray^[i].TrustStatus.dwErrorStatus = 32, то есть CERT_TRUST_IS_UNTRUSTED_ROOT, хотя см. "хотя..." пункта 1; 3. Если руками идти в цикле от 0 до 1 включительно, то в памяти сразу за тестовым сертификатом размещается корневой (получается получить Subject!); Кирилл? :) Может, настройки по умолчанию для ChainEngine что-то запрещают и следует инициализировать со своими настройками (с помощью CertCreateCertificateChainEngine)? Код: Код:
Типы:
PCERT_SIMPLE_CHAINARRAY = ^CERT_SIMPLE_CHAINARRAY;
CERT_SIMPLE_CHAINARRAY = array[0..99] of CERT_SIMPLE_CHAIN;
Переменные:
EnhkeyUsage: CERT_ENHKEY_USAGE;
CertUsage: CERT_USAGE_MATCH;
ChainParams: PCERT_CHAIN_PARA;
Chain: PCCERT_CHAIN_CONTEXT;
ChainPointer: PPCCERT_CHAIN_CONTEXT;
SimpleChain: PCERT_SIMPLE_CHAIN;
ChainArray: PCERT_SIMPLE_CHAINARRAY;
Выполнение:
EnhkeyUsage.cUsageIdentifier := 0;
EnhkeyUsage.rgpszUsageIdentifier := nil;
CertUsage.dwType := USAGE_MATCH_TYPE_AND;
CertUsage.Usage := EnhkeyUsage;
GetMem(ChainParams, SizeOf(CERT_CHAIN_PARA));
ZeroMemory(ChainParams, SizeOf(CERT_CHAIN_PARA));
ChainParams.cbSize := SizeOf(CERT_CHAIN_PARA);
ChainParams.RequestedUsage := CertUsage;
GetMem(Chain, SizeOf(CERT_CHAIN_CONTEXT));
ZeroMemory(Chain, SizeOf(CERT_CHAIN_CONTEXT));
ChainPointer := PPCCERT_CHAIN_CONTEXT(Chain);
if not CertGetCertificateChain(0, Context, nil, nil {Context.hCertStore}, ChainParams, 0, nil, @Chain) then
begin
GlobalError('Error code:' + IntToStr(GetLastError));
Exit;
end;
ChainArray := PCERT_SIMPLE_CHAINARRAY(Chain.rgpChain);
for i := 0 to Chain.cChain - 1 do
begin
if (ChainArray^[i].TrustStatus.dwErrorStatus = CERT_TRUST_NO_ERROR) then
begin
if not CertNameToStr(PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, @ChainArray^[i].rgpElement.pCertContext.pCertInfo.Subject, CERT_X500_NAME_STR, Value, MaxFieldLength) = 0 then
begin
MessageDlg('Error decoding: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
Exit;
end;
end
else
begin
ShowMessage('Trust Error');
end;
end;
CertFreeCertificateChain(Chain);
FreeMemory(ChainPointer);
FreeMem(ChainParams);
ChainArray := nil;
|
|
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 19.02.2008(UTC) Сообщений: 66 Откуда: Москва
|
|
|
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 25.12.2007(UTC) Сообщений: 1,733  Откуда: КРИПТО-ПРО Поблагодарили: 177 раз в 168 постах
|
Chain.cChain - это количество цепочек, которые можно построить от сертификата пользователя к самоподписанному сертификату. То, что она одна это вполне нормально. В случае использования гибридной схемы, например, их могло бы быть несколько. А вот сами сертификаты цепочки лежат в массиве @ChainArray^[i].rgpElement, причем @ChainArray^[i].rgpElement[0] будет соответствовать сертификату пользователя. У них у каждого есть свой статус, который можно посмотреть. Почему нет доверия корневому сертификату - сложно сказать. Если hChainEngine=NULL, то цепочка будет строиться для текущего пользователя. Цитата:Пока решил альтернативным способом, с помощью функции CertGetIssuerCertificateFromStore. В MSDN вместо нее как раз рекомендуют использовать функции построения цепочек. |
|
|
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 19.02.2008(UTC) Сообщений: 66 Откуда: Москва
|
Провёл ревизию приведённого здесь исходника. Попробывал в качестве параметра store указать открытое заранее хранилище Trusted Root Certificates (реестр), где точно находится корневой сертификат. К сожалению, cChain возвращается равной 1, а статус сертификата - untrusted. Kirill Sobolev написал:Chain.cChain - это количество цепочек, которые можно построить от сертификата пользователя к самоподписанному сертификату. То, что она одна это вполне нормально. В случае использования гибридной схемы, например, их могло бы быть несколько. А вот сами сертификаты цепочки лежат в массиве @ChainArray^[i].rgpElement, причем @ChainArray^[i].rgpElement[0] будет соответствовать сертификату пользователя. Так. Теперь понял. Есть массив цепочек, в каждой из которых есть массив элементов, из которых уже можно получить сертификат. Тогда действительно нормально, что возвращается одна цепочка. Мне надо сделать цикл по элементам конкретной цепочки. P.S.: странно. Сейчас посмотрел параметры цепочки: cbSize - 2193804; cElement = 256. Наверно не то привожу к типу массива элементов цепочек. Отредактировано пользователем 28 января 2010 г. 18:51:11(UTC)
| Причина: Не указана
|
|
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 19.02.2008(UTC) Сообщений: 66 Откуда: Москва
|
Точно. Неправильно считал адреса. Подгядел как сделано в компонентах Clever Interner Suite: Код:
function TclCertificateStore.GetCertificateChain(hStore: HCERTSTORE; ACertificate: TclCertificate): Integer;
const
revFlags: array[TclRevocationFlags] of DWORD = (0, $10000000, $20000000, $40000000);
var
pChainContext: PCCERT_CHAIN_CONTEXT;
ChainPara: CERT_CHAIN_PARA;
pChain: PCERT_SIMPLE_CHAIN;
pElement: PCERT_CHAIN_ELEMENT;
i, j: Integer;
certInChain: TclCertificate;
p: Pointer;
begin
pChainContext := nil;
Result := 0;
try
ZeroMemory(@ChainPara, sizeof(ChainPara));
ChainPara.cbSize := sizeof(ChainPara);
if not CertGetCertificateChain(0, ACertificate.Context, nil,
ACertificate.Context.hCertStore, @ChainPara, revFlags[CRLFlags], nil, @pChainContext) then
begin
raise EclCryptError.Create(EclCryptError.GetLastErrorText(), clGetLastError());
end;
for i := pChainContext.cChain - 1 downto 0 do
begin
p := Pointer(Integer(pChainContext.rgpChain) + i * SizeOf(PCERT_SIMPLE_CHAIN));
pChain := PCERT_SIMPLE_CHAIN(p^);
for j := pChain.cElement - 1 downto 0 do
begin
p := Pointer(Integer(pChain.rgpElement) + j * SizeOf(PCERT_CHAIN_ELEMENT));
pElement := PCERT_CHAIN_ELEMENT(p^);
if not CertAddCertificateContextToStore(hStore, pElement.pCertContext, CERT_STORE_ADD_NEW, nil) then
begin
raise EclCryptError.Create(EclCryptError.GetLastErrorText(), clGetLastError());
end;
certInChain := TclCertificate.Create(pElement.pCertContext);
try
DoCertificateVerified(certInChain, pElement.TrustStatus.dwErrorStatus,
pElement.TrustStatus.dwInfoStatus);
finally
certInChain.Free();
end;
end;
end;
Result := pChainContext.TrustStatus.dwErrorStatus;
finally
if (pChainContext <> nil) then
begin
CertFreeCertificateChain(pChainContext);
end;
end;
end;
С этим всё ок. 1 цепочка с 2 сертификатами корневым и пользовательским. Замечу, что у меня последний элемент в цепочке был пользовательским сертификатом.
|
|
|
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close