CRM-система для УК и ТСЖ

Поддержка длинных строк

Будете спамить рекламой - будем нещадно банить)))
Сообщение
Автор
two_oceans
Ветеран
Сообщений: 546
Зарегистрирован: 30 сен 2016, 17:17
Благодарил (а): 439 раза
Поблагодарили: 415 раза

Поддержка длинных строк

#21 Сообщение two_oceans » 24 июл 2017, 00:49

Подумал еще - 1) новый ГОСТ совершенно не снимает проблемы с параметрами хэша. Их все также не менее 3 наборов; 2) в методическим указаниях по ГИС пока вроде тишина про гост-2012, то есть пока что спешки нет. Без методических я не в курсе какие коды алгоритмов вписать в XML для нового ГОСТа. Вот тут что-то нашлось, но будет ли это приниматься ГИС, не ясно.

По строкам - добавил запись в бинарные файлы. Спохватился, так как понял - если запишу структуру без обработки, то в файл запишется значение указателя на данные строки, а не сами данные. Ранее была поддержка текстовых файлов через совместимость с pchar. Точнее, совместимость не полная: нормально для обычных данных, но если "строка" содержит #0 в середине (например, не кодированные в base64 значения хэша/подписи), то запишется только часть до него.

По cryptoapi - обычно когда функция возвращает истину, не нужно смотреть GetLastError(), но в режиме отладки у меня вставлена функция которая принимает результат cryptoapi и название функции, вызывает GetLastError(), все выводит в консоль, а результат возвращает дальше (в условные операторы).

Выяснились 2 (пока) глюка: 1) после ошибки "не установлен криптопровайдер", даже если второй вызов (другого криптопровайдера) успешен, GetLastError возвращает тот же код, то есть код не обнуляется при успехе. Поэтому теперь делаю SetLastError(0) перед этим. Похоже, надо обнулять после каждой обработанной ошибки, иначе есть шанс получить код ошибки, которая была десяток операций назад; 2) если запросить контекст, ничего не сделать и закрыть его, то возвращается истина, но GetLastError показывает код ошибки "неожиданный конец данных ASN.1". Судя по поиску, у кого-то установка программ вываливается с эти кодом, весьма печально если причина - неочищенный GetLastError после открытия-закрытия контекста.

two_oceans
Ветеран
Сообщений: 546
Зарегистрирован: 30 сен 2016, 17:17
Благодарил (а): 439 раза
Поблагодарили: 415 раза

Поддержка длинных строк

#22 Сообщение two_oceans » 07 авг 2017, 07:08

