Microsoft管理控制台(MMC)中的证书管理单元可以在Windows机器上构建PKCS #10证书请求,无需任何额外软件。本指南将逐屏讲解代码签名证书的向导操作,并从大多数旧教程遗漏的部分开始:2023年6月1日,代码签名私钥的规则发生了变化,这一变化决定了MMC生成的请求是否可用。
在打开向导之前,请先阅读这项要求。本指南其余部分假定你已经知道你的订单走哪条路线。
代码签名密钥必须在硬件上生成
根据CA/浏览器论坛代码签名基准要求,自2023年6月1日起生效,每个公开信任的代码签名证书的私钥必须在符合至少FIPS 140-2 Level 2、Common Criteria EAL 4+或同等标准的硬件加密模块中生成、存储和使用。这涵盖标准证书(组织验证和个人验证)以及扩展验证证书。EV代码签名证书原本就是这样运作的;2023年的变化将同样的规则扩展到了标准产品。
该要求同时也规定了密钥本身的规格。RSA密钥必须至少为3072位,ECDSA密钥必须使用NIST P-256、P-384或P-521曲线,SHA-1不允许用于代码签名证书。
同样重要的是,证书颁发机构必须证明密钥确实存放在硬件中,使用该要求列出的方法之一。实际操作中,你会遇到以下几种方式:
- CA向你邮寄一个硬件令牌,该令牌上已经存有CA在该设备上生成的密钥对。
- 你使用制造商的证书对请求进行反签名,这就是密钥证明(key attestation)的含义:证明该密钥是在符合规范的设备内以不可导出的方式创建的。
- 你使用CA指定的加密库与硬件模块组合。
- 你提供IT审计报告、云密钥保护服务出具的报告,或通过合规签名服务签署的协议。
MMC针对Microsoft Software Key Storage Provider构建的请求都无法满足上述任何一种方式。该提供程序会在Windows软件存储中创建密钥,因此无论向导其余部分如何填写,生成的请求都会被公开信任的代码签名证书拒绝。证书颁发机构同时也已停止为这类产品提供基于浏览器的密钥生成以及可下载的.pfx交付方式。
如果你的目标是获得公开信任的证书,路线在下单时就已确定。要么由CA在令牌上生成密钥并邮寄给你,此时你无需自己创建CSR;要么你在自己已拥有的硬件上生成密钥,并随请求一并提交证明文件。代码签名证书交付方式指南对这两种方式进行了比较,具体设备的操作步骤见下:
MMC仍然适用的场景
该向导并未过时。真正决定密钥诞生位置的,是你在其中选择的提供程序,而以下三种情况下它仍然是正确的工具。
由硬件提供程序支持的请求。向导中的加密服务提供程序列表会显示机器上安装的每一个提供程序,而不仅仅是微软的软件提供程序。一旦令牌的驱动程序或智能卡迷你驱动程序安装完成,其提供程序也会出现在该列表中。区别在于密钥对诞生的位置:软件提供程序在你的计算机上生成密钥对,而硬件提供程序(例如智能卡或令牌提供程序)则指示设备生成密钥对,之后由设备持有私钥并控制对其的访问权限。选择硬件提供程序,MMC生成的请求所对应的密钥就从未存在于软件中。
在依赖这一点之前有两点需要注意。MMC只生成PKCS #10请求,不会附带生成大多数证书颁发机构所需的密钥证明文件,那份文件来自设备自身的工具。此外,CA决定接受哪种验证方法,许多CA会指定使用自己的专用工具。在生成任何东西之前,先向你的CA询问它支持哪条路线,因为用错误的工具创建的密钥事后无法迁移。
内部或企业CA。基准要求约束的是公开信任的证书。由你自己的Active Directory证书服务CA为内部签名颁发的证书不在此范围内,因此密钥如何存储由你自己的策略决定,软件提供程序在此是合理的选择。但要记住你所得到的:以这种方式签名的代码,只有在已经信任你内部根证书的机器上才会被信任,在其他所有地方,Windows仍会将发布者标记为未知。
测试签名与准备工作。对于测试证书,以及为你今后针对硬件生成正式请求时准备好确切的主体值,软件请求是可以接受的。
第1步:打开证书管理单元
按下Windows键 + R,输入mmc并按回车。你也可以在任务栏搜索框中输入mmc并从那里打开。接受用户账户控制提示。此时会打开一个空白的Console1窗口。
点击文件,然后点击添加/删除管理单元。在可用的管理单元列表中选择证书,然后点击添加。
此时Windows会询问该管理单元应管理哪个证书存储区:我的用户账户、服务账户或计算机账户。对于代码签名证书而言,这个选择比对Web服务器证书更为重要,因为它决定了密钥存放的位置以及你的签名工具会在哪个存储区中查找:
- 我的用户账户会将密钥放入已登录用户的个人存储区。当开发人员以交互方式签名时,这通常是常见的选择,因为微软的signtool默认打开当前用户的My存储区。
- 计算机账户会将密钥放入机器存储区,适用于以服务账户身份运行签名操作的构建服务器。签名工具需要被告知去该存储区查找:signtool使用/sm开关来指定机器存储区。
如果选择我的用户账户,点击完成。如果选择计算机账户,点击下一步,保持本地计算机(此控制台正在运行的计算机)的选中状态,然后点击完成。无论哪种情况,都点击确定关闭添加或删除管理单元窗口。

