:: Visual Foxpro, Foxpro for DOS
Прямое чтение и запись BLOB-объектов (Crypto API)
rvc44
Автор

Сообщений: 2211
Откуда: Тамбов
Дата регистрации: 06.12.2005
Всем привет!

Несколько лет назад приходилось писать код для получения серийного номера сертификата ключа подписи прямым чтением BLOB-объекта:
* ПОЛУЧИМ СЕРИЙНЫЙ НОМЕР СЕРТИФИКАТА КЛЮЧА ПОДПИСИ ПРЯМЫМ ЧТЕНИЕМ BLOB-ОБЪЕКТА
* Пример серийного номера сертификата: 1e 8d 70 93 00 00 00 00 02 34
LOCAL lnSNLen, lcSerialNumber, lcSNReversed, lcSNHex
* Размер поля "Серийный номер" хранится в 4 первых байтах BLOB-объекта CRYPT_INTEGER_BLOB,
* содержащегося внутри структуры CERT_INFO, по смещению 5 в данной структуре.
lnSNLen = CTOBIN(SubStr(lcCERT_INFO, 5, 4), "4RS") && 10 байт. CTOBIN converts a binary character representation to a numeric value.
* = MessageBox('Длина поля "Серийный номер" сертификата составляет ' + AllT(Str(lnSNLen))+' байт',64,'Сообщение')
* Ссылка на значение поля "Серийный номер" хранится в 4 последних из 8 байтах BLOB-объекта CRYPT_INTEGER_BLOB,
* содержащегося внутри структуры CERT_INFO, по смещению 9 в данной структуре.
* Поскольку содержимое BLOB-объекта CRYPT_INTEGER_BLOB числовое, а не символьное,
* то API-функцию CertNameToStr() для получения данных BLOB-объекта здесьприменять нельзя!
* Прочитаем серийный номер сертификата ключа подписи напрямую из BLOB-объекта:
lcSerialNumber = SYS(2600, CTOBIN(SubStr(lcCERT_INFO, 9, 4), "4RS"), lnSNLen)
* Big Endian bit = Обратный порядок байтов
* вывод серийного номера необходимо осуществить с порядком байтов Big Endian bit,
* cделаем реверс порядка байтов в строке с серийным номером до её преобразования в формат Hex
lcSNReversed = ""
For lnI=m.lnSNLen To 1 Step -1
lcSNReversed = lcSNReversed + SubStr(lcSerialNumber, lnI, 1)
EndFor
* Преобразуем серийный номер в 16-ричный формат:
m.lcSNHex = Space(0)
For m.lnI=1 to lnSNLen
m.lcSNHex = m.lcSNHex + " "+SubStr(Transform(Asc(SubStr(m.lcSNReversed,m.lnI,1)),"@0"),9)
EndFor
m.lcSNHex = AllT(m.lcSNHex)

Сейчас озадачился вопросом реализации обратного действия, т.е. как осуществить прямую запись CryptoAPI BLOB-объекта из проекта на VFP. В общем, есть такой Сишный код:
// Add the cosigner's certificate to the message.
CERT_BLOB CosignCertBlob;
CosignCertBlob.cbData = pCosignerCert->cbCertEncoded; && В первых 4 из 8 байтах BLOB-объекта хранится размер поля
CosignCertBlob.pbData = pCosignerCert->pbCertEncoded; && В последних 4 из 8 байтах BLOB-объекта хранится значение поля
который нужно "перевести" на VFP.

