Signtool позволяет мне подписать код, но Set-AuthenticodeSignature говорит, что "сертификат не подходит для подписи кода"

У меня есть самоподписанный сертификат подписи кода (сделанный с указаниями этого ответа), и он отлично работает, когда я использую signtool.exe. Но если я попытаюсь подписать его с помощью Powershell, это не сработает.

Подписание с помощью значка

C:\>signtool sign /v /n "VetWeb" SetupRDPPermissions.ps1
The following certificate was selected:
    Issued to: VetWeb
    Issued by: VetWeb CA
    Expires:   Sat Dec 31 18:59:59 2039
    SHA1 hash: 84136EBF8D2603C2CD6668C955F920C6C6482EE4

Done Adding Additional Store
Successfully signed: SetupRDPPermissions.ps1

Number of files successfully Signed: 1
Number of warnings: 0

Подписание в Powershell

PS C:\> $cert = @(Get-Childitem cert:\CurrentUser\My | Where-Object -FilterScript {$_.Subject -eq 'CN=VetWeb'})[0]
PS C:\> Set-AuthenticodeSignature SetupRDPPermissions.ps1 $cert
Set-AuthenticodeSignature : Cannot sign code. The specified certificate is not suitable for code signing.
At line:1 char:26
+ Set-AuthenticodeSignature <<<<  SetupRDPPermissions.ps1 $cert
    + CategoryInfo          : InvalidArgument: (:) [Set-AuthenticodeSignature], PSArgumentException
    + FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.SetAuthenticodeSignatureCommand

PS C:\> $cert | format-list *


PSPath             : Microsoft.PowerShell.Security\Certificate::CurrentUser\My\84136EBF8D2603C2CD6668C955F920C6C6482EE4
PSParentPath       : Microsoft.PowerShell.Security\Certificate::CurrentUser\My
PSChildName        : 84136EBF8D2603C2CD6668C955F920C6C6482EE4
PSDrive            : cert
PSProvider         : Microsoft.PowerShell.Security\Certificate
PSIsContainer      : False
Archived           : False
Extensions         : {System.Security.Cryptography.Oid}
FriendlyName       :
IssuerName         : System.Security.Cryptography.X509Certificates.X500DistinguishedName
NotAfter           : 12/31/2039 5:59:59 PM
NotBefore          : 6/1/2012 1:49:31 PM
HasPrivateKey      : True
PrivateKey         : System.Security.Cryptography.RSACryptoServiceProvider
PublicKey          : System.Security.Cryptography.X509Certificates.PublicKey
RawData            : {48, 130, 1, 235...}
SerialNumber       : CF330347F35AC0B4427AFFA82DB51238
SubjectName        : System.Security.Cryptography.X509Certificates.X500DistinguishedName
SignatureAlgorithm : System.Security.Cryptography.Oid
Thumbprint         : 84136EBF8D2603C2CD6668C955F920C6C6482EE4
Version            : 3
Handle             : 479608336
Issuer             : CN=VetWeb CA
Subject            : CN=VetWeb

Почему я могу подписывать с помощью файла signtool.exe, но не Powershell?


P.S. запуск Get-Childitem cert:\CurrentUser\My -CodeSigningCert не возвращает результатов.

Ответ 1

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

makecert -n "CN=PowerShell Local Certificate Root" -a sha1 -eku 1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer -ss Root -sr localMachine

И затем персональный сертификат из вышеупомянутого центра сертификации с использованием

makecert -pe -n "CN=PowerShell User" -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk -ic root.cer

После создания используйте

$cert = @(Get-ChildItem cert:\CurrentUser\My -CodeSigning)[0]

для подписания (при условии, что у вас есть только один сертификат для кодов). Например, если имя script - xyz.ps1, используйте эту команду в PowerShell

Set-AuthenticodeSignature path/to/xyz.ps1 $cert

Ответ 2

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

Теперь, почему signtool может подписать, а не Set-AuthenticodeSignature, объяснение может быть в Введение в подписание кода Документ Microsoft.

