Проверка электронной цифровой подписи Authenticode. Часть 1. Теория

Dragokas

Angry & Scary Developer
Команда форума
Супер-Модератор
Разработчик
Клуб переводчиков
Сообщения
7,813
Реакции
6,592
0.title.jpg


Привет!
Я как-то довольно давно заинтересовался темой цифровых подписей, какова их защита, как они устроены изнутри, как с ними работать из-под CryptoAPI. По мере изучения возникало много подводных камней. Наконец, я готов рассказать и вам на доступном языке о принципах шифрования и подписания, практике и готовой реализации проверки подписей.

Затронуто много косвенных тем, так что статья весьма объёмна. Запаситесь чипсами и пивом :). А в перерывах, можете сразу пощупать 3-ю часть статьи, где вас ждёт готовая программа, а также несколько хорошо прокомментированных исходников, в т.ч. для пакетной проверки всех PE-файлов в системе с отчётом в формате CSV. Большинство примеров кода представлено на языке VB6, просто потому что на C++ примеров очень много в сети, а на этом языке подобных комплексных реализаций я не видел вообще, да и этот язык я лучше всего знаю.

Итак, статья состоит из 3 частей:
Часть 1. Теория
Часть 2. Описание реализации
Часть 3. Набор программ

Содержание:

Часть 1. Кусочек теории.
1.1. Что такое электронная цифровая подпись (ЭЦП) и зачем она нужна?
1.2. Надёжность ЭЦП и эксплуатация вредоносным ПО.
1.2.1. Человеческий фактор и приватные ключи.
1.2.2. Уязвимости в структуре ЭЦП.
1.2.3. Стойкость алгоритма хеша.​
1.3. Что означает, легитимна ли подпись?
1.4. Терминология, алгоритм подписания и проверки.
1.4.1. Что такое Authenticode (Code signing).
1.4.2. Что такое хеш.
1.4.3. Что такое выборка (digest).
1.4.4. Что такое приватный и публичный ключи, симметричное и асимметричное шифрование.
1.4.5. Что такое сертификат, центр сертификации и цепочка доверия.
1.4.6. Форматы файлов сертификатов и ключей для Authenticode подписи и их преобразование.
а) Виды форматов.
б) Преобразование форматов.​
1.4.7. Что такое подпись и подписание.
1.4.8. Что такое отпечаток (Thumbprint / Fingerprint).
1.4.9. Как проверяется подпись.
1.4.10. Чем отличаются понятия «алгоритм подписи», «алгоритм хеша подписи», «алгоритм хеша выборки», «алгоритм хеша отпечатка».​
1.5. Само-подписанный (self-signed) сертификат.
1.6. Двойная (вторичная) подпись.
1.7. Способы подписания
1.8. Перечисление сертификатов в хранилище
1.9. Удаление подписи.
1.10. Покупка сертификата.​
Часть 2. Описание реализации программы проверки подписей
2.1. Подготовка к проверке
2.2. Запуск процедуры проверки и обработка результатов
2.3. Очистка ресурсов.
2.4. Извлечение сертификатов и содержащейся в них информации
2.5. Извлечение атрибутов и крос-подписей​

Часть 3. Программа проверки Authenticode ЭЦП
- Назначение
- Совместимость / Требования
- Примеры использования / Флаги и дополнительная информация​

Заключение
Приложения и исходные коды
Дополнительная литература
 
Последнее редактирование:
Часть 1. Кусочек теории.

1.0.Apple_Piece.jpg

1.1. Что такое электронная цифровая подпись (ЭЦП) и зачем она нужна?

ЭЦП – это информация, с помощью которой можно удостовериться, что:
1. Файл подписан конкретным издателем;
2. Файл не повреждён после того, как его подписали.

Это гарантирует, что файл получен от доверенного (на ваш субъективный взгляд) издателя и не был модифицирован (перепакован, пропатчен, повреждён при скачивании случайно или специально).

Если проверка ЭЦП прошла успешно, то при запуске с повышенными привилегиями, в окне UAC вы увидите слова «Проверенный издатель» и его имя:

1.1.1.UAC_verified.jpg


Иначе:

1.1.2.UAC_not_verified.jpg


А если эта программа запускается без повышения привилегий, то после скачивания с сети при запуске вы получите предупреждение:

1.1.3.Secur_Warning.jpg


А вот в случае с легитимной подписью система не будет отображать этого сообщения для файла, у которого при запуске присутствует поток Zone.Identifier:$DATA.

Также из положительных моментов, такую подпись в перспективе можно будет внести в белые списки производителей антивирусов.
Если вы планируете разрабатывать драйвера для распространения, цифровая подпись будет обязательна.

Также, приложениям, подписанным легитимной ЭЦП, разрешается запуск с уровнем целостности UIAccess при указании соответствующего параметра в манифесте и размещении файла программы в одном из безопасных расположений.


1.2. Надёжность ЭЦП и эксплуатация вредоносным ПО.