Подвижки за 2 недели:
Разобрался с классом fphttpclient (аналог дельфивского thttpclient как я понимаю), принимает на вход и выдает на выход TStream, Пришлось помучиться со стримами, так как перенос с дельфи оказался не 100% и документация по отличиям сводится к исходнику модуля sysutils, а в нем куча включаемых файликов (подогнаны под разные платформы). В итоге сделал переходник с моего композитного типа строки на ansistring и его передал при создании стрима. С получением результата дело наладилось когда поставил стрим в нулевую позицию перед чтением.
Для отладки всего это богатства написал страничку на php принимающую POST запрос и сохраняющую его в файл. Это тоже оказалось не очевидно: $HTTP_RAW_POST_DATA по умолчанию оказался отключен, если тип содержимого - стандартные данные формы, а по чтению из php://input как оказалось нужно внимательней читать пример file_get_contents(). Подкорректировал скрипт на vbscript для отладки страницы (он как раз и выдает POST как стандартные данные формы). В итоге страничка приняла данные и от скрипта и от fphttpclient.
Далее научился программно искать на портале smev 2 информацию о сервисе (пока только федеральном) - для этого нужно отправить POST запрос с данными поиска в формате AJAX и получить ответ в формате AJAX с мнемоникой и версией сервиса, потом повторить (только уже GET) указав мненонику и версию - в итоге будет AJAX с паспортом сервиса, перечнем операций и их SoapAction-ами, списком узлов СМЭВ, на которых сервис зарегистрирован, включая адреса по которым сервис доступен. Остается только разобрать полученное и выбрать узел, соответствующий региону (или федеральный или 2 тестовых). С региональными сервисами процесс аналогичен, но в запрос чуть отличается.
Попробовал записать полученное в некий файл (кэш) и считывать чтобы не дергать портал при каждом запросе. Сначала попробовал в двоичный файл и ... чтение не вышло. Похоже композитный тип надо еще внимательно дорабатывать. Выяснился странный глюк - выделяю временную строку с 20Мб памяти, считываю из файла - все ОК. Пытаюсь изменить размер целевой строки: копирую указатель на старый буфер, обнуляю исходный указатель (без освобождения), выделяю память, копирую из старого буфера в новый (вот тут наверно ничего не делается так как в большинстве случаев целевая строка пуста) - ОК, освобождаю старый буфер - исключение Invalid pointer operation. Уже проверяю перед освобождением, что IsBadWritePtr возвратил 0/false (то есть права на запись есть) и все равно не-нет да проскочит ошибка освобождения буфера. Как будто его уже освободили или не выделили. А без освобождения - утечка памяти. Про освободили/не выделили сказать пока сложно - на взгляд вроде бы везде явное выделение памяти есть. Однако возможны неявные ситуации. Попробовал включить отображение адресов - так активно выделяются и освобождаются, глазами все не отследить, нужен менеджер памяти для этого.
По ходу отладки уже нашел баг - параметр функции был композитная строка с передачей по значению, по недосмотру туда передавалась строковая константа и компилятор об это даже не пикнул - попытался создать в стеке переменную композитной строки и туда затолкать константу в виде shortstring, типа присваивание же есть. Ага, а выделение памяти я должен в присваивании делать, непонятно как узнав, что память не выделена. Конечно, проверяю указатель на nil и (теперь) limit на ноль, но в стеке могут быть неочищенные значения с прошлого раза, так что гарантии это не дает и указатель может указывать на освобожденную память. Если это "куча", полученная менеджером памяти паскаля, то с точки зрения системы это все же допустимая память, а менеджер памяти определяет несоответствие. Так что выходит надо дорабатывать: или пилить еще один менеджер памяти для конкретного типа или общаться с паскалевским менеджером или запрашивать память напрямую у системы или передавать всегда параметры композитные строки по ссылке (тогда компилятор хотя бы ругнется "при передаче по ссылке тип должен совпадать").

Так что двоичный файл отложил, теперь пишу в xml (точнее подобный) формате. Проблема в принципе такая же, так что пока передаю неинициализированную строку на чтение, по ходу чтения выясняется нужный размер и под него выделяется память. Если нужно перечитать, перед чтением принудительно освобождаются строки.
Далее глюки продолжаются - последняя новость: в строке 152 символа (было несколько добавлений строк), память выделена под 400 Кб и при добавлении еще одной строки или при выводе на экран снова Access violation. Чуть раньше - все выводится без проблем. Вообще на ровном месте.
А на работе еще Семерка, сразу предлагает поискать решение. :lol: Поиск решений отключил, в список исключаемых из отчета программ добавил, но эта ерунда все равно выпадает (теперь в виде кнопки "закрыть программу") и, что самое неприятное, перехватывает исключение раньше чем выйдет информация о строках где сбой от отладочной версии программы. Кто-нибудь знает как вообще отключить такую "заботу" хотя бы для конкретной программы? Что они теперь предполагают, что все отлаживают внешним отладчиком?

Sergey Cheban
Активист
Сообщений: 216
Зарегистрирован: 05 ноя 2016, 07:45
Благодарил (а): 74 раза
Поблагодарили: 113 раза

Поддержка длинных строк

#23 Сообщение Sergey Cheban » 07 авг 2017, 11:39

two_oceans писал(а):ОК, освобождаю старый буфер - исключение Invalid pointer operation.

Есть сильное подозрение, что несколько раньше у Вас случился memory overrun и повредились внутренние данные менеджера памяти. После этого всё работает до тех пор, пока испорченные данные не понадобятся менеджеру памяти. Т.е. проблема вообще не в том месте, которое падает.

two_oceans
Ветеран
Сообщений: 546
Зарегистрирован: 30 сен 2016, 17:17
Благодарил (а): 439 раза
Поблагодарили: 415 раза