如果你不需要保存控制台,有两个快捷方式可以完全跳过管理单元步骤:certmgr.msc直接打开当前用户的证书存储区,certlm.msc打开本地计算机存储区。如果你手动构建了控制台并打算日后再用,请使用文件然后保存来保留它。
第2步:开始自定义请求
在控制台树中,展开证书,右键点击个人文件夹(如果该存储区中已有证书,则点击其下的证书文件夹)。选择所有任务,然后高级操作,然后创建自定义请求。如果你更喜欢,同样的命令也可以在操作菜单中找到。
证书注册向导会打开到开始之前页面。点击下一步。
在选择证书注册策略页面,在自定义请求标题下选择不使用注册策略继续进行,然后点击下一步。这会告诉Windows为外部CA构建一个独立请求,而不是针对Active Directory模板进行注册。
自定义请求页面有三个设置项:
- 模板。选择(无模板)CNG密钥。这将使用密钥存储提供程序,也是现代硬件提供程序注册时所使用的方式。(无模板)旧密钥使用较旧的CryptoAPI提供程序,仅在特定设备或应用程序需要时才使用。
- 禁止默认扩展。除非你打算只发送手动设置的扩展项,否则保持不勾选。
- 请求格式。选择PKCS #10。所有CA都接受该格式。CMC用于专门要求该格式的系统。
点击下一步。在证书信息页面,你会看到一行标记为自定义请求、状态为可用的条目。点击该行右侧的详细信息箭头将其展开,然后点击出现的属性按钮。证书属性对话框会打开,包含四个选项卡:常规、主题、扩展和私钥。

第3步:输入主体信息
在常规选项卡中,输入一个友好名称,如果需要也可以输入说明。这两项都只是本地标签,用于日后在存储区中查找该证书。它们都不属于请求内容,也不会被验证。
切换到主题选项卡。这里将组装将来显示为软件发布者的身份信息。在主题名称下,从类型下拉列表中选择一项,在值框中输入对应的文本,然后点击添加 >。每一项都会移动到右侧的列表中,Windows会以简写形式显示它们(CN=、O=、OU=、L=、S=、C=)。对以下每一项重复此操作:
- 通用名称(CN):你所在组织的注册名称,或者对于个人证书而言,个人的完整法定姓名。这是Windows在标注发布者时向用户显示的身份信息。
- 组织(O):证书所属的注册组织名称。如果名称中包含诸如&符号之类的符号,请将其拼写出来或去掉,因为该字段不接受这些字符。“AB & C Corporation”应改写为“AB and C Corporation”或“ABC Corporation”。
- 组织单位(OU):负责该注册的部门,例如IT部门。可选。
- 地区(L):组织注册所在的城市。
- 州/省(S):完整拼写的州或省名称。使用Florida,而不是FL。
- 国家(C):组织注册所在地的两字母ISO国家代码,例如US。
请输入与你的法律记录完全一致的详细信息,因为CA在颁发任何证书之前都会依据公开及官方渠道的信息对其进行核实。信息不匹配是代码签名订单卡住的最常见原因。
将备用名称框保持为空。使用者备用名称是通过主机名来标识服务器的,而代码签名证书标识的是发布者而非机器,因此不包含任何DNS条目。