1.2.1. Человеческий фактор и приватные ключи.

Известно много случаев, когда издатель получил сертификат законно, но использует его для распространения вредоносных или нежелательных программ. Пример: Lenovo – раз, два.

Некоторые компании по расторопности распространяли программу вместе с приватными ключами. Пример: снова Lenovo. И вот результат. Также периодически бывают случаи кражи сертификатов у хорошо известных производителей. Пример: Foxconn и ПО Duqu2. Поэтому не стоит слепо доверять цифровой подписи. Однако, запуская файл, вы сможете убедиться, что его создал, например, Петя, а не злой сосед Вася . Даже если центр сертификации (CA) выпустит сертификат на имя, схожее с уже существующими, существует механизм отзыва сертификатов. Правда, никто Вам не скажет сколько ПК успеет заразиться за это время.

1.2.2. Уязвимости в структуре ЭЦП.

Следует учитывать, что проверяется целостность только кода (исполняемой части файла), а не всего файла целиком. Некоторые недобросовестные программисты (в т.ч. именитые фирмы – в этических целях я не буду их называть) в целях упрощения / экономии используют один и тот же бинарный образ уже готовой подписи для разных файлов (без переподписания), добавляя свои метаданные прямо в структуру подписи, в ту её часть, что не проверяется. Для обеспечения более строгой проверки структуры подписи существует твик реестра, выпущенный в рамках бюллетеня безопасности Microsoft. Однако, такая защита вызывала больше проблем, чем пользы, даже во время запуска служб Майкрософт. Так что фикс был отозван.

С оглядкой на данный фикс, некоторые особо хитрые разработчики нашли и другие лазейки для обхода проверки с другой стороны (заодно открыв новую дыру в своём ПО). Как результат, известны случаи создания дроппера вредоносного ПО способом пропатчивания файла без повреждения ЭЦП у программ данных конкретных разработчиков.

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

1.2.3. Стойкость алгоритма хеша.
Наиболее старый из алгоритмов хеша подписи, который вы всё ещё можете встретить, – это MD5. Он использовался для подписания части системных файлов в ОС Windows 2000 и ранее.

Подделать такой хеш сейчас не составит труда. Посмотрите, например, хотя бы эти статьи:
Peter Selinger: MD5 Collision Demo
Cryptanalysis of SHA-1 - Schneier on Security
Забавляемся с хешами

На смену ему пришел алгоритм SHA1. Однако, на текущее время он тоже имеет изъяны, т.к. было найдено несколько способов подделать и такой хеш. См. статьи:
Коллизия для SHA-1 за 100$ тыс
OpenNews: До конца года ожидается появление практических атак по подбору коллизий для SHA-1
Атака BitErrant с коллизиями SHA-1: создаём разные .exe с одинаковым файлом .torrent

В частности, некоторые исполняемые файлы подвержены атаке SHAttered, которая работает ~ в 100.000 раз быстрее, чем полный перебор. Чтобы проверить подвержен ли файл с SHA1 быстрому подбору коллизии, можно воспользоваться инструментом sha1collisiondetection, разработанным Marc Stevens (CWI) и Dan Shumow (Microsoft) и доступным на GitHub. Если это подтверждается, достаточно перекомпилировать файл и проверить его снова.

В данный момент для подписания файлов используется в основном только алгоритм SHA2, а сертификаты подписываются только SHA2 (детальнее см. раздел 1.6 «Двойная подпись»).

Время, начиная с которого сертификаты с хешем SHA1 признаются не крипто-стойкими, указано в ветке реестра (на Win 8.1 и выше):
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config\Default => WeakSha1ThirdPartyAfterTime (FILETIME)
Для SHA1 – это дата 01.01.2016.
Для MD5 – это дата 01.03.2009.

Подписи файлов, поставленные с использованием этих алгоритмов позже указанной даты, будут считаться недействительными.
Детальнее, см. Microsoft TechNet. Protecting Against Weak Cryptographic Algorithms.


1.3. Что означает, легитимна ли подпись?

Эта подпись должна быть выдана центром сертификации (Certification authority (CA)), чей сертификат находится в хранилище доверенных корневых сертификатов (TRCA), либо вшит в системные файлы, являющиеся частью механизма проверки.
Вы можете увидеть TRCA через оснастку certmgr.msc

1.3.1.certmgr.jpg


Соответственно, одного их этих CA можно увидеть в цепочке доверия в свойствах файла => вкладка «Цифровая подпись» => Сведения => Просмотр сертификата => Путь сертификации:

1.3.2.Root_Cert.jpg


Проверка подписи выполняется передачей идентификатора политики WINTRUST_ACTION_GENERIC_VERIFY_V2 в функцию WinVerifyTrust(). Эта политика выдвигает такие требования:

1) Все сертификаты вверх по цепочке доверия в подписанном файле должны также находиться и в хранилище доверенных корневых сертификатов.

