
1. 项目概述为什么我们需要自签名驱动程序如果你在Windows上尝试安装一个自己开发的硬件驱动或者测试一个第三方未签名的驱动大概率会碰到那个令人头疼的黄色感叹号系统弹窗冷冰冰地告诉你“Windows无法验证此驱动程序的发布者”。这背后是微软从Windows Vista时代开始强化的驱动程序强制签名策略。简单说微软要求所有在内核模式也就是能直接和硬件、系统核心打交道的深层权限下运行的驱动程序都必须由一个受微软信任的证书颁发机构CA签发的证书进行数字签名。这个机制就像给驱动程序发了一张“良民证”系统通过验证这张“证”的真伪和有效性来判断这个驱动是否可信、是否被篡改过。那么自签名驱动证书就是为了解决我们这些开发者和测试者在“良民证”办下来之前或者根本不想办的临时身份问题。购买一个受微软信任的、能用于内核模式代码签名的EV代码签名证书不仅流程繁琐、需要公司资质而且价格不菲。对于个人开发者、学生、或是公司内部在真机上进行驱动测试和调试的阶段自签名证书就成了一个必不可少的工具。它允许我们在自己可控的测试机器上安装并运行我们自己编译的驱动程序而不用每次都去折腾禁用驱动强制签名那需要修改BIOS/UEFI设置既麻烦又不安全。这个过程的核心就是创建一套我们自己的“私人印章”自签名根证书然后用它来给我们的驱动“盖戳”签名最后让我们的电脑信任这个“私人印章”将根证书安装到受信任的根证书颁发机构存储。听起来有点绕但实际操作起来借助Windows SDK里的工具和PowerShell流程可以非常清晰。2. 核心工具链与环境准备在开始动手之前我们需要把“厨房”准备好。整个自签名流程主要依赖两个核心工具集Windows SDK特别是其中的签名工具和PowerShell。别被吓到你不需要安装一整个Visual Studio。2.1 必备工具安装与验证首先确保你的系统是Windows 10或Windows 11。然后我们需要获取Windows SDK。最轻量化的方式是直接下载并安装“Windows SDK for Windows 10/11”的独立安装包。在安装时你只需要勾选“Windows Software Development Kit”以及其下的“Signing Tools for Windows”这一个功能即可。这样安装后你会在C:\Program Files (x86)\Windows Kits\10\bin\版本号\x64这样的路径下找到我们后续要用到的关键工具makecert.exe较旧但某些场景简单、certmgr.exe以及更现代的signtool.exe和pvk2pfx.exe。不过对于全新的Windows 11或较新的Win10系统我更推荐直接使用系统内置的PowerShellNew-SelfSignedCertificatecmdlet和SignTool它可能已随Visual Studio Build Tools或SDK安装。你可以打开一个管理员权限的PowerShell窗口通过以下命令快速检查关键工具是否可用# 检查SignTool是否在环境变量中 where.exe signtool # 检查PowerShell证书模块是否可用 Get-Command -Name New-SelfSignedCertificate -ErrorAction SilentlyContinue如果signtool命令找不到你需要将SDK的bin目录比如C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64添加到系统的PATH环境变量中或者后续在使用时指定完整路径。注意所有与证书创建、签名相关的操作强烈建议在管理员权限的PowerShell中进行。因为安装证书到受信任的根存储区需要管理员权限否则你会遇到“拒绝访问”的错误。2.2 理解证书存储与密钥容器在动手创建证书前花两分钟理解两个概念会让你后续操作更清晰证书存储Windows像一个文件柜把不同类型的证书分门别类放在不同的“抽屉”里这些“抽屉”就是证书存储。我们最关心两个“受信任的根证书颁发机构”Cert:\LocalMachine\Root和“个人”Cert:\LocalMachine\My。根证书要放进“受信任的根”抽屉系统才会信任由它签发的所有东西而用于签名的具体证书包含私钥通常放在“个人”抽屉。密钥容器与私钥保护证书包含公钥而对应的私钥是签名行为的关键必须妥善保护。在创建证书时私钥可以生成在软件密钥容器里相对方便或者使用硬件安全模块HSM等更安全的方式。对于测试用途软件容器足够。你需要知道私钥的访问密码如果有的话signtool签名时会用到。3. 创建自签名根证书与代码签名证书这是整个流程的第一步也是奠定信任基础的一步。我们将创建一个自签名的根证书CA然后用这个根证书去签发一个具体的代码签名证书。为什么分两步模仿了真实世界的PKI体系结构清晰也便于管理例如一个根证书可以签发多个不同用途的子证书。3.1 使用PowerShell创建证书这是目前最推荐的方式无需额外工具直接使用PowerShell内置命令清晰且强大。# 以管理员身份运行PowerShell # 1. 为当前用户创建一个自签名根证书CA证书 # -DnsName 指定主题名称这里我们起名为“MyPrivateRootCA” # -KeyUsage 指定证书用途CertSign表示可用于签发其他证书CRLSign用于吊销列表签名 # -KeyUsageProperty All 允许所有密钥用法 # -KeyAlgorithm指定算法为RSA-KeyLength 2048指定密钥长度 # -HashAlgorithm指定哈希算法为SHA256 # -KeyExportPolicy Exportable 允许私钥可导出重要方便备份和转移到其他机器 # -CertStoreLocation 指定证书存储位置为当前用户的“个人”存储 $rootCert New-SelfSignedCertificate -Type Custom -KeySpec Signature -Subject “CNMyPrivateRootCA” -KeyUsage CertSign, CRLSign, DigitalSignature -KeyUsageProperty All -KeyAlgorithm RSA -KeyLength 2048 -HashAlgorithm SHA256 -KeyExportPolicy Exportable -CertStoreLocation “Cert:\CurrentUser\My” -NotAfter (Get-Date).AddYears(10) # 设置10年有效期 Write-Host “根证书指纹” $rootCert.Thumbprint # 2. 将根证书导出为.cer文件仅公钥用于分发和安装到“受信任的根” $rootCertPath “Cert:\CurrentUser\My\$($rootCert.Thumbprint)” Export-Certificate -Cert $rootCertPath -FilePath “.\MyPrivateRootCA.cer” # 3. 使用刚创建的根证书签发一个代码签名证书 # -Signer 参数指定用哪个证书来签发即我们的根证书 # -TextExtension 设置增强型密钥用法必须包含代码签名1.3.6.1.5.5.7.3.3 # -KeyUsage DigitalSignature 指定密钥用法为数字签名 $codeSignCert New-SelfSignedCertificate -Type CodeSigning -KeySpec Signature -Subject “CNMyDriverCodeSign” -KeyUsage DigitalSignature -KeyAlgorithm RSA -KeyLength 2048 -HashAlgorithm SHA256 -KeyExportPolicy Exportable -CertStoreLocation “Cert:\CurrentUser\My” -Signer $rootCert -TextExtension (“2.5.29.37{text}1.3.6.1.5.5.7.3.3”) -NotAfter (Get-Date).AddYears(5) Write-Host “代码签名证书指纹” $codeSignCert.Thumbprint # 4. 将代码签名证书连同其私钥导出为.pfx文件密码保护 # 这个.pfx文件是给signtool用来签名的关键文件 $securePassword ConvertTo-SecureString -String “YourStrongPassword123!” -Force -AsPlainText Export-PfxCertificate -Cert $codeSignCertPath -FilePath “.\MyDriverCodeSign.pfx” -Password $securePassword执行完以上脚本你会在当前目录得到两个文件MyPrivateRootCA.cer根证书公钥和MyDriverCodeSign.pfx代码签名证书及私钥有密码保护。请务必妥善保管.pfx文件和密码私钥泄露等同于你的签名权泄露。3.2 传统方式使用MakeCert和Pvk2Pfx备用方案如果你的环境非常老或者遇到PowerShell命令兼容性问题可以使用Windows SDK中的传统工具。但请注意makecert已被标记为弃用。REM 以管理员身份打开CMD并切换到SDK工具目录如 REM cd “C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64” REM 1. 创建根证书的私钥(.pvk)和证书(.cer) makecert -r -pe -n “CNMyPrivateRootCA” -ss Root -sr LocalMachine -sky signature -sv MyRootCA.pvk MyRootCA.cer REM 执行上述命令后会弹出窗口让你设置私钥的保护密码请牢记。 REM 2. 使用根证书创建一个代码签名证书 makecert -pe -n “CNMyDriverCodeSign” -ss MY -sr LocalMachine -sky signature -eku 1.3.6.1.5.5.7.3.3 -iv MyRootCA.pvk -ic MyRootCA.cer MyDriverCodeSign.cer REM 3. 将.cer和.pvk合并成.pfx文件signtool需要的格式 pvk2pfx -pvk MyRootCA.pvk -spc MyRootCA.cer -pfx MyRootCA.pfx -pi 你的私钥密码 pvk2pfx -pvk MyDriverCodeSign.pvk -spc MyDriverCodeSign.cer -pfx MyDriverCodeSign.pfx -pi 你的私钥密码实操心得PowerShell方案是首选它更现代与系统集成更好避免了图形界面弹窗易于脚本化自动化。传统工具链在涉及复杂属性设置时可能更灵活但对于标准的驱动自签名PowerShell完全够用。务必记录下证书的指纹Thumbprint或保存好.pfx文件路径下一步要用。4. 安装证书并配置系统信任创建了证书只是做好了“印章”现在需要让系统认识并信任这个“印章”。4.1 安装根证书到“受信任的根证书颁发机构”这是最关键的一步。系统必须信任我们的自签名根证书CA才会信任由它签发的任何子证书包括我们的驱动签名证书。方法一通过证书管理器MMC图形界面安装推荐给新手按Win R输入mmc回车打开管理控制台。点击“文件” - “添加/删除管理单元”。在左侧列表找到“证书”点击“添加”。选择“计算机账户”点击“下一步”然后选择“本地计算机”点击“完成”-“确定”。在控制台左侧展开“证书本地计算机”右键点击“受信任的根证书颁发机构” - “所有任务” - “导入”。在导入向导中浏览并选择你刚才生成的MyPrivateRootCA.cer文件。后续步骤全部点击“下一步”或“完成”直到导入成功。方法二通过PowerShell命令安装适合自动化# 以管理员身份运行PowerShell $rootCertPath “.\MyPrivateRootCA.cer” Import-Certificate -FilePath $rootCertPath -CertStoreLocation Cert:\LocalMachine\Root执行后你可以通过Get-ChildItem Cert:\LocalMachine\Root | Where-Object {$_.Subject -eq “CNMyPrivateRootCA”}来验证根证书是否已成功安装。4.2 确认代码签名证书在“个人”存储中如果你按照第3节的PowerShell脚本操作代码签名证书已经自动安装到了当前用户的“个人”存储Cert:\CurrentUser\My。对于驱动签名有时需要将其安装到本地计算机的“个人”存储。你可以通过MMC控制台添加“计算机账户”的证书管理单元查看“个人”存储或者用PowerShell移动/导入# 从当前用户存储获取证书对象 $codeSignCert Get-ChildItem Cert:\CurrentUser\My | Where-Object {$_.Subject -eq “CNMyDriverCodeSign”} | Select-Object -First 1 # 导出为.pfx再导入到本地计算机存储如果尚未存在 if ($codeSignCert) { $tempPfxPath “$env:TEMP\tempCodeSign.pfx” $securePassword ConvertTo-SecureString -String “YourStrongPassword123!” -Force -AsPlainText Export-PfxCertificate -Cert $codeSignCert -FilePath $tempPfxPath -Password $securePassword Import-PfxCertificate -FilePath $tempPfxPath -CertStoreLocation Cert:\LocalMachine\My -Password $securePassword -Exportable Remove-Item $tempPfxPath }注意事项将根证书安装到“受信任的根证书颁发机构”是一个全局性的、高权限操作。这意味着任何由你这个根证书签发的软件在本机上都会被系统视为可信。因此这个根证书和对应的私钥必须严格保管仅限于测试环境使用绝不能泄露或用于生产环境签名分发给他人的软件。5. 使用SignTool为驱动程序文件签名现在“信任链”已经建立我们可以开始给实际的驱动程序文件通常是.sys、.dll、.exe或.cat文件签名了。signtool.exe是微软官方的签名工具功能强大。5.1 为单个驱动文件签名假设你有一个编译好的驱动程序文件MyDriver.sys并且你的代码签名证书.pfx文件在当前位置。# 切换到包含signtool和驱动文件的目录或在命令中使用完整路径 $signtoolPath “C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe” $driverFile “.\MyDriver.sys” $pfxFile “.\MyDriverCodeSign.pfx” $pfxPassword “YourStrongPassword123!” # 基本签名命令 $signtoolPath sign /fd SHA256 /f $pfxFile /p $pfxPassword $driverFile # 更完整的命令添加时间戳推荐即使证书过期签名在时间戳时刻仍有效 $signtoolPath sign /fd SHA256 /f $pfxFile /p $pfxPassword /tr http://timestamp.digicert.com /td SHA256 $driverFile参数解析sign执行签名操作。/fd SHA256指定文件摘要算法为SHA256。SHA1已不安全务必使用SHA256。/f指定包含私钥的证书文件.pfx格式。/p提供.pfx文件的密码。/tr指定时间戳服务器的URL。这是一个极其重要的选项。它会在签名中嵌入一个来自第三方权威时间戳服务器的“时间戳”。这样即使你的签名证书在未来过期了系统也会根据时间戳判断在证书有效期内做的签名仍然是有效的。没有时间戳证书一过期签名立即失效。/td SHA256指定时间戳请求的摘要算法也使用SHA256。5.2 为驱动程序包.inf和.cat签名对于通过.inf文件安装的驱动通常需要对驱动包进行签名而不仅仅是单个.sys文件。这涉及到创建目录文件.cat并对其进行签名。创建目录文件.cat目录文件是一个包含了驱动包内所有文件哈希值的集合文件。可以使用Inf2Cat.exe工具同样在Windows SDK中来生成。$inf2catPath “C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\inf2cat.exe” $driverDir “.\DriverPackage\” # 你的驱动包目录内含 .inf 文件 $inf2catPath /driver:$driverDir /os:10_X64 /verbose/os参数指定目标操作系统如10_X64表示Win10/11 64位。执行后会在驱动包目录生成一个.cat文件。为目录文件.cat签名使用signtool对生成的.cat文件进行签名命令与签名.sys文件类似。$catFile “.\DriverPackage\MyDriver.cat” $signtoolPath sign /fd SHA256 /f $pfxFile /p $pfxPassword /tr http://timestamp.digicert.com /td SHA256 $catFile修改.inf文件确保.inf文件中的[Version]节包含了正确的CatalogFile指向。[Version] ... CatalogFileMyDriver.cat签名完成后你可以右键点击.sys或.cat文件选择“属性” - “数字签名”选项卡查看签名详情确认签名者是你自己的证书并且签名有效、带有时间戳。6. 启用测试签名模式与安装驱动即使驱动已经正确签名在标准的Windows系统上默认仍然只接受由微软“Windows Hardware Developer Center”门户签发的、受信任的证书。为了让系统接受我们自签名的驱动需要启用“测试模式”。6.1 启用测试模式在管理员权限的PowerShell或CMD中执行bcdedit /set testsigning on执行后必须重启计算机。重启后你会在桌面右下角系统托盘时钟附近看到“测试模式”和Windows版本号的水印这表明测试模式已启用。在这个模式下系统允许安装由测试根证书即我们安装的MyPrivateRootCA签名的驱动程序。注意测试模式会降低系统的安全级别因为它允许未经过微软正式认证的驱动加载。仅应在专用的开发或测试机器上开启切勿在生产环境或个人日常使用的电脑上开启。6.2 安装已签名的驱动现在可以安装你的驱动了。有多种方法通过设备管理器如果有未知设备带感叹号右键“更新驱动程序软件” - “浏览我的计算机以查找驱动程序软件”选择包含已签名.inf和.cat文件的驱动包目录。使用PnPUtil命令行工具推荐这是最干净、可脚本化的方式。# 以管理员身份运行PowerShell pnputil /add-driver “.\DriverPackage\MyDriver.inf” /install这个命令会将驱动包添加到驱动存储区并尝试安装。使用pnputil /enum-drivers可以查看所有已安装的驱动包。如果一切顺利设备管理器中的感叹号会消失你的驱动将成功加载。你可以使用sc query 服务名或设备管理器的“驱动程序详细信息”来确认驱动文件路径和签名信息。7. 常见问题排查与实战技巧在实际操作中你几乎一定会遇到各种报错。这里整理了一份速查表帮你快速定位问题。问题现象可能原因排查步骤与解决方案签名时错误SignTool Error: No certificates were found that met all the given criteria.1..pfx文件路径或密码错误。2..pfx证书不包含代码签名增强密钥用法EKU。3. 证书不在指定的存储中。1. 检查文件路径和密码确保无误。可用certutil -dump -p 密码 pfx文件测试。2. 用certutil -dump查看证书详情确认有1.3.6.1.5.5.7.3.3 (Code Signing)。3. 尝试通过指纹从证书存储签名signtool sign /sha1 证书指纹 /tr ... 文件。安装驱动时提示“Windows 无法验证此设备所需的驱动程序的数字签名”1. 测试模式未开启或未生效。2. 根证书未正确安装到“受信任的根证书颁发机构”。3. 驱动文件签名无效或损坏。1. 运行bcdedit确认testsigning值为Yes并已重启。2. 在MMC中确认MyPrivateRootCA证书在“计算机账户”的“受信任的根证书颁发机构”存储中。3. 右键检查驱动文件属性中的数字签名是否有效签名链是否完整应显示到你的根CA。签名带有时间戳但系统仍提示签名证书过期时间戳服务器未响应或返回错误导致时间戳未成功嵌入。1. 检查网络连接。2. 尝试更换时间戳服务器URL如微软的http://timestamp.sectigo.com或http://timestamp.digicert.com。3. 使用signtool verify /pa /v 文件验证签名和时间戳详情。使用PnPUtil安装时失败错误代码0xE000024B驱动包的.cat文件签名无效或.inf文件中的CatalogFile指向错误。1. 重新对.cat文件进行签名并确保成功。2. 检查.inf文件确认CatalogFile后的文件名与实际.cat文件名完全一致。3. 尝试手动在设备管理器中指定安装看是否有更具体的错误信息。驱动加载成功但设备仍无法正常工作这是驱动本身的功能性问题与签名无关。1. 使用调试工具如WinDbg附加内核调试查看驱动加载日志和可能的BugCheck。2. 检查系统事件查看器eventvwr.msc中“Windows日志”-“系统”里是否有来自“DriverFrameworks-UserMode”或“Kernel-PnP”的错误事件。如何彻底清理测试环境需要移除驱动、证书并关闭测试模式。1. 使用pnputil /delete-driver 驱动包.inf的完整路径 /uninstall /force移除驱动包。2. 在MMC中从“受信任的根证书颁发机构”和“个人”存储中删除你导入的自签名证书。3. 运行bcdedit /set testsigning off并重启。独家避坑技巧时间戳服务器是生命线一定要用/tr参数。不同的时间戳服务器可能有不同的可用性和延迟准备2-3个备用如 DigiCert, Sectigo, GlobalSign。如果某个服务器失败换一个再试。证书指纹比文件更方便一旦将代码签名证书导入到系统的“个人”存储在signtool中使用/sha1或/sha256参数指定证书的指纹Thumbprint进行签名比每次都指定.pfx文件和密码更安全、更方便尤其适合自动化脚本。 $signtoolPath sign /fd SHA256 /sha1 “你的证书指纹” /tr http://timestamp.digicert.com /td SHA256 $driverFile交叉验证签名签名后养成用signtool verify /v /pa 文件命令验证的习惯。/pa参数使用默认验证策略输出会详细显示签名者、时间戳和整个证书链一目了然。虚拟机是你的最佳沙盒驱动开发与测试强烈建议在虚拟机如Hyper-V、VMware中进行。可以方便地做快照在签名、安装、测试出错时一键还原避免搞乱宿主机系统。INF文件细节确保.inf文件中的[Version]节CatalogFile指向正确且[SourceDisksNames]和[SourceDisksFiles]等节中的文件路径和名称与实际文件完全匹配一个字符的错误都可能导致安装失败。整个流程走下来你会发现驱动自签名的核心逻辑就是“创建信任链根CA-代码签名证书 - 让系统信任根安装根证书 - 用链中的证书签名驱动 - 在特定模式测试模式下允许加载”。理解了这个逻辑无论工具命令如何变化你都能从容应对。最后再次强调这套方法仅用于开发、测试和学习切勿将用自签名证书签名的驱动分发出去。