Signtool允许我签署代码,但Set-AuthenticodeSignature说“证书不适合代码签名”

时间:2012-06-07 17:47:35

标签: powershell code-signing signtool

我有自签名代码签名证书(使用this answer的说明制作),当我使用signtool.exe时,它可以正常工作。但是如果我尝试使用Powershell进行签名,则会失败。

使用signtool签名

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不会返回任何结果。

3 个答案:

答案 0 :(得分:9)

我有同样的问题,我想出的答案是我必须create two certificates。首先,使用

建立受信任的根证书颁发机构
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]

用于签名(假设您只有一个代码签名证书)。例如,如果脚本的名称是xyz.ps1,请在PowerShell中使用此命令

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

答案 1 :(得分:3)

根据get-help certificate -CodeSigningCert来自证书提供商的动态参数仅获取具有代码签名权限的证书。

现在为什么signtool可以签名而不是Set-AuthenticodeSignature,解释可能在Introduction to Code Signing 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

这是我的开发版证书版本:

# 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

答案 2 :(得分:0)

问题是签名证书格式错误,错过了正确的KU&amp; EKUs。我个人建议通过openssl.cnf使用OpenSSL来生成证书。

  • 任何需要签名证书的人都可能拥有带有网络管理员的路由器,可能是带有网络管理员的NAS,VPN服务器等等,所有这些都应具有用于TLS加密的SSL证书。
    • 使用openssl通过openssl.cnf创建中心自签名CA的最佳策略,然后创建用于代码签名的ICA(由自签名CA签名),其中然后用来签署代码签名证书。
    • 最简单地安装最新版本的OpenVPN客户端(https:// openvpn.net/index.php/open-source/downloads.html)实用程序,其中包含openssl-utils
      • 添加到路径:C:\Program Files\OpenVPN\bin
  • 我的GitHub有一个pre-built openssl.cnf,其中包含信息部分,其中包含所有必需的命令,从第430行开始
    • CA创建需要2个命令(创建并导出到PKCS12)
    • ICA创建需要3个命令(创建,签名和输出到PKCS12)
    • 签名证书需要3个命令(创建,签名和输出到PKCS12)
      • 客户端证书部分是用于签署证书的

OpenSSL KU&amp; EKUs

代码签名证书应具有以下设置:

  • keyUsage = critical, nonRepudiation, digitalSignature

    • nonRepudiation
      • 证书可用于签署上述数据,但证书公钥可用于提供不可否认服务
      • 这可以防止签名实体错误地拒绝某些操作
    • digitalSignature
      • 证书可用于应用数字签名
      • 数字签名通常用于实体身份验证&amp;完整的数据源身份验证
  • extendedKeyUsage = critical, codeSigning, msCodeInd, msCodeCom, mcCTLSign, timeStamping

    • codeSigning
      • 代码签名
    • msCodeInd
      • Microsoft个人代码签名(authenticode)
    • msCodeCom
      • Microsoft商业代码签名(authenticode)
    • mcCTLSign
      • Microsoft Trust List Signing
    • timeStamping
      • 受信任的时间戳

签名工具

PreReqs:

  1. 安装Windows SDK
  2. 导航至:控制面板\所有控制面板项目\系统&gt;高级系统设置&gt;环境变量...&gt;路径&gt;编辑...
  3. 将以下内容添加到PATH:
    • C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\x64
      • 确保\10\bin\10.0.15063.0\x64反映PC的正确路径
  4. 命令:

    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>
        • 指定在搜索证书时打开的商店。默认为&#34; MY&#34;商店。
      • /fd
        • 指定用于创建文件签名的文件摘要算法。 (默认为SHA1)
      • /ph
        • 如果支持,则为可执行文件生成页面哈希值。
      • /td <alg>
        • *与/tr / tseal 开关一起使用,以请求RFC 3161时间戳服务器使用的摘要算法。*
      • /tr <URL>
        • 指定RFC 3161时间戳服务器的URL。如果未指定此选项(或/t),则签名文件将不会加时间戳。如果时间戳失败,则会生成警告。此开关不能与/t开关一起使用。
    3. 的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签名添加到Windows PowerShell脚本或其他文件中。
        • -HashAlgorithm
          • 指定用于计算数字签名的散​​列算法。
            • PS 2.0:Windows默认哈希算法为SHA1。
            • PS 3.0:Windows默认哈希算法为SHA256。
        • -IncludeChain <String>
          • 确定证书信任链中的哪些证书包含在数字签名中。 NotRoot是默认值。此参数的可接受值为:
            • Signer 仅包含签名者的证书。
            • NotRoot 包含证书链中的所有证书,但根权限除外。
            • All 包含证书链中的所有证书。
        • -Certificate <X509Certificate>
          • 指定将用于对脚本或文件进行签名的证书。输入一个变量,用于存储表示证书的对象或获取证书的表达式。
          • 要查找证书,请使用Get-PfxCertificate或使用证书(Cert :)驱动器中的Get-ChildItem cmdlet。如果证书无效或没有代码签名权限,则命令失败。