Пример, когда часть сертификатов не являются доверенными:
1.3.3.Chain_Not_Trusted.jpg


2) Конечный сертификат должен иметь разрешение на подписание кода. Это отображено в поле «Назначение сертификата» (EKU).

1.3.4.EKU.jpg


3) Не вышел срок действия сертификата (за одним исключением*).
*Если на файл наложена подпись сервера штампа времени, то подпись файла будет действительна даже после истечения срока действия сертификата.
Иначе, вы увидите:
1.3.5.Expired.jpg


Легитимная подпись в свойствах файла выглядит таким образом:
1.3.5.Sign_Legit.jpg
 
Последнее редактирование:
1.4. Терминология, алгоритм подписания и проверки.

1.4.1. Что такое Authenticode (Code signing).
"Authenticode" (или «Code signing») означает, что сертификат предназначен для подписания кода, иначе говоря, программ и скриптов, а не документов, электронных писем, http интернет пакетов и тому подобного.

К файлам, содержащим код, относят такие форматы, как PE (.exe, .dll, .ocx, .sys, ...), VBScript (.vbs), JScript (.js), Cabinet-архивы (.cab), элементы панели управления (.cpl) и некоторые другие.

Рассмотрим поближе такие понятия как: хеш, алгоритм хеша, подпись, сертификат, отпечаток, выборка и т.п. (часть информации взята из ответов участников конференции StackExchange CBHacking и Tom Leek (в переводе, с авторской переработкой и дополнениями)).

1.4.2. Что такое хеш.

Хеш – это значение фиксированной длины, которое получено после выполнения набора арифметических операции над строкой, файлом или другим блоком данных. Грубо говоря, мы подаём на вход длинную строку, затем берём код каждого символа этой строки, складываем по определённому принципу (называемому алгоритмом хеша), и в результате получаем значение, обычно записываемое в 16-ричном виде.

Вот примеры наиболее распространённых хешей:

Алгоритм | длина фразы хеша (в символах) | размер хеша (в битах)
CRC32 | 8 | 32
MD5 | 32 | 128
SHA-1 | 40 | 160
SHA-256 | 64 | 256
SHA-384 | 96 | 384
SHA-512 | 128 | 512

Подробную таблицу сравнительных характеристик SHA вы можете посмотреть на wiki здесь и здесь.

Программно рассчитывать хеш можно, например, через CryptoAPI (пример) или Cryptography API: Next Generation (CNG) (пример).


1.4.3. Что такое выборка (дайджест).
Выборка (digest) – обычно подразумевает, что мы берём данные не целиком, а избирательно, только какую-то часть, которая и называется выборкой. Расположение этой части зависит от структуры данных и вида алгоритма, для которого эта выборка используется.

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

1.4.3.Выборка_Authenticode.png


1.4.4. Что такое приватный и публичный ключи, симметричное и асимметричное шифрование.

Представьте себе шифрование по алгоритму Цезаря, где код каждого символа строки сдвигается на некоторое одинаковое количество пунктов (например, вперёд по алфавиту). Здесь ключом является – количество пунктов сдвига.

1.4.4.1.Caesar.jpg


Зная алгоритм и ключ, вы можете расшифровать такое сообщение.
Этот алгоритм называется симметричным, потому что один и тот же ключ используется и для шифрования, и для расшифровки.

Существуют и так называемые асимметричные алгоритмы, например, RSA. Здесь ключи для шифрования и дешифровки – разные. Т.е. ключ шифрования не подходит для расшифровки, и наоборот. Кроме того, невозможно рассчитать ключ шифрования, если у вас есть ключ дешифровки.

1.4.4.2.Private_Public_Keys.jpg


Представьте, что вам дали сообщение, зашифрованное ключом (он называется – приватный). Вы знаете, по какому принципу происходит шифрование, и у вас даже есть ключ (публичный), которым можно расшифровать сообщение. Но с помощью этого же ключа у Вас не получится снова зашифровать исходное сообщение, чтобы получить такую же шифро-фразу, потому как результат уже не расшифруется тем же ключом. Такова особенность асимметричных алгоритмов. Подробнее о них вы можете почитать в протоколе Диффи-Хеллмана-Меркла или посмотреть это видео:


Приватный ключ ещё называют закрытым (или секретным).
Публичный ключ также называют открытым и обычно свободно распространяют.

Поскольку алгоритм RSA весьма медленный, зачастую им не шифруют всё сообщение. Вместо этого используется один из симметричных алгоритмов, а RSA накладывают на сам ключ, использованный на первом этапе – в симметричном шифровании.

В контексте подписания и проверки цифровых подписей шифрование всего сообщение не нужно и не требуется. Вместо этого, RSA накладывается на хеш сообщения.

Итоговая схема:
ФАЙЛ => выборка => хеш + приватный ключ => шифрованный хеш.

1.4.5. Что такое сертификат, центр сертификации и цепочка доверия.