第4步:选择提供程序、密钥长度和哈希算法
打开私钥选项卡。其中包含若干可折叠的分组:加密服务提供程序、密钥选项、选择哈希算法、选择签名格式以及密钥权限。点击标题即可展开。
首先展开加密服务提供程序,因为这正是基准要求所针对的设置项。该列表会显示机器上安装的每个提供程序,各自带有一个复选框。请确保只勾选了你真正需要的那个提供程序:
- 对于公开信任的代码签名证书,请选择属于你的令牌或HSM的提供程序。只有在设备的驱动程序或迷你驱动程序安装完成后,它才会出现在此列表中,因此请先插入设备并安装其软件。
- RSA, Microsoft Software Key Storage Provider是软件选项。仅在内部CA或测试证书场景下使用它。
- 该列表中也包含ECDSA相关条目,例如ECDSA_P256, Microsoft Software Key Storage Provider。在选择之前,请先确认你的CA是否支持将ECDSA用于代码签名,因为并非所有产品都支持。
展开密钥选项。将密钥长度设置为3072或4096。RSA 3072是代码签名的最低要求,使用2048生成的请求将被拒绝。如果所选提供程序的下拉列表中没有3072选项,则使用4096。
在同一分组中,不要勾选“允许导出私钥”。这是对旧版MMC教程最重要的一处修正。可导出的密钥可以作为.pfx文件从机器上复制出去,而这恰恰是硬件要求所要防止的情况,密钥证明这条路径明确证明密钥是以不可导出的方式创建的。唯一需要勾选它的情况,是内部签名场景中确实需要将证书和密钥迁移到另一台机器,即便如此,这也会削弱密钥的安全性。同样,将允许归档私钥保持不勾选。强私钥保护是可选项,会让Windows在每次使用该密钥时都进行提示,这对于共享工作站上的签名密钥来说是合理的选择。
展开选择哈希算法,将哈希算法设置为sha256。代码签名证书不允许使用SHA-1。

如果你要针对内部CA进行注册,扩展选项卡值得留意。展开密钥用法并添加数字签名,然后展开增强型密钥用法(应用程序策略)并添加代码签名。公开CA是根据你所订购的产品来构建证书,而不是根据你请求中的扩展项,因此对于公开订单而言,这个选项卡不会改变任何结果。内部CA则可能会遵循它。
点击确定关闭证书属性,然后点击下一步。
第5步:保存请求
向导会询问你想将脱机请求保存到何处?点击浏览,选择一个你可以掌控的文件夹,为文件命名,例如codesigning.req,然后确认。请始终浏览到某个文件夹,而不是直接输入一个不带路径的文件名:如果不指定路径,请求会保存在控制台当前运行所在的任意文件夹中,这通常不是你想要的位置,也很难再次找到。
在文件格式下,保持Base 64的选中状态。这是CA用来粘贴到注册框中的文本格式。二进制会写入原始的DER格式,大多数订单表单不接受这种格式。点击完成。

