
CCSecureBoot
在CC:Tweaked中实现启动安全。
CCSecureBoot
在 CC: Tweaked 中实现启动安全功能。
安装
必须已安装 CC: Tweaked 1.112.0 或更高版本。
只需将构建好的 JAR 文件安装到你的 mods 文件夹中即可。此模组仅在服务器端运行,因此多人游戏客户端无需安装。
使用方法
默认情况下,所有计算机的 Secure Boot 均处于禁用状态。要为某台计算机启用 Secure Boot,请运行 enroll-secure-boot 程序。该程序将为计算机生成一个新密钥,并将其存储在软盘上以备安全保管。
enroll-secure-boot 首先会显示一些关于 Secure Boot 的重要信息,并请求确认以继续。接着会提示输入密钥密码——此步骤为可选项,但推荐设置以防止密钥意外泄露。如果未检测到磁盘,程序会等待插入磁盘。一切就绪后,密钥将被生成并保存,同时一张恢复启动配置也会被放置在磁盘上。
启用 Secure Boot 后,计算机只能从带有签名的文件启动。可以使用 sign 命令签署文件,该命令会在程序旁边创建一个 .sig 文件。签名时必须将密钥盘插入磁盘驱动器。
Secure Boot 禁止直接访问 Shell——默认情况下它只会启动到 startup.lua(该文件必须被签名)。如果插入了密钥盘,将会出现一个启动菜单,其中包含启动 Shell 的选项。
Secure Boot 运行在 pxboot 上,允许自定义启动界面,包括添加更多菜单项、更改默认启动项和超时时间,以及美化菜单样式。额外的配置可以从 /pxboot_config.lua 加载,该文件也必须被签名。有关如何为 pxboot 编写配置的更多信息,请参阅其仓库。
要禁用某台计算机的 Secure Boot,可以在任何插入了该密钥卡的计算机上运行 unenroll-secure-boot 命令。取消注册是通过密钥卡而非计算机 ID 进行的,因此即使某台计算机已无法启动,也可以通过此方法取消其注册。密钥同时也会被撤销,这有助于防止密钥泄露后被滥用。
如果计算机的密钥丢失,则无法恢复该计算机——将无法再修改启动文件或从 Secure Boot 中取消注册该计算机。请将密钥盘存放在安全的地方,避免其他玩家接触到。
保护你的代码
Secure Boot 仅确保进入程序的信任根——它不保证你的整个计算机系统是安全的。确保代码免受黑客攻击是用户自己的责任,包括检查所有被加载的代码并避免不安全的程序。
启用 Secure Boot 后,由于启动管理器的设置方式,你会自动免受两种最基本的程序绕过方法的威胁:按 Ctrl+T 终止到 Shell,以及插入带有启动文件的磁盘。在程序中无需应对这些情况(尽管理想情况下,你应该安全地处理 terminate 事件,而不是报错并重启)。
为帮助代码签名,CCSecureBoot 提供了一个基于启动管理器相同代码的易用库。只需调用 dofile("/rom/modules/main/codesign.lua") 即可使用几个简化签名检查的函数:
codesign.verify(path):简单验证文件的签名,并返回布尔值表示文件是否安全。codesign.execute(cmd, ...):shell.execute的封装,用于检查命令的签名。这不允许运行 ROM 中的程序——请使用普通的shell.execute来运行已知安全的程序。codesign.loadfile(path, mode, env):loadfile的封装,用于检查文件的签名。它自动允许/rom/modules中的模块,但不适用于 ROM 的其他部分。codesign.dofile(path):dofile的封装,用于检查文件的签名。它自动允许/rom/modules中的模块,但不适用于 ROM 的其他部分。codesign.enforceModuleSigning():要求所有通过require加载的模块都进行代码签名。在程序开始时调用一次——该设置将在程序剩余生命周期内保持生效。此设置不会在codesign.execute/shell.execute调用中保持——需要在新程序中再次调用。codesign.sign(data, password):为提供的数据生成签名块。此格式与.sig文件相同。必须插入密钥盘,如果密钥受密码保护,则必须提供密码。codesign.load(data, sig, name, mode, env):load的封装,使用提供的签名块检查代码的签名。
如果你的程序通过 require 使用模块,请在任何模块加载之前启用模块签名,以确保它们被正确签名且不会被替换为不受信任的代码:
-- require 可能会加载本地模块而不是 ROM 中的模块——始终使用 dofile 加载 codesign:
local codesign = dofile "/rom/modules/main/codesign.lua"
codesign.enforceModuleSigning()
-- 现在 require 可以安全地加载外部模块:
local yourmod = require "yourmod"
-- ...
提醒一下,切勿通过 load 加载不受信任的代码而不使用受限环境,尤其是当输入来自调制解调器时。如果你要加载代码,应为其提供一个高度受限的环境,仅包含必要的函数(如果有的话)。(尽管 textutils.unserialize 会加载代码,但它使用空环境,因此被认为是安全的。)
内部工作原理
CCSecureBoot 使用 PKCS 或 S/MIME 协议栈来存储加密信息,并使用 Ed25519 进行签名。大部分繁重的工作由 libcert 和 ccryptolib 在 Lua 端完成,以及 Bouncy Castle 在 Java 端完成。
服务器保存一个唯一的私钥,存储在保存目录的 computercraft/root.key 中,以及关联的证书,存储在 computercraft/certs/root.pem 中。这些被用作服务器的信任根。计算机随后可以请求由根证书签名的自身证书,验证时这些证书会被追溯到根证书。请求通过隐藏在 require 调用背后的 Java API 传递。
CCSecureBoot 将一个程序插入 /rom/autorun,该程序检查注册状态,如果当前计算机已注册,则运行 pxboot。它通过查找 /rom/pxboot/certs/enrolled/<id> 来检查注册状态,其中 /rom/pxboot/certs 是位于 computercraft/certs 中的保存挂载点(允许模组在运行时修改它)。
所使用的 pxboot 版本包含一个模块,该模块将签名检查插入到所有加载代码的命令中。签名以 PEM 编码的 PKCS#7 容器格式存储在被签名文件旁边,其中包含签名者的证书及签名。这使得签名可以独立存在,无需维护单独的有效证书列表——嵌入的证书可以对照受信任的根证书进行验证。
注册 Secure Boot 涉及为当前计算机 ID 生成 PKCS#10 签名请求。计算机首先生成私钥,然后为关联的公钥创建签名请求。CSR 中有一个主题字段 uniqueIdentifier(OID 2.5.4.45),包含计算机的 ID。此 ID 必须与运行中的计算机匹配,否则签名请求将被拒绝。
该 CSR 随后以 PEM 格式传递给服务器进行签名,使用 secureboot.enroll(csr)。如果 ID 匹配,新的 X.509 证书将被传回(PEM 编码),并在 computercraft/certs/enrolled//rom/pxboot/certs/enrolled 中为计算机 ID 创建一个文件,告知引导加载程序检查签名。
之后,证书和密钥分别以 X.509 和 PKCS#8 格式保存,均为 PEM 编码。为安全起见,用于加载 Shell 的启动配置和启动程序被创建在磁盘上,并使用新密钥签名。
签名是一个简单的 PKCS#7 签名操作,使用软盘上存储的证书和密钥。
取消注册涉及调用 secureboot.unenroll(cert, signature),需要提供计算机的证书(PEM 编码的 X.509)以及一个签名的挑战字符串。挑战文本只是目标计算机 ID 的字符串形式,签名以原始的 Ed25519 签名形式传递,为简化起见放弃了 PKCS#7 包装(因为 Java 端没有简单的 PKCS#7 签名检查)。如果证书有效且签名通过,则删除注册文件,并将证书存储在证书撤销列表中,该列表保存在 computercraft/certs/revoked.crl。
许可证
CCSecureBoot 根据 MPLv2 许可证发布,部分内容根据 MIT 许可证发布。
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。