Сертификат связывает личность (издателя) с публичным ключом (который где-то имеет соответствующий приватный ключ). Сперва вы признаёте, что сертификат действителен – то есть содержащийся в нём ключ действительно принадлежит лицу или организации, которое он идентифицирует. Для защиты от подделки сертификаты также подписываются цифровой подписью.

Центр сертификации – это объект (обычно, организация), которой доверено выдавать сертификаты, утверждающие, что индивидуальный получатель, компьютер или организация, запрашивающие сертификат, выполняют условия установленной политики (подробнее: см. раздел 1.10 «Покупка сертификата»). Под политикой здесь обычно подразумевают, что центр сертификации подтвердил подлинность предоставленных получателем документов, которые его идентифицируют (имя, место проживания и т.п.).

Сертификат может быть подписан не напрямую центром сертификации, а промежуточным звеном, которому Центр предоставил права выдавать сертификаты. Это называется цепочкой доверия. Её можно проследить, изучив цифровую подпись сертификата:

1.4.5.Цепочка доверия.png


Сертификат считается легитимным, если он подписан (закрытым) ключом, соответствующим (публичному ключу) сертификата, которому вы доверяете. Соответственно, в цепочке доверия к самому первому (корневому) сертификату звена у вас должны быть установлены отношения доверия (в контексте исполняемых файлов Windows это означает, что такой сертификат должен быть помещён в корневое хранилище – см. подробнее далее в разделе 1.5.).

1.4.6. Форматы файлов сертификатов и ключей для Authenticode подписи и их преобразование.

а) Виды форматов.

Важным моментом с точки зрения безопасности является тот факт, что разные форматы сертификатов могут хранить только приватный ключ, только публичный, или оба из них.

Расширение имени файла | Формат | Типы ключей, которые содержит
.pfx, .p12 | PKCS # 12 | Приватный + Публичный
.spc | PKCS # 7 | только публичный (открытый)
.cer | X.509 (ASN.1 DER или Base-64 + PEM хидер) | только публичный (открытый)
.pvk | Microsoft PVK | только приватный (закрытый)
.key | сырой ключ | только приватный (закрытый)


PKCS # 12 и PKCS # 7 – это международные спецификации криптографии с открытым ключом.

Формат X.509 (его ещё называют сертификатом открытого ключа). Он состоит из таких частей:

1.4.6.X.509.png


Внутри каждого сертификата формата X.509 хранится пара Distinguished Names (DN) в формате X.500. Один DN принадлежит владельцу сертификата, а второй DN указывает идентификатор CA, подписавшей сертификат. В случае с self-signed сертификатом, оба эти DN указывают на владельца сертификата.

Distinguished Name задается в виде разделенных через запятую атрибутов, например:
«CN=Andrey Chesnokov, OU=dev64, O=dev64-wordpress, L=Unknown, ST=Unknown, C=RU»
«C=RU, PostalCode=115093, S=Moscow, L=Moscow, STREET="Street Serpukhovsko B, 44", O=RIVER SOLUTIONS, CN=RIVER SOLUTIONS»

Здесь отдельные атрибуты расшифровываются так:
CN — common name (уникальное имя владельца)
L — localityName (местоположение: город)
ST — stateOrProvinceName (название штата или провинции)
O — organizationName (имя организации)
OU — organizationUnit, department or division (департамент или отдел)
C — country, two-letter country code (двухбуквенный код страны)
STREET = streetAddress (адрес: улица)
DC = domainComponent (метка доменного имени)
UID = userid (идентификатор пользователя)

Часть из атрибутов может быть пропущено, например, присвоено значение Unknown.
Формат строки описан в RFC2253 и RFC1779.

Подробнее о внутренней структуре формата сертификата X.509 можно почитать в статьях:
X.509 — Википедия
Разбираем x.509 сертификат
Структура PKCS7-файла
RFC5280

Microsoft PVK – является недокументированным форматом, однако кое-что о его структуре можно почитать в этой заметке:
PVK file format

Примечательно, что на этапе генерации пары ключей, вам необходимо будет ввести пароль. Это дополнительная мера защиты. Приватный ключ шифруется одним из алгоритмов – 3DES, RC4 или RC2. Без знания пароля потенциальный злоумышленник, выкравший файл сертификата, не сможет воспользоваться приватным ключом.


б) Преобразование форматов.

Иногда возникает необходимость сконвертировать форматы сертификатов из одного в другой. Для этих целей вам могут пригодиться такие инструменты из состава Windows SDK, как pvk2pfx.exe, cert2spc.exe, а также openssl.

Примеры конвертации:
.cer => .spc
Код:
cert2spc.exe certificate.cer certificate.spc
.pvk + .spc => .pfx
Код:
pvk2pfx.exe -pvk key.pvk -pi "password" -spc certificate.spc -pfx certificate.pfx -po "password"
.pfx => зашифрованный .key (приватный ключ)
Код:
openssl.exe pkcs12 -in certificate.pfx -nocerts -out encrypted.key
.pfx => .cer (сертификат с публичным ключом)
Код:
openssl.exe pkcs12 -in certificate.pfx -clcerts -nokeys -out certificate.cer
Расшифровка приватного ключа (зашифрованного RSA):
Код:
openssl.exe rsa -in encrypted.key -text -out decrypted.key

