做出引入包,并找出签名校验断掉的地方
目标
从零开始制作要导入隔离网络的软件包并签名,再以接收方身份进行验证,并通过两种篡改亲自确认验证会在哪一层失败。
为什么重要
这个 Pod 中没有 gpg,也无法安装。实际隔离网络通常也是如此——不在许可清单中的软件,本身就必须先接受导入审核。因此,我们使用随处可用的 openssl 进行签名和验证。完整性也不是一层,而是两层:文件哈希保证“这是清单中所说的那个文件”,签名则保证“这份清单由掌握相应密钥的人制作”。只检查一层时,必然会放过其中一种情况;只有亲自构造两种情况后,才能真正体会这一点。
步骤
- 使用
python3在/root/bundle/payload/下创建六个文件,其中两个是二进制文件。 - 在
/root/bundle/stage/MANIFEST.sha256中使用相对路径记录每个文件的 SHA-256。 - 在
/root/bundle/keys/中创建 RSA 2048 密钥对,将私钥权限设为 600,并将公钥指纹保存在release.pub.sha256中。 - 使用
openssl dgst -sha256 -sign创建/root/bundle/stage/MANIFEST.sig。 - 打包为
/root/bundle/out/intake-2609-01.tar.gz,并创建同名.sha256文件。不要包含密钥文件。 - 解压到
/root/bundle/recv/,按软件包哈希 → 签名 → 文件哈希的顺序验证,并将结果写入receipt.txt。 - 在
/root/bundle/tamper-a/和/root/bundle/tamper-b/中进行两种篡改,并将结果写入/root/bundle/tamper.txt。A 只修改payload/deps/libpq.so.5.bin的一个字节;B 在此基础上还修改清单中的对应行。 - 在
/root/bundle/intake.md中编写包含七个章节的导入审批申请。
参考
- 不要使用
head或grep打开二进制文件。文件中混有 NUL,结果不可信。只使用file、sha256sum和openssl。 sha256sum -c会以当前目录为基准查找清单中记录的路径。请在 payload 目录内运行。- 若只修改一个字节,使用
printf '\xff' | dd of=파일 bs=1 seek=1024 count=1 conv=notrunc很方便。 - 常见错误 1:使用
openssl dgst -sign时省略-out,改用>重定向。这样会损坏二进制数据。 - 常见错误 2:重新打包后没有重新生成
.sha256。请将打包和生成哈希放在同一个脚本中。
创建要导入的目录树
使用 python3 在 /root/bundle/payload/ 下创建六个文件,其中两个是二进制文件。
使用 python3 创建六个文件。其中两个是二进制文件,无法用肉眼确认,只能通过指纹验证。不要修改生成脚本,原样使用。
创建逐文件哈希清单
在 /root/bundle/stage/MANIFEST.sha256 中使用相对路径记录每个文件的 SHA-256。
在 payload 目录中使用相对路径生成。find 的 -printf '%P\n' 会去掉开头的 ./。接收方会解压到另一个目录,因此绝对路径在那里没有用处。
创建签名密钥对并保留指纹
在 /root/bundle/keys/ 中创建 RSA 2048 密钥对,将私钥权限设为 600,并将公钥指纹保存在 release.pub.sha256 中。
使用 openssl genrsa 创建 2048 位私钥,并将权限设为 600。使用 -pubout 导出公钥,转换为 DER 后通过 sha256sum 生成指纹。
对清单签名
使用 openssl dgst -sha256 -sign 创建 /root/bundle/stage/MANIFEST.sig。
签名对象不是整个 payload,而是清单这一份文件。使用 openssl dgst -sha256 -sign 时必须添加 -out——如果重定向屏幕输出,二进制数据会损坏。
打包软件包(不包含密钥)
打包为 /root/bundle/out/intake-2609-01.tar.gz,并创建同名 .sha256 文件。不要包含密钥文件。
将 payload、清单和签名打包在一起。不要包含公钥——如果公钥与软件包通过同一途径送达,控制该途径的人就能将四者全部替换。打包后使用 tar -tzf 目视确认其中包含的内容。
按顺序执行接收方流程
解压到 /root/bundle/recv/,按软件包哈希 → 签名 → 文件哈希的顺序验证,并将结果写入 receipt.txt。
顺序是关键:整个软件包的哈希 → 签名 → 各文件哈希。如果先检查文件哈希,就会依据一份尚未确认真伪的清单进行比对。
通过两种情况确认验证失败位置
在 /root/bundle/tamper-a/ 和 /root/bundle/tamper-b/ 中进行两种篡改,并将结果写入 /root/bundle/tamper.txt。A 只修改 payload/deps/libpq.so.5.bin 的一个字节;B 在此基础上还修改清单中的对应行。
创建两份副本:A 中只修改二进制文件的一个字节;B 在相同篡改基础上,将清单对应行也更新为新哈希。对两份副本都执行签名验证和文件哈希比对。
编写导入审批申请
在 /root/bundle/intake.md 中编写包含七个章节的导入审批申请。
需要七个章节。审核人员必须能够在看不到我们屏幕的情况下重复同样的验证,因此不要只写“已通过”,而要写明数值和命令。