November 2025

S M T W T F S
       1
2345678
9101112131415
16171819202122
23242526272829
30      

Style Credit

Expand Cut Tags

No cut tags
Tuesday, September 20th, 2016 08:04 pm
Драйвер под ОС Windows, начиная с 64битной Висты должен быть подписан. Я имею в виду kernel mode driver. Иначе доброе ядро его даже не попытается загрузить и напишет в EventLog про невозможность это сделать.
Понятно, что для тестовых применений можно сделать self signed сертификат, добавить его в trusted, попинать bcdedit дабы добавить тестовую конфигурацию или например грузиться под дебаггером. Ниже для памяти освещены ключевые моменты. Обработка ошибок по понятным причинам выкинута.


Например сделать сертификат можно так:

%W7BASE%\bin\x86\MakeCert.exe -r -pe -sv xxx_testsign.pvk -n "CN=XXX Test Sign Certificate" xxx_testsign.cer
нажать на кнопку NONE в диалоге создания, потом запустить
%W7BASE%\bin\x86\pvk2pfx.exe -pvk xxx_testsign.pvk -spc xxx_testsign.cer -pfx xxx_testsign.pfx
А добавить его куда надо, на машинке для опытов -- так:
(Надо быть Администратором)
%W7BASE%\bin\x86\CertMgr.exe /add xxx_testsign.cer /s /r localMachine root
%W7BASE%\bin\x86\CertMgr.exe /add xxx_testsign.cer /s /r localMachine trustedpublisher

На PC разработчика тогда надо будет сделать сначала так:
(PrivateCertStore -- это имя, которое мы придумали сами. Нужно оно нам будет, чтобы ссылаться на него при подписывании. Можно написать просто My -- тогда положат сертификат в дефолтный юзерский стор)
CertUtil -user -importPFX PrivateCertStore xxx_testsign.pfx NoRoot
Здесь у Вас спросят пароль -- и если при генерации нажата была кнопка None -- можно смело жать Enter, иначе -- вспоминаем введенный пароль.
Ну и собственно подписывание выглядит вот так

%W7BASE%\bin\x86\Signtool sign /s PrivateCertStore /n XXX /t http://timestamp.verisign.com/scripts/timestamp.dll <Имя файла что подписываем>

Где XXX -- это часть имени, по которому будут искать сертификат. Если вы нагенерили мильён сертификатов с похожими именами, возможно вместо /n XXXX использовать /sha1 AAABBBA1237183761864381 -- SHA1 Thumbprint Вашего любимого сертификата

В копилку полезностей:
Проверить root мы или не root в .bat скрипте можно например вот так:

call :isAdmin
if NOT %errorlevel% == 0 (
echo Please run this script as Administrator
goto exit
)

:isAdmin
fsutil dirty query %systemdrive% >nul
exit /b

Ну и, чтобы два раза не вставать -- bcdedit и его лобызания:

Так можно разрешить тестовые подписи:
bcdedit /copy {current} /d "_TESTSIGN_ON_" > %temp%\tmpVHDGUID.txt
FOR /F "tokens=7 delims=. " %%A in (%temp%\tmpVHDGUID.txt) DO set GUID=%%A
bcdedit /set %GUID% TESTSIGNING ON
Что здесь происходит -- Копируем текущую конфигурацию. Ей назначается некий GUID. Вычёсываем этот GUID и говорим, что для него TESTSIGNING ON

Для дебага телодвижений меньше. Просто копируем текущий бутрекорд в новый, с гордым именем _DEBUG_ON_:
Хинт: Все остальные галочки для дебага можно легко и непринужденно натыкать, вызвав msconfig.exe и выбрав вновь созданный бутрекорд.
bcdedit /copy {current} /d "_DEBUG_ON_"


Но мы сейчас не о разработке, а о релизе. И здесь есть нюансы.

Нюанс №1. Сертификат. Нужно пойти и потратиться на EV Code Signing Certificate. На момент написания -- не на любой EV сертификат, а на сертификат от Symantec (дороже) или DigiCert (дешевле). В любом случае на три года это не менее 1000 зеленых денег.