Немного прикинул, тряхнув стариной, и вот что у меня получилось:
* 30.05.2018, ПРЯМАЯ ЗАПИСЬ BLOB-ОБЪЕКТА VFP
* Add the cosigner's certificate to the message.
* Original MSDN code: hттps://msdn.microsoft.com/en-us/library/windows/desktop/aa904939(v=vs.85).aspx
* SYS(2600) return Pointer as String
* CTOBIN - Converts a binary character representation to a numeric value
* BINTOC - Converts a numeric value to a binary character representation.
* Указатель на закодированный сертификат, размером 4 байта. SYS(2600) - Return Pointer as String
pbCertEncoded = CTOBIN(SubStr(lcCERT_CONTEXT, 5, 4), "4RS") && Указатель на закодированный сертификат CERT_CONTEXT -> BYTE* pbCertEncoded
* Размер, в байтах, закодированного сертификата
cbCertEncoded = CTOBIN(SubStr(lcCERT_CONTEXT, 9, 4), "4RS") && Размер, в байтах, закодированного сертификата CERT_CONTEXT -> DWORD cbCertEncoded
* BLOB-объект (CryptoAPI) состоит из 8 байт.
* В первых 4 из 8 байтах BLOB-объекта хранится размер поля
* В последних 4 из 8 байтах BLOB-объекта хранится значение поля
lcCosignCertBlob = 0 + BINTOC(cbCertEncoded, "4RS") + BINTOC(pbCertEncoded, "4RS")
*-- Выделяем 8 байт под объект BLOB
*-- hттp://msdn2.microsoft.com/en-us/library/aa366781.aspx -Memory Management Functions...
*-- Запрашиваем память у Windows и получаем указатель на неё (дескриптор)
*-- 0x0040 означает неперемещаемую (фиксированную) память, заполненную нулями
*-- m.lnLen указывает размер выделяемой памяти в байтах.
*-- Если память под pbCERT_BLOB выделять пустой строкой в VFP, то работать не будет
pbCERT_BLOB = LocalAlloc(0x0040, 8)
* Копируем объект BLOB в выделенную память
SYS(2600, pbCERT_BLOB, 8, lcCosignCertBlob)
* Структура CERT_CONTEXT определана в MSDN:
* hттp://msdn.microsoft.com/en-us/library/aa919756.aspx
*|typedef struct _CERT_CONTEXT {
*| DWORD dwCertEncodingType; 0:4
*| BYTE* pbCertEncoded; 4:4 Указатель на закодированный сертификат, имеет размер 4 байта.
*| DWORD cbCertEncoded; 8:4 Размер, в байтах, закодированного сертификата.
*| PCERT_INFO pCertInfo; 12:4 Указатель на структуру CERT_INFO
*| HCERTSTORE hCertStore; 16:4 Указатель
*|} CERT_CONTEXT, *PCERT_CONTEXT; total 20 bytes
*|typedef const CERT_CONTEXT *PCCERT_CONTEXT;
* Структура CERT_INFO определана в MSDN:
* hттp://msdn.microsoft.com/en-us/library/aa919721.aspx
*|typedef struct _CERT_INFO {
*| DWORD dwVersion; 0:4 && Certificate's version number (CERT_V3)
*| CRYPT_INTEGER_BLOB SerialNumber; 4:8 && BLOB (Cryptography) structure containing the certificate's serial number. The least significant byte is the zero byte of the pbData member of SerialNumber. The index for the last byte of pbData is one less than the value of the cbData member of SerialNumber. The most significant byte is the last byte of pbData. Leading 0x00 or 0xFF bytes are removed. For more information, see CertCompareIntegerBlob.
*| CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; 12:12
*| CERT_NAME_BLOB Issuer; 24:8 && Поле "Поставщик" (issuer) содержит имя УЦ, издателя сертификата
*| FILETIME NotBefore; 32:8
*| FILETIME NotAfter; 40:8
*| CERT_NAME_BLOB Subject; 48:8 && Certificate subject's encoded name.
*| CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo; 56:24
*| CRYPT_BIT_BLOB IssuerUniqueId; 80:12
*| CRYPT_BIT_BLOB SubjectUniqueId; 92:12
*| DWORD cExtension; 104:4
*| PCERT_EXTENSION rgExtension; 108:4 && Указатель на CERT_EXTENSION
*|} CERT_INFO, *PCERT_INFO; total 112 bytes

Прошу оценить свежим взглядом и сделать вывод: "взлетит" данный код или нет? Что-то мне не очень нравится:
BYTE* pbCertEncoded
Ratings: 0 negative/0 positive
Re: Прямое чтение и запись BLOB-объектов (Crypto API)
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
В чём смысл всего этого безобразия? Не понимаю зачем лезть внутрь pbCertEncoded... Создаётся сертификат совсем по другому.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Прямое чтение и запись BLOB-объектов (Crypto API)
rvc44
Автор

Сообщений: 2211
Откуда: Тамбов
Дата регистрации: 06.12.2005
Игорь, Вы не уловили сути. Здесь ни о каком создании сертификата речь даже не идет.
Глобальная цель - решить задачу по подписанию определенного файла второй подписью.
Не подписать еще раз подписанные данные, а именно наложить вторую, а если потребуется и третью отсоединенную (detached) подпись в формате PKCS#7, причем, что важно, в одном, а не 2 или 3 отдельных файлах. Последнее время, Росреестр только так принимает в электронном виде подписанные концессионные соглашения и сведения о произведенной кадастровой оценке объектов недвижимости. На один XML-файл требуют один SIG-Файл, содержащий 3 разных подписи внутри, а три разных SIG-файла к одному XML не допускается. Найденный алгоритм осуществления подобного безобразия, предполагает именно такой код. У Вас есть другие идеи, как это осуществить?

Обратите внимание на ссылку "Original MSDN code" выше, заменив "тт" на "tt" в http в третьей сверху строке комментариев к коду (операция CoSign - "Доподписание").



Исправлено 4 раз(а). Последнее : rvc44, 01.06.18 01:50
Ratings: 0 negative/0 positive
Re: Прямое чтение и запись BLOB-объектов (Crypto API)
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Т.е. если это всё конкретно для
CERT_BLOB CosignCertBlob;
CosignCertBlob.cbData = pCosignerCert->cbCertEncoded;
CosignCertBlob.pbData = pCosignerCert->pbCertEncoded;

То должно работать во-первых и без LocalAlloc (в MSDN нет указаний на то что для этой функции нужно как-то "по особому" память для структуры выделять - да и в коде примера там тривиальная локальная переменная и потом просто указатель на неё передаётся в функцию),
во-вторых по сути "внутрь" структуры чей адрес в pbCertEncoded лежит ты и не лезешь - только сам адрес (указатель) берёшь из другой структуры. А раз так, то всё упрощается до
lcCosignCertBlob = SubStr(m.lcCERT_CONTEXT, 9, 4) + SubStr(m.lcCERT_CONTEXT, 5, 4);
И да, в таком случае проблем нет - не ты своим прикладным кодом, а сами АПИ функции лезут внутрь этих бинарных закодированных структур


------------------
WBR, Igor
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 22 (Гостей: 22)

© 2000-2024 Fox Club 
Яндекс.Метрика