Некоторые другие примеры командной строки преобразования форматов можно посмотреть в этой базе знаний Symantec.

Выше рассмотрены только сертификаты для подписания кода. Так, следует заметить, что например, для SSL-сертификатов существуют и другие форматы, например, .jks – Java Key Stroke – это хранилище открытых и закрытых ключей и сертификатов. Работать с ним можно с помощью инструмента keytool из состава Java Runtime Environment.

Пример для JKS -> DER см. в моей заметке: Как получить ЭЦП для подписания документов (для жителей Украины).

Вот ещё часть примеров для демонстрации возможностей openssl (взято отсюда):
PEM -> DER
Код:
openssl x509 -outform der -in certificate.pem -out certificate.der
PEM -> P7B
Код:
openssl crl2pkcs7 -nocrl -certfile certificate.cer -out certificate.p7b -certfile CACert.cer
PEM -> PFX
Код:
openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CACert.crt
DER -> PEM
Код:
openssl x509 -inform der -in certificate.cer -out certificate.pem
P7B -> PEM
Код:
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.cer
P7B -> PFX
Код:
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.cer
openssl pkcs12 -export -in certificate.cer -inkey privateKey.key -out certificate.pfx –certfile CACert.cer
PFX --> PEM
Код:
openssl pkcs12 -in certificate.pfx -out certificate.cer –nodes
 
1.4.7. Что такое подпись и подписание.

1.4.7. Signing_What.jpg


Подпись – это небольшое криптографическое волшебство, когда вы берёте маленький кусочек данных, которым почти всегда является криптографический хеш выборки от сообщения, файла или другого блока данных (что-то наподобие SHA-256), и затем выполняете над ним операцию (называемой «подписание») с использованием приватного ключа. Этот хеш шифруется и в результате мы получаем подпись, которая чаще всего содержит:
– имя издателя;
– отпечаток сертификата (чтобы можно было найти сертификат);
– проверенные и неудостоверенные атрибуты, например, время подписания, если присутствует кросс-подпись сервера точного времени;
– и другую информацию.

Затем эта подпись помещается либо в конец подписываемого файла, либо в другой файл (например, каталог безопасности), либо другим образом может быть передана извне.

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

В контексте исполняемых файлов Windows процесс происходит подобно такому сценарию: кто-то (допустим, Microsoft) компилирует исполняемый файл. Дальше в Microsoft хешируют этот файл, создавая нечто вроде выборки SHA256. Дальше они берут этот хеш и подписывают его с помощью приватного ключа, который есть только у Майкрософт. Файл распространяется и все, у кого есть публичный ключ от Майкрософт, смогут проверить, что именно Майкрософт подписала файл и что файл не был изменён с момента его подписания.

1.4.8. Что такое отпечаток (Thumbprint / Fingerprint).

1.4.8. Fingerprint.jpg


Отпечаток (Thumbprint или Fingerprint) – это выборка в виде криптографического хеша, которая обычно используется для того, чтобы найти ключ или сертификат.
Например, предположим, что у вас есть блок подписанных данных, для которых нет сертификата в комплекте. Проверять публичный ключ каждого сертификата, установленного в вашей системе, чтобы увидеть сможет ли он подойти для проверки подписи, будет медленно и глупо. Вместо этого, подпись почти наверняка будет содержать отпечаток, который идентифицирует сертификат с публичным ключом, необходимым для проверки этой подписи.

Отпечатки хранятся в сертификате вместе с самим ключом, хотя вы также можете просто хешировать ключ, чтобы получить отпечаток.

Другим примером может служить внешняя подпись исполняемых файлов, сделанная через каталог безопасности (.cat-файл). Файл каталога состоит из двух частей. Первый – это список хэшей выборки, то есть отпечатки других файлов. Вторая часть – это единая подпись для всех отпечатков. Таким образом, вы можете распространять кучу файлов (часть из которых могут быть не исполняемыми и вообще не иметь стандарта для их подписания), для которых вы хотите удостовериться, что получатель сможет проверить, что все они принадлежат вам и не были подделаны. Вы просто добавляете файл каталога (.cat), который содержит отпечатки каждого файла, и подписываете его вашим ключом.

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

1.4.9. Как проверяется подпись.

1.4.9.VerifySign.jpg