Поддержка длинных строк

#24 Сообщение two_oceans » 07 авг 2017, 13:02

Я так и понимаю, что проблема обычно не в том месте на которое указывает отладка, ну или ошибки в том же месте достаточно тривиальны и находятся до компиляции. Не так давно - выдало ошибку в строке, где конец процедуры и одно только слово "end;". Или когда вываливалось от неявного преобразования параметра - перед вызовом функции вывод на консоль есть, сразу после входа в функцию вывода нет. Точнее падает при попытке вывести параметры, без параметров иногда выводит. Отладчик там вообще выдал, что не узнает из какого исходника и какой строки данный код, вооружившись двумя дизассемблерами (использую старый W32Dasm c отладчиком и IDA Freeware, которая хорошо распознает фреймы стека и стандартные модули паскаля), по ассемблерному коду опознал, что это функция присвоения значения из shortstring в композитную строку. Дальше раскрутил - неявное преобразование.

Спасибо за наводку, посмотрю исходники на предмет того, как проверить и отслеживать состояние встроенного менеджера памяти. У меня была неясная мысль, что есть зависимость сбоя от количества выделенной памяти (вроде не выделять ли самые большие куски из системы напрямую), спасибо что дали мысли определенную форму. Подозреваю, что если дело в менеджере - придется действительно выделять напрямую (через мини-менеджер).
За сегодня накидал мини-менеджер памяти для конкретного типа промежуточным слоем, но ясности это не принесло, кроме того, что теперь время от времени валится на нем, так как выделение/освобождение памяти теперь через него (но проходит через паскалевский менеджер). До сбойного места при склеивании строк пока дело не дошло.

Sergey Cheban
Активист
Сообщений: 216
Зарегистрирован: 05 ноя 2016, 07:45
Благодарил (а): 74 раза
Поблагодарили: 113 раза

Поддержка длинных строк

#25 Сообщение Sergey Cheban » 07 авг 2017, 14:09

two_oceans писал(а):За сегодня накидал мини-менеджер памяти для конкретного типа промежуточным слоем, но ясности это не принесло, кроме того, что теперь время от времени валится на нем, так как выделение/освобождение памяти теперь через него (но проходит через паскалевский менеджер).

