摘要

  • RFC 6487禁止RPKI资源证书的Authority Key Identifier包含authorityCertIssuer和authorityCertSerialNumber;在更通用的RFC 5280语法中,这两个字段却是可选成员。
  • Barry的994a598提交把authorityCertIssuer接到一个必须接收数组的GeneralNames解析器。次日,Rapport的b1a59a把原来的标量字符串改成仅含一个rfc822Name的数组,并把FORT日志预期从序列号字段纠正为签发者字段。
  • 测试依次运行Barry、所选依赖方验证器、日志检查和VRP检查。源码证明了应有顺序,却没有公开执行记录、解码后的证书或版本化结果来证明这条链实际跑通。
  • Rapport列出四种可选验证器,但这项测试只有在选择fort2时才核对精确诊断。其他验证器的空VRP结果能说明后果,却未必能说明原因。

负面测试也有正面举证责任

被测规则并不含糊。Authority Key Identifier用来把证书与签发者公钥联系起来。RFC 6487要求资源证书携带这一扩展,自签名证书是例外;扩展必须是非关键扩展,其中不得出现authorityCertIssuer和authorityCertSerialNumber。底层的RFC 5280则允许这两个成员存在,只要求二者同时出现或同时缺席。换言之,RPKI在通用X.509语法之上收紧了配置空间。

一项反例测试看起来只需三步:造出含禁用字段的证书,把它交给验证器,再确认下游ROA没有产生可接受的路由起源载荷。真正容易被跳过的是第一步。如果生成器读不懂夹具、悄悄省略字段,或者尚未写出证书就退出,验证器根本没有面对预定缺陷。最终VRP为空,可能只是因为输入从未抵达。

Barry正是这条链的起点。LACNIC在2025年介绍它时,称其可以根据键值描述生成正常或故意异常的RPKI仓库;Rapport再把这些仓库送给依赖方验证器并检查输出。这种分工让复杂边界条件得以重复,也意味着测试对象不止验证器一个:制造输入的工具本身也必须留下证据。

一个字符串为何不能代替GeneralNames

2026年9月1日,Barry提交994a598321336baf1767f0fbfb460ed96c29fe4f加入了AKI的authorityCertIssuer支持。ext.c把该字段绑定到内部类型ft_gnames;field.c里的parse_gnames只接受集合或数组,先计算成员数量,再为每个成员分配ASN.1的GeneralName对象。如果输入不是数组,代码会走向“需要集合/数组”的错误分支。

同一提交新增的功能夹具把输入契约写得很直观:数组里分别放入rfc822Name、iPAddress和registeredID。这不是合规资源证书范例,而是在证明Barry能够编码不同GeneralName分支。

Rapport测试的前一版本并没有使用这种形状。它写的是authorityCertIssuer = "CN=Fake Issuer",也就是一个标量字符串。把夹具与当前解析器放在一起,可以得出严格受限的判断:旧形状不符合当前parse_gnames的数组契约。却不能倒推出某次历史运行一定怎样失败,因为公开材料没有给出当时使用的Barry二进制、命令行、退出状态和日志。

9月2日的Rapport提交b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c修正了形状。新值是一个数组,内含type = rfc822Name,value则是一个示例邮箱字面量。邮箱看起来是否像真实签发者并不重要:RPKI禁止的是整个成员。重要的是,测试现在以生成器能处理的类型表达了这项违规。

标准没有在这两天内变化,期望验证器拒绝的政策也没变。变化发生在更靠前的控制点——夹具终于更有可能造出它声称要测试的证书。

日志原来还指向了另一个字段

旧版run.sh要求FORT日志出现authorityCertSerialNumber,但夹具试图加入的明明是authorityCertIssuer。修正提交把断言改为签发者字段。这不只是拼写清理,而是补上第二道证据关口:即使输入造对了,错误地标注拒绝原因也会让测试失真。

