2025-09-16

為 Powershell Script (*.ps1) 或自行編譯的執行檔 (*.exe) 建立自我信任的數位簽章

以下使用的環境為以 Windows Server 建立的Standalone CA,Enterprise CA 大同小異
首先建立一個憑證範本,用以提交 Code Signing Request 給 CA
其中藍字部分改為自己需要的內容
將其存檔為 CodeSigning.inf (純文字檔)
[Version]
Signature="$Windows NT$"

[NewRequest]
Subject = "CN=Dino9021 Code Signing, OU=IT, O=DinoClub, L=Hsinchu, S=Taiwan, C=TW"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = FALSE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
RequestType = PKCS10
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"

[Extensions]
2.5.29.37 = "{text}"
_continue_ = "1.3.6.1.5.5.7.3.3" ; Code Signing EKU
[NewRequest] 區段各設定值說明
Subject:
憑證主體名稱,通常格式為 CN=名稱,也可以加上 OU=部門,O=公司,C=國家 等。

KeySpec:
金鑰用途
1 表示簽章(AT_SIGNATURE)
2 表示加密(AT_KEYEXCHANGE)
KeyLength:
金鑰長度,建議使用 2048 或以上

Exportable:
是否允許匯出私密金鑰:TRUE 表示可以匯出(例如匯出成 PFX)

MachineKeySet:
是否將金鑰儲存在本機(電腦)憑證存儲區:FALSE 表示儲存在使用者憑證存儲區

SMIME:
是否用於 S/MIME 電子郵件加密:通常設為 FALSE

PrivateKeyArchive:
是否允許私密金鑰備份(通常用於 Key Recovery):FALSE 
UserProtected:
是否要求使用者在使用金鑰時確認(例如使用者介面提示):FALSE

UseExistingKeySet:
是否使用現有金鑰:FALSE 表示建立新金鑰

RequestType:
憑證申請格式:PKCS10 是最常見的格式

ProviderName:
加密服務提供者(CSP):例如 Microsoft RSA SChannel Cryptographic Provider,這是支援 RSA 的 CSP
[Extensions] 區段各設定值說明
2.5.29.37:
EKU 的 OID(Object Identifier)
1.3.6.1.5.5.7.3.3:
表示 Code Signing 的用途
接著執行 CMD 指令,產生憑證要求檔案 CodeSigning.req :
certreq -new CodeSigning.inf CodeSigning.req
將憑證要求送至 CA :
certreq -submit CodeSigning.req
過程中會要求選擇 CA :

選好按 OK 後會返回擱置序號 :
RequestId: 91
RequestId: "91"
Certificate request is pending: Taken Under Submission (0)
發行憑證 :
certutil -resubmit 91
取得憑證 :
certreq -retrieve 91 CodeSigning.cer
取得憑證指紋 (Fingerprint)
certutil -dump CodeSigning.cer | findstr /c:"Cert Hash(sha1)" 
=> Cert Hash(sha1): 88 71 d5 a7 f3 06 1d 11 7c 61 5e bb 0e fd 49 b1 b6 35 fe b8
安裝憑證 :
certreq -accept CodeSigning.cer
匯出包含私鑰的憑證成為 .pfx 檔,要給一個私鑰密碼 MyStrongPassword
$certPath = "Cert:\CurrentUser\My\8871d5a7f3061d117c615ebb0efd49b1b635feb8"
$outputPath = "CodeSigning.pfx"
$pfxPassword = ConvertTo-SecureString -String "MyStrongPassword" -Force -AsPlainText
Export-PfxCertificate -Cert $certPath -FilePath $outputPath -Password $pfxPassword -ChainOption EndEntityCertOnly
以上為憑證產生的步驟

以下為簽章環境與步驟
  • 根憑證必須被信任是基本
  •  CodeSigning.pfx 檔複製到負責簽章的電腦,並安裝到 LocalMachine 的 Personal 中
    (安裝到 CurrentUser 也可以,但安裝到 LocalMachine 後續會比較方便)
  • 將 CodeSigning.cer 檔複製到負責簽章的電腦,並安裝到 CurrentUser 的 Trusted Publishers 中
  • 為 Powershell Script (.ps1) 簽章:
    $Cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq '8871d5a7f3061d117c615ebb0efd49b1b635feb8' }
    Set-AuthenticodeSignature -FilePath 'ScriptToSign.FullName' -Certificate $Cert -TimestampServer "http://timestamp.digicert.com"
    Get-PfxCertificate:
    讀取 PFX 憑證
    Set-AuthenticodeSignature:
    對指定檔案進行 Authenticode 簽章
    -TimestampServer:
    加入時間戳,避免憑證過期後簽章失效
  • 為執行檔 (.exe) 簽章:
    • 取得 Windows SDK 下載安裝檔
    • 安裝時只需要選擇 Windows SDK Signing Tools for Desktop Apps 即可
    • 簽章指令:
      "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe" sign /sha1 "8871d5a7f3061d117c615ebb0efd49b1b635feb8" /sm /s MY /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 "C:\Work\HelloWorld.exe"
      • sign:
        指定要對檔案進行簽章
      • /sha1 FingerPrint:
        使用 SHA-1 指紋碼來選擇憑證(這是憑證的唯一識別碼)
      • /sm /s MY:
        指定使用 LocalMachine 儲存區(系統層級)而非 CurrentUser
        如果要指定使用 CurrentUser 儲存區而非 LocalMachine 要改為 /s MY (前面沒有 /sm)
      • /fd SHA256:
        檔案摘要演算法 指定用來簽署檔案的摘要演算法,SHA256 是目前建議使用的安全演算法
      • /tr http://timestamp.digicert.com:
        時間戳記伺服器 使用 RFC 3161 標準的時間戳記伺服器,確保簽章在憑證過期後仍有效
      • /td SHA256:
        時間戳記摘要演算法 指定時間戳記使用的摘要演算法,通常與 /fd 相同
      • "C:\Work\HelloWorld.exe":
        要簽章的執行檔路徑
以下為程式執行環境要求:

        CodeSigning.cer 必須安裝到執行程式電腦 個人憑證存放區域 Trusted Publishers

沒有留言:

張貼留言