В целом, проверка подписи выполняется по такому сценарию:
1) поиск сертификата по отпечатку, указанному в подписи
2) расшифровка хеша из подписи с помощью публичного ключа, полученного из сертификата из п.1.
3) расчёт хеша выборки файла и его сравнение с расшифрованным хешем из п.2 (если совпадает, значит, файл не был модифицирован с момента его подписания).
4) сравнение цели (предназначения), для которой выполняется проверка подписи с целью, для которой разрешено использовать сертификат (в данном случае, преследуются 2 цели – защита файла от модификации, подтверждение имени издателя).
5) отдельно проверяется легитимность каждого из сертификатов по цепочке доверия, при этом корневой сертификат цепочки должен присутствовать в системном хранилище.
6) проверяется, что наступил и ещё не истёк срок действия сертификата
7) дополнительные проверки, зависящие от выбранного провайдера проверки, диктующего политику, например, проверка особых атрибутов, указывающих, что драйвер имеет WHQL-подпись.

Чтобы проверить подпись из-под консоли, вы можете воспользоваться моей утилитой SignVerify (sv.exe), программой SignTool из состава Windows SDK, либо утилитой Марка Руссиновича SigCheck:
Код:
SV "file.exe"
SigCheck "file.exe"
SignTool verify /v /pa "file.exe" (для проверки Authenticode-подписи)
SignTool verify /v /kp "file.sys" (для проверки подписи драйвера)

1.4.10. Чем отличаются понятия «алгоритм подписи», «алгоритм хеша подписи», «алгоритм хеша выборки», «алгоритм хеша отпечатка».

Алгоритм подписания – это последовательность действий, когда:

– подписант владеет парой публичный/приватный ключ. Публичный ключ является открытым, а приватный ключ – закрытым. Даже, несмотря на то, что оба ключа математически связаны друг с другом, невозможно перерасчитать приватный ключ, имея под руками публичный (именно поэтому публичный ключ можно безопасно распространять).
– на переданном входящем сообщении подписант использует свой приватный ключ, чтобы рассчитать подпись, которая будет неповторимой как для пары ключей подписанта, так и для входящего сообщения.
– механизм проверки, который получает на вход сообщение, подпись и публичный ключ, и затем отвечает: «да» (они совпадают) или «нет» (не совпадают).

Краеугольным камнем безопасности подписи является то, что не должно быть возможным без знания секретного приватного ключа генерировать пару «сообщение» + подпись, которая будет принята алгоритмом проверки.

Вы можете столкнуться с некоторыми «объяснениями», в которых пытаются сказать, что цифровые подписи – это своего рода шифрование. Там обычно говорят подобно этому: «вы выполняете шифрование с помощью приватного ключа». Не верьте этому. Эти объяснения неправильные и сбивают с толку. Шифруется только хеш выборки файла.

Разберём пример:

1.4.10.1.Fingerprint_Algo.png


Берётся выборка файла, которой является часть файла без подписи. Она хешируется по определённому математическому алгоритму. На изображении выше – использован алгоритм sha256. Это алгоритм хеша выборки (hash of digest). Затем этот хеш шифруется. Алгоритм шифрования – RSA. Ниже в поле «Значение» мы видим этот зашифрованный хеш (первые 2 байта – заголовок, признак sha256, остальные байты – сам хеш).

Алгоритм отпечатка (fingerprint / thumbprint) – часто встречается при обсуждении сертификатов. «Отпечаток» сертификата является результатом хэш-функции, применяемой к самому сертификату (в системах Windows используется хеш-функция SHA-1). Когда вы устанавливаете новый сертификат в корневое хранилище, то интерфейс Windows покажет вам именно этот отпечаток (16-ричные значения). Вы должны проверить, что он правильный (предположительно, вы сравниваете его с сопутствующим печатным документом, который содержит ожидаемый отпечаток корневого центра сертификации, или вы звоните администратору и называете ему шестнадцатеричные цифры для сверки). Отпечаток используется только для идентификации сертификата, но не проверки его подлинности.

1.4.10.2.Install_Root_CA.png


И наконец, когда Центр сертификации выдаёт вам сертификат с парой приватный/публичный ключ, здесь также используются алгоритмы хеширования и шифрования – это и называется алгоритмом хеша подписи сертификата. Если мы видим нечто вроде RSA/SHA-256, подразумевается, что ваш сертификат был сгенерирован с алгоритмом подписи RSA и алгоритмом хеш-функции SHA-256.

1.4.10.3.SignAlgo.png
 
Последнее редактирование:
1.5. Само-подписанный (self-signed) сертификат.

Само-подписанный (иначе говоря – само-выданный) сертификат означает, что вы выдали его сами для себя. Подписанный этим сертификатом файл не будет проходить проверку подлинности. Вы увидите сообщение «Цепочка сертификатов обработана, но обработка прервана на корневом сертификате, у которого отсутствует отношение доверия с поставщиком доверия»:

1.5.1.Not_trusted_sign.jpg


Это означает, что:
- исполняемая часть файла успешно прошла проверку целостности
- один из сертификатов цепочки доверия отсутствует в списке TRCA.

Однако, self-signed подписи имеют свои плюсы:
- вы можете убедиться, что файл не повреждён. Если файл повреждён, Вы увидите сообщение «Эта цифровая подпись не действительна»:

