自动代码签名 - 保护私钥

Posted

技术标签:

【中文标题】自动代码签名 - 保护私钥【英文标题】:Automated Code Signing - Protecting the private key 【发布时间】:2014-04-21 07:26:30 【问题描述】:

我想自动化一些 ClickOnce 部署工件的代码签名 - 应用程序 exe 和清单。我正在使用signtool 来完成此操作。为了使私钥可用于签名并保护包含私钥的证书文件(.pfx 文件),我的计划是使用不可导出的密钥将证书安装到本地计算机证书存储中。 (我知道有一些方法可以导出密钥,即使它被标记为不可导出。)这台机器是一个持续集成服务器,只有少数人可以访问。我希望以这样一种方式设置它,即任何时候需要使用私钥时,都需要输入私钥密码。然后我将设置一个自动化作业(使用Jenkins),这将需要一个收集私钥密码的构建参数。 Mask Passwords plugin 将用于在输入和控制台输出时屏蔽密码。

但是,我遇到了一些障碍。首先,即使有“启用强私钥保护。如果启用此选项,应用程序每次使用私钥时都会提示您”。导入证书时,它似乎仅在将其导入当前用户存储时可用,而不是本地机器存储。其次,即使此选项可用,signtool 工具也不提供在使用商店中的证书进行签名时设置密码的选项。密码参数“/p”仅在使用 pfx 文件作为私钥源(“/f”选项)时适用。鉴于此,这似乎不是一个可行的选择。注意:即使“启用强私钥保护”。可用于机器商店中的证书,我的测试表明,尝试使用启用此选项的证书只会弹出一个对话框,询问是否允许使用它,这显然不适用于自动化作业。我原本以为“提示”意味着它会要求输入密码。

我考虑过的另一个选项是创建 ACL 以保护证书存储中的私钥。这可以通过右键单击证书并选择所有任务来完成... |管理私钥...对话框。这会将私钥的使用限制为仅授权的人。 (注意:当没有私钥权限的用户尝试使用它进行签名时,他们会收到消息“SignTool 错误:未找到符合所有给定条件的证书。”)但是,我不想授予访问权限到 Jenkins 构建服务使用的凭据,因为这样任何构建作业都可以签署代码。我可以创建一个作业,该作业将执行脚本以以特定用户身份运行签名命令。这需要将域用户名和密码作为构建参数。我可以使用 Jenkins Mask Passwords 插件来做到这一点。不过,我真的不喜欢这样,因为我对 Mask Passwords 足以防止域凭据暴露感到不舒服,如果域凭据被泄露,将提供对更多内容的访问,而不仅仅是私钥。

如果我放弃将证书存储在机器存储中的最初想法,则可以选择将证书 pfx 文件放在构建机器上的 ACL 安全文件夹中,只有构建过程和签名用户有权访问该文件夹。这样做将允许我创建一个构建作业以使用包含的私钥,同时不会将文件暴露给有权访问该机器的其他人。要使用私钥,构建参数需要收集私钥密码。

最后,可以选择使用智能卡来存储证书,但我们决定不这样做。

所以,我的问题是,是否有任何其他方法可以做到这一点:1)保护私钥不被复制,2)防止私钥被未经授权的用户使用来签署代码,以及 3)给定私人密钥密码由授权用户提供,生成服务签名的私钥?

【问题讨论】:

【参考方案1】:

首先我将尝试分别回答您的问题:

    保护私钥不被复制:只有加密硬件(智能卡或 hsm)才能真正保护密钥不被复制。 Windows 证书存储(即使您正确指出了不可导出的选项)或 PKCS#12 (PFX) 文件仅提供虚假的保护。 防止未经授权的用户使用私钥签署代码:IMO 这需要用户交互,例如输入密码或 PIN。如果您将密码作为参数传递,则其他进程总是有可能获得它,即通过进程信息、日志等。 鉴于私钥密码由授权用户提供,使私钥用于构建服务签名:加密硬件(智能卡或 hsm)可通过 CSP(windows 证书存储)以交互方式输入PIN 应该可以与 signtool 一起使用,没有任何问题。

