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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Maxim Korobov  
#1 Оставлено : 22 июня 2009 г. 17:35:13(UTC)
Maxim Korobov

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

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

Есть сертификат, выпущенный на ЦС.

В моей программе я получил контекст сертификата. Подскажите как программно получить контекст (или где про это прочитать) родительского сертификата (сертификата ЦС).
Offline Maxim Korobov  
#2 Оставлено : 22 июня 2009 г. 17:58:06(UTC)
Maxim Korobov

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

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

Похоже, нашел. CertGetCertificateChain.
http://msdn.microsoft.com/en-us/library/aa376078(VS.85).aspx
Offline Maxim Korobov  
#3 Оставлено : 23 июня 2009 г. 22:12:21(UTC)
Maxim Korobov

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

Группы: Участники
Зарегистрирован: 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;
Offline Maxim Korobov  
#4 Оставлено : 30 июня 2009 г. 20:12:24(UTC)
Maxim Korobov

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

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

Пока решил альтернативным способом, с помощью функции CertGetIssuerCertificateFromStore.
Подробнее по адресу:
http://etutorials.org/Programming/secure+programming/Chapter+10.+Public+Key+Infrastructure/10.6+Performing+X.509+Certificate+Verification+with+CryptoAPI/

Тем не менее, если кто-то видит ошибку в моем коде или еще где-либо, прошу помочь.
Offline Kirill Sobolev  
#5 Оставлено : 1 июля 2009 г. 17:07:27(UTC)
Кирилл Соболев

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

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,733
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 177 раз в 168 постах
Chain.cChain - это количество цепочек, которые можно построить от сертификата пользователя к самоподписанному сертификату.
То, что она одна это вполне нормально. В случае использования гибридной схемы, например, их могло бы быть несколько.
А вот сами сертификаты цепочки лежат в массиве @ChainArray^[i].rgpElement, причем @ChainArray^[i].rgpElement[0] будет соответствовать сертификату пользователя.
У них у каждого есть свой статус, который можно посмотреть. Почему нет доверия корневому сертификату - сложно сказать.
Если hChainEngine=NULL, то цепочка будет строиться для текущего пользователя.

Цитата:
Пока решил альтернативным способом, с помощью функции CertGetIssuerCertificateFromStore.

В MSDN вместо нее как раз рекомендуют использовать функции построения цепочек.
Техническую поддержку оказываем тут
Наша база знаний
Offline Maxim Korobov  
#6 Оставлено : 28 января 2010 г. 18:47:17(UTC)
Maxim Korobov

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

Группы: Участники
Зарегистрирован: 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)  | Причина: Не указана

Offline Maxim Korobov  
#7 Оставлено : 28 января 2010 г. 21:53:58(UTC)
Maxim Korobov

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

Группы: Участники
Зарегистрирован: 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 сертификатами корневым и пользовательским.
Замечу, что у меня последний элемент в цепочке был пользовательским сертификатом.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.