修正后的脚本顺序值得逐项阅读。它先调用run_barry,再调用run_rp,随后检查日志,最后执行check_vrps。一份可审计结果应在每一步留下不同收据:Barry的版本与成功退出;所生成证书的哈希和AKI解码;验证器的产品、版本、配置与信任锚;稳定的拒绝代码或日志;预期与实际VRP集合的哈希。

当前公开仓库没有给出这一整套收据。GitHub在b1a59a上显示零个check run,Rapport页面也没有tag和release。这些负面事实不能证明维护者从未在本地或私有环境运行测试,只能说明外部读者无法把一次源码修正升级为公开、可复现、绑定版本的合规结论。

空集合是后果,不是病因

Rapport的check_vrps先根据参数创建预期文件。这项测试调用它时没有传入任何VRP,所以预期文件为空。辅助脚本再把验证器导出的CSV标准化、排序,并与空文件比较。两者一致,只证明这次输出中没有VRP。

这道断言必不可少。测试仓库在异常CA证书之下放了一个ROA,如果验证器仍导出对应路由载荷,负面测试就失败了。然而,许多不同路径都能得到空集:验证器正确识别AKI违规;仓库抓取失败;信任锚错误;链上还有别的缺陷;或者Barry根本没把对象提供出来。没有前后文的“零VRP”无法给这些路径排序。

FORT在这项测试中多一条具体证据。脚本调用check_logfile fort2,而这个辅助函数只有在当前RP恰好等于第一个参数时才查日志,否则直接返回。因此,关于authorityCertIssuer的精确日志断言仅属于FORT 2分支。

同一提交的README列出了fort2、routinator、rpki-client和rpki-prover四个选择器,并说明每次运行只测一个。适配器数量不能直接当作对称的证据列。其他三个分支仍可核对空VRP后果,但源码没有展示各自用来锁定违规字段的诊断断言。若报告把四列都写成“因authorityCertIssuer而拒绝”,就超出了测试所能证明的范围。

把一枚绿灯拆成三栏

对采购、升级和事件复盘真正有用的结果表,不应只有“通过/失败”。至少要分成三栏:是否构造了指定违规对象,验证器作出了什么决定,输出产生了什么后果。第一栏保存Barry提交与二进制指纹、夹具哈希、退出状态、证书文件及其AKI解码;第二栏保存验证器版本、配置、信任锚和拒绝信号;第三栏保存预期和实际VRP集合。

不同验证器未必承诺稳定的人类可读日志。可移植测试不必强迫大家输出同一句英文。结构化错误类别、产品自己的稳定代码,或把结论限定为“没有接受任何载荷”,都可以成立。可比性来自每一格都准确描述证据,而不是假装接口相同。

还要区分三个成熟度状态:测试已写入源码、测试已对某个候选构建执行、结果已纳入版本化套件。第一个状态方便同行审阅;第二个状态才有运行环境和产物;第三个状态才可与运营者准备部署的版本对应。把三者压成一个绿色图标,就会让主分支的变化悄悄改写历史保证。

解码证书是不可省略的桥

这条链里最便宜、也最能减少歧义的补充证据,是保存Barry生成的证书并对AKI做一次独立解码。夹具告诉读者作者想加入什么,解析器告诉读者程序接受什么形状;只有产物告诉读者最终写进DER的是什么。把证书哈希、解码工具版本和可见字段一起保存,才能把输入意图固定成验证器真正收到的字节。

独立解码还有一个作用:它能区分“生成器新增了能力”与“这一项测试确实使用了能力”。994a598同时提供字段绑定、GeneralNames解析器和功能测试,足以说明Barry具备新的表达机制。Rapport的数组形状又与机制相符。但如果没有本次运行的证书产物,仍无法排除配置覆盖、路径选择或构建版本造成的偏差。源码链很强,却不是运行链的替身。

运行记录也不必庞大。一次测试可以产生一份小型机器可读清单:输入仓库描述的哈希、Barry提交与二进制哈希、生成对象列表、目标验证器及版本、开始和结束时间、退出状态、诊断类别、预期与实际VRP哈希。将清单与CI任务或release关联,比截取一页日志更稳定,也更便于不同产品保留各自的诊断语言。