Попробуйте реализовать вот этот приём, раз уж у Вас есть свой менеджер памяти: https://en.wikipedia.org/wiki/Guard_byte.
Некоторые компиляторы умеют делать это самостоятельно (см. https://en.wikipedia.org/wiki/AddressSanitizer, например), но про паскаль, увы, я ничего не знаю. Ну и не забывайте, что memory overrun может происходить не на тех данных, которые Вы выделяете через свой менеджер памяти, а на каких-то других.
Ещё посмотрите в сторону heaptrc (http://wiki.freepascal.org/heaptrc). Может быть, он поможет найти проблему.
И ещё посмотрите, нет ли у вас аналога функции _heapchk (https://docs.microsoft.com/ru-ru/cpp/c- ... ce/heapchk) или способа её вызвать. Я просто не в курсе.

two_oceans
Ветеран
Сообщений: 546
Зарегистрирован: 30 сен 2016, 17:17
Благодарил (а): 439 раза
Поблагодарили: 415 раза

Поддержка длинных строк

#26 Сообщение two_oceans » 07 авг 2017, 20:28

Спасибо. Действительно менеджер паскаля использует что-то подобное, хотя в подробности не вдавался: в начале блока точно пишется скрытая служебная структура, в том числе в ней указан размер блока, что позволяет освобождать память не указывая размер - менеджер сам его считает. И между блоками расстояние достаточное, скорее всего в конце тоже есть служебные маркеры. heaptrc вообще прямо в яблочко, как раз на FreePascal компилирую. Раньше о нем читал, что утечки памяти выявлять удобно, а тут не вспомнил.

Мини-менеджер пока только добавляет адреса в список при выделении и проверяет наличие в списке перед освобождением и сообщает о несоответствиях, конечно маловато, но дополнительная страховка.

Однако, похоже разгадка оказалась вообще совсем в другом (хотя обломы с памятью не исключаю до конца) - компилятор Фрипаскаля понимает разные "диалекты" Паскаля и некоторые управляющие конструкции не работают в одних, но работают в других. Обычно диалект распространяется только на один модуль и смешивание неудобств не доставляет. В частности, в диалекте Дельфи работает обработка исключений try.. except..end; try..finally..end; но не работает объявление операторов. На диалекте Фрипаскаля наоборот. Поэтому модуль длинных строк на одном диалекте, а httpclient на другом. О несоответствии этих конструкций текущему диалекту модуля компилятор должным образом ругается.

Однако, также есть отличия в синтаксисе инициализации/выгрузки модуля от классического BEGIN END (аналог main в си) и специальных ExitProc (каждый модуль сохраняет указатель ExitProc при загрузке, потом восстанавливает при выгрузке и если не NULL вызывает функцию по этому адресу - выходит нечто похожее на стек модулей). Уже давненько привык к варианту секций initialization .. finalization .. end. В этот раз тоже было так записано, модуль работал, когда более-менее отладил его - перешел к следующему, который его использует. И где-то в этот момент видимо изменился диалект, секции initialization и finalization просто стали игнорироваться без каких-либо сообщений об ошибке.
Отправлено спустя 27 минуты 31 секунды:
Фактически, уже чудо что хотя бы что-то работало на непроинициализированном модуле. После очередной отладки обратил внимание, что помимо ошибок доступа еще не читается кэш ответов портала (при чудесах с памятью не удивительно) и вываливаются обращения к EnterCriticalSection (пока отлаживал просто их комментировал - в тестовой программе все равно только одна thread). А InitializeCriticalSection и чтение файла как раз были в inialization. Сложил 2 и 2, вставил туда еще вывод строки на консоль - не выводит, перенес код инициализации и выгрузки в отдельные процедуры, вручную их вызвал - заработало, хотя наверно теперь надо все модули проверить. И уже не знаю на кого злиться - на авторов компилятора, который не предупреждает, что часть кода просто игнорируется или на себя что не использую классику, которая точно реализована в компиляторе.

two_oceans
Ветеран
Сообщений: 546
Зарегистрирован: 30 сен 2016, 17:17
Благодарил (а): 439 раза
Поблагодарили: 415 раза

Поддержка длинных строк

#27 Сообщение two_oceans » 09 авг 2017, 08:00

За вчерашний день проверил остальные модули и оказалось еще интереснее: похоже секция initialization вызывается только в модулях напрямую указанных в основной программе. Причем порядок автоматически выстраивается, а если указанный модуль в программе не используется, то он может исключаться. То есть если модуль 1 использует модуле 2, а основная программа использует модуль 1, то сработает инициализация модуля 1, но не модуля 2. Определенная логика прослеживается. В этот раз у меня вышло что в основной программе указаны 2 модуля, а из них еще тянутся 7 штук. Переписал все кроме мини-менеджера на отдельные процедуры инициализации.

Загрузил эталонные примеры хэша в Base64 кодированном виде (для проверки нужен ли переворот хэша для данного криптопровайдера). Мини-менеджер все же определенно нужная вещь! В одном из вызовов перевода хэша в Base64 пропустил взятие адреса буфера и композитный тип перезаписался строкой-результатом. Данные испортились, в том числе указатель на буфер (но длина хэша мала, пострадали соседние переменных, но критического сбоя не произошло). И тут проявил себя мини-менеджер: 1) не дал освободить незарегистрированный адрес буфера (что привело бы к вылету) и вывел об этом сообщение, по которому я нашел ошибку; 2) когда программа закончилась, освободил все неосвобожденные буферы по своим данным. То есть несмотря на переполнение буфера и временную утечку памяти все закончилось хорошо.

Еще бы восстанавливать такие испорченные адреса буфера - вообще будет замечательно. Теоретически - надо еще фиксировать адреса самих записей и их флаги, но практически - все неявные присвоения пролетают стороной (неявные преобразования уже должны ловиться мини-менеджером, можно допилить). Некоторые мысли как это обойти есть: например, при обнулении композитного типа проверять "а был ли такой адрес переменной композитного типа" и вставить проверки переданных композитных строк (если обнуление не нужно) в каждой функции. За одно можно выводить сообщения о неявных присвоениях/преобразованиях. Минус - придется наверно написать вспомогательную программу просматривающую код и сообщающую куда вставить проверки.

С присвоениями, кстати, оказалось, что не только композитный тип, но и все структуры, содержащие его, нужно присваивать очень аккуратно - иначе в них будет совсем не то.

two_oceans
Ветеран
Сообщений: 546
Зарегистрирован: 30 сен 2016, 17:17
Благодарил (а): 439 раза
Поблагодарили: 415 раза

Поддержка длинных строк

#28 Сообщение two_oceans » 18 авг 2017, 06:50

За неделю с хвостиком есть подвижки: если кратко мини-менеджер немного усовершенствован и может восстанавливать часть данных, однако проверки по тексту еще не расставлены. Проверки в присваивании включены, но замечаний не показали.

Доработал связки по сертификатам, получилась первая рабочая версия (выдающая реальное значение подписи), перед возвращением данных производится проверка подписи - проверка проходит нормально. В процессе где-то пропала информация про сертификат (которая правильно выводилась с заглушкой значения подписи хэшем), но можно считать ма-а-а-аленькой победой. qws Для получения доступа к контейнеру соответствующему сертификату используется CryptAcquireCertificatePrivateKey - возвращает контекст криптопровайдера с контейнером и закрытым ключом. Тут плохая новость в том, хотя возвращает Истина (ошибок нет) и пригодный для работы контекст, но в GetLastError() появляется код ошибки 127 (не найден адрес процедуры) и как обычно он может всплыть только после нескольких операций и разрушить логику работы приложения.

Еще выяснился минус - функция преобразования в base64 из набора cryptoapi вставляет переводы строки (символы 13 и 10), хотя символа 13 вообще не должно быть в каноническом виде, да и обычно значение подписи пишется в одну строчку даже без символа 10. Это не смертельно, так как значение подписи не попадает в "каноничные области" (те места, которые обязаны быть каноничными), но выглядит в итоге не очень хорошо, так что придется переводы строк убрать. Ранее это же было со значением хэша, там значение входило в "каноничную область", но перевод строки был только в конце и его пришлось отрезать. Теперь планирую найти где теряется сертификат и отработать проверку полученного подписанного xml, убирая по пути различные заглушки. Далее останется проверка каноникализации и тестирование на межведе.

Про каноникализацию нашел хорошую статью с примерами как и что делать вручную и под ее вдохновением набросал (но никак не тестировал еще) реализацию, за исключением 2 моментов - обработки атрибутов по умолчанию и замены символьных ссылок. С ними проблема в том, что они указываются в !DOCTYPE и могут быть не включены в документ, а указаны по внешней ссылке, то есть надо загружать документ откуда-то и его обрабатывать, а он может указывать на другой документ и т.д. Есть большие сомнения, что это когда-нибудь встретится в запросах между ИС, тем не менее без этого текст считается не каноничным. В общем, каноникализация оставлена "на сладкое".

Вчера весь день пытался заставить cryptoapi выдать подпись конкретным сертификатом. Идея была в использовании функции поиска сертификата CertFindCertificateInStore с определенным значением в расширенном использовании ключа. Вот только я видимо не понимаю как она работает, потому что она ничего не находит, хотя сертификат с указанным использованием есть и функцией перечисления всех сертификатов находится. В функцию поиска по расширенному использованию передается структура из количества строк и массива pchar значений (rgpszUsageIdentifier - в префиксах Си я не очень разбираюсь, первый раз такой rgpsz вижу, но комментарий стоит array of psz). Уже ее заполнял и как массив указателей на буферы и как указатель на массив указателей на буферы - результат один.

Еще посмотрю MSDN, возможно тут некая заморочка при переносе описания струтуры на Паскаль и придется менять описание. Хранилище используется "Личные" , и при перечислении и при поиске один и тот же дескриптор хранилища. Конечно можно и перечислять все потом проверять критерии, но если есть функция поиска по нужному параметру, зачем такое извращенство. Хотя наверняка при реализации этого будет быстрее понять, что нужно затолкать в структуру. Тут я понял почему некоторые программы идут с рекомендацией устанавливать только один сертификат: снес все остальные сертификаты и сделал через перечисление. Однако не теряю надежды добить поиск сертификата.

Соответственно придется хорошенько подумать относительно аналогичных функций для OpenSSL - поиска и перечисления сертификатов.

Sergey Cheban
Активист
Сообщений: 216
Зарегистрирован: 05 ноя 2016, 07:45
Благодарил (а): 74 раза
Поблагодарили: 113 раза

Поддержка длинных строк

#29 Сообщение Sergey Cheban » 20 авг 2017, 05:42

two_oceans писал(а):Вчера весь день пытался заставить cryptoapi выдать подпись конкретным сертификатом. Идея была в использовании функции поиска сертификата CertFindCertificateInStore с определенным значением в расширенном использовании ключа. Вот только я видимо не понимаю как она работает, потому что она ничего не находит, хотя сертификат с указанным использованием есть и функцией перечисления всех сертификатов находится.

Чёрт его знает. Но... А что Вы будете делать, когда у Вас заведутся несколько сертификатов с этим значением в enhanced key usage (из них парочка - устаревшие)? По-моему, правильнее по fingerprint (CERT_FIND_HASH) выбирать.

two_oceans писал(а):(rgpszUsageIdentifier - в префиксах Си я не очень разбираюсь, первый раз такой rgpsz вижу, но комментарий стоит array of psz). Уже ее заполнял и как массив указателей на буферы и как указатель на массив указателей на буферы - результат один.

Я тоже такое впервые вижу, но см. https://en.wikipedia.org/wiki/Hungarian_notation и https://msdn.microsoft.com/en-us/library/aa260976(VS.60).aspx. RanGe of Pointers to String Zero-terminated.
Вот пример на паскале: http://www.cryptopro.ru/forum2/default.aspx?g=posts&m=10354#post10354.

two_oceans писал(а):Соответственно придется хорошенько подумать относительно аналогичных функций для OpenSSL - поиска и перечисления сертификатов.

Вроде, OpenSSL ни про какие хранилища сертификатов не знает. Ему нужен либо сам сертификат в виде блоба, либо, на худой конец, имя файла. В принципе можно и с криптоапи поступить так же, давать ему сертификат в файле, но это не очень хорошо: windows позволяет сохранить сертификат в хранилище без возможности экспорта, это снижает риск утечки приватного ключа.

two_oceans
Ветеран
Сообщений: 546
Зарегистрирован: 30 сен 2016, 17:17
Благодарил (а): 439 раза
Поблагодарили: 415 раза

Поддержка длинных строк

#30 Сообщение two_oceans » 21 авг 2017, 07:41

Sergey Cheban писал(а):Источник цитаты Но... А что Вы будете делать, когда у Вас заведутся несколько сертификатов с этим значением в enhanced key usage (из них парочка - устаревшие)? По-моему, правильнее по fingerprint (CERT_FIND_HASH) выбирать.
Принципиально согласен, отпечаток лучше всего, но с другой стороны его и хранить/передавать очень неудобно. Еще чуть хуже - пара издатель+ серийный номер. Тут задумка была не загружать программу привязкой к сертификату (по крайней мере, пока тест). Сертификат с таким enhanced key usage один и другой не планируется пока. Согласен, что так небезопасно - либо должен явно настраиваться сертификат для автоподписания при смене либо явно подтверждаться пользователем каждый раз.

Случай с устаревшими наверно не принципиален - дальше планируется проверять не истек ли сертификат. Но не нашелся вообще ни один. Другой вопрос, что да, теоретически могут быть несколько действительных сертификатов с одним и тем же enhanced key usage. Даже если брать только enhanced key usage ЭП-ОВ (1.2.643.100.2.2, для смэв, на котором я тренируюсь), то теоретически у одной организации может быть несколько ИС, подключенных к СМЭВ, и для каждой из них нужен отдельный сертификат ЭП-ОВ. Обычно конечно разные ИС на разных серверах, но если вдруг на одном сервере сошлись, то это будет ужас их отличить.

Ситуацию усложняет и то, что ЭП-ОВ не включает персональных данных либо адреса почты и в данном случае CN = наименованию организации (к слову, с таким CN сертификатов с разной комбинацией enhanced key usage и ФИО уже 5 штук). По рекомендациям предусмотрено, что в качестве CN можно использовать наименование или мнемонику ИС, но: 1) УЦ даже не спросил нужно ли нам указывать определенное CN; 2) самый первый сертификат ИС нужно приложить к заявлению на регистрацию и получить в ответ мнемонику (то есть в нем невозможно указать мнемонику, так как она будет выдана позже). В итоге действительно кроме отпечатка либо издателя+номера не остается других способов идентифицировать нужный сертификат.
Sergey Cheban писал(а):Источник цитаты RanGe of Pointers to String Zero-terminated.Вот пример на паскале: http://www.cryptopro.ru/forum2/default. ... #post10354.
Спасибо за ссылку, но этот пример скорее поможет при перечислении и проверке каждого перечисленного сертификата, чем при задании поиска. Начать можно с того, что у меня в модуле (как и в теме по ссылке) вообще не указано что это массив! Однако это не должно было повлиять на "массив" из одного элемента который в памяти расположен также как просто элемент.