1.5.2.Signature damaged.jpg


Из минусов:
любой человек может изготовить такой же сертификат (с вашим именем в свойствах подписи). Правда, он будет иметь другой S/N и отпечаток (хеш-сумму).

Однако, вы можете заранее предоставить пользователю свой публичный сертификат (файл .cer). Если пользователь установит его в хранилище доверенных корневых сертификатов, Ваши программы на таких машинах будут успешно проходить проверку подлинности.

Пример добавления сертификата в TRCA:

1.5.3.Install_cert.jpg


Модуль modDigiSign.bas (из приложения к статье, см. раздел 3) позволяет рассматривать самоподписанные сертификаты как легитимные, если возвести флаг SV_AllowSelfSigned.


1.6. Двойная (вторичная) подпись.

С 2016 года Microsoft повысила минимальную планку для алгоритма хеша подписи сертификата, который будет считаться криптостойким от «взлома». ЭЦП файлов, подписанных начиная с 01.01.2016 с использованием сертификатов с хешем SHA1, считается недействительной.

Однако, старые системы (как XP/Vista) не умеют проверять новые ЭЦП с SHA256, даже если установить все последние обновления. Как результат, программа с легитимной подписью SHA256 вообще откажется запускаться (исключение: само-подписанные сертификаты):
1.6.1.Cannot_Verify_SHA256.png


*Одним из неофициальных способов принудительно запустить эту программу на старой ОС будет удаление подписи, см. раздел 1.9.

А драйвера с подписью SHA256 смогут работать на системах, начиная лишь с Windows 7 и то только, если установить обновления.

В целом, картина совместимости выглядит так (по данным GlobalSign):
1.6.2.SHA-OS-Compatibility.png


где первая строка – это алгоритм хеша, с которым подписан сертификат,
а /fd – алгоритм выборки хеша, которым будет подписан файл с помощью указанного сертификата*.

*подробнее о различиях – см. в разделах 2.4. Извлечение сертификатов и содержащейся в них информации (подпункты 3.1., 5.2.1.) и раздел 1.4.10. Терминология.

1.6.3.SHA-OS-Compatibility-2_ru.png


Чтобы подпись user-mode программы успешно проверялась во всех версиях ОС полезно подписывать файлы одновременно двумя подписями с разными хешами, как например это делает автор AIMP:

1.6.4.Twice_Sign_AIMP.jpg


Чтобы добавить вторичную подпись, укажите ключ /as в утилите signtool (требуется Windows SDK не ниже v.8.1). Пример команды:
Код:
signtool.exe sign /fd SHA256 /f "certificate.pfx" /p "password" /td SHA256 /tr "%timestamp%" /as "file.exe"
где /td – это предпочитаемый алгоритм хеша подписи сервера штампа времени.

Убедитесь, что сервер умеет распознавать требуемый хеш. В противном случае, принудительно указывайте нужный хеш, используя специально сформированный URL-адрес. Например:
Для SHA256:
Time Stamping Server - Powered by Kayako Help Desk Software
RFC 3161 Compliance
http://sha256timestamp.ws.symantec.com/sha256/timestamp

Для SHA1:
Time Stamping Server - Powered by Kayako Help Desk Software
RFC 3161 Compliance
http://timestamp.verisign.com/scripts/timstamp.dll

Для проверки вторичной подписи через модуль DigiSign.bas сперва получите кол-во подписей из поля NumberOfSigns, затем передайте флаг SV_CheckSecondarySignature при повторной проверке. Функция поддерживается только в Windows 8 и новее. Для получения количества подписей следует отключить проверку через каталог. Пример кода:
VB.NET / VBA:
Private Function VerifySecondarySign(sFile As String) As SignResult_TYPE
   
    Dim SignResult As SignResult_TYPE
   
    ' we should disable checking by catologue, because in that case number of signatures will be unavailable
    SignVerify sFile, SV_DisableCatalogVerify, SignResult
   
    If (SignResult.NumberOfSigns > 1) Then
   
        SignVerify sFile, SV_CheckSecondarySignature, VerifySecondarySign
    End If
End Function

По-умолчанию, модуль ‘modDigiSign’ сперва всегда проверяет подпись с хешем SHA256.
 
1.7. Способы подписания

Относительно физического расположения подписи выделяют 2 их варианта:

1) Внутренняя (embedded) подпись.

Вы можете проверить её присутствие, используя мою функцию IsSignPresent().
Для формата PE эта подпись расположена в структуре SecurityDir в Data_Directories секции Optional_PE_Header.
Более детальная информация доступна в официальной спецификации: MSDN: Microsoft Portable Executable and Common Object File Format Specification

Другие форматы файлов могут хранить подпись иначе. Например, для VBScript и JScript она добавляется в конец файла и выглядит так:

1.7.1.JS_sign.jpg


Такую подпись можно увидеть в свойствах файла на вкладке «Цифровая подпись».

2) Подписание через внешний cat-файл.

