ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Windows驱动开发:自签名证书原理与实战,解决驱动强制签名问题

Windows驱动开发:自签名证书原理与实战,解决驱动强制签名问题 1. 项目概述为什么我们需要自签名驱动程序如果你在Windows上开发过硬件驱动、虚拟设备或者一些需要深入系统底层的软件大概率遇到过那个令人头疼的黄色感叹号。设备管理器里你的硬件旁边赫然写着“Windows 无法验证此设备所需的驱动程序的数字签名”。在Windows Vista之后的64位系统上特别是开启了安全启动Secure Boot的Windows 10/11驱动强制签名策略Driver Signature Enforcement就像一道铁闸没有微软认证签名的驱动根本无法加载。对于个人开发者、测试工程师或者企业内部开发来说动辄数百甚至上千美元的EV代码签名证书以及漫长的微软WHQL认证流程在开发调试阶段既不现实也无必要。这时“自签名”就成了打通这堵墙的唯一钥匙。自签名驱动顾名思义就是自己给自己颁发的“通行证”。它不依赖微软或受信任的第三方证书颁发机构CA而是由开发者自己生成一个根证书并用这个根证书为驱动程序文件.sys, .cat, .inf等进行签名。然后我们将这个自生成的根证书手动安装到目标测试机器的“受信任的根证书颁发机构”存储区告诉系统“相信我这个证书是我发的用它签名的驱动都是安全的”。这样一来系统就会允许加载你签名的驱动。这个过程听起来有点“自己给自己盖章”的意味但在封闭的开发和测试环境中它是完全合法、高效且成本为零的解决方案。本文将手把手带你走通从证书创建、驱动签名到系统信任的完整流程并分享我踩过的那些坑和独家技巧。2. 核心工具链与原理拆解在动手之前我们必须理解参与这个流程的几个核心角色和它们之间的关系。这不是一个简单的“点一下按钮”的操作知其然更要知其所以然才能在未来遇到各种诡异问题时游刃有余。2.1 数字签名与证书链的底层逻辑驱动签名本质上是数字签名技术在软件分发领域的应用。其核心目的是完整性验证和身份认证。完整性验证确保驱动文件从签名后到安装前没有被任何人包括病毒或传输错误篡改。这是通过哈希算法实现的。身份认证告诉系统这个驱动是谁发布的。即使驱动完好无损系统也需要知道它是否来自一个可信的来源。这个过程依赖一个信任链根证书Root Certificate信任的起点。它是一对自生成的、长期有效的非对称加密密钥公钥和私钥。私钥必须绝对保密公钥则随证书分发。我们将根证书安装到系统的“受信任的根证书颁发机构”就等于告诉系统“凡是用这个根证书下属密钥签名的东西我都认。”代码签名证书Code Signing Certificate在实际商业签名中我们通常不会直接用根证书签名因为根证书太宝贵了。我们会用根证书签发一个专门用于代码签名的“子证书”。在自签名场景下为了简化我们常常直接使用一个“自签名的代码签名证书”它自己既是颁发者也是使用者。但从原理上你可以理解为它就是我们的“签名工具”。驱动文件签名用代码签名证书的私钥对驱动文件计算出的哈希值进行加密生成签名块并将签名块和证书本身一起嵌入到驱动文件或单独的.cat文件中。系统验证时用证书中的公钥解密签名得到原始哈希值再与当前文件计算出的哈希值对比。一致则通过完整性验证同时检查证书链是否最终追溯到一个受信任的根证书通过则完成身份认证。2.2 核心工具Windows SDK 与 PowerShell微软提供了一套完整的工具链来完成这些操作主要包含在Windows SDK和系统自带的PowerShell中。MakeCert.exe (已弃用但仍有参考价值)旧版SDK中的证书创建工具。虽然微软推荐使用更强大的New-SelfSignedCertificatePowerShell cmdlet但很多老旧教程仍在使用它。了解它有助于理解参数含义。Signtool.exe签名工具的核心。它位于Windows SDK的bin目录下负责实际执行签名操作。我们需要用它来为.sys、.dll、.exe或.cat文件添加数字签名。Inf2Cat.exe驱动程序开发中的关键工具。驱动程序包通常包含一个.inf安装信息文件。Inf2Cat会验证.inf文件的语法并根据其中指定的目标操作系统版本生成一个目录文件.cat。这个.cat文件才是最终需要被签名的对象它包含了驱动包内所有文件的哈希列表。PowerShell (New-SelfSignedCertificate)这是现代Windows中创建自签名证书的首选方式。它功能强大可以直接在系统中创建证书并存储到指定的证书存储区无需生成额外的.pfx或.cer文件当然也可以导出。注意对于纯粹的驱动签名我们主要与Signtool和证书打交道。Inf2Cat是在你从源代码构建驱动包时才需要的。如果你拿到的是一个已经编译好的.sys文件可能只需要直接签名.sys但如果是一个完整的驱动安装包包含.inf则通常需要签名.cat文件。2.3 证书存储区系统的“信任名单”Windows的证书管理器certmgr.msc将证书分类存放在不同的逻辑存储区理解它们至关重要个人My存放你拥有的、带有私钥的证书。我们自签名的代码签名证书带私钥通常先放在这里。受信任的根证书颁发机构Trusted Root Certification Authorities这是系统的“终极信任名单”。任何证书只要其根证书在此列表中该证书签名的内容就会被信任。我们的自签名根证书最终必须安装到这里对于测试机器。中间证书颁发机构Intermediate Certification Authorities在复杂的商业证书链中这里存放的是由根证书签发的中介证书。自签名场景下一般不涉及。核心流程概括在开发机上创建证书并签名驱动 - 将证书不含私钥导出为.cer文件 - 在测试机上将.cer文件导入“受信任的根证书颁发机构” - 安装驱动。3. 详细实操流程从零到驱动加载成功下面我将以在Windows 11开发/测试环境为例演示最常用的两种自签名流程。请确保你已安装最新版本的Windows SDK和对应的Windows驱动程序工具包WDK或者至少安装了Visual Studio它通常包含这些工具。3.1 方法一使用PowerShell创建证书并签名推荐这是目前最简洁、最“原生”的方法完全在PowerShell环境中完成。步骤1以管理员身份启动PowerShell右键点击开始菜单选择“Windows PowerShell (管理员)”或“终端 (管理员)”。所有证书操作都需要管理员权限。步骤2创建自签名根证书和代码签名证书我们将创建一个专用于代码签名的证书。在PowerShell中执行以下命令# 创建一个新的自签名证书用于代码签名并存储在“个人”存储区 $cert New-SelfSignedCertificate -Subject CNMyDevelopmentRootCA # 证书主题CN是通用名可自定义 -KeyUsageProperty Sign # 密钥用途签名 -KeyUsage DigitalSignature # 密钥用法数字签名 -KeyAlgorithm RSA # 密钥算法RSA -KeyLength 2048 # 密钥长度2048位安全且兼容性好 -HashAlgorithm SHA256 # 哈希算法SHA256必须使用SHA256或以上 -CertStoreLocation Cert:\LocalMachine\My # 存储位置本地计算机的个人存储 -Type CodeSigningCert # 证书类型代码签名证书 # 将证书同时添加到“受信任的根证书颁发机构”仅限开发机 $rootStore New-Object System.Security.Cryptography.X509Certificates.X509Store(Root, LocalMachine) $rootStore.Open(ReadWrite) $rootStore.Add($cert) $rootStore.Close() Write-Host 证书已创建并添加到受信任根证书区。指纹: $($cert.Thumbprint) -ForegroundColor Green关键参数解析-Subject “CN…”这是证书的标识名。CNCommon Name最好包含有意义的名称如公司或项目名。-KeyLength 20482048位RSA是当前安全与兼容性的平衡点。4096位更安全但有些旧工具或系统可能支持不佳。-HashAlgorithm SHA256必须使用SHA256或SHA384、SHA512。Windows从某个版本开始已禁止用SHA1签名的驱动加载。-CertStoreLocation “Cert:\LocalMachine\My”证书创建在“本地计算机”的“个人”存储区。相比“当前用户”存储这能让所有用户访问到该证书更适合开发环境。重要警告上述命令将证书同时加入了“受信任的根证书颁发机构”。这仅适用于你的开发机对于其他测试机你应该只导出公钥证书.cer再手动导入其“受信任的根证书颁发机构”而绝不在测试机上生成或拥有私钥。步骤3找到你的证书指纹创建成功后记下输出的Thumbprint指纹它是一个40位的十六进制字符串如a1b2c3d4e5f67890123456789012345678901234。你也可以通过以下命令查看Get-ChildItem -Path Cert:\LocalMachine\My -CodeSigningCert | Format-List Subject, Thumbprint, FriendlyName步骤4使用Signtool为驱动文件签名首先找到signtool.exe。它通常在C:\Program Files (x86)\Windows Kits\10\bin\版本号\x64\或x86目录下。为了方便可以将其路径加入系统环境变量PATH或者直接使用完整路径。假设你的驱动文件是mydriver.sys在包含该文件的目录下打开PowerShell执行# 使用证书指纹进行签名 C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe sign /fd SHA256 /sha1 YOUR_CERT_THUMBPRINT mydriver.sys # 或者使用证书主题名称如果唯一 # C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe sign /fd SHA256 /n CNMyDevelopmentRootCA mydriver.sys签名参数解析sign执行签名命令。/fd SHA256指定签名文件时使用的摘要算法必须与证书哈希算法匹配或更高推荐统一用SHA256。/sha1 指纹通过证书指纹指定使用哪个证书进行签名。这是最精确的方式。/n “主题名”通过证书的主题名指定。如果存储区有多个相似主题的证书可能出错。/tr 时间戳服务器URL和/td SHA256这是强烈建议添加的参数用于添加时间戳。即使你的证书过期带有有效时间戳的签名在签名时刻仍然是有效的。例如/tr http://timestamp.digicert.com /td SHA256。一个更健壮的签名命令示例 C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe sign /fd SHA256 /sha1 a1b2c3d4e5f67890123456789012345678901234 /tr http://timestamp.digicert.com /td SHA256 mydriver.sys步骤5验证签名签名完成后务必验证 C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe verify /v /kp mydriver.sys/v详细输出。/kp验证策略确保签名符合内核模式代码签名的要求。 如果看到“Successfully verified”字样并且哈希算法、证书链信息正确说明签名成功。3.2 方法二传统方式MakeCert Signtool虽然MakeCert已过时但在一些特定环境或遵循老旧指南时可能还会遇到。了解它有助于排错。步骤1创建自签名根证书你需要找到makecert.exe通常也在Windows SDK目录下。通过命令行管理员操作makecert -r -pe -n CNMyTestRootCA -ss CA -sr LocalMachine -a sha256 -cy authority -sv MyTestRootCA.pvk MyTestRootCA.cer-r创建自签名根证书。-pe将私钥标记为可导出。-n “CN…”证书主题。-ss CA证书存储名自定义为“CA”。-sr LocalMachine存储位置为本地计算机。-a sha256签名算法。-cy authority证书类型为颁发机构。-sv .pvk指定输出的私钥文件。最后是输出的公钥证书文件。执行过程中会提示你为私钥文件设置密码。步骤2创建代码签名证书由根证书签发makecert -pe -n CNMyTestCodeSigning -a sha256 -cy end -sky signature -ic MyTestRootCA.cer -iv MyTestRootCA.pvk -sv MyTestCodeSigning.pvk MyTestCodeSigning.cer-cy end证书类型为终端实体用于签名。-sky signature密钥用途为签名。-ic和-iv指定颁发者证书和私钥文件。步骤3将PVK和CER合并为PFX文件Signtool通常使用包含私钥的PFX文件进行签名。使用pvk2pfx.exe工具pvk2pfx -pvk MyTestCodeSigning.pvk -spc MyTestCodeSigning.cer -pfx MyCodeSigning.pfx -po mypfxpassword步骤4使用PFX文件签名signtool sign /fd SHA256 /f MyCodeSigning.pfx /p mypfxpassword /tr http://timestamp.digicert.com /td SHA256 mydriver.sys/f指定PFX文件路径。/pPFX文件的密码。步骤5将根证书MyTestRootCA.cer安装到测试机的“受信任的根证书颁发机构”这是让测试机信任你签名的关键一步。双击.cer文件选择“安装证书” - “本地计算机” - “将所有证书放入下列存储” - “浏览” - 选择“受信任的根证书颁发机构”。3.3 为完整驱动包.inf .sys签名如果你的驱动包含.inf文件最佳实践是签名目录文件.cat。步骤1使用Inf2Cat生成目录文件首先确保你的.inf文件语法正确且[Version]节中定义了正确的CatalogFile和DriverVer日期。然后在包含.inf文件的目录打开“适用于VS的x64/x86本机工具命令提示符”来自VS安装inf2cat /driver:. /os:10_X64/driver:.指定驱动文件所在目录为当前目录。/os:10_X64指定目标操作系统为Windows 10 64位。可以指定多个如/os:7_X64,8_X64,10_X64,11_X64。成功后会生成一个.cat文件。步骤2签名.cat文件使用signtool像签名.sys一样签名这个.cat文件。signtool sign /fd SHA256 /sha1 YOUR_CERT_THUMBPRINT /tr http://timestamp.digicert.com /td SHA256 mydriver.cat步骤3验证.cat签名signtool verify /v /kp mydriver.cat步骤4安装驱动现在你可以右键点击.inf文件选择“安装”。系统会检查关联的.cat文件的签名并因为其根证书已被信任而允许安装。4. 测试机部署与信任建立开发机上签名成功只是第一步。要让驱动在另一台干净的测试机上运行必须建立信任。操作流程从开发机导出根证书在开发机上打开certmgr.msc导航到“受信任的根证书颁发机构” - “证书”找到你创建的自签名根证书如MyDevelopmentRootCA。右键 - “所有任务” - “导出”。在导出向导中选择“不不要导出私钥”然后选择格式为“DER 编码二进制 X.509 (.CER)”最后指定导出路径和文件名如MyRoot.cer。将证书文件传输到测试机。在测试机上导入证书双击.cer文件点击“安装证书”。选择“本地计算机”点击“下一步”。选择“将所有证书放入下列存储”点击“浏览”。关键步骤选择“受信任的根证书颁发机构”点击“确定”然后完成导入。安装驱动现在测试机已经信任了你的根证书。你可以通过设备管理器更新驱动、右键安装.inf或使用pnputil命令来安装已签名的驱动包。重要安全提示自签名根证书是你的“万能钥匙”。务必妥善保管导出的.cer文件并绝不将包含私钥的.pfx文件或带私钥的证书存储区权限随意分发。测试完成后应从测试机的“受信任的根证书颁发机构”中删除此证书。5. 高级配置、排错与实战心得即使按照步骤操作你也可能会遇到各种问题。下面是我在多年实践中总结的常见坑点和解决方案。5.1 禁用驱动程序强制签名临时测试在极端情况下你可能需要完全关闭驱动签名强制以进行调试。注意这会严重降低系统安全性仅限临时在测试机上使用且重启后可能失效或需要重新操作。方法A高级启动菜单Windows 10/11设置 - 更新与安全 - 恢复 - 高级启动立即重新启动。重启后选择“疑难解答” - “高级选项” - “启动设置” - 重启。重启后按F7键选择“禁用驱动程序强制签名”。方法B使用BCDEdit命令需要管理员权限# 禁用 bcdedit /set testsigning on bcdedit /set nointegritychecks on # 在某些系统上可能需要 # 启用 bcdedit /set testsigning off bcdedit /set nointegritychecks off执行后需要重启。桌面右下角会出现“测试模式”水印。5.2 常见错误与排查表错误现象可能原因解决方案SignTool Error: No certificates were found that met all the given criteria.1. 证书指纹或主题名错误。2. 证书不在指定的存储位置如用了/sm却证书在用户存储。3. 证书不满足用途如不是代码签名证书。1. 用Get-ChildItem Cert:\LocalMachine\My -CodeSigningCert确认指纹和主题名。2. 检查signtool是否用了/sm机器存储参数与证书实际存储位置匹配。3. 确保证书类型为Code Signing。SignTool Error: The specified PFX password is not correct.PFX文件密码错误。检查/p参数后的密码或重新生成PFX。Windows cannot verify the digital signature for the drivers...1. 测试机未安装对应的根证书。2. 签名算法过时如SHA1。3. 驱动文件在签名后被修改。1. 将根证书(.cer)导入测试机的“受信任的根证书颁发机构”。2. 使用/fd SHA256重新签名。3. 重新签名驱动文件。INF contains invalid catalog file....inf文件中CatalogFile指向的.cat文件不存在或未签名。使用inf2cat生成正确的.cat文件并完成签名。The hash algorithm is not compatible with the public key algorithm.证书密钥算法与签名哈希算法不兼容。创建证书时使用-KeyAlgorithm RSA和-HashAlgorithm SHA256签名时使用/fd SHA256。驱动安装成功但无法启动代码52驱动文件本身签名验证通过但驱动程序的映像可能因其他原因无效如依赖文件缺失、不兼容的Windows版本。检查系统事件查看器eventvwr.msc中系统日志的详细错误。使用WinDbg等工具进行内核调试。5.3 自动化与集成实践对于频繁的驱动构建和测试手动操作效率太低。这里分享一个我常用的PowerShell脚本框架可用于自动化签名流程# AutoSignDriver.ps1 param( [string]$DriverPath ., [string]$CertThumbprint YOUR_CERT_THUMBPRINT_HERE, [string]$TimestampUrl http://timestamp.digicert.com ) $SignToolPath C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe function Sign-File { param([string]$FilePath) Write-Host 正在签名: $FilePath -ForegroundColor Yellow $SignToolPath sign /fd SHA256 /sha1 $CertThumbprint /tr $TimestampUrl /td SHA256 $FilePath if ($LASTEXITCODE -ne 0) { Write-Host 签名失败: $FilePath -ForegroundColor Red exit 1 } Write-Host 验证签名: $FilePath -ForegroundColor Yellow $SignToolPath verify /v /kp $FilePath if ($LASTEXITCODE -ne 0) { Write-Host 验证失败: $FilePath -ForegroundColor Red exit 1 } Write-Host 成功: $FilePath -ForegroundColor Green } # 签名所有.sys文件 Get-ChildItem -Path $DriverPath -Filter *.sys | ForEach-Object { Sign-File -FilePath $_.FullName } # 如果有.cat文件也签名 $catFile Get-ChildItem -Path $DriverPath -Filter *.cat if ($catFile) { Sign-File -FilePath $catFile.FullName } Write-Host 所有驱动文件签名完成 -ForegroundColor Cyan你可以将此脚本集成到CI/CD流水线如Azure DevOps, Jenkins的构建后步骤中实现驱动编译后的自动签名。5.4 关于时间戳的深刻教训我曾经因为忽略时间戳在证书过期后导致所有已签名的驱动在全新系统上都无法安装。时间戳服务器的作用是记录你执行签名操作的那个时间点。即使你的签名证书在2024年1月1日过期只要你的驱动是在此日期之前例如2023年12月1日签名的并且签名时添加了有效的时间戳那么系统在验证时会检查“签名时刻”证书是否有效而不是“安装时刻”。因此永远使用时间戳签名。除了上面用的DigiCert还有其他公共时间戳服务器http://timestamp.sectigo.comhttp://timestamp.comodoca.comhttp://timestamp.globalsign.com/scripts/timestamp.dll在signtool中使用/tr参数指定。如果某个服务器不可用可以尝试换一个。5.5 内核模式与用户模式签名的细微差别我们主要讨论的是内核模式驱动.sys的签名它要求最严格。对于用户模式的驱动程序或普通应用程序.exe, .dll签名流程基本相同但验证策略宽松一些。例如某些用户模式组件可能在没有签名的情况下也能运行但会有SmartScreen警告而内核驱动没有有效签名则根本无法加载。在签名时内核驱动更强调使用/kp参数进行验证并确保哈希算法符合Windows硬件兼容性计划的要求。6. 从自签名到生产签名路径与考量自签名是开发和测试的利器但绝不能用于公开发布。要分发驱动你必须获得受微软信任的代码签名证书。标准代码签名证书来自受信任的CA如DigiCert, Sectigo。适用于普通应用程序和部分用户模式驱动。但自Windows 10 1607版起对于新的内核模式驱动仅此证书已不够。扩展验证EV代码签名证书这是发布内核模式驱动和通过微软WHQL认证的必需品。EV证书的私钥存储在硬件加密设备如USB令牌中安全性极高。购买EV证书后你可以用它来签名驱动并将其提交给微软进行WHQL测试。通过后驱动将获得微软的正式数字签名可以在所有开启安全启动的Windows系统上无缝安装。Windows Hardware Compatibility Program (WHQL)这是微软官方的硬件兼容性测试和签名程序。使用EV证书签名驱动提交后微软会进行一系列测试。通过后你的驱动会被加入微软的官方驱动目录并通过Windows Update自动分发。这是驱动分发的“黄金标准”。个人经验之谈在项目早期用自签名快速迭代原型和进行内部测试。当驱动功能稳定准备进行外部Beta测试或小范围分发时可以考虑购买标准代码签名证书如果只是用户模式或直接上EV证书如果是内核模式。在提交WHQL之前务必使用EV证书在所有目标Windows版本上进行充分的签名和测试因为EV证书的签名行为与自签名在某些边缘情况下可能有细微差别。整个自签名的熟练过程实际上为你后续操作生产证书打下了坚实的基础因为工具signtool和核心概念证书链、时间戳是完全相通的。
返回列表