Могу понять почему не указан массив - если установить массив более чем из одного элемента компилятор изменит размер структуры, а если объявить как массив из одного элемента (как обычно делается для массива неизвестной длины), то нужно отключать проверку индексов массива при работе со структурой (иначе вылетит исключение). Так что явно придется менять описание структуры.
Есть еще одна мысль, где искать ошибку - возможно в описании еще и перепутаны одноименные A и W функции и на самом деле надо передать Юникод строку (да еще с двойным нулем в качестве завершающего символа). Хотя как я понимаю должна бы возвратиться ошибка обращения к памяти в этом случае.
Sergey Cheban писал(а):Источник цитаты Вроде, OpenSSL ни про какие хранилища сертификатов не знает. Ему нужен либо сам сертификат в виде блоба, либо, на худой конец, имя файла.
Хранилище доверенных сертификатов по крайней мере у него точно есть, только на Windows оно обычно не работает, так как путь в большинстве сборок вкомпилирован в стиле Linux. В общем, об этом я и говорю, что при работе с OpenSSL еще и свое хранилище делать.
Sergey Cheban писал(а):Источник цитаты В принципе можно и с криптоапи поступить так же, давать ему сертификат в файле, но это не очень хорошо: windows позволяет сохранить сертификат в хранилище без возможности экспорта, это снижает риск утечки приватного ключа.
Как выяснилось, одно другому не мешает! Можно передавать сертификат в файле в cryptoapi и получать ссылку на ключ.