Вот моя версия генерации авторитета сертификации:

# Gen-CACert.ps1
clear-host

$scriptBlock = {.\Makecert -n `"CN=PowerShell Authorite de certification`"  <# Sujet du certificat (conforme à la norme X50 #>`
                           -a sha1                                          <# Algorithme utilisé #>`
                           -eku 1.3.6.1.5.5.7.3.3                           <# Option du certificat (signature de code) #>`
                           -r                                               <# Certificat auto signé #>`
                           <# -ss `"$($args[0])`"                              Dossier de stockage du certificat #>`
                           -ss `"root`"                                     <# Dossier de stockage du certificat #>`
                           -sr localMachine                                 <# Magasin de stockage localmachine ou currentuser (defaut) #>`
                           -sv `"$($args[0]).pvk`"                          <# Nom du fichier contenant la clef privée #>`
                           `"$($args[0]).cer`"}                             <# Nom du fichier certificat #>

$PoshCARoot = "PoshCARoot"
Invoke-Command -ScriptBlock $scriptBlock  -ArgumentList $PoshCARoot

Вот моя версия генерации сертификата dev:

# Gen-DevCert.ps1
clear-host

$scriptBlock = {.\Makecert  -pe                            <# La clef privée est exportable #>`
                            -n `"CN=PowerShell Dev Team`"  <# Sujet du certificat (conforme à la norme X509 #>`
                            -a sha1                        <# Algorithme utilisé #>`
                            -eku 1.3.6.1.5.5.7.3.3         <# Option du certificat (signature de code) #>`
                            -ss `"My`"                     <# Dossier de stockage du certificat #>`
                            -sr currentuser                <# Magasin de stockage localmachine ou currentuser (defaut) #>`
                            -iv `"$($args[0]).pvk`"        <# Clef privée de l'autorité #>`
                            -ic `"$($args[0]).cer`"        <# Certificat de l'autorité #>`
                            `"$($args[1]).cer`"}           <# Nom du fichier certificat #>

$PoshCARoot = "PoshCARoot"
$PoshDevTeam = "PoshDevTeam"
Invoke-Command -ScriptBlock $scriptBlock  -ArgumentList $PoshCARoot,$PoshDevTeam

Ответ 3

Проблема заключается в том, что сертификат подписи искажен и отсутствуют правильные KU & EKUs. Я рекомендую использовать OpenSSL через openssl.cnf для генерации сертификатов.

  • Любой, кто нуждается в подписывающем сертификате, вероятно, имеет маршрутизатор с веб-администратором, может быть, NAS с веб-администратором, VPN-сервером и т.д., Каждый из которых должен иметь сертификаты SSL для шифрования TLS.
    • Лучшая политика - создать центральный самоподписанный ЦС, используя openssl через openssl.cnf, затем ICA для подписи кода (подписанный самоподписанным ЦС), который затем используется для подписи сертификата подписи кода.
      • Windows: установить OpenVPN (включая openssl-utils)
        • Добавить в PATH: C:\Program Files\OpenVPN\bin
      • BSD/Linux: Установить openssl || openssl-utils
  • Готовый файл openssl.cnf содержит всю информацию & требуются команды, начиная со строки 430
    • Создание CA требует 2 команды (создание и экспорт в PKCS12)
    • Для создания ICA требуется 3 команды (создать, подписать и экспортировать в PKCS12)
    • Для подписи Cert требуется 3 команды (создать, подписать и экспортировать в PKCS12)
      • Раздел "Сертификаты клиента" - это то, что используется для подписания сертификатов


OpenSSL KUs & EKUs


Сертификаты подписи кода должны иметь следующий набор:

  • keyUsage  = critical, nonRepudiation, digitalSignature
    
    • nonRepudiation
      • Сертификат может использоваться для подписи данных, как указано выше, но открытый ключ сертификата может использоваться для предоставления услуг, не вызывающих сомнений.
        • Это предотвращает ложное отрицание подписывающим лицом какого-либо действия
    • digitalSignature
      • Сертификат может быть использован для применения цифровой подписи
      • Цифровые подписи часто используются для аутентификации объекта и аутентификация источника данных с целостностью

  • extendedKeyUsage  = critical, codeSigning, msCodeInd, msCodeCom, mcCTLSign, timeStamping
    
    • codeSigning
      • Подписание кода
    • msCodeInd
      • Индивидуальная подпись кода Microsoft (authenticode)
    • msCodeCom
      • Подписание коммерческого кода Microsoft (authenticode)
    • mcCTLSign
      • Подписание списка доверия Microsoft
    • timeStamping
      • Надежная временная метка


Инструмент для подписи


PreReqs:

  1. Установить Windows SDK
  2. WinKey + R > sysdm.cpl> ОК
    • Дополнительно> Переменные среды...> Путь> Изменить...
  3. Добавить в PATH: C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\x64
    • Убедитесь, что \10\bin\10.0.15063.0\x64 отражает правильный путь для вашего ПК и усилителя; OS

Команды:

  1. set TS=http://sha256timestamp.ws.symantec.com/sha256/timestamp
    
    • Устанавливает переменную %TS% для следующей команды
  2. signtool sign /s my /fd SHA256 /ph /td SHA256 /tr %TS1% "Path\to\File"
    
    • sign
      • Подписывать файлы с помощью встроенной подписи
    • /s <name>
      • Укажите Магазин, который нужно открыть при поиске сертификата. По умолчанию это магазин "MY".
    • /fd
      • Определяет алгоритм дайджеста файла, который будет использоваться для создания подписей файлов. (По умолчанию SHA1)
    • /ph
      • Создавайте хэши страниц для исполняемых файлов, если они поддерживаются.
    • /td <alg>
      • Используется с переключателем /tr или /tseal для запроса алгоритма дайджеста, используемого сервером отметок времени RFC 3161.
    • /tr <URL>
      • Задает URL-адрес сервера меток времени RFC 3161. Если этот параметр (или /t) не указан, подписанный файл не будет иметь отметки времени. В случае сбоя метки времени выдается предупреждение. Этот переключатель нельзя использовать с переключателем /t.

PowerShell

  1. $Cert = Get-PfxCertificate -FilePath "Path\to\Signing\Cert"
    
    • Устанавливает переменную $Cert для следующей команды
  2. Set-Variable -Name TS -Value "http://sha256timestamp.ws.symantec.com/sha256/timestamp" -Scope "Global"
    
    • Устанавливает переменную $TS для следующей команды
  3. Set-AuthenticodeSignature -HashAlgorithm "sha256" -IncludeChain "all" -FilePath "File"  -Certificate $Cert -TimestampServer $TS
    
    • Set-AuthenticodeSignature
      • Добавляет подпись Authenticode в сценарий PowerShell или другие файлы.
    • -HashAlgorithm
      • Определяет алгоритм хеширования, используемый для вычисления цифровой подписи.
        • PS 2.0: алгоритм хеширования по умолчанию - SHA1
        • PS 3. 0+: алгоритм хеширования по умолчанию - SHA256
    • -IncludeChain <String>
      • Определяет, какие сертификаты в цепочке доверия сертификатов включены в цифровую подпись. NotRoot является значением по умолчанию. Допустимые значения для этого параметра:
        • Signer: Включает только сертификат подписавшего.
        • NotRoot: Включает все сертификаты в цепочку сертификатов, за исключением корневого центра.
        • All: Включает все сертификаты в цепочку сертификатов.
    • -Certificate <X509Certificate>
      • Указывает сертификат, который будет использоваться для подписи скрипта или файла. Введите переменную, в которой хранится объект, представляющий сертификат, или выражение, которое получает сертификат.
      • Чтобы найти сертификат, используйте Get-PfxCertificate или командлет Get-ChildItem на диске Certificate (Cert :). Если сертификат недействителен или не имеет полномочий для подписи кода, команда не выполняется.