Этот сертификат будет нужен для общения с Microsoft. Дело в том, что начиная с Win10 билд 1607 для того, чтобы ядро загрузило драйвер, он должен быть подписан самим Microsoft, не меньше. Т.е. раньше достаточно было, чтобы у Вашего драйвера была валидная Code Signing подпись от одного из многих сертификатчиков и добавленный Cross Certificate, который заруливал цепь доверия от сертификатчика в Microsoft. Сейчас нет. Есть исключения для давно приобретенных сертификатов, которые еще не протухли, но в общем случае -- нет.
Как это работает на практике:
Сертификатчики присылают EV сертификат на физическом носителе. Предполагается, что теперь всё, его надо хранить как девственность и выдавать под роспись.
Далее, Вы идете на sysdev.microsoft.com и регистрируете там Company Account. Это двухэтапная процедура.
1) Заводим учетную запись Майкрософт -- рекомендую завести ее на свое корпоративное мыло, то есть при ее создании не жать "Получить новый адрес электронной почты", а ввести имеющийся, корпоративный. Так Вы сможете отделять свою личную учетку (если она есть\будет) от корпоративной.
2) Регистрируем сам Company Account. При этом Вам дадут скачать исполняемый файл, который надо будет подписать той самой EV подписью и выслать обратно товарищам из Sysdev. Далее будет куча соглашений -- здесь консультируемся с корпоративным юристом кто именно уполномочен в Вашей организации с ними соглашаться -- и на выходе Ваша компания появится в списке компаний, к которым можно "присоединиться", а Вы становитесь админом, к которому прилетают просьбы о присоединении.

С этого момента Ваши коллеги, "присоединившиеся" так сказать, к компании, и Вы в том числе, получаете счастливую возможность воспользоваться "File signing services" и таки подписать Ваш пакет драйверов подписью от MS.
На вход сия система принимает CAB файл в котором лежат Ваши драйверы. Структура его должна быть следующей:
Driver1
     driver1.sys
     driver1.inf
Driver2
     driver2.sys
     driver2.inf

Обратите внимание -- CAT файлов нет -- парни из Sysdev сгенерят их в процессе подписывания. Если положите свои -- их просто выкинут.
Если у Вас драйвер, при установке которого Inf не нужен -- это никого не интересует. Inf должен быть. Например такой:

[Version]
Signature                = "$Chicago$"
Class                    = "LegacyDriver"
ClassGuid                = {8ECC055D-047F-11D1-A537-0000F8753ED1}
DriverPackageType        = KernelService
Provider                 = "Your Company Name"
DriverVer                = "09/25/2016","1.0.0.7"
CatalogFile              = XXXX.cat
[DefaultInstall]
CopyFiles = Setup.CopyFiles
[DefaultInstall.Services]
AddService = XXXX,,Setup.AddService
[SourceDisksFiles]
XXXX.sys = 1
[SourceDisksNames]
1 = "Disk"
[DestinationDirs]
DefaultDestDir = 12
[Setup.CopyFiles]
XXXX.sys
[Setup.AddService]
ServiceName   = XXXX
DisplayName   = "Some display name"
Description   = "Some description"
ServiceType   = 1 ; SERVICE_KERNEL_DRIVER
StartType     = 1 ; SERVICE_SYSTEM_START
ErrorControl  = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\XXXX.sys
[Strings]

Никаких поддиректорий. Inf переделываете, чтобы он не рассчитывал ни на какую вложенность директорий. И поддерживал ровно одну архитектуру.
При этом, если Вы собираетесь поддерживать 2 архитектуры -- делаете 2 CAB'а. Такое вот удобство.
А на выходе, если все пошло нормально, вы получите _ВНЕЗАПНО_ не cab, а zip c подписанными бинарями и сгенеренными CAT файлами.

Чуть не забыл. Если всё пошло _не_ нормально -- никаких уведомлений, ничего, просто процесс не завершится в разумные сроки (около 15 минут). В этом случае надо писать в саппорт (sysdev@microsoft.com), они ответят и пришлют логи.

Это так называемый Attestation Signing. На выходе Вы получите пакет драйверов, который сможет запускаться на Win10 _и только на ней_. При этом типе подписывания Вам придется согласиться с тем, что Вы драйвер потестировали, он работает нормально, и если в MS начнут сыпаться баги по этому драйверу Вы обязываетесь их иногда разгребать.

Если вдруг Ваш продукт предназначен не исключительно для Win10 (Кто бы мог предположить?) то здесь начинается нюанс №2.

Как уже упоминалось, парни из Sysdev подпишут Вам драйвер только для 10 версии Windows. На 8 или 8.1 например, да и на предыдущих -- он не запустится.
выходов как водится 2, один другого краше.
1) Гонять WHQL\HCL\<как бишь там их еще> тесты, сабмитить результаты Sysdev для каждой поддерживаемой OS и гордо получать подпись -- этот путь может позволить себе, нуэээ, не каждый.
2) Иметь 2 пэкеджа с драйверами, один для 10+, второй для всех остальных