我同意用户交互的要求对于自动构建服务可能并不十分方便,但您可能不得不在具有用户交互的安全解决方案和没有用户交互的不太安全的解决方案之间做出选择

方便但不太安全的解决方案没有。 1:在我看来,您已经找到了一个可以接受的解决方案,因为您没有提供它的任何缺点。

如果我放弃将证书存储在机器存储中的最初想法,则可以选择将证书 pfx 文件放在构建机器上的 ACL 安全文件夹中,只有构建过程和签名用户有权访问该文件夹。这样做将允许我创建一个构建作业以使用包含的私钥,同时不会将文件暴露给有权访问该机器的其他人。要使用私钥,构建参数需要收集私钥密码。

但是请注意,PFX 文件不仅可以从实时系统中复制,也可以从备份中复制而无法检测到。

方便但不太安全的解决方案没有。 2:将私钥存储在不需要输入 PIN 的智能卡上,并且只允许受信任的用户访问系统。这将确保您的私钥不能被复制,同时它仍然可以轻松访问 signtool。但是,它可能需要您拥有两台单独的构建服务器 - 一台没有智能卡可供所有用户访问,另一台只有受信任的用户可以访问智能卡。

不方便的安全解决方案:将私钥存储在需要输入 PIN 并在构建过程中需要用户交互(输入 PIN)的智能卡上。

您还可以考虑在自动模式下使用自签名的协同签名证书对开发版本进行签名,并在手动模式下使用受信任的协同签名证书对公开发布版本进行签名。

【讨论】:

【参考方案2】:

我看到的唯一选择是使用 HSM。

您可以生成受操作员卡/卡组保护的私钥(例如 Thales 有这种 HSM)。操作员卡集可以设置一个法定人数,该法定人数指定在请求使用此私钥的应用程序可以使用私钥之前,必须有多少操作员插入卡。 Thales 也有一个支持此功能的 CSP。

问题可能是 CSP 将调用窗口以向用户显示必须插入卡(以及输入的卡的可选密码)。当您在某个可以登录的桌面用户帐户下运行构建服务器时,此问题可能会得到解决。当您以该用户身份登录并启动构建服务器时,它必须请求使用私钥(例如通过签署一些虚拟文件或其他东西)。窗口将弹出,操作员(根据法定人数要求)将一张一张插入他们的卡,并可选择输入他们的密码。插入所有必需的卡后,您的构建服务器将可以使用该密钥。任何其他应用程序(可能由其他用户启动)将通过相同的过程来使用该密钥。如果您的构建服务器崩溃(构建服务器是否崩溃?)您将执行相同的过程。

HSM 还具有防篡改功能,因此私钥在恕我直言是安全的。很抱歉只谈论泰雷兹 HSM,但我个人没有任何其他 HSM 的经验。

【讨论】:

【参考方案3】:

似乎依赖受密码保护的 PFX 文件而不是证书存储是安全的。即使在 PFX 所在的硬盘文件夹上没有 ACL 保护,获取 PFX 文件的任何人都无法使用它来签署任何内容,除非他们也有密码。

然后,在该计算机上设置一个参数化的 Jenkins“签名”作业,该作业完全封装 PFX 密码,这样任何人都无法看到它。 (我正在考虑某种类型的脚本,可能是 Powershell,转换为黑盒 EXE。)授权的 Jenkins 作业可以链接到签名作业以完成签名。 EXE 会在每次使用时记录下来,作为审计功能。只需要弄清楚如何防止未经授权使用签名工作...一定有办法做到这一点?

【讨论】:

以上是关于自动代码签名 - 保护私钥的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 自动代码签名分发

XCode 存档:“未找到代码签名身份:未找到有效的签名身份(即证书和私钥对)。”

天威诚信代码签名证书助手操作指南

如何从 .SPC(代码签名证书)和 .PKCS12(私钥)生成 PKCS12 (.p12)?

RSA私钥公钥加密解密与签名SHA256相关代码

RSA私钥公钥加密解密与签名SHA256相关代码