用任意纯文本编辑器(例如记事本)打开该文件,并复制整个内容块,包括第一行和最后一行:
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIEbDCCA1QCAQAwZDELMAkGA1UEBhMCVVMx...
...base64 encoded request...
-----END NEW CERTIFICATE REQUEST-----
Windows注册工具通常会写出上面所示的较长措辞,标记行中带有NEW一词,而OpenSSL则写出BEGIN CERTIFICATE REQUEST和END CERTIFICATE REQUEST。如果你的文件使用的是较短形式,也没有问题:其内容是同样的PKCS #10请求,证书颁发机构两种形式都能接受。请照原样复制内容,不要改写标记行。
向导不会生成一个可供你保存或复制的私钥文件,这是需要注意的一点,而旧教程中告诉你要保管好公钥和私钥文件的说法,描述的是另一种工具。MMC会将新生成的私钥保留在Windows密钥存储区内,位于你在第1步中选择的账户下,仅存在于该计算机上。待处理的请求通常会显示在管理单元中的证书注册请求下。由此产生三个后果:
- 在等待颁发期间,不要删除待处理的请求。删除它会丢弃密钥,届时颁发的证书将无法使用。
- 在同一台计算机、同一账户环境下完成订单。在用户存储区中生成的请求无法在机器存储区中完成,反之亦然。
- 在生成请求和安装证书之间,不要重新构建或重新镜像该机器。
第6步:提交请求之前检查一遍
请求一旦创建就无法编辑,因此现在就检查它,而不是等验证开始后才发现拼写错误。Windows无需任何额外软件就能读取它。在存放该文件的文件夹中打开命令提示符并运行:
certutil -dump codesigning.req
如果已安装OpenSSL,以下命令同样可以读取该文件,并且还会检查请求的签名:
openssl req -noout -text -verify -in codesigning.req
在输出结果中确认四点:主体信息中列出的国家、州/省、地区、组织和通用名称都与你的预期完全一致;公钥长度为3072位或更长,或使用了被批准的ECDSA曲线;签名算法为SHA-256;以及在使用OpenSSL命令时,出现verify OK这一行,这可以确认该请求是由与之匹配的私钥所签名的。你也可以将该文本块粘贴到CSR解码器中,以便在浏览器中查看。
如果发现任何问题,请从第2步重新生成一个新请求。要查看机器上有哪些可用的提供程序,包括你已安装的任何硬件提供程序,运行:
certutil -csplist
第7步:在同一台机器上安装颁发的证书
在证书订购过程中提交Base 64文本块,完成CA要求的验证,并在证书颁发到达后下载它。由于私钥一直保留在Windows密钥存储区中,证书必须返回到同一存储区才能被使用。
在同一个管理单元中,右键点击个人,选择所有任务,然后导入,并将向导指向该文件。Windows会将证书与请求中保留的密钥进行匹配,证书注册请求下的待处理条目也会随之消失。之后打开该证书,检查常规选项卡是否显示你拥有与此证书对应的私钥。如果没有这一行,说明配对未成功,你可以使用证书的序列号重新建立关联:
certutil -repairstore My <serial-number>
如果该证书属于当前用户而非机器,请添加-user开关:
certutil -user -repairstore My <serial-number>
之后你的签名工具会从存储区中提取该证书。请记住你在第1步中选择的存储区:signtool默认读取当前用户的My存储区,除非你传入/sm参数以指定机器存储区。
创建同一请求的其他方式,请参阅CertReq、OpenSSL、Java Keystore以及macOS钥匙串访问指南。你也可以查阅更全面的代码签名教程,或了解其他生成CSR的方法。
常见问题
可以,但仅限于请求由硬件支持或面向私有CA的情况。自2023年6月1日起,CA/浏览器论坛要求每个公开信任的代码签名证书的私钥必须在符合FIPS 140-2 Level 2或Common Criteria EAL 4+标准的硬件加密模块中生成并保存。MMC针对Microsoft Software Key Storage Provider构建的请求会在软件中创建密钥,因而会被拒绝。改为在向导中选择你的令牌或HSM提供程序,则能让密钥保留在硬件中;而对于内部CA或测试证书而言,软件请求仍然可行。
不应该,对于代码签名密钥而言不应勾选。可导出的密钥可以作为.pfx文件从机器上被复制出去,这与硬件要求的初衷相违背,而密钥证明这条路径明确证明了密钥是以不可导出的方式创建的。旧版MMC教程建议你勾选该项,但这一建议已经过时。唯一适用的情况是内部签名场景中,证书和密钥确实需要迁移到另一台机器。
选择签名操作将在其中运行的存储区。“我的用户账户”会将密钥放入已登录用户的个人存储区,这也是signtool默认查找的位置,因此适合开发人员以交互方式签名。“计算机账户”会将密钥放入机器存储区,适合在服务账户下运行的构建服务器,之后签名工具需要被告知去该存储区查找。无论你选择哪一个,都要在同一环境下生成请求并安装颁发的证书。
没有可供保存的私钥文件。MMC会将密钥保留在你生成请求所在计算机上的Windows密钥存储区内,位于你所选择的账户下,并在“证书注册请求”下显示尚未完成的请求。不要删除该待处理请求,也不要在证书安装完成之前重建该机器,因为这两种操作都会摧毁密钥,导致颁发的证书无法使用。
RSA密钥至少需要3072位,4096位也是常见选择。如果使用ECDSA,曲线必须是NIST P-256、P-384或P-521,并且你应先确认你的证书颁发机构是否支持将ECDSA用于代码签名。将哈希算法设置为sha256。代码签名证书不允许使用SHA-1。
几乎在所有情况下都应选择CNG密钥。它使用密钥存储提供程序,这也是当前硬件令牌和HSM在Windows上注册自身的方式,同时也是私钥选项卡中加密服务提供程序列表所显示的内容。旧密钥则回退到较旧的CryptoAPI提供程序,只有在特定设备或应用程序需要时才值得选择。
运行certutil -dump codesigning.req,这在Windows上无需任何额外软件;如果已安装OpenSSL,也可以运行openssl req -noout -text -verify -in codesigning.req。核对主体值、密钥长度以及签名算法。请求一旦生成就无法编辑,因此如果发现任何问题,应重新创建一个,而不是尝试修改该文件。