Пункт 2 я освещу подробнее (если у Вас отдел тестирования состоит из 10+ человек можете поручить ему освоить вариант №1, но будьте готовы к сюрпризам).

Итак, нам надо "просто подписать драйвер" для ОС начиная с WinXP SP3 до Win8.1.
Если Ваш диапазон уже -- Вам повезло, можете часть балетных па пропустить.

Вариант 1) У Вас уже есть сертификат, которым Вы подписывали всё раньше, тк давно занимаетесь этим делом и он еще не протух -- Вуаля, подписываете им как и раньше и радуетесь жизни.

Вариант 2) У Вас только свежепойманный EV сертификат

Вариант 3) У Вас есть только что купленный non-EV code signing certificate

Вариант 3 может быть существенно более удобен нежели вариант 2 тк позволяет иметь несколько копий сертификатов по разным машинам. В остальном по сути они не отличаются.
Итак. Как подписать драйвер, чтобы он нормально запустился на всем озвученном зоопарке ОС? Что при этом надо иметь в виду?

1) XP и Vista32 при загрузке драйвера не проверяют подпись вообще, так что Ваш драйвер загрузят и без нее. Но с предупреждением _при установке_ про "Родина в опасности". Так что лучше подписать.

2) В один прекрасный день алгоритм хеширования SHA1 вышел из моды, сертификатчики перешли на выпуск SHA256 и SHA384 сертификатов. А Vista64 об этом предупредить забыли. Как результат Vista не в состоянии проверить SHA256 подпись. Win7 при рождении тоже ничего не знала о SHA256, но появился спасительный KB3033929. В общем если подписать драйвер Вашим новым, 256битным сертификатом, он не загрузится на 64битной висте и на семерке без апдейтов. Ну и всё что до семерки будет предупреждать пользователя о риске беспорядочной половой жизни.

3) Microsoft периодически выступает с заявлениями вроде "С 1 Апреля 1812 года мы перестанем доверять SHA1 сертификатам вообще", правда в действие эти угрозы пока не приводили.

Что делать?

В WDK\DDK от Win10 Signtool научился _добавлять_ подписи к уже имеющимся. Это прорыв товарищи. Итак нам нужно дважды подписать наш драйвер. Первый раз SHA1 сертификатом, второй раз SHA256. В обоих случаях не забываем про ключ /ac и _правильный_ кросс сертификат.
Где взять SHA1 сертификат? Сертификатчики обычно совершенно безвозмездно, т.е. даром, выдают SHA1 сертификат в комплект к SHA256, но делают это не по умолчанию, а по запросу. Пишем сертификатчикам письмо, получаем SHA1 сертификат.
Обращаю внимание, это будет полностью другой сертификат с полностью другим thumbprint'ом и цепочкой доверия. И ему нужен будет _другой_ кросс сертификат.

Итак, имеем у себя SHA256 и SHA1 сертификаты. Подписываем всё примерно так:

set SHA256_CROSS_CERTIFICATE=/ac crosscertforyourcert256.crt
:: there is a lot of timestamping servers, use any SHA256 timestamping server here, preferably the one from your cert authority
set SHA256_TIMESTAMPING_SERVER=/tr http://timestamp.comodoca.com/rfc3161
set SHA256_CERT_THUMBPRINT=/sha1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
set SHA1_CROSS_CERTIFICATE=/ac crosscertforyourcertSHA1.cer
:: again, use any SHA1 timestamping server, best choice is your CA's server
set SHA1_TIMESTAMPING_SERVER=/t http://timestamp.comodoca.com
set SHA1_CERT_THUMBPRINT=/sha1 YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
"%W10TOOLS%\Signtool" sign %SHA1_CROSS_CERTIFICATE% %SHA1_TIMESTAMPING_SERVER% %SHA1_CERT_THUMBPRINT% yourfile
:: /as flag means "append signature", the order of signatures is important
"%W10TOOLS%\Signtool" sign %SHA256_CROSS_CERTIFICATE% %SHA256_TIMESTAMPING_SERVER% /fd sha256 /td sha256 /as %SHA256_CERT_THUMBPRINT% yourfile


Вот примерно так всё и происходит с подписыванием релиза. А как развлекаетесь Вы?