При использовании такого способа файл не модифицируется во время подписания. Вместо этого Authenticode хеш файла помещается в один из cat-файлов (так называемые каталоги безопасности), расположенные по пути: %SystemRoot%\system32\CatRoot\

Этим способом подписаны многие файлы Microsoft, а также все Plug and Play драйвера. Загрузочные драйвера должны обязательно иметь внутреннюю подпись. Но это не исключает возможности наличия у них параллельно подписи через каталог. Детальнее см.: MSDN: Embedded Signatures in a Driver File.

Файл, подписанный через каталог, может не пройти проверку подлинности после переноса на другую машину, т.к. его хеша может не оказаться в cat-файлах.

Давайте посмотрим на такую подпись поближе, используя Sysinternals SigCheck:

1.7.2.SignCheck_Cat.jpg


В этом примере вы можете сразу заметить, что файл c:\windows\write.exe имеет внешнюю подпись, т.к. указан путь к конкретному файлу каталога (.cat). Также, если вы зайдетё в свойства этого файла, то не увидите вкладки 'цифровая подпись'. Это означает, что внутренней подписи у файла нет. Однако, некоторые файлы могут содержать обе подписи.
Теперь взглянем на свойства соответствующего .cat файла, запустив его двойным щелчком мыши:

1.7.3.SecurCatalogue.jpg


Вы увидите, что один из тегов совпадает с хешем PE256 (так называемым Authenticode-хешем), файла 'write.exe':

1.7.4.Sigcheck_Hash.jpg


Этот хеш рассчитывается на основе всех секций исполняемого файла, кроме:
- поля с хешем PE
- секций «Таблицы сертификатов»
- «Атрибутов таблицы сертификатов».
Детальнее см. в спецификации: MSDN. Windows Authenticode Portable Executable Signature Format

Все cat-файлы также подписаны.


1.8. Перечисление сертификатов в хранилище

Список установленных сертификатов вы можете увидеть, открыв оснастку certmgr.msc

1.8.certmgr.png


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

Перечень важных корневых сертификатов можно найти в этой базе знаний.
Для перечисления обычно используют связку из API функций: CertOpenSystemStore /
CertEnumCertificatesInStore / CertGetNameString / CertGetCertificateContextProperty / CertCloseStore.
Этим способом я извлекал хеши предустановленных сертификатов Microsoft для пополнения базы.
В помощь: список имён хранилищ – MSDN: StoreName Enumeration
Пример программы на C++: MSDN: Example C Program: Listing the Certificates in a Store
Для VB6 в конце статьи есть программа CertEnumerator.


1.9. Удаление подписи.

1.9.RemoveSign.jpg


В некоторых особых случаях требуется удалить подпись.
Иногда SignTool отказывается заменять текущую подпись новой без удаления старой.
Кто-то преследует другие тестовые цели, как проверку влияния подписи на детектирование образца антивирусами и т.п.

Удаление обычно выполняют через связку API функций: ImageEnumerateCertificates / ImageRemoveCertificate. В этом случае, контрольная сумма PE будет восстановлена автоматически.

Примеры программы на C++ и VB6 есть в конце статьи (см. папку RemoveSign).


1.10. Покупка сертификата.

Есть несколько типов сертификатов, которые также отличаются по типам файлов, которые вы сможете ними подписать, например:

– Microsoft Authenticode
– Kernel Mode Signing
– Microsoft Office Vba Signing
– Java Code Signing
– Code Signing for Apple
– Adobe Air Signing
– Microsoft Windows Phone
– Android
– Qualcomm BREW
(подробнее см. статью: Code Signing сертификаты или сертификаты разработчика. Виды, как выбрать)

Обратите внимание, что некоторые сертификаты не позволяют подписывать драйвера, а другие – могут, но только начиная с Windows 8.
Некоторые обеспечивают возможность выполнить проверку легитимности файла только на ОС Windows Vista и новее, по той причине, что их корневой сертификат не предустановлен на более ранние ОС.

Для драйверов требуется сертификат "EV (extended validation)". Заодно он позволяет автоматически проходить проверку Smart Screen, но чтобы его оформить потребуется больше документов, а общая стоимость будет ~ в 2 раза дороже обычного сертификата. Словом, на данный момент EV уже не выдают частным лицам, а только организациям.

Так что перед покупкой Вам стоит оценить все подобные факторы, подробно расспросить поставщика, почитать отзывы и т.п.

В дополнение, можете ознакомиться с двумя хорошими статьями от Олега Казакевича:
Приобретение цифрового сертификата для подписи драйвера (частное лицо)
Инструкция: подписывание драйверов для Windows 10 (EV)
Первая написана давно, так что правила для некоторых фирм уже изменились, а в остальном информация очень полезная и познавательная.
Вторая статья подразумевает, что Вы уже приобрели сертификат EV и испытываете трудности с правильной последовательностью действий при подписании драйвера.
 
Последнее редактирование:
Назад
Сверху Снизу