这份清单还应明确运输层。Rapport可以通过rsync或RRDP向验证器呈现仓库;只记录最终空集,会把“对象被拒绝”与“对象没有取得”混在一起。写下实际使用的协议、请求是否成功、验证周期何时结束,可以让读取失败、超时和密码学拒绝分别落在不同类别。测试不需要假装网络永不出错,只需要避免把网络错误误计为规范通过。

任一组件升级后再次执行时,还要比较输入产物哈希。证书或仓库对象一旦变化,新结果就属于一次新实验,不能无声覆盖旧表格。

同理,验证器配置也应进入身份记录。缓存策略、传输开关、严格模式和信任锚的差异,都可能改变同一二进制对同一仓库的路径。把这些变量连同时间戳保存,才能让后来者判断差异来自产品、配置还是测试基础设施,而不是根据一枚颜色图标猜测。

这也是可复现性的最低成本版本。

对网络运营团队而言,这种粒度可以直接映射到变更审批。源代码中的测试用于评估覆盖范围;对候选构建的执行结果用于批准升级;绑定release的历史结果用于事后追溯。三者各有用途,不应由其中任意一个冒充全部。

LACNIC在2025年12月仍称Barry和Rapport处于早期阶段,当时的介绍重点是FORT;后来README已经列出四个验证器。合理读法是项目持续演进。旧博客不应否认新能力,新适配器清单也不能反向证明所有测试从一开始就拥有四份等价结果。

因此,当前最强结论很克制:Barry获得了构造authorityCertIssuer的类型机制;Rapport随后修正了输入形状,并把FORT诊断与被测字段对齐。测试定义明显更完整。公开证据尚未证明它在FORT或另外三款依赖方验证器上实际通过。

来源

  1. LACNIC Blog,“Open-Source Projects at LACNIC”:https://blog.lacnic.net/en/open-source-projects-lacnic/
  2. Barry提交994a598:https://github.com/LACNIC/barry/commit/994a598321336baf1767f0fbfb460ed96c29fe4f
  3. Barry字段解析与绑定:https://github.com/LACNIC/barry/blob/994a598321336baf1767f0fbfb460ed96c29fe4f/src/field.c 和 https://github.com/LACNIC/barry/blob/994a598321336baf1767f0fbfb460ed96c29fe4f/src/ext.c
  4. Barry的GeneralNames功能夹具:https://github.com/LACNIC/barry/blob/994a598321336baf1767f0fbfb460ed96c29fe4f/test/functional/tests/gnames.rd
  5. Rapport修正提交b1a59a:https://github.com/LACNIC/rapport/commit/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c
  6. 修正后的Rapport夹具与runner:https://github.com/LACNIC/rapport/blob/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/rd 和 https://github.com/LACNIC/rapport/blob/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/run.sh
  7. Rapport检查函数与README:https://github.com/LACNIC/rapport/blob/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/tools/checks.sh 和 https://github.com/LACNIC/rapport/blob/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/README.md
  8. RFC 6487:https://www.rfc-editor.org/rfc/rfc6487.html
  9. RFC 5280:https://www.rfc-editor.org/rfc/rfc5280.html
  10. 修正前69da5fe提交中的夹具与runner:https://github.com/LACNIC/rapport/blob/69da5fe98cf09594fc009f4151a84368c08489ba/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/rd 和 https://github.com/LACNIC/rapport/blob/69da5fe98cf09594fc009f4151a84368c08489ba/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/run.sh
  11. 修正提交b1a59a改动的文件:https://github.com/LACNIC/rapport/commit/b1a59a39ea3b3f8ddc66571a7177c8afb1d0967c/checks
  12. main分支上夹具路径的历史:https://github.com/LACNIC/rapport/commits/main/tests/rfc6487/4.8.3-c-aki-with-authoritycertIssuer-rejected/rd
  13. Rapport标签与发行版:https://github.com/LACNIC/rapport/tags 和 https://github.com/LACNIC/rapport/releases