Дано: приватный сертификат установлен со ссылкой на закрытый ключ (тут ссылка имеется ввиду не адрес в памяти, а имя и параметры контейнера и криптопровайдера) и хранится в хранилище Windows (закрытый ключ тоже в хранилище либо на токене). Берем сертификат из файла или из памяти (без закрытого ключа, декодированный из base64, если в файде был кодированный), передаем в CertCreateCertificateContext получаем pCertContext (сертификат в закодированном ASN.1 и раскодированном виде - раскодируются основные поля, не все), передаем pCertContext в CryptAcquireCertificatePrivateKey и получаем hCryptProv (полноценный контекст криптопровайдера с ключевой парой, то есть в том числе со ссылкой на закрытый ключ! соответствующий переданному сертификату), который можем использовать для подписи. Для сопоставления есть разные параметры, наиболее удобный - по открытому ключу в сертификате в хранилище и в переданном pCertContext. Побочный положительный эффект - не нужно гадать AT_KEYEXCHANGE или AT_SIGNATURE в контейнере - определяется автоматически и возвращается. То есть даже если в контейнере 2 ключевых пары, то открытый ключ (или сертификат) идентифицирует пару однозначно, а просто имя контейнера - нет.
Если экспорт ограничен - хотя блоб закрытого ключа не получим, но в остальном все так же.


Вернуться в «ГИС ЖКХ. Форум разработчиков программного обеспечения и всего, что с ним связано»

Кто сейчас на форуме

Количество пользователей, которые сейчас просматривают этот форум: нет зарегистрированных пользователей и 1 гость