From 5e474fffd22e10a700b3feced9ca50baf3b80b66 Mon Sep 17 00:00:00 2001 From: yuyr Date: Tue, 27 Jan 2026 10:33:31 +0800 Subject: [PATCH] add crl data model --- .gitignore | 2 + Cargo.toml | 11 + README.md | 11 + specs/00_common_types.md | 217 +++++++++ specs/04_crl.md | 141 ++++++ src/data_model/crl.rs | 429 ++++++++++++++++++ src/data_model/mod.rs | 2 + src/lib.rs | 1 + ...99DEAB073EFD74C250C0A382B25012B5082AEE.crl | Bin 0 -> 1268 bytes ...FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl | Bin 0 -> 456 bytes .../BfycW4hQb3wNP4YsiJW-1n6fjro.cer | Bin 0 -> 1530 bytes ...FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl | Bin 0 -> 456 bytes ...FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft | Bin 0 -> 5092 bytes .../repo/cernet/0/AS142067.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142068.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142069.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142070.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142071.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142072.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142073.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142074.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142075.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142076.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142077.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142078.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142079.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142080.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142081.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142082.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142083.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142084.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142085.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142086.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142087.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142088.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142089.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142090.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142091.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142092.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142093.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142094.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142095.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142096.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142097.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142098.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142099.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142100.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142101.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142102.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142103.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142104.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142105.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142106.roa | Bin 0 -> 1762 bytes .../repo/cernet/0/AS142650.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142651.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142652.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142653.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142654.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142655.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142656.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142657.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142658.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS142659.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144698.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144699.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144700.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144701.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144702.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144703.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144704.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144705.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144706.roa | Bin 0 -> 1758 bytes .../repo/cernet/0/AS144707.roa | Bin 0 -> 1758 bytes .../rpki.cernet.net/repo/cernet/0/AS23910.roa | Bin 0 -> 1973 bytes .../rpki.cernet.net/repo/cernet/0/AS4538.roa | Bin 0 -> 1956 bytes tests/test_crl_decode.rs | 68 +++ 76 files changed, 882 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 specs/00_common_types.md create mode 100644 specs/04_crl.md create mode 100644 src/data_model/crl.rs create mode 100644 src/data_model/mod.rs create mode 100644 src/lib.rs create mode 100644 tests/fixtures/0099DEAB073EFD74C250C0A382B25012B5082AEE.crl create mode 100644 tests/fixtures/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl create mode 100644 tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142067.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142068.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142069.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142070.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142071.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142072.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142073.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142074.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142075.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142076.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142077.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142078.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142079.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142080.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142081.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142082.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142083.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142084.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142085.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142086.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142087.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142088.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142089.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142090.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142091.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142092.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142093.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142094.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142095.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142096.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142097.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142098.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142099.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142100.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142101.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142102.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142103.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142104.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142105.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142106.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142650.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142651.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142652.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142653.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142654.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142655.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142656.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142657.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142658.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142659.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144698.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144699.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144700.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144701.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144702.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144703.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144704.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144705.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144706.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144707.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS23910.roa create mode 100644 tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa create mode 100644 tests/test_crl_decode.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c96eb1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target/ +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..49f8bfa --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rpki" +version = "0.1.0" +edition = "2024" + +[dependencies] +der-parser = "10.0.0" +hex = "0.4.3" +thiserror = "2.0.18" +time = "0.3.45" +x509-parser = { version = "0.18.0", features = ["verify"] } diff --git a/README.md b/README.md index e69de29..e89d904 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,11 @@ + + +# 单元测试 + +``` +cargo test + +# 查看输出 +cargo test -- --nocapture +``` + diff --git a/specs/00_common_types.md b/specs/00_common_types.md new file mode 100644 index 0000000..cabf293 --- /dev/null +++ b/specs/00_common_types.md @@ -0,0 +1,217 @@ +# 00. 公共类型、编码约定与 OID 表 + +本文件定义各数据对象文档共用的类型与记号。 + +## 0.1 规范关键字 + +文中 “MUST/SHOULD/MAY/MUST NOT/SHOULD NOT” 语义遵循 RFC 2119 / RFC 8174。 + +## 0.2 编码/序列化约定 + +### 0.2.1 DER + +- `DER`:ASN.1 Distinguished Encoding Rules(DER)。RPKI Signed Object 与其 eContent 均要求 DER 编码。RFC 6488 §2;RFC 9286 §4.2;RFC 9582 §4。 + +### 0.2.2 X.509 v3 扩展(Extension)编码模板 + +> 用途:解释证书/CRL里“按 OID 挂扩展”的通用编码方式。该模板来自 RFC 5280,对 RPKI 来说是“所有 extnID 扩展”的外层载体。 + +证书与 CRL 的扩展都使用同一个外层结构(DER 编码)。其 ASN.1 定义如下:RFC 5280 §4.1。 + +```asn1 +Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING + -- contains the DER encoding of an ASN.1 value + -- corresponding to the extension type identified + -- by extnID + } +``` + +解码要点: + +- 先按 `extnID` 选择“要用哪一种内层 ASN.1 结构”。 +- 再把 `extnValue` 的 octets 作为 DER 进行**二次解码**,得到该扩展的内层值(例如 SIA/AIA/CRLDP/3779 资源扩展等)。 + +编码要点: + +- 先把内层值按其 ASN.1 结构 DER 编码,得到 `inner_der`; +- 再写入 `extnValue = OCTET STRING(inner_der)`。 + +RFC 引用:RFC 5280 §4.1(证书扩展位置);RFC 5280 §4.2(扩展定义与语义)。 + +### 0.2.3 AIA/SIA 的内层容器结构(AccessDescription + GeneralName URI) + +Authority Information Access(AIA)与 Subject Information Access(SIA)的内层值都是一个 “AccessDescription 列表”。其 ASN.1 定义如下:RFC 5280 §4.2.2.1;RFC 5280 §4.2.2.2。 + +```asn1 +AuthorityInfoAccessSyntax ::= + SEQUENCE SIZE (1..MAX) OF AccessDescription + +SubjectInfoAccessSyntax ::= + SEQUENCE SIZE (1..MAX) OF AccessDescription + +AccessDescription ::= SEQUENCE { + accessMethod OBJECT IDENTIFIER, + accessLocation GeneralName } +``` + +其中 `accessLocation` 的 `GeneralName`(URI 用 `uniformResourceIdentifier` 分支)定义如下:RFC 5280 §4.2.1.6。 + +```asn1 +GeneralName ::= CHOICE { + otherName [0] OtherName, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ORAddress, + directoryName [4] Name, + ediPartyName [5] EDIPartyName, + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } +``` + +解码要点: + +- 先按 `extnID` 识别是 AIA(`1.3.6.1.5.5.7.1.1`) 或 SIA(`1.3.6.1.5.5.7.1.11`); +- 再把 `extnValue` 解码成 “SEQUENCE OF AccessDescription”; +- 每条 `AccessDescription` 用 `accessMethod` 的 OID 区分语义; +- URI 通常出现在 `GeneralName.uniformResourceIdentifier`(IA5String)中。 + +RFC 引用:RFC 5280 §4.2.2.1;RFC 5280 §4.2.2.2;RFC 5280 §4.2.1.6。 + +### 0.2.2 Base64(仅 TAL) + +- `Base64`:TAL 中的 `subjectPublicKeyInfo` 以 DER 字节序列经 Base64 编码表示;允许插入换行。RFC 8630 §2.2。 + +### 0.2.4 换行 + +- `LF` 或 `CRLF`:TAL 文件允许使用 `\n` 或 `\r\n`。RFC 8630 §2.2。 + +## 0.3 基本类型(抽象模型层) + +> 说明:这些类型用于描述“语义对象”,不等同于 ASN.1 具体类型,但会给出从 ASN.1/文本到该类型的解析规则。 + +- `DerBytes`: `bytes`,承载一个 DER 编码对象的原始字节(入口)。 +- `Oid`: `string`(点分十进制),例如 `1.2.840.113549.1.9.16.1.26`。 +- `Uri`: `string`,URI 文本;其语法来自 RFC 3986,但在 RPKI profile 下会被进一步限制(见各对象文档)。 +- `Utf8Text`: `string`,UTF-8 文本(例如 TAL 注释行)。RFC 8630 §2.2(引用 RFC 5198 §2 的限制)。 +- `UtcTime`: `string`,承载“UTC 时间点”的语义值;来源可能是 X.509 `Time`(UTCTime/GeneralizedTime)或 ASN.1 `GeneralizedTime`(如 Manifest)。RFC 5280 §4.1.2.5;RFC 9286 §4.2。 +- `HexBytes`: `bytes` 的十六进制展示形态(仅文档说明用,不建议作为接口字段)。 + +## 0.4 RPKI 资源集合语义(高层表示) + +### 0.4.1 IP 资源集合(语义模型) + +用于表达 RFC 3779 的 `IPAddrBlocks`(以及 ROA 的“仅前缀”子集)。 + +#### 类型:`IpResourceSet` + +- `families: list[IpFamilyResources]` + +#### 类型:`IpFamilyResources` + +- `afi: enum { ipv4, ipv6 }` +- `safi: optional[int]` + - 在公用互联网资源证书语义中,SAFI **MUST NOT** 使用。RFC 6487 §4.8.10。 +- `choice: enum { inherit, explicit }` +- `explicit_resources: optional[list[IpRangeOrPrefix]]` + +#### 类型:`IpRangeOrPrefix` + +- `kind: enum { prefix, range }` +- `prefix: optional[IpPrefix]` +- `range: optional[IpRange]` + +#### 类型:`IpPrefix` + +- `address: bytes`(IPv4 4 字节或 IPv6 16 字节的网络序) +- `prefix_len: int` + +#### 类型:`IpRange` + +- `min: bytes` +- `max: bytes` + +解析与约束要点(实现应在解析阶段保留必要信息供后续验证使用): + +- RFC 3779 `IPAddress`/`IPAddressRange` 以 `BIT STRING` 编码前缀/范围,并对排序/去重/规范编码给出要求。RFC 3779 §2.2.3.6-§2.2.3.9。 +- RFC 3779 `inherit` 语义表示资源集合继承自签发者。RFC 3779 §2.2.3.5。 + +### 0.4.2 AS 资源集合(语义模型) + +用于表达 RFC 3779 的 `ASIdentifiers`。 + +#### 类型:`AsResourceSet` + +- `asnum: optional[AsIdentifierChoice]` + - 在 RPKI profile 中,`asnum` 与 `rdi` 不能都缺省到导致“无 AS 资源扩展”的语义;但 RC 层面允许 “仅 IP” 或 “仅 AS” 或两者都存在。RFC 6487 §4.8.10;RFC 6487 §4.8.11。 +- `rdi: optional[AsIdentifierChoice]` + - RPKI profile **不支持** RDI,MUST NOT 使用。RFC 6487 §4.8.11。 + +#### 类型:`AsIdentifierChoice` + +- `choice: enum { inherit, explicit }` +- `explicit_ranges: optional[list[AsRangeOrId]]` + +#### 类型:`AsRangeOrId` + +- `kind: enum { id, range }` +- `id: optional[int]`(0..4294967295) +- `range: optional[AsRange]` + +#### 类型:`AsRange` + +- `min: int` +- `max: int` + +解析与约束要点: + +- `inherit` 语义与排序/范围编码规则来自 RFC 3779。RFC 3779 §3.2.3.3;RFC 3779 §3.2.3.8。 + +## 0.5 常用 OID 表(最小集合) + +> 说明:表中 “来源 RFC” 给出该 OID 在本模型中的直接规范引用点;在实现时也可以直接用点分十进制比对。 + +| OID | 符号名/含义 | 来源 RFC | +|---|---|---| +| `1.2.840.113549.1.7.2` | CMS SignedData(ContentInfo.contentType) | RFC 6488 §3(1a) | +| `1.2.840.113549.1.9.3` | CMS signedAttrs: content-type | RFC 6488 §3(1f) | +| `1.2.840.113549.1.9.4` | CMS signedAttrs: message-digest | RFC 6488 §3(1f) | +| `1.2.840.113549.1.9.5` | CMS signedAttrs: signing-time | RFC 9589 §4(更新 RFC 6488 §3(1f)/(1g)) | +| `1.2.840.113549.1.9.16.1.24` | ROA eContentType: id-ct-routeOriginAuthz | RFC 9582 §3 | +| `1.2.840.113549.1.9.16.1.26` | Manifest eContentType: id-ct-rpkiManifest | RFC 9286 §4.1 | +| `1.3.6.1.5.5.7.1.1` | X.509 v3 扩展:authorityInfoAccess | RFC 5280 §4.2.2.1 | +| `1.3.6.1.5.5.7.1.11` | X.509 v3 扩展:subjectInfoAccess | RFC 5280 §4.2.2.2;RPKI 约束见 RFC 6487 §4.8.8 | +| `1.3.6.1.5.5.7.48.2` | AIA accessMethod: id-ad-caIssuers | RFC 5280 §4.2.2.1 | +| `1.3.6.1.5.5.7.48.5` | SIA accessMethod: id-ad-caRepository | RFC 5280 §4.2.2.2;RPKI 语义见 RFC 6481 §2.2;约束见 RFC 6487 §4.8.8.1 | +| `1.3.6.1.5.5.7.48.10` | SIA accessMethod: id-ad-rpkiManifest | RFC 6487 §4.8.8.1 | +| `1.3.6.1.5.5.7.48.11` | SIA accessMethod: id-ad-signedObject | RFC 6487 §4.8.8.2 | +| `1.3.6.1.5.5.7.48.13` | SIA accessMethod: id-ad-rpkiNotify(RRDP Notification) | RFC 8182 §3.2 | +| `1.3.6.1.5.5.7.1.7` | RFC 3779 IP 资源扩展:id-pe-ipAddrBlocks | RFC 3779 §2.2.1 | +| `1.3.6.1.5.5.7.1.8` | RFC 3779 AS 资源扩展:id-pe-autonomousSysIds | RFC 3779 §3.2.1 | +| `2.5.29.31` | X.509 v3 扩展:cRLDistributionPoints | RFC 5280 §4.2.1.13;RPKI 约束见 RFC 6487 §4.8.6 | +| `2.5.29.32` | X.509 v3 扩展:certificatePolicies | RFC 5280 §4.2.1.4;RPKI 约束见 RFC 6487 §4.8.9;更新见 RFC 7318 §2 | +| `2.5.29.14` | X.509 v3 扩展:subjectKeyIdentifier | RFC 5280 §4.2.1.2;RPKI 约束见 RFC 6487 §4.8.2 | +| `2.5.29.35` | X.509 v3 扩展:authorityKeyIdentifier(证书/CRL) | RFC 5280 §4.2.1.1(证书);RFC 5280 §5.2.1(CRL);RPKI 约束见 RFC 6487 §4.8.3 / RFC 9829 §3.1 | +| `2.5.29.15` | X.509 v3 扩展:keyUsage | RFC 5280 §4.2.1.3;RPKI 约束见 RFC 6487 §4.8.4 | +| `2.5.29.19` | X.509 v3 扩展:basicConstraints | RFC 5280 §4.2.1.9;RPKI 约束见 RFC 6487 §4.8.1 | +| `2.5.29.20` | CRL 扩展:cRLNumber | RFC 5280 §5.2.3;RPKI 约束更新见 RFC 9829 §3.1 | +| `1.3.6.1.5.5.7.14.2` | RPKI Certificate Policy:id-cp-ipAddr-asNumber | RFC 6484 §1.2;证书中使用要求见 RFC 6487 §4.8.9 | +| `1.3.6.1.5.5.7.2.1` | Policy Qualifier:id-qt-cps | RFC 5280 §4.2.1.4;RPKI 限制见 RFC 7318 §2 | +| `2.16.840.1.101.3.4.2.1` | `id-sha256`(SHA-256 摘要算法 OID) | RFC 7935 §2(引用 RFC 5754) | +| `1.2.840.113549.1.1.1` | `rsaEncryption`(CMS SignerInfo.signatureAlgorithm 生成时使用) | RFC 7935 §2(引用 RFC 3370) | +| `1.2.840.113549.1.1.11` | `sha256WithRSAEncryption`(证书/CRL 签名算法;CMS 验证兼容) | RFC 7935 §2(引用 RFC 4055) | + +## 0.6 `None` 类型字段的含义(文档约定) + +在本目录的“抽象数据模型(接口)”字段表里,如果某字段的类型标为 `None`,表示: + +- 该字段/子字段在通用 ASN.1 结构里**可能存在**(或是可选字段/可扩展集合),但在 RPKI profile 下被明确规定 **MUST NOT be present / MUST be omitted**; +- 因此它**不应作为正常语义数据对象的可用字段**出现; +- 实现可以选择两种方式之一: + 1) **不在对象结构中建模该字段**,仅在“约束清单”里写明禁止出现;解析时若遇到该字段则直接报“profile 违规”;或 + 2) 为了便于输出结构化诊断,把它保留成“永远为 None 的占位字段”,并规定:若从 DER 中解析到该字段,则对象不符合 profile。 + +注意:像 CMS `signedAttrs` 中的 “other attributes MUST NOT be included” 这类规则,本质是“集合不得含额外成员”。文档里用 `other_attrs: None` 只是为了把“禁止项”放进同一张字段表,便于实现逐条对照;它不代表 ASN.1 里真的有一个名为 `other_attrs` 的字段。 diff --git a/specs/04_crl.md b/specs/04_crl.md new file mode 100644 index 0000000..8b861d3 --- /dev/null +++ b/specs/04_crl.md @@ -0,0 +1,141 @@ +# 04. CRL(Resource Certificate Revocation List) + +## 4.1 对象定位 + +RPKI CA 必须发布符合 profile 的 CRL,用于声明其签发且未过期证书中的撤销集合。RFC 6487 §5。 + +RFC 9829 更新了 RFC 6487 对 CRL Number 以及 “current CRL” 识别的处理规则。RFC 9829 §3。 + +## 4.2 原始载体与编码 + +- 载体:X.509 CRL。 +- 编码:DER(遵循 RFC 5280 的 CRL 结构与字段语义,但受 RPKI profile 限制)。RFC 6487 §5(“consistent with RFC 5280”)。 + +### 4.2.1 X.509 v2 CRL 基本语法(ASN.1;RFC 5280 §5.1) + +CRL 在编码层面是 RFC 5280 定义的 `CertificateList`(DER)。RFC 5280 §5.1。 + +```asn1 +CertificateList ::= SEQUENCE { + tbsCertList TBSCertList, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING } + +TBSCertList ::= SEQUENCE { + version Version OPTIONAL, + -- if present, MUST be v2 + signature AlgorithmIdentifier, + issuer Name, + thisUpdate Time, + nextUpdate Time OPTIONAL, + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, version MUST be v2 + } OPTIONAL, + crlExtensions [0] EXPLICIT Extensions OPTIONAL + -- if present, version MUST be v2 + } +``` + +> 注:`Version`/`Time`/`CertificateSerialNumber`/`Extensions` 的定义在 RFC 5280 §4.1;`AlgorithmIdentifier` 的定义在 RFC 5280 §4.1.1.2(RFC 5280 §5.1 的注释段落给出引用)。 + +### 4.2.2 CRL 扩展中常用内层结构(ASN.1;RFC 5280 §4.2.1.1;RFC 5280 §5.2.3) + +RPKI profile(经 RFC 9829 更新)要求 CRL **仅允许**两个扩展:AKI 与 CRL Number。RFC 9829 §3.1。 + +```asn1 +id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + +AuthorityKeyIdentifier ::= SEQUENCE { + keyIdentifier [0] KeyIdentifier OPTIONAL, + authorityCertIssuer [1] GeneralNames OPTIONAL, + authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + +KeyIdentifier ::= OCTET STRING + +id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } + +CRLNumber ::= INTEGER (0..MAX) +``` + + +## 4.3 抽象数据模型(接口) + +### 4.3.0 `Asn1TimeUtc`(X.509 `Time` 的抽象) + +X.509 中的 `Time` 是一个 CHOICE,可用 `UTCTime` 或 `GeneralizedTime` 编码;但在语义层面都表达一个 UTC 时间点。RFC 5280 §4.1.2.5;RFC 5280 §5.1.2.4。 + +因此在抽象模型中,将 `Time` 规范化为 “UTC 时间点 + 原始编码形态”: + +| 字段 | 类型 | 语义 | 约束/解析规则 | RFC 引用 | +|---|---|---|---|---| +| `utc` | `UtcTime` | 规范化后的 UTC 时间点 | 从 `UTCTime`/`GeneralizedTime` 解码并转换为 UTC 时间点 | RFC 5280 §4.1.2.5.1;RFC 5280 §4.1.2.5.2 | +| `encoding` | `enum{UTCTime, GeneralizedTime}` | 原始编码类型 | 需要保留编码形态以支持 profile 的编码约束校验 | RFC 5280 §5.1.2.4;RFC 5280 §5.1.2.5 | + +### 4.3.1 `RpkixCrl` + +| 字段 | 类型 | 语义 | 约束/解析规则 | RFC 引用 | +|---|---|---|---|---| +| `raw_der` | `DerBytes` | CRL DER | 原样保留(建议) | RFC 6487 §5 | +| `version` | `int` | CRL 版本 | MUST 为 v2;RP 不要求处理 v1 | RFC 6487 §5 | +| `issuer_dn` | `RpkixDistinguishedName` | CRL issuer | issuer DN 约束同证书 issuer(CN/serialNumber 规则) | RFC 6487 §5(引用 §4.4) | +| `signature_algorithm` | `Oid` | CRL 签名算法 | 必须为 `sha256WithRSAEncryption`(`1.2.840.113549.1.1.11`) | RFC 6487 §5;RFC 7935 §2(引用 RFC 4055) | +| `this_update` | `Asn1TimeUtc` | 本次 CRL 生成时间 | X.509 `Time`(UTCTime/GeneralizedTime)解码为 UTC 时间点,并保留原始编码形态 | RFC 5280 §5.1.2.4;RFC 5280 §4.1.2.5 | +| `next_update` | `Asn1TimeUtc` | 下次 CRL 计划时间 | **MUST present**(尽管 ASN.1 标注 OPTIONAL);解码同 `this_update` | RFC 5280 §5.1.2.5 | +| `revoked_certs` | `list[RevokedCert]` | 撤销条目 | 仅包含未过期且已撤销证书 | RFC 6487 §5 | +| `extensions` | `CrlExtensions` | CRL 扩展 | **仅允许** AKI 与 CRL Number 两个扩展 | RFC 9829 §3.1(更新 RFC 6487 §5) | + +### 4.3.2 `RevokedCert` + +| 字段 | 类型 | 语义 | 约束/解析规则 | RFC 引用 | +|---|---|---|---|---| +| `serial_number` | `int` | 被撤销证书序列号 | 必须存在 | RFC 6487 §5 | +| `revocation_date` | `Asn1TimeUtc` | 撤销时间 | X.509 `Time` 解码为 UTC 时间点,并保留原始编码形态;revocationDate 的表达规则同 `thisUpdate` | RFC 6487 §5;RFC 5280 §5.1.2.6(引用 §5.1.2.4) | +| `entry_extensions` | `None` | 条目扩展 | CRL entry extensions MUST NOT present | RFC 6487 §5 | + +### 4.3.3 `CrlExtensions` + +| 字段 | 类型 | 语义 | 约束/解析规则 | RFC 引用 | +|---|---|---|---|---| +| `authority_key_identifier` | `bytes` | AKI.keyIdentifier | **extnID=`2.5.29.35`**;RP MUST 处理 AKI;CRL 扩展仅允许 AKI 与 CRLNumber | RFC 9829 §3.1;RFC 5280 §5.2.1 | +| `crl_number` | `int` | CRLNumber | **extnID=`2.5.29.20`**;RP 必须忽略其排序语义;仅检查 non-critical 且数值范围:0..2^159-1 | RFC 9829 §3.1(引用 RFC 5280 §5.2.3) | + +## 4.4 字段级约束清单(实现对照) + +- CA 必须签发 version 2 CRL;RP 不要求处理 v1。RFC 6487 §5。 +- CRL 不得包含 Indirect CRL 或 Delta CRL。RFC 6487 §5。 +- CRL 范围必须覆盖该 CA 签发的全部证书。RFC 6487 §5。 +- `nextUpdate` MUST present(尽管 ASN.1 标注 OPTIONAL)。RFC 5280 §5.1.2.5。 +- 时间编码规则(`thisUpdate`/`nextUpdate`/`revocationDate`):2049(含)及之前必须用 `UTCTime`;2050(含)及之后必须用 `GeneralizedTime`;应用必须能处理两者。RFC 5280 §5.1.2.4;RFC 5280 §5.1.2.5;RFC 5280 §5.1.2.6(引用 §5.1.2.4)。 +- 只允许两个 CRL 扩展:AKI 与 CRLNumber;除此之外不允许任何 CRL 扩展。RFC 9829 §3.1。 +- RP 必须处理 AKI;CRLNumber 仅做 “non-critical + 数值范围” 检查并忽略其它语义。RFC 9829 §3.1。 +- 每个撤销条目仅允许 Serial Number 与 Revocation Date;不允许条目扩展。RFC 6487 §5。 + +## 4.5 CRL 验签与绑定校验(验证阶段) + +> 本节描述“基于已解析的数据对象对 CRL 做签名校验(cryptographic signature validation)”所需输入与处理步骤。其定位属于验证阶段(而非纯解码阶段)。 + +### 4.5.1 验签所需输入 + +- **CRL 对象本身**:包含 `tbsCertList`(待签名数据)、`signatureAlgorithm`、`signatureValue`。RFC 5280 §5.1。 +- **CRL issuer 的 CA 证书(或其公钥)**:用于提供验签公钥(`SubjectPublicKeyInfo`)。RFC 5280 §6.3.3 (f)-(g)。 +- (链路上下文)用于验证 issuer CA 证书链的同一信任锚(trust anchor):CRL issuer 的证书链必须与目标证书使用同一信任锚。RFC 5280 §6.3.3 (f)。 + +### 4.5.2 绑定与一致性校验(推荐最小集合) + +在执行签名验签之前,RP 通常应进行下列绑定校验以确保“用的是正确的 issuer 证书/公钥”: + +1. **Issuer DN 匹配**:`CRL.issuer_dn` 必须等于 issuer CA 证书的 `subject`。RFC 5280 §5.1(`issuer` 字段);RFC 5280 §6.3.3 (b)(“verify that the CRL issuer matches the certificate issuer” 的一般化要求)。 +2. **AKI ↔ SKI 绑定**:若 issuer CA 证书包含 `SubjectKeyIdentifier`(SKI,OID `2.5.29.14`),则其值应与 CRL 的 `AuthorityKeyIdentifier.keyIdentifier`(AKI,OID `2.5.29.35`)匹配。RFC 5280 §4.2.1.1;RFC 5280 §4.2.1.2;RFC 5280 §6.3.3 (c)(3)(delta 与 complete CRL 的 AKI 匹配规则;在非 delta 场景下同样用于选择正确的签发者公钥)。 +3. **KeyUsage 约束**:若 issuer CA 证书存在 `KeyUsage` 扩展(OID `2.5.29.15`),则必须包含 `cRLSign` 位。RFC 5280 §4.2.1.3;RFC 5280 §6.3.3 (f)。 + +> 注:SKI 的生成算法在 RFC 5280 中不强制限定(不同 CA 可能采用不同方式生成 keyIdentifier);因此一般做“字节值匹配”,而不对 SKI 值做“从公钥推导再比对”的强校验。 + +### 4.5.3 签名验签 + +完成上述绑定后,使用 issuer CA 证书提供的公钥对 CRL 签名进行验签: + +- 使用 issuer 的 `SubjectPublicKeyInfo` 验证 `signatureValue` 是对 `tbsCertList` 的正确签名。RFC 5280 §6.3.3 (g)。 +- RPKI profile 限定签名算法为 `sha256WithRSAEncryption`(OID `1.2.840.113549.1.1.11`),并要求算法参数编码符合 X.509/PKIX 约束(常见为 absent 或 NULL)。RFC 6487 §5;RFC 7935 §2;RFC 5280 §4.1.1.2。 diff --git a/src/data_model/crl.rs b/src/data_model/crl.rs new file mode 100644 index 0000000..6d52d7f --- /dev/null +++ b/src/data_model/crl.rs @@ -0,0 +1,429 @@ +use x509_parser::extensions::{AuthorityKeyIdentifier, ParsedExtension, X509Extension}; +use x509_parser::prelude::FromDer; +use x509_parser::prelude::X509Version; +use x509_parser::revocation_list::CertificateRevocationList; +use x509_parser::asn1_rs::Tag; +use x509_parser::certificate::X509Certificate; +use x509_parser::x509::SubjectPublicKeyInfo; +use x509_parser::x509::AlgorithmIdentifier; + +const OID_SHA256_WITH_RSA_ENCRYPTION: &str = "1.2.840.113549.1.1.11"; +const OID_AUTHORITY_KEY_IDENTIFIER: &str = "2.5.29.35"; +const OID_CRL_NUMBER: &str = "2.5.29.20"; +const OID_SUBJECT_KEY_IDENTIFIER: &str = "2.5.29.14"; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Asn1TimeEncoding { + UtcTime, + GeneralizedTime, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Asn1TimeUtc { + pub utc: time::OffsetDateTime, + pub encoding: Asn1TimeEncoding, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct BigUnsigned { + /// Minimal big-endian bytes. For zero, this is `[0]`. + pub bytes_be: Vec, +} + +impl BigUnsigned { + pub fn to_hex_upper(&self) -> String { + hex::encode_upper(&self.bytes_be) + } + + pub fn to_u64(&self) -> Option { + if self.bytes_be.len() > 8 { + return None; + } + let mut value: u64 = 0; + for &b in &self.bytes_be { + value = (value << 8) | (b as u64); + } + Some(value) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct RevokedCert { + pub serial_number: BigUnsigned, + pub revocation_date: Asn1TimeUtc, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CrlExtensions { + pub authority_key_identifier: Vec, + pub crl_number: BigUnsigned, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct RpkixCrl { + pub raw_der: Vec, + pub version: u32, + pub issuer_dn: String, + pub signature_algorithm_oid: String, + pub this_update: Asn1TimeUtc, + pub next_update: Asn1TimeUtc, + pub revoked_certs: Vec, + pub extensions: CrlExtensions, +} + +#[derive(Debug, thiserror::Error)] +pub enum CrlDecodeError { + #[error("X.509 CRL parse error: {0}")] + Parse(String), + + #[error("trailing bytes after CRL DER: {0} bytes")] + TrailingBytes(usize), + + #[error("CRL version must be v2, got {0:?}")] + InvalidVersion(Option), + + #[error("CRL signatureAlgorithm must be sha256WithRSAEncryption ({OID_SHA256_WITH_RSA_ENCRYPTION}), got {0}")] + InvalidSignatureAlgorithm(String), + + #[error("CRL signature algorithm parameters must be absent or NULL")] + InvalidSignatureAlgorithmParameters, + + #[error("CRL signatureAlgorithm must match TBSCertList.signature")] + SignatureAlgorithmMismatch, + + #[error("CRL extensions must be exactly two (AKI + CRLNumber), got {0}")] + InvalidExtensionsCount(usize), + + #[error("unsupported CRL extension OID {0}")] + UnsupportedExtension(String), + + #[error("duplicate CRL extension OID {0}")] + DuplicateExtension(String), + + #[error("AuthorityKeyIdentifier must contain keyIdentifier")] + AkiMissingKeyIdentifier, + + #[error("AuthorityKeyIdentifier must not contain authorityCertIssuer or authorityCertSerialNumber")] + AkiHasOtherFields, + + #[error("CRLNumber must be non-critical")] + CrlNumberCritical, + + #[error("CRLNumber out of range (must fit in 0..2^159-1)")] + CrlNumberOutOfRange, + + #[error("CRL entry extensions must not be present")] + EntryExtensionsNotAllowed, + + #[error("CRL nextUpdate must be present (RFC 5280 §5.1.2.5)")] + NextUpdateMissing, + + #[error("{field} time encoding invalid for year {year}: got {encoding:?}")] + InvalidTimeEncoding { + field: &'static str, + year: i32, + encoding: Asn1TimeEncoding, + }, +} + +impl RpkixCrl { + /// Decode a DER-encoded X.509 v2 CRL and enforce the RPKI profile constraints from + /// `specs/prepare/data_models/04_crl.md` (RFC 6487 §5; RFC 9829 §3.1; RFC 5280 §5.1). + pub fn decode_der(der: &[u8]) -> Result { + let (rem, crl) = CertificateRevocationList::from_der(der) + .map_err(|e| CrlDecodeError::Parse(e.to_string()))?; + if !rem.is_empty() { + return Err(CrlDecodeError::TrailingBytes(rem.len())); + } + + let version = match crl.version() { + Some(X509Version::V2) => 2, + Some(v) => return Err(CrlDecodeError::InvalidVersion(Some(v.0))), + None => return Err(CrlDecodeError::InvalidVersion(None)), + }; + + let sig_oid = crl.signature_algorithm.algorithm.to_id_string(); + let tbs_sig_oid = crl.tbs_cert_list.signature.algorithm.to_id_string(); + if sig_oid != tbs_sig_oid { + return Err(CrlDecodeError::SignatureAlgorithmMismatch); + } + if sig_oid != OID_SHA256_WITH_RSA_ENCRYPTION { + return Err(CrlDecodeError::InvalidSignatureAlgorithm(sig_oid)); + } + validate_sig_params(&crl.signature_algorithm)?; + validate_sig_params(&crl.tbs_cert_list.signature)?; + + let extensions = parse_and_validate_extensions(crl.extensions())?; + + let revoked_certs = crl + .iter_revoked_certificates() + .map(|rc| { + if !rc.extensions().is_empty() { + return Err(CrlDecodeError::EntryExtensionsNotAllowed); + } + let revocation_date = asn1_time_to_model(rc.revocation_date); + validate_time_encoding("revocationDate", &revocation_date)?; + Ok(RevokedCert { + serial_number: biguint_to_big_unsigned(rc.serial()), + revocation_date, + }) + }) + .collect::, _>>()?; + + let this_update = asn1_time_to_model(crl.last_update()); + validate_time_encoding("thisUpdate", &this_update)?; + + let next_update = crl + .next_update() + .map(asn1_time_to_model) + .ok_or(CrlDecodeError::NextUpdateMissing)?; + validate_time_encoding("nextUpdate", &next_update)?; + + Ok(RpkixCrl { + raw_der: der.to_vec(), + version, + issuer_dn: crl.issuer().to_string(), + signature_algorithm_oid: OID_SHA256_WITH_RSA_ENCRYPTION.to_string(), + this_update, + next_update, + revoked_certs, + extensions, + }) + } + + /// Verify the cryptographic signature on this CRL using the issuer certificate. + /// + /// Signature verification needs the issuer public key (RFC 5280 §6.3.3 (f)-(g)). + /// In RPKI practice, this public key is obtained from the CRL issuer CA certificate + /// (and that certificate must already be validated up to the same trust anchor). + /// + /// This helper also performs common binding checks: + /// - CRL `issuer_dn` must equal issuer certificate `subject` + /// - if issuer KeyUsage is present, require `cRLSign` + /// - if issuer SKI is present, require it matches CRL AKI.keyIdentifier + pub fn verify_signature_with_issuer_certificate_der( + &self, + issuer_cert_der: &[u8], + ) -> Result<(), CrlVerifyError> { + let (rem, issuer_cert) = X509Certificate::from_der(issuer_cert_der) + .map_err(|e| CrlVerifyError::IssuerCertificateParse(e.to_string()))?; + if !rem.is_empty() { + return Err(CrlVerifyError::IssuerCertificateTrailingBytes(rem.len())); + } + + let subject_dn = issuer_cert.subject().to_string(); + if subject_dn != self.issuer_dn { + return Err(CrlVerifyError::IssuerSubjectMismatch { + crl_issuer_dn: self.issuer_dn.clone(), + issuer_subject_dn: subject_dn, + }); + } + + if let Some(ku) = issuer_cert + .key_usage() + .map_err(|e| CrlVerifyError::IssuerCertificateParse(e.to_string()))? + { + if !ku.value.crl_sign() { + return Err(CrlVerifyError::IssuerKeyUsageMissingCrlSign); + } + } + + if let Some(issuer_ski) = get_subject_key_identifier(&issuer_cert) { + if issuer_ski != self.extensions.authority_key_identifier { + return Err(CrlVerifyError::AkiSkiMismatch); + } + } + + self.verify_signature_with_issuer_spki(issuer_cert.public_key()) + } + + /// Verify the cryptographic signature on this CRL using the issuer SubjectPublicKeyInfo. + pub fn verify_signature_with_issuer_spki( + &self, + issuer_spki: &SubjectPublicKeyInfo<'_>, + ) -> Result<(), CrlVerifyError> { + let (rem, crl) = CertificateRevocationList::from_der(&self.raw_der) + .map_err(|e| CrlVerifyError::CrlParse(e.to_string()))?; + if !rem.is_empty() { + return Err(CrlVerifyError::CrlTrailingBytes(rem.len())); + } + crl.verify_signature(issuer_spki) + .map_err(|e| CrlVerifyError::InvalidSignature(e.to_string())) + } + + /// Verify the cryptographic signature on this CRL using a DER-encoded SubjectPublicKeyInfo. + pub fn verify_signature_with_issuer_spki_der( + &self, + issuer_spki_der: &[u8], + ) -> Result<(), CrlVerifyError> { + let (rem, spki) = SubjectPublicKeyInfo::from_der(issuer_spki_der) + .map_err(|e| CrlVerifyError::IssuerSpkiParse(e.to_string()))?; + if !rem.is_empty() { + return Err(CrlVerifyError::IssuerSpkiTrailingBytes(rem.len())); + } + self.verify_signature_with_issuer_spki(&spki) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum CrlVerifyError { + #[error("issuer certificate parse error: {0}")] + IssuerCertificateParse(String), + + #[error("trailing bytes after issuer certificate DER: {0} bytes")] + IssuerCertificateTrailingBytes(usize), + + #[error("issuer SubjectPublicKeyInfo parse error: {0}")] + IssuerSpkiParse(String), + + #[error("trailing bytes after issuer SubjectPublicKeyInfo DER: {0} bytes")] + IssuerSpkiTrailingBytes(usize), + + #[error("CRL parse error: {0}")] + CrlParse(String), + + #[error("trailing bytes after CRL DER: {0} bytes")] + CrlTrailingBytes(usize), + + #[error("CRL issuer DN does not match issuer certificate subject")] + IssuerSubjectMismatch { + crl_issuer_dn: String, + issuer_subject_dn: String, + }, + + #[error("issuer certificate keyUsage present but missing cRLSign")] + IssuerKeyUsageMissingCrlSign, + + #[error("CRL AKI.keyIdentifier does not match issuer certificate SKI")] + AkiSkiMismatch, + + #[error("CRL signature verification failed: {0}")] + InvalidSignature(String), +} + +fn asn1_time_to_model(t: x509_parser::time::ASN1Time) -> Asn1TimeUtc { + let encoding = if t.is_utctime() { + Asn1TimeEncoding::UtcTime + } else { + Asn1TimeEncoding::GeneralizedTime + }; + Asn1TimeUtc { + utc: t.to_datetime(), + encoding, + } +} + +fn validate_time_encoding(field: &'static str, t: &Asn1TimeUtc) -> Result<(), CrlDecodeError> { + let year = t.utc.year(); + let expected = if year <= 2049 { + Asn1TimeEncoding::UtcTime + } else { + Asn1TimeEncoding::GeneralizedTime + }; + if t.encoding != expected { + return Err(CrlDecodeError::InvalidTimeEncoding { + field, + year, + encoding: t.encoding, + }); + } + Ok(()) +} + +fn validate_sig_params(sig: &AlgorithmIdentifier<'_>) -> Result<(), CrlDecodeError> { + match sig.parameters.as_ref() { + None => Ok(()), + Some(p) if p.tag() == Tag::Null => Ok(()), + Some(_p) => Err(CrlDecodeError::InvalidSignatureAlgorithmParameters), + } +} + +fn parse_and_validate_extensions(exts: &[X509Extension<'_>]) -> Result { + if exts.len() != 2 { + return Err(CrlDecodeError::InvalidExtensionsCount(exts.len())); + } + + let mut authority_key_identifier: Option> = None; + let mut crl_number: Option = None; + + for ext in exts { + let oid = ext.oid.to_id_string(); + match oid.as_str() { + OID_AUTHORITY_KEY_IDENTIFIER => { + if authority_key_identifier.is_some() { + return Err(CrlDecodeError::DuplicateExtension(oid)); + } + let aki = parse_aki(ext)?; + authority_key_identifier = Some(aki); + } + OID_CRL_NUMBER => { + if crl_number.is_some() { + return Err(CrlDecodeError::DuplicateExtension(oid)); + } + if ext.critical { + return Err(CrlDecodeError::CrlNumberCritical); + } + let n = parse_crl_number(ext)?; + if n.bits() > 159 { + return Err(CrlDecodeError::CrlNumberOutOfRange); + } + crl_number = Some(biguint_to_big_unsigned(&n)); + } + _ => return Err(CrlDecodeError::UnsupportedExtension(oid)), + } + } + + Ok(CrlExtensions { + authority_key_identifier: authority_key_identifier.unwrap(), + crl_number: crl_number.unwrap(), + }) +} + +fn parse_aki(ext: &X509Extension<'_>) -> Result, CrlDecodeError> { + let ParsedExtension::AuthorityKeyIdentifier(aki) = ext.parsed_extension() else { + return Err(CrlDecodeError::Parse("AKI extension parse failed".into())); + }; + validate_aki_profile(aki)?; + Ok(aki + .key_identifier + .as_ref() + .ok_or(CrlDecodeError::AkiMissingKeyIdentifier)? + .0 + .to_vec()) +} + +fn validate_aki_profile(aki: &AuthorityKeyIdentifier<'_>) -> Result<(), CrlDecodeError> { + if aki.key_identifier.is_none() { + return Err(CrlDecodeError::AkiMissingKeyIdentifier); + } + if aki.authority_cert_issuer.is_some() || aki.authority_cert_serial.is_some() { + return Err(CrlDecodeError::AkiHasOtherFields); + } + Ok(()) +} + +fn parse_crl_number(ext: &X509Extension<'_>) -> Result { + match ext.parsed_extension() { + ParsedExtension::CRLNumber(n) => Ok(n.clone()), + ParsedExtension::ParseError { error } => Err(CrlDecodeError::Parse(error.to_string())), + _ => Err(CrlDecodeError::Parse("CRLNumber extension parse failed".into())), + } +} + +fn biguint_to_big_unsigned(n: &der_parser::num_bigint::BigUint) -> BigUnsigned { + let mut bytes = n.to_bytes_be(); + if bytes.is_empty() { + bytes.push(0); + } + BigUnsigned { bytes_be: bytes } +} + +fn get_subject_key_identifier(cert: &X509Certificate<'_>) -> Option> { + cert.extensions() + .iter() + .find(|ext| ext.oid.to_id_string() == OID_SUBJECT_KEY_IDENTIFIER) + .and_then(|ext| match ext.parsed_extension() { + ParsedExtension::SubjectKeyIdentifier(ki) => Some(ki.0.to_vec()), + _ => None, + }) +} diff --git a/src/data_model/mod.rs b/src/data_model/mod.rs new file mode 100644 index 0000000..d20a38c --- /dev/null +++ b/src/data_model/mod.rs @@ -0,0 +1,2 @@ +pub mod crl; + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c0dd03b --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod data_model; diff --git a/tests/fixtures/0099DEAB073EFD74C250C0A382B25012B5082AEE.crl b/tests/fixtures/0099DEAB073EFD74C250C0A382B25012B5082AEE.crl new file mode 100644 index 0000000000000000000000000000000000000000..e5b446a4d6bde27988909eb937c0fc34c86f2b54 GIT binary patch literal 1268 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142067.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142067.roa new file mode 100644 index 0000000000000000000000000000000000000000..013a5773244ec51823f748107b43d52e52f9dd54 GIT binary patch literal 1762 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142069.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142069.roa new file mode 100644 index 0000000000000000000000000000000000000000..abccbe207ece90426d5d82d1a3ddf3a25b7f575a GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qgz8VM{2(mCSFd1+ga5A$qC@?YwGchk{V!2_^#B#-;iFwZgW+p}^ zCJ_@~wF%QSyseV91^yMV4P0W<%V=o83%8t+o0Y-9%TUxnn2kA)Wyuu zz`(%J(9l31B+M$TVPNX!Z0T(3WMN@yVCH7-Y~W(-W?^RJY++$(>g4KTX6|a~X5s4O zXdoxfYh-3%Xk=huXkcn&7$weYWNu(+XlY<*XkcU*Wnc_5lv!BA(!|2e(A?R{(AnI~ z!pzv&(8Aoz(!$)p)WFcuz}3mo*~r4s&CJc*povil+0Bfs49rc8{0s(7j9g4jjEoE? zBd$#2%NOHPQ9aSAP*ufs#IHeedLh3~(YmN_uDi+;Wx5SdcUv*EtUOp###dez99irW z^rv)66aQu}y>O_&{*#`^4VIL|M*UE=>8xrv9Q?>%_%E9b}c%)?Cooa&EOPn>$^ z7~h&_3`e9^9_Hh9T2ixe%atURvub~%Yo>IhelA_0sAgmHD}0j0?W_p5C!z^n4(9dG zP592c9=qFPRU=e%!ShwF-D`tWvySV`{~2&Da*@fF>Wv3DZ>-?0kyBr5IDxBEF!clz z+qImld%V}yC_LO4={9k~vY0P%TTb0lo_$4@TWhUAwb{O+BNsa#sD13}zaO(&Swe2v zqi@X>$^!QcnV1jYQduf&eMLU56UK zeK(K?Nh`BR7>G59u>P47-4T#q!)xEB(=m15wYvFzyA1e13iufr|Ff_#GqE=qB!l?! zEHMUA1`!Lw7KF3~6%|+JC0pt17Zqe@>LsTZ<)xPB<)xPB7o`^D>qGeZ2KvON8NKA9 z9D_PG4sA9@R#tXKMwTLj0)spl-+-wt3B|s|g1pRRxOK&uCHX~_`c9@s=B{q07KScn zW`>5YMovy9W)^Pd&gMpLE{1MyM*2=^mC4~I8G%X0<$eJsk;R!_;kt%-W@%YP`5+${ z_`&RB6dq_nyLQ0S zJlk`dS$1vT_cz;p^2h2AT0ymiKWjEcTvB_%zfi;W>iOwkUzso&HZiU;XkuK(#K_!$ zJz*mkoC~rIq}X63EGM%eFG@LTAcK%&HRMMWS%%;;N*^K1VyMKTpi?wk$Esp+$GJJD zd$Y^ywuoLnzFFu)fN1lwMfr`pnhKGli;RhdON>tuDhbBz2V`9+==dXA`>25?p*WJfibzL?AnrsNw3lk{<9cpiwQe* z7&A^$l-|sKrRvYG&$ll<4_A+py|H5dstHpJ4A1!$2Fh_4-Fcfb`HAO_gy$I&uj}Xb zlxQYOE}!r7Xute1eaAT7jJ5r%jH4RfxwKC?G->jWXEwi^PJ3)$w0y}!>yzP;Q>;#L zH!fi7IbyxFKw{a}ta2^Z=3BRJEnPBm{XXlkWX(8L|M(@xr8@h=1-=E_ v-4|qBePHjQS-sJ)_$9Ab^CZs4ANhBN+D=^?d3WZcjkf;Rk|miRe^CJd-FI=} literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142070.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142070.roa new file mode 100644 index 0000000000000000000000000000000000000000..30d1fd1b29a535e8967f8d923f5a997ecc0509df GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qgz8MG`2(mCSFd1+ga5A$qC@?YwGqEgaV!2_^#B#-;iFwZgW+p}^ zCJ~wc^DI}f9duCmd*$hsh_I|nQo5@Rc;S{aaTO`^nkjm!-U4J{1}4Gj!Uq6~~-hB6ClI2xKc8d{hcn;RLM z8W%SIvKdQxjGp;8#FO0A-kE8m4Ug5k)Oe!iIIz`iII_E zrS{wVZ*(V2H@<(&|L}!%9{GOxefFRJ87)++ifr1j=rH!Pb}sv^u?>Um(%)pw(8i2 z?Q8L6beQeGtAHCKd6uX%J+Oj?W|S4XIg&D=rWpO)LNhsv#t2XlOtXR zMlmlw$1Hh0aYsqf9hsD!%_+;S33!CfwD=}9G1_FZ;M(N>*H_%&Jy*eTLr`H~=BG8? zN)HV_x?fh^;p)!B%*epFxQX$&K@;O)16elaP+2|}F&2@9SrW-bri>C^*#&%^bFMaS zxc}P5KprHm%pzeR)*!)wd7(^LFEC^c=(iT)yT$z__rLSL9ke#WQoLZEZTB4ViTB2W+T9B^~;p-dd6PsrA zl8bT->ex86*%(<_*%=vGiVO-2@?d-ernV#$`w|QCGLzxf6=#;@7gg#znHrh9x|v!S zx|o?68oC-eIhmMQxS2bf8@ag{y15zYJEc`7hnr*sCK;Fe1(-w@XL^O}8s?d$WfkRv zd|==QvyYLR#mT_Izz)VY;BGTQu^-|;xC0RWbqqE%F)}bW&@0MMG>`xVngS>g`3!gr zxL~I7F&QYq*o^ETX<-9F1AcH$M&x7U#Lf*)?2HUTX>5Gnod5jfxTYsx+shZR!c6Ta%B6T{DxEMQh$v22ObX7eJ_5@ zU7wwPLHON<#<05<-?#ifr}Cp}&x)_S-)_DSE_>DCP!wUi*Ut3$tr#P<)t!!t3`_T? z1xoX+tG}e}c6h%1?CE=JbZ@OasjYfH?2oh8*R`UpzSlPFy?lhPpho>wc2>`(f(ttu zws=2aW_oOW@UvNze3$(H$G0P!g zt`YfnbyLCAvl5R?!GYy%TaDUxgsGfNyZ7nGqcvw`p7U~?QgeCDq-53fK(7Dy2mYL* zWz(Gxr`)l5a{Xbt!}1_A8HrVjbJj1PXE9U0#rtzW=j;b|N$-`-EIL2@oK@$oeJLkX z>5TQ#vbFoZTu}DDqGj&PtZ~0##%H~XuKUh&1)A1rE&AHf_hFKGug-H80YOW#vwT~9 tldT=23JbODlI(x1kea+_b;cv7H+*0AF)}jj zO*PfJs<2OEW|)@u>9sOd8EZVtuS$z8nL0D%XVAYj4VzYN58t@@{D*+z7cN~H;#@Jm z&Srb|?LIY0r)u#Bt0oJx87_CviYLy|;j!6SlArPE`Y9PB=IfihMQTm;J2`H|XKY`b zzRbKK*>QKpn|as2zg~JTOMm0GIrbs<72>?ErEZVSOrFqF@AYP-xzL;Mda^iYP+ug!(waIPsbwL1IGg=ZqRr!J?s23r>Wn3+UFiRc1$V$ zb@}PDn|!o)w=yv^GB7S~Vmxlp#CX_1mW?@7mXAe@MP#P>ip9)ri49XlC!f)M;rV!_ zQCEV2JV;uZMZ!R=L4@_soal~#{2E^SHl2>C`>xf^@7ra-2U5V#$oQXyg_()H!5|sL zmuHDFh%$&+5VjzsEvTrtGB4RmU%#jzJ5w(?wJ0yOL@zJ3M87DtAYUKC*Ei57HqGcI z7v&h#v2kd#F|x9KfH8OW~Gqo^u zF*7qXbTx8vGBLAoGj}#Oa&s|sb2HL+N~=r`H^~T0GA{QEFo`VA^a|HC%ri^ND#{1> zz`ze?A0s!5lYxVQ9gJ_l-DZShKg54<2O#|G7;I=_WMFQnSCpSvv1~#UFU^$c13OF z%~$0&jJ#VZ)w8ompt^Yjvl{oDul()WW3(wCG#e?-+pX>sU##buPxN&5MJ)zke)U|6X-z<97q@ zNG}ziDF=7#I5VxxucGqkR0;9!P_t#Gs;B16ROoi;Xk+fxIzH!MXU*3`8XwPJc0009 zw(64N1%bK-w~3niY^isOUnt12Ud(Gd_7Zl7jHsA@@&U>z2)a)nC}(o*_m$1*;5}B1OSmyYh?fc literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142072.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142072.roa new file mode 100644 index 0000000000000000000000000000000000000000..7a447f793ec5809e390c3c7ba77ccb2df1721351 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qgei#TF2(mCSFd1+ga5A$qC@?YwGqEjbV!2_^#B#-;iFwZgW+p}^ zCJ|Fx?>m7`k5|2Wd*8_S?2NxZ8U9Nd@WL%;>k7 zIU2}`^BS2M7#bNE7#f%w8AXZn8krjy8d@3{8X6cGMHv{w3}qJ9aCLDrG&OdyG&XQC zb~bi$H8C6C)$T zD!pk_7+a6tV7PnuR+d8KYTvsX-?~44#`JU3f<=9^wBM%8UwC)<+UO4EtNfc1&Smzj z{lmEL{kaXYpQI05pEdJOxYMHE<|83e@9pxvgdOwl?$K8Z>C3N?g)!t?M6+FGAp>Da{f#YR{D}Ku{-r1L1^|Z<7 z~;v@YDVvQmbrN>l#N=SNLV z27hX}*Y9?jZ0jz5WXjsrhb|UTQe@q(6awMlB0UfWKetJl$N^__7j^n-1s zvs~^Wr5UrHTsP@wVrFDuT-?NX+@Oi^uz@TabEqsIix`W@+mFFF4K5$v=VZJhFKM#) zqsTY`D+76uv@(l?fmnkG>z_H%9Rc|@y!LH69aHyRtDE1q%YYB0fS-}^KMM;p6MKU} zGKeqF5@Qf$5V0U^K}cIrQE_EnvX#DmQ9*X5UUF(tUTTS6UTTScQEEZHK7_AtpigX? z(MvAMF{oqX&}L&~Wo2h%WGONzFvx@P4Vc=JQ0z-A$jeNITUVS}l3!G*?__FZ?&@Z0 zVd!FJW@zYYZr!1YGor%;EkNE?$_3uRj&W;W-nV_YraFb%;tX|S6a}N zjaDC0vVK1O_0l(B>0za>iyo&au$%0E?fWCveD>uP?Dg~hN^ShTctc%+Z9?&y3;WJ+ vm^My*&~vTCGfN z1_lO(hK2_EAYoQv4Fgj*XG>>OCkqQx12Z>sX9E{wHw!Z(XA28UQzus!Gjmr&PImLPL389#-@hG zrY4RSX0FDjt_DtymS)aIW(JlPmIjW7ZXmOo7?qIS%*e{X+{DPwV9>^dK(JHoId}~7r?}s%Bt?7Gsp8VrUKEM+Z-D2=5KGj$yz{WL> zm8mhOdK&MK@2ZFU%(j^Oo9&EV!V`P+sLtK=bMt<26t>I=?=M{?{Nr{AuTRv?x5=;5 z9S)uOmAUrF)ahYI1x2^HJ1IpUxbvpStZ#-$#Ang}yq2BYTznq#xbEzA&H7~`<)d`< zC%u7dJ5;H)vu!Y#__V94gDlBE}+eNM=`usc^`OJktlerX5O{F=62c zAp?1kv@(l?fmnkG>z_H%9Rc|@y!LH69aHyRtDE1q%YYB0fS-}^KMM;p6MKU}GKeqF z5@Qf$5V0U^K}cIrQE_EnvX#DmQ9*X5UUF(tUTTS6UTTScQEEZHK7_AtpigX?(MvAM zF{oqX&}L&~Wo2h%WGONzFvx@P4Vc=JQ0z-A$jeNITUVS}l3!G*?__FZ?&@Z0Vd!FJ zW@zYYZr!1Y7HnnjP5!^Gxe+4Rr*$*M?ACnwLtB{7ulmc#az~D1R$%+W_=o`fY9M$mLPK!}!DShsl{A{cB7k9vL<Pk)LcM;9Y214|PlgWeyvB`)(88AV^8cQS7GfZb58i-H9w-`Q#ZieG_w@(>4KHos literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142074.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142074.roa new file mode 100644 index 0000000000000000000000000000000000000000..abf8125f17a459798e5c7889a308a3c6c949ae7f GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qgei;ZG2(mCSFd1+ga5A$qC@?YwGjS|vV!2_^#B#-;iFwZgW+p}^ zCXvwS(8kMK-$edi9~eB}MEv3%lgL~HUby9q+^h@+UWTFu!fec;EX+JSj+Tb5rY>fN z1_lO(hK2_EAYoQv4Fgj*XG>>OCkqQx12Z>sX9E{wHw!Z(XA28UQzus!Gjmrrp9K*29_qqMiv$p zj&6o#W)>#ShK{C&F6I`NPG)Wf7S2wFhE5ia22G4g$Zlq2WngY%n&&D2A30Xh>{q{bvqUx_#N!#zW?;g~Ny-Dvs z+NYCpr)G0syQi^KHpi?lZ=Th9_^P$e=UO8Z*Wk2#ZNaW;sfC<;7MwF=cP-uAY`rq= zM^0nbMW3>(*>zGoCY;RmDDHHBy>7Kjz~pN6$tqJ_ruBAqt=c%}hoXYryNJv2Th4uV zwPc)Sv~>yF_TC<=kDKq#+B2t4ouTPmwoJsPpe2@tY^hx>2|q*jYSmXuZf{rGve1`n zZl+Jzk-krreK(grVmlOf`gl{wv|J6*juXFaD=S_G59u>P47-4T#q!)xEB(=m15wYvFzyA1e13iufr|Ff_#GqE=qB!l?! zEHMUA1`!Lw7KF3~6%|+JC0pt17Zqe@>LsTZ<)xPB<)xPB7o`^D>qGeZ2KvON8NKA9 z9D_PG4sA9@R#tXKMwTLj0)spl-+-wt3B|s|g1pRRxOK&uCHX~_`c9@s=B{q07KScn zW`>5YMovy9W)^Pd&gMpLE{1MyM*2=^mC4~I8G%X0<$eJsk;R!_;kt%-W@%YP`5+${ z_`&RB?^& zvgk|lMX}VD*-L_~U7T&M=5hVAXjndt^F_jru1fR%In828#*Y`VnB}|VnLPTsLHBLO zo9KZ1#q~)Y&025PiRuU+E7|o~F!Avd=dMd0e;i+(YmNDMfJ@S$`fk}#qi^&18~pkm z_n+8Sc}hQVdDC8*H6h%B3X*vzc$2f&Caa#9eU0&b?BnXgOEnCe7*`oIF)m|bWNyHo zu#pSS1=$8tY_JlRli83Lr5rVoLCCQh@*|2YNExM%kYzDcVo}(*^?P9MRa#F+;1qi{`+^4$*eTq z66d?CbpM<2$~evqV874U!*^v#T#AZD+MlS(g_pjry2bXzJK*X9rEmA!o>rJt*7w|4 zeE4>QjZ6NU{VKcSI?f9IDUpmlnzFxP;W{Zh)$9Ws7w(r5unzll=*zxmJ1#iOnOwFK zY1y$cPO{maB}aAn`v0Pb4^L_r5r_)CG(ThC2cD&oZ84{%cO<-8wbZ`ia)9QNTMsTr z-4IRkWS2=>sq~|S-Rbz9cTsPjiu!*ReR#~%FPSkfmgn)+hzatsSuy!Ps?HsL-4ZKa spkc1`RouAaxuI8^;m-a**0HP9djQ{`u literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142075.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142075.roa new file mode 100644 index 0000000000000000000000000000000000000000..755181c7aa8dc94e6d98207247b77a49a4df5ba8 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qgej5lI2(mCSFd1+ga5A$qC@?YwGjT3xV!2_^#B#-;iFwZgW+p}^ zCK0EJkrG!6RrhQNO%Ltu;DuYx$j!=N;AJRkAk4-b%EHXU<7jE~riORRdhb&<5#>GvBm?)J=@=-bC)p(WI?G4*=-C+S7y6I++ga#^ICFvLpS^iyP|cKOJJ>FEhU7hy{^|Qk~ucsP( zc`Ua2Nr#mSGw+hrJJ&m;_W3i%_(Jk1by9R(|>=+Wl_o!HaL+UblGY&L>k+ zu#zWhaoo?9yT9@>F*7nSE^cBxZqUSd*g%$zIaHR9MT|v6(z#{YME5KAnzQz_H%9Rc|@y!LH69aHyRtDE1q%YYB0fS-}^KMM;p6MKU} zGKeqF5@Qf$5V0U^K}cIrQE_EnvX#DmQ9*X5UUF(tUTTS6UTTScQEEZHK7_AtpigX? z(MvAMF{oqX&}L&~Wo2h%WGONzFvx@P4Vc=JQ0z-A$jeNITUVS}l3!G*?__FZ?&@Z0 zVd!FJW@zYYZr!1Y0#9S4BwluS*LQo*(GB ze!i%p%j$9c#id1acB%v%@H@Ms?Ll4j)dxSj9M0z12slsAo1rqVZ&A~{)WaS5><-7P ze(hZ@-r1tL%iJPH)0*C9$6x|g@^5WlAru?^IXqodkaZ>G7 zZ}y{ycfDMz?U+)V*C`?+km)(+WzoMQrPo<5x@WVLxy(4xVx70n?#kbH#*PPcPsgou zjacyHu#1{z*#w207k0m772JOAZ~FKq=;DTg{K7+(-ZFDmopU_zI7RwDr|w^#w`#S! z6;DZT=-ra(DdEYu<@~QRNw-zy>!rR`mj(DdF4Zjl`8VdG@H5Y;+&c}M7*`oIF)m|b zWNyHou#pSS1=$8tY_JlRli83Lr5rVoLCCQh@*|2YNExM%kYzDcVo~_;ZfncR_or+x zaVyFTtkv^5`(#t?WP>O3xD}?~{H@H`fgD|otPCtoj12V_L05V+Yj62fWZXSe*)6dx zH*{h4W;w~k$FC=)*LEf%n3uSg2pzH}m76?aw%!XZk4_+qr+M^uHkK;x;#Ss+Z^+$xVs=9Q!V@ zwd_r9e!lZ~_2Q4O)ZRVtbLgnrRdFEMZQkRvJ`+Mi{>pDi;H(YEsQk6p%|PCF+jZ6B xuXeB9&Urue>_^ubv#Zt|NE5mLazfYL`Xr_AE9-q)E8iYyPMZ5+N7Ay+IsgoCixvO? literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142076.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142076.roa new file mode 100644 index 0000000000000000000000000000000000000000..8aef0a5e227391dddd1fe6cbffd2625a0c73106b GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg{ul@w2(mCSFd1+ga5A$qC@?YwGYKqcV!2_^#B#-;iFwZgW+p}^ zCK2(weTOeso%;PL)AmUE)R`_b=9um^;DuYx$j!=N;AJRkAk4-b%EHXU<7jE;PJH8M9aG_*7@G&C?Yk1{ZZ8OkiI;cDpSV(R8>YUpNS zY3ycZ>}uj-VP;@vVr1ZGXz1c-VPxcFWM*MvV9>;|KT5T`^CB(6R&{*gnY6blk&8{v^_SCL zg>$CN>(v%4vC#i=YvZ)kgpaKZUu$%=P*#0o{9&cgU zS!D*_MN4km+3h%|%)Q}lx6|Px@134Refg1BRWErXklkCJr8PO!tkwQ>v&@8#&s-Q_j6LO~0#72ygQ@DCUT8w7uNT z6XyrPC`>xf^@7ra-2U5V#$oQXyg_()H!5|sL zmuHDFh%$&+5VjzsEvTrtGB4RmU%#jzJ5w(?wJ0yOL@zJ3M87DtAYUKC*Ei57HqGcI z7v&h#v2kd#F|x9KfH8OW~Gqo^u zF*7qXbTx8vGBLAoGj}#Oa&s|sb2HL+N~=r`H^~T0GA{QEFo`VA^a|HC%ri^ND#{1> zz`ze?A0s!5lYxVQ9gJ_l-DZShKg54<2O#|G7;I=_WMFQlSCpSvlND_%p=M-1?7; zBl|Cxbv3vhh9$}>kdsdvS?@QYK-L$VC!mH*U};OVK6*>mmuX@A3< zCC8kj+mp=7w!IWR(0uoA`=QzI1s_*DeX4SUsnwTH?!dy3$j7q{n;2IaG%+q?Vq|W> zp0JS%&IQ>9Qf#mimXq0#7o{9EkU_|?8uBBGEJzupkC0_CRAN!+o$&ue$jZRd#K^#rwY=rphlVv53`8>x#dY+<)4n$z zdpqk=<<@u3j2`B4R>dr<*B`L`6J`IlJu0f{zYW(MmgBY4XZGE{b)}fwX}j~Xj?{k^ zPtJOpF2e|c&%=9lnMtNT9cre%94DFo1+J9lJ-EPd`ikJX7xw+N0Q{eAn*aa+ literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142077.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142077.roa new file mode 100644 index 0000000000000000000000000000000000000000..73ef213443c96c2bc7b213a19f1f444d2c66a949 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg{u&4y2(mCSFd1+ga5A$qC@?YwGYKweV!2_^#B#-;iFwZgW+p}^ zCXw>Rag&$p87+3QonW0IX!Epkb3>H@FWhoQZdL{ZFGEoSVK(Ma7G@qEM@vIjQx`Ks z0|Ns?Lqh|7kT9#ThJmS@v!%1ClZAz;ftj1Rvw@4Tn}wN?vxSAFsgtXVnYpW_n}w^B zqk)__uaTL7p^<@sp@FH9VU#$pk-34Pp{0SLp@ETMlz}nKP-bBbR~G|gCl_NEOJidf z7dK~TS4%?^V-pJ(M`v?4Ggl{LOA8}23ky?cgC<5LWH&RiGB7tW@-rATF>*0AF)}hd zKC|XQS;+3qN7fX&e$v|d=(Swyl)uHwCKbC^L_EIweCni$r$0td+ZLg~!Szb$W|3}U zmF6wqzX^v8n=*14)Se#M?>c{q{pSqU=^r;rzc_Td`SRh`s~SSN!L?y$6I)*E9y_|` zp=+_(;^Tc{ImO4l-__RrP}<&_6{8=%zPLF0DDMt|L!lxQ-%mTC{denQk!w{?h1cx+ zG{s`Y;**sb(z#YGjGUGpKYpY=pD~xcf|0v?&AQK8pVo4`-*)}fqSgN%oG5*N-7@jg zwM5BseS6*KbB$vscz_H%9Rc|@y!LH69aHyRtDE1q%YYB0fS-}^KMM;p6MKU} zGKeqF5@Qf$5V0U^K}cIrQE_EnvX#DmQ9*X5UUF(tUTTS6UTTScQEEZHK7_AtpigX? z(MvAMF{oqX&}L&~Wo2h%WGONzFvx@P4Vc=JQ0z-A$jeNITUVS}l3!G*?__FZ?&@Z0 zVd!FJW@zYYZr!1YaDgi#*HDn_KbA z{n`7>^VXG(moopAbE`;+o_Zg4GV#iVtuu}qH@)BJz1aHD=jj~hlspU1Cpe$jxurxv zd3C(=k2&oX&YOgKR6_X;G$%|f-D|*-aAn2B8|x0Q@^q>H=sInIWLNhV$C=yWJ{J9( z#h-CL?#KzTvZifG-by_0H|`8MzG}%C!QM45eryZ8r}j1fbEx@WhqH?en;2IaG%+q? zVq|W>p0JS%&IQ>9Qf#mimXq0#7o{9EkU_|?8uBBGEJzupkC0_CRANyOfAEyw!1_rR zYe8_4$q6g#D-qMWZ=R}h-g4o>UoF*5Ey&Tu$jZRd#K_RO_TA5~Pu@AXw;Wv)9?w|U5S%b~=3h&>4VUgFT=;%`xrgu+qbtwV^$T+y7~gN=eSi9? zc=7LrZ)=2Sb#z?$?0)0&e!l&M5(~b5+BCDd$y|P7`DXpCiyJ>|epRv|y-NCkK-X8{ z?Uo&H7c1$gE?lTQ_x`sfdp`;`P8M%Y{h(H-%;$U1;^91-DWBt&{ykH6itGIf0C)n9 AA^-pY literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142078.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142078.roa new file mode 100644 index 0000000000000000000000000000000000000000..ab5ea8dc3cdde2ccad0d119a3c853881e2c9fc3c GIT binary patch literal 1762 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142080.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142080.roa new file mode 100644 index 0000000000000000000000000000000000000000..c8cb6ec5ddfe9e47321bdb54eabff5c29b903219 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg84QFC1X-9Em<+fLIGNcQ6d0L;nM4*evD`3dV!2|_#Jpz#GZP~d zlSq(5LXrM%&hTA-Hf7D8=){_x%AsPw3%8t+o0Y-9%TUxnn2kA)Wyuu zz`(%J(9l31B+M$TVPNX!Z0T(3WMN@yVCH7-Y~W(-W?^RJY++$(>g4KTX6|a~X5s4O zXdoxfYh-3%Xk=huXkcn&8YRwaWNu(+XlY<*XkcU-Wnc_5lv!BA)Y#m@(Z$HX#l+am z+0o6#(%8b((%Ib2%+blx+}z2+)YR0)!otkbpovil+0Bfs49rc8{0s(7j9g4jjEoFx zg%UE3+&RIq`H+m=v%R?ovRXE9R}>!OIo7cE&EzBT9x+!O@^%MaUUOafgs(kua_@gE;tH_*J;!-s7318ODHBa@ZOIY- z@#BHGFn!3zoh)vid{5q^jYY#S+`v zZam`XTKLx0d!bV0!-^*fG3MOO`-PicZmoXjv7(dzZn4UQZ(cQx&FcT{Gdmd^y}|64w)wd7(^LFEC^c=(iT)yT$z__rLSL9ke#WQoLZEZTB4ViTB2W+T9B^~;p-dd6PsrA zl8bT->ex86*%(<_*%=vGiVO-2@?d-ernV#$`w|QCGLzxf6=#;@7gg#znHrh9x|v!S zx|o?68oC-eIhmMQxS2bf8@ag{y15zYJEc`7hnr*sCK;Fe1(-w@XL^O}8s?d$WfkRv zd|==QvyYLR#mT_Izz)VY;BGTQu^-|;xC0RWbqqE%F*2|)&@0MMG>`xVngS>g`3!gr zxL~I7F&QYq*o^ETX<-9F1AcH$M&x7U#Lf*)?2HWV=|^QICp#BU+S&g&>{_($wkCnw z?4gSV#7v#noITkXrQO=O)#HzS+mHY6{dtefcoF$#OLy!e<#R<|_jF2*PJK5a(6aZ4 zpVI5_>S#HoF0Yl&2gQCKe|vZp$EH2&S1+%xRc8hyPu&YnBRx8-ED&R4cO zB}=?c2>iVCuwUo>)#oR!>$g&tJu_%1n$@MX^Zf@L` z&|ijUR))`Oa-ER6UYRADdkUA4&()Zn$kD~f%D~dZ$gtRsne}3d9D{qH@z33pyE&Jc z-kUS)e%Qxjfz!Wb9Whzqb3r>C*qdJiMW3ZytzkUk9FD8dlN3aV0rM%>+|79o0jql=$5W;3w!ZP z^i12TOS;FVwF_E2Ry6u9Cm}TF!yS%-q_8m0!_O~7)ZB^CWBGct)o xEBXFbsN*E_=naz5sfJ7MzxBJ)Y~9ngeUpgjx|@lU-`QSE%w8(#cI%J0H2@gre**vj literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142081.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142081.roa new file mode 100644 index 0000000000000000000000000000000000000000..c0c0f824aaf27147ca8748a23ad398463725a1bd GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg84ZLD1X-9Em<+fLIGNcQ6d0L;nM4;fvD`3dV!2|_#Jpz#GZP~d zlZecf&SjlpUzhD`TKhiz$yzbv{2);SUby9q+^h@+UWTFu!fec;EX+JSj+Tb5rY>fN z1_lO(hK2_EAYoQv4Fgj*XG>>OCkqQx12Z>sX9E{wHw!Z(XA28UQzus!GjmrE|zX47OsXa=4OtD zj%KFLPNuFdW)?<<#!jXtmd0i#Miwr{PNs%t22G4g$Zlq2WngY%dLyn8Z+w=b94 z?K+WpHt4H3r*=SB+1f2h)(gJ;nfb(b-xQrqj=CmCV~aQ1G#sdUP~CF2)8K*b^%mAo z7w6A-wz#^`L~>4dmD-INl`4U^p3JE4j=a5K9MDu?*W~ANogE{ zGB@STr|ox14;I|hdhwt>ThclYjZl*xU7LUQdb`4r^ZRxg@PQQYGcx{XVPR%sZ!ky( z@#R@!45ADo7KAMbX$vYUuFOle($_C4$j;PDPA$qyEz!$MEzvJZEy&l0@bwM!iA^(l z$wfH^b!;5kY>cd|?2L>oMFs^1c`&{KQ(F>>eTfBmnaObLiZe^{iz@Y*lZ?y#0!$){Grhuf4fD*>vWoIS zJ}~fu*~iGu;$+}pU7#Ua?>J{ZD8c2WwO#u{$diFz?MOm@Z-JwO^pB&Zu7AzFjxpv@m^R)@*_?DmcQVZ40SCi-{ z4R`3ebNF4f#M0kwWfk4aFFb5cbxNx>E1rEmr(i?RiOuZ?9~@V>8MrNC{};8b9p5k8 z%u9CLGACPjdVItDwVl(y?T$%nI#O?JU$ge-$AhwbDmhB$BzP{*;&Vt{H&3#mEoy4c z<7*CcwoiGwc3xW!yQ^6FFRizxZ;K4Juuq@bld)^_rTuYzI~Q+|3Ke2IDJl6wAh6C( zbmIgzXPr3;N%wC&4d{HqZfx4j*mHjIj8k7f{N35K)5k(fHjM7KQvKT6{C>%VKe#RlC-dV1U zQU0IKj93n_pC>mRI`M1S?DfIXdk+*MM;9Y214|Pl13%C4d5HoK@^plP`HiRSc<^|x zT&dV3F1>T-!{h%;CaxA(vRqQ;sKf0oFaOBPKAN&4C{%6PYuAI<|Gnazb9qCnWOWD2 zn{C;LAKQJGl4k7x7+&Ic_?O<4jb^V*)@F*CFL#g+b-5+LW~~3)XV&hEJW0B@|0rD( z$dNQyu9?dL07MFUa{vGU literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142082.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142082.roa new file mode 100644 index 0000000000000000000000000000000000000000..10f411d231d5c7fedb0cb67f7abfce3d11c69a96 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$QgnGA#t1X-9Em<+fLIGNcQ6d0L;nZy<}vD`3dV!2|_#Jpz#GZP~d zlZfc_?e8zDEU*0AF)}jT z^-YM?fAR0yv9)E(=6p@N=yvDIC4Jk54HEyoJIuRyk8Mu$oqIvmEN#M)k4}%*pU!D` zv1}3lOWlUMA!^B*`cm^fJ}@!eDv`hTI771|M@r|&s;!=`$LFU-Hz~H9jdzsZzU4o! zwABCkFFwk8wZ1r%p{C5$+O}o7FB_}(LiI()EXnImTFS0@6E}^!<66Z{W~-l-3Ny1! zR1$MP?))bZ7b(oSaK)?339F_R7u-mxP5XH$w%AWU;G4pi|0?eDFPuE%c=V}#W5on5 z-t>;*$i;k;e%T$ZpTd17-u3$s^yrGnub>*g2ESP61?TF%&KE!4nb2J7Qqi4T`#*b1 zSpSQXq7dnDCT2zk#>GvH#|@eo4;#p`F^9_Xv52vV1h${KBICH))}r^8Ot7=E$6o7u zDhBc(X=N4(1F;4X)<1KiI|A}+coNZ%=~GCABNBQVLh+%Lc+vN+Q#T-PwqEG?@jALIiA zKbU=t+$>H84hD8Gz5#ce5sLi~|G^!A@ULUAp^1@!g^^xSexiW{D9{u@fyigTW55M7 zjgQGd3C3n*2T2PX2paH%b21_yBPVulaAId<*tT{?WjyZ>Umg9F$*ws;)tMeX4mZzR z-c*Rbw{G&)LwRR*?EHT63a`G{o<@7m5?+PC-3rD^H#Ft^Yo;ihW_UIo|--I{O&;6nh>t@b>D?{RkzpjM)P?dw}}ed=J~$DakUillNs0l zOiFy(wP^B8&%3UYT&q8}zE;Rcnp85OuI|KvDRQso?5Wwg^O?`0lCGXePUhBS%a@vE zF|Gf(W%@S1U;C~^8FXz(dN9dBH%;{6g}vc1Yj36gdU5rZ*Gk8Qby?`WLXTASQK^zomss6Q}X+}i(a|- zD1Hu_ws)?~ZM%Y(oBAphv|rhUB1ab^D+5atBZL3JS+0F~8u}_Dq)BlhpK1My=LAwXo9pl}0vm z;@i)*HJr%?E>V@!b{)3R6yxu&S{bR7!|cS`(*C{v)ue?s{p^-b?ppi;Yw@SNKHTJg)M;ZTbFu5x!K4zai-||rzOiX<_^0G_((}>P>baLx&glupFWIu( qVCUOa@xRor9pBS6eMa=ggwMZEK7H)BoAsKv!oziz$|Z%>0b2m!KW6j* literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142083.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142083.roa new file mode 100644 index 0000000000000000000000000000000000000000..da4b57c1c8cdbb7e8de1a48ba8fcb172c32529c4 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$QgnGJ*u1X-9Em<+fLIGNcQ6d0L;nZy?~vD`3dV!2|_#Jpz#GZP~d zlZahXUdQs|Z@9iMon6_pV0ESDjr2JNyl~4Ixmg(uybMJRgxQ!wS(tfv94!r9Oiv8zY`g}%o-^$ZFXXsl$ za%8)GxMu1em1A);<4l>S=db@fL4#SId2ytat7?wg(j9ld-23-ppFvvH+&vy)>+0^W z<=Go}LCPopou1yC54tr|zix`35_I_L>zl{wjh*lR{(N_?aeJ)({(}cxgW0Z~wT(}m z?7FYB^KkzAsVYnF<*yBSArtsvcyKe{zJN5H$T}$brJ2^(PO23$8 zyQ}lDdHTEzStA;-(O2hzmsHS_CKZE|+DfdV8y09xeGwxu^~f4Ez8JGLlTNM7c>Rit z=Y`dW-MbFNeNkm%W@KPo+{Ad?po#IYfh-$ys4O3g7>kIWkF)&0z+WbspKc|^SlyV? zXmewcfjmfBnMJ}ttU-kJ&z$IvfczR>`!=19sr#lkckVq{=ptXGtuXdnR!GzCx~@)__L zaKTLDV=_>Ju^HJx(!vIU2K?ZhjL65xiJcpq*clnZV|TP~IL#c(xOBI}=0fiqhubz6 zin|~Gsk#>8~1kP_Bn~a?VSFyAm3wAV?W<_wqs{D?oyh1 z|Hy_uH_?YVb=tPdDLa4vWe-eX)6{d^{oB_2e1vn8jkT{RXJ*BPL>A1?{qK55v*xXPf3aTyaM za|8B-ja+ap$TpB-gO#wH%!a%u<*0!SLXOptA5mmM$|!w=EQ_HMi-NMhql0U0MXHRlK=n! literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142084.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142084.roa new file mode 100644 index 0000000000000000000000000000000000000000..069ccd7c08838b89dcbc0585a24c9c43b8338862 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$QgSqy{?1X-9Em<+fLIGNcQ6d0L;nIsl8vD`3dV!2|_#Jpz#GZP~d zlSm26TQi*0AF)}i| zlK*}f z)ZnXrryaiD5ns+@ljEr)C*}8I_f*TLp-=e2a}4}F?wBrHD^V=aCVqFJ@~uz)CR~3f z9$gc^D2VC3#>T03t|F&)N&mVlzS{L^M}(r(9E(?5c643YEt9!EmT&R>4wZvdE*ujN zGVW5f))726>wxyP`}?Q7?z!i_-hTGsv#}G@434Q3{rhmQTHx{qo-hkv4zFL(*^<+Hd(jul~%!B+&y~<9-A&Ep!z)xKugw zHuv_rkiVJlnV1G59u>P47-4T#q!)xEB(=m15wYvFzyA1e13iufr|Ff_#GqE=qB!l?! zEHMUA1`!Lw7KF3~6%|+JC0pt17Zqe@>LsTZ<)xPB<)xPB7o`^D>qGeZ2KvON8NKA9 z9D_PG4sA9@R#tXKMwTLj0)spl-+-wt3B|s|g1pRRxOK&uCHX~_`c9@s=B{q07KScn zW`>5YMovy9W)^Pd&gMpLE{1MyM*2=^mC4~I8G%X0<$eJsk;R!_;kt%-W@%YP`5+${ z_`&RBgu}2v?M?7PvadB+k$lX!o9`wGy@~z5DzdZ`KYW&YRIme%~ zFi33ezO|=eruCau((y^N^a8rSoMw~}w!ixK*Q{QHXupEPb5;d7Z#cysvvZ!N6OhybR$KT(nY>v4BzT*HwO=l6`J6`?W93Z<-jn zVfM4?wemq}9MV^A9qe1ywCbCEsLyw~xBNWMg>G;75-#vVQ?=yI<7upsr9v~dBy|=a zS!Um;o_evw&-(wNeKsee?2l<}36@guXOy>Ik&?e!UqQlNJ;$(#ag{+6<1!{j<_7Eu z8@b?IkZmBv1}kAXnGJbS%25LugdD3OKcdKjlu`N!Sr$Vj76q3&pQ^YDIl35G8CaSa8D2c-kt$HLzcBx-;+}mEH~q*t%u~x^ z<5Ht|Oj<6{WnPiD)TyG{;13oPLZb>Y=boH@AYV64;6ScAPsZtM_E&{ptIth*s+0e` z`)^yrj9XU^X&=83eXnRy$(`TQ8`{{zZq+GX&F9=8za}E`tWV~QNQ3wDA(_eG*JJ#$_)S;09@e! literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142085.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142085.roa new file mode 100644 index 0000000000000000000000000000000000000000..bad4a9964ca1ce79bfe544bb32e0dd96b06541e8 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$QgSq+2@1X-9Em<+fLIGNcQ6d0L;nIso9vD`3dV!2|_#Jpz#GZP~d zlZe9GkCVAxdt2^$a>?9wRnl!9K_goOUby9q+^h@+UWTFu!fec;EX+JSj+Tb5rY>fN z1_lO(hK2_EAYoQv4Fgj*XG>>OCkqQx12Z>sX9E{wHw!Z(XA28UQzus!Gjmr78Vw6#^#2m78XuM zu4Yb_#^%OOmPUq-CT7OQ&Q5M7ZZ78LE*56y22G4g$Zlq2WngY%^s3j?rgWNynn@+@vEG}>iP!@z7unHiyT6F6UqA2Nq$Z{}ixW+3Qe#)99DQQD?e2xr=`X9A-nTpV-3)Xr`(V+v zT$ka`&US%q=MJg+9bd%!luyOx>{M&hw7|aB#lfp;jxIlQ_i)Yu%hd~SPLDFuijOf_ z=W;k@`Q42?NB4iacjedr6~{hFv`5QKJ-aKdOn+^MnDm85=IL)=Cz)PSw`!1XEIN42 z_PO23?EPW)#Sg8_^^RZluIG5Bkh_pzqx3~re{0NttUyj8K3_0 zxBN!BfjmfBnMJ}ttU-kJ&z$IvfczR>`!=19sr#lkckVq{=ps#lbsXdnR!GzCx~@)__L zaKTLDV=_>Ju^HJx(!vIU2K?ZhjL65xiJcpq*cln@++Qw8Z;xZs&)n`IGN*BEcp50euInAj5<77y@5939LLz}mIsxhAsc_Wi2XeP3! zi|ftKtOU+r%3Wz#gq^BZ0mu>R0TTV;Y-CCU8_~c5?2kqB05B~AU7YNnb zn|({qXaB)2Rb!XOS7PKtw&vJ)#LwLovQJxR3hTS(IqHW?O1>#X-8O7uTxHP2xQvOB zxdD5^MlLuPWE)7a!Ae+8WwsMIqz3f`t#>34Yr7+w<#!`^K*o%vtsQ w`VSpnxk`dF{9Q?W{MK&|cK9zkRw&bu<5zG>#%0U($M3zb9B-d*A;vln0Bvl6&;S4c literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142086.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142086.roa new file mode 100644 index 0000000000000000000000000000000000000000..52a65326371f6dd7622525dc7c0a99501bc6bb35 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg*$jjY1X-9Em<+fLIGNcQ6d0L;nG_Z@vD`3dV!2|_#Jpz#GZP~d zlSmqG>&~+e&gjSoZYgqj_v`q<`4?6j@WL%;>k7 zIU2}`^BS2M7#bNE7#f%wnM8^68krjy8d@3{8X6dxL>U;v3}qJ9aB?xTFf(>`adb0r zb8|H|b}=6C)$T z=9nef2OSo5UY_gl_rk2Bx=txaoXbz$bF`fy-?Fi`+C)7#Q_wD0d62X+i-dt#g9z)NInf;f`8B-uZ8{xO_g$---?z(v52S#fk?}tZ3o{dYgF!Ng zFV7NV5M>atAZ$TMTToGPWnQwCzJ5_bcBWo(YEfQliC$i6iGERPLB2kOuWz7FY?{$a zF3K^eW8=_fV`ODzXJlk4GAJ;}gYgZR+LBQ0ODxFCOom%moLQ1zRH^S|YGm%}W@=&R zVrFJ&=xXHTWMXFFX6|fmZjuq0WL)kSU=mrJ=@qVPm}i!jRg@3% zfq@^)K1Oa9Cj$oqI~d=9yUhs2eu)3z4nX+VG1$<=$iTu(uP8s!KmrtK3ZOvbGvG1c zf|JOmaXZ(Zen*khe0&$K>djoD=tX!&b~V%?xStT`-#HVlOLU%WwZO! zza72}H5muD6fqm_j8A|1pyhP_SN$_*eLCOz_P(AU`9#ik@!2*@9UZagmdDA*Tb@hI zo1e?KSF5dPrsJZ?2R5i3;#>S|`mvkW1Ps<#C<;|Lh;06Pakhm=z1`QDQ#O}|%1+w# zSEgj*!@kY_S6#CXymOn<5aw?vWg&Ze$y70o`~9;%ss-k)UjFF)Y{MqTRR&Fr%a|CM z8?YyA&s6HrfW}DRILLuQ*;Xg<}6_UJm>Yly=SYCql=N1fu)I&p?A8Coh*mkGrxKJ&R+hiI7{@c z=HcE|L50qd>x>s(6FHpb9AF}KXvbNPH8;a&Z0?)iQL~_tYr9PBsYVZm*_?upZgDSe z{P`^}{ZaD4jn7=0@|aotcYm>NU)k61$i3mQ&E+LMshfAFc~~#k{gTD1Au5{O|8ABY zpVdK$jpFW>?*8mriRE2|tE8K%B^*D-&tYk~AEYJ1@;2~DkVhvY!)eFNI`#jD7to^Ce) literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142087.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142087.roa new file mode 100644 index 0000000000000000000000000000000000000000..58164985506dca233877ec139fdf1e19f54dffd6 GIT binary patch literal 1762 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142089.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142089.roa new file mode 100644 index 0000000000000000000000000000000000000000..fb9e0803ab84884e31b36f19798a841b53bfe568 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$QgISqsj1X-9Em<+fLIGNcQ6d0L;nUohavD`3dV!2|_#Jpz#GZP~d zlSs5)*n;M5Ud$_e#A_COI$_OWb#A@^FWhoQZdL{ZFGEoSVK(Ma7G@qEM@vIjQx`Ks z0|Ns?Lqh|7kT9#ThJmS@v!%1ClZAz;ftj1Rvw@4Tn}wN?vxSAFsgtXVnYpW_n}w^B zqk)__uaTL7p^<@sp@FHPS(G@hk-34Pp{0SLp@E@Ulz}nKP-bBb6Jt{gBO@1Mb2B3g zQ$sgXM`Jfr7jt7HXA@InGb1BoXG>FaQ)2@&gC<5LWH&RiGB7tW@-rATF>*0AF)}jT zoANv4=jvK}0S-OR8#Qb-JS$!MJ9x5OPyXxC^NU^dD!5H&yOZnEPIF1m^W1ieCLf*6 zxYEUaV*io@bq9a{zxPBbfX{x;cPW9h>C4nIZYTU`OV3XD{KYRqW7=;0b-%wI|Ewxd zx>;3RO1Gtu<=g(332S$x>6sb-^pm`}y5-!(R<+dLO}RYpCoc`NXP^G?&;k?VD>A7| z5}Ef-nLRnQe|i6}3A-!41Vvn5uIL-rxiRa&i%oAIPyE4eFu~_zJx^6l%Ia0m)V7?S z_j$eXO`rP}AH!|SZ6h}QR8l*zBk@O$?p$koh5c3Yr(8d?;E>8b!RWKzQ?jOBTe5N1 zU8&=#?wh)HD3~%aGcqtPZel!c(8PGyK$eX;RF;oLj77vbLg{juM&Q@QU#}Y-2~JWz z86M1LAPb`4r^ZRxg@PQQYGcx{XVPR%sZ!ky( z@#R@!45ADo7KAMbX$vYUuFOle($_C4$j;PDPA$qyEz!$MEzvJZEy&l0@bwM!iA^(l z$wfH^b!;5kY>cd|?2L>oMFs^1c`&{KQ(F>>eTfBmnaObLiZe^{iz@Y*lZ?y#0!$){Grhuf4fD*>vWoIS zJ}~fu*~iGu;$+}pU7#Ubt>J{ZD8c2WwO#u{$do#ms_#s|FJpa)uTJ(avz`#Hnl;C?T6TG&)ywn+`g6W2yxjJ;TV4NO*lqJ0qD-eB zaYW7tFU&f1Wn%G$r);IM%WQ16c1ipB`F+?p@j<(YaK@(J4hD^zuL+gC>}!0Heo*S4 zXWiAsMi1S?J}oH_Sg4})aDCJ1i`G%C!CN;n$xhmz)A-P=X~&m-xxn~g!D4KQR zLA%dp*$F!yoBW(I?YdoqSI` zrk!pSVM_HXui)1an8o|q?4-o2k1lbGY|l0?J^m@$CtM>!6~7rw5U wYo7VakbPp(#4?UooafKYE$9xoz}>Ci-M;(i-?uldw8}NBQWkGtta{l20L~S3h5!Hn literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142090.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142090.roa new file mode 100644 index 0000000000000000000000000000000000000000..87b4a0aa0805c5aa45f854ea6a5eca13fcce7911 GIT binary patch literal 1762 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142092.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142092.roa new file mode 100644 index 0000000000000000000000000000000000000000..1429773a5b80884e9af14f887b4db9df80f5ff12 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qgc?^UN1X-9Em<+fLIGNcQ6d0L;nba0EvD`3dV!2|_#Jpz#GZP~d zlZblU?{|{6!P~E<*Z+{(S<$t+^<}I9FWhoQZdL{ZFGEoSVK(Ma7G@qEM@vIjQx`Ks z0|Ns?Lqh|7kT9#ThJmS@v!%1ClZAz;ftj1Rvw@4Tn}wN?vxSAFsgtXVnYpW_n}w^B zqk)__uaTL7p^<@sp@FHPWt2Ftk-34Pp{0SLp@E@glz}nKP-bBbXJbPnV?#qj7iUL9 zQ&U$9BR4k-XJbPbCpSxTOA}K^O9M+oGe;L^gC<5LWH&RiGB7tW@-rATF>*0AF)}jD zy`*OluhOJqFJsC)Xt^7anFproWHE-^cm%2owlElHd!e$&+I z${p4Gxqp{`Q2y~|pRxXmhbs=Xo;q~jLBvOIJ?AI2Jqb%!>^k9P;N~K~uKD9Nhpo3m zcwNt3PYPCeF!#Uq+>Xk`G`V^2qPZ%QC$w6`o!HyGGd&?N$H_op-A9&#vp!t;%DusD zbBcdinr8U!&;K1(bO+s-w)fsamm3FJHC~+RpSWSt|6i-zBp#gH8K>~CtlsATe0J;4 zEJrFBE$^?hQZZ*@W@KPo+{Ad?po#IYfh-$ys4O3g7>meZAw$7C3qxP%|2QnWfBKZD z2@|vK7|4U9m02VV#2Q3c|ICT*2*|JDwQtkun7Z#;-Tb~?27Dj|{EUqMSy-5v*c%Lz zL40|Z7=tK-hy`H_LfV3giYxPyt@QPa3bHfxl2eQFQcLvmQcLuUQVa6+A$)xUePYv$ zUUE^6K^+^1HX9==D?1}2OOZi=K^}~6z|@w6VqaoGUS=}fy5h`|{Gv*ICsQMHS2t4& zLl-kMLqk_1Cnpm#3paCTb0aqwLpL`geW$d_R`vp5+z7}&x12Hb5%DE34A2X_F%zmCC%CPoI9MtVj0i3Sp&KvMt(BA)?| z0T;|PJ|+Vt7@LtDBrR+pXuuE7$%uT6oY=X+iJg%ltKnVi^+4uhQ>Ip$+U=k0FM8pC z$~9vSmGy$vDy^MO3)gd>uKyOJr>pmKWB<%AOjDD3F6sO1d@)H+(r3BapW~(%MG}rg z%RFINxBrW)@J7A;dv1#RO=Mj>w^66yM50-Ucy^#{U5KULyPeMe`m1>t)Y%J2aA()g zzAwEb?fuzu+x*}C2J0e^oK#wK=xXa}i!CX+>%`WYElvG?&}8}~FQz7g&zo-;-`V#1 z$HmPb8JNFZ-@5hpmjfp@a4t3Qba`J8CA8S&)355kert9vR=MvJv-t0fmnthdDrJs~ ze%%mre@Sy#p6&HdelE}Z|691WiwT9!P}=-Ryv4C;&TQV9@xEdg*1j}sVq9g=#JG%! zk+}hT!bUDQ7i1eqvB64MPG&=1lycNS1|i34$d4$pAZ3(3LYBo)iABMv`Pv-sYJ5Iz)?*g#>#5HVzq(c7w$J0_ zuZiFGt`IA+=3JXT!*p_Yr-A@&lfM&Q?Mi;q_G**GS=FuC84MpiO|PAZ=2nSvF4#YD&jXKV zcUH`f7cqDgJjWs|A^nLC!^|6^{%8A}!}Hqbo~j8>=ycr05TW?@#{WeVeKa=79IgFY wc6pY&bsdjbVTRt$^!tZ=Z<*$J_Uy{sd+(27$bHXy3;wO_`&PF4I=f6R0K=AlNdN!< literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142093.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142093.roa new file mode 100644 index 0000000000000000000000000000000000000000..b51b08227775c1ffb31a464efb18be9acc29d9d1 GIT binary patch literal 1762 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142095.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142095.roa new file mode 100644 index 0000000000000000000000000000000000000000..d4016607ac6f014453a5c105b5db767aaf93369a GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg`3-~(1X-9Em<+fLIGNcQ6d0L;nKTzPvD`3dV!2|_#Jpz#GZP~d zlZa&1t>Bf@{<;aC{CafN?6()rgz8*0;DuYx$j!=N;AJRkAk4-b%EHXU<7jEk(GhDiIJbdpox)-sfm%1Vcp!l z@3($)t+=sSV3E!0OqP~6#RZ3|?ZcZ=6|Y{n@t=Eb`!u^{^XGowWfWQzwkue5xwYud z6wNb|>V=6*_U@j;#e27Oci3sA^EZ_5?CDq5dz!Il>lA73`U|&S?ml|UaBk}3!$0z7 zIdHw7-X{D#vsZ1)LXJKj-okJ3+X7{#-p)Ibd8~LU^K={a<^7R)s=rTUweHkDX_>fn zX4$g*$xG!rwy~Z~KkmQo)vNxT>CJHqr+jh!TiNw8A^+X8fTF-1l9^ZR zF_33t4wY4AkuVTz5Mli@C%PjbzlPVoO{Zh(zH4>!`*s=dffVpFGX7^_VP;})Fh~aR zG>{(khd~O)>(LjLZE3Od^Xjy~1@3^UTt+it<4| zFz|!f$H>j%WZ+<62jd%Xw;7?>5Ah$|0SNy(1{<0f8CaU?73C)yNPq%O0ThUQ20R8_ zFw^*$43uDOMs|?2uz{cfKR72N@-cE^=LRQsMuroONh@}E-)232cW?O?o!-(D6^5U$ zJ-hiV)F9)ka;%N+eOYV$q{knZ7;pZtw|?P~pARf2#97ZjH_w7gdEK>ZS7&wK(SCdR z`gsNZBTc<*CO7$8UN1@HwVdVjV@>+W!`gRp8}>a>s(rCI{(i^%otw**rhJ@`^?1v{ zik`hX?!5Ki^wy==1eiSidQW7>l%_|%GpDClot2i{=PG(nHE{=D^@+vWRu6~K| zWpcWFzdEhT`Iq?iq-n7_DRNtS_f12NE=E=cmL^7qjOh|GjCn6-1??}n_4ir*D&MRV zALcG@ex+=@!Qs}upv2m*S1qjs=d2bII%z!9mPhmXk*ct=538U2Y~K{Tr#R-%voDp! zU(KB?DtS&+=~Yb&-cWPG%y*~8J^N4gi>7M}r87GO7x$a|-K3IoF!WmEY5BKFtjD6gon zmX1xv)4u32oH32jka`f;=HpfuIXg*ryYGpMdTh=8(l-Qe9iA^V`_$BJHgfDzKioKH uTHkn(`|$p+1@Gkam@mxuo6)@U_vux^6BC?FrSg}YTxw{y`fTdHWM2TXl6{5% literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142096.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142096.roa new file mode 100644 index 0000000000000000000000000000000000000000..f50bb33d291727bba2200631f5371b77a4e6a284 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg1q_4@1X-9Em<+fLIGNcQ6d0L;nG6;*vD`3dV!2|_#Jpz#GZP~d zlZfZ>1>3Jp=gv*DxOd^_Lz_K^pIr4a;DuYx$j!=N;AJRkAk4-b%EHXU<7jE;PJH8M9aG_*7@G&C?Yk1{ZZ8OkiIVPI(L;%wq<>}>32 z;%I4TF6;b2I!qF{$hDPL8)<=DR94*i4V>eymh@gW+uau7dAgJvF`x3GwbK9>@EF zj5Bv?a4+kccH~fw_vMr~!p#%=Qm@+WzVyklZ9_|?Rf@_44Hx5-M^9DN1+DG-SLQxp zKcAWq^=Hzb0~+${=f3^)HSwWxcs>c;QWR56lCSS;F&YzjmnmyCt7)wK8 zbXwRe-O6cvSF`P>KDu|H#!~-)*P7`;>Ti0!7hRb5NcHxQe+Nq}BksJ9D0dNkU#Oa_96tPIrO=6U-20l3Jy87F zbKk~59we>IB4HrbAj0}*PIN~=ehsgEn@-2neb?&d_w6#^11aEVWc<&WXZ2wM=+7F1MRnU`#(uU}Ml^43n`ZQq zi*gL=*f_M=7+G1_85voM3n$5)1M&li}7CXO`p_Rq8vL8kxJgnOYdS zn3)+Gx*9n-nV4C)nLC>sxw#m+xf$s@rBx<}n`8tg8JGJ7m_!z5dWGv6=9#5s73G6` zVBiO{kCB_j$-u$D4#qd&ZZkr$AL2i_0}%do3^p_|GO#q$E6PtakN^dm0w@sq40sH< zV5adg87RTnjO-w3VFN(}esE4krf|L`XnVe6fglueeKvgJ9I> zr?u6u4)02zzQC*9wM(+N+9fmH$Yyt8S+i&4i_LQwCFZX>>tNxn*L^|OZvE%|XMfMQ zdh#yE>3eyLu63@M_PH?H(orFu(;)j3<0P$RyS<;ZN}sx9*u=QXpowuA6C-m2 z_JoaGa4yI;kYayeQ?Ufeb>9)sP=iWI@U(eS|EFp%RM%x8?HPbv=4{Z$gfF zFb1BJ*%J0-_H?TW;wk+*p8dmwdwn&^hM2E^?Kvg0>OP=E8}Bp1gBSM$R6BQ-Fm9qLgnOv zB@2wpw41i?2@QCk>m#sQ-tW8Di{N+P_pMx_^?9AH{}FjDh6L9GFBS-1oGJ7nCpu_# z$HZBiW!~5uaMV}URcEu!4cMH!Fz2VGVWzH{3%m;(ehH?Wo&J| rzUE&p3t1Q@+8Xh5wzB0+n8YdTl3^lsBvQnF{r@ez@rmo$rtJg(6H#TO literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142097.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142097.roa new file mode 100644 index 0000000000000000000000000000000000000000..e697357838300c67c2f6694d092d3eb328fb57eb GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg1r3A^1X-9Em<+fLIGNcQ6d0L;nG6>+vD`3dV!2|_#Jpz#GZP~d zlSo*1kQe_3(KJneiGx1PN1iQoXPR%o3%8t+o0Y-9%TUxnn2kA)Wyuu zz`(%J(9l31B+M$TVPNX!Z0T(3WMN@yVCH7-Y~W(-W?^RJY++$(>g4KTX6|a~X5s4O zXdoxfYh-3%Xk=huXkcn&7$weYWNu(+XlY<*XkcU*Wnc_5lv!BA(b&zv)X~M!$=uw? z$Xm$->gY#M0E<*ucrfpovil+0Bfs49rc8{0s(7j9g4jjEoFN zQjI%G3fZ4pipQjW(pq4Z_EdChmbl7=zn`vk=BkE76%@Wuh`HfdV^^V{^^@yR+7Z25 zS;EUBUq~nH$ezDfcIW*yr_(2FT&4PNEjnGV;@Fy6eFdC97XC(6cR_PnQi3cUn>>diM;`{yZ(mYkx`9v1H% zJhNJ-Gbrpy2~JXDUC+%?n#2%&?|)VNE4H`ydUsl1`62qY*YR1F5=-^$h)N$%)~B(; zw#oX8E~?!vVwoNZ%=~GCABNBQVLh+%Lc+vN+Q#T-PwqEG?@jALIiA zKbU=t+$>H84hD8Gz5#ce5sLi~|G^!A@ULUAp^1@!rMX^FexiW{D9{u@fyigTW55M7 zjgQGd3C3n*2T2PX2paH%b21_yBPVulaAId|2q;^i{5+@ssUlN0&v7JWThh0|-#{S>5^_t_c`9|kES4{R z8GAM(F!SpNo#|c|jjs20e%v9r!DR=tz!b}QDqGJu7%!+;y7WMeeD%B|`u^K^?w|eA zDlc2IHPK(e@q%!1ys41lyRPic0He7li^5K(N544KlOQ4U|8IPbcz{`BPxzi0)eAU! zul1H*yZl^uyOy;6gJS{q6+%PlCmv#u=s(6h>|?;MSc(hQpzR~a-hE@NV3Zor2#-v*JI6^r$M>(&0(D@fL{du^$> z#DTNHy?nw>&`DJ`9bd&_WT|3wJy}ka! zVBS|Pg;1%lEan%*jmpgJ{T-Zj$`&7rJ>&68xcdL9fAf#nU8sN06hEcvl8=6BU#hBx pvE8~lk@|Bh;zFigGz{}%cehR6w^`ztp2pk#{=$s2#atKX0RVDmUP}M~ literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142098.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142098.roa new file mode 100644 index 0000000000000000000000000000000000000000..e7e6a19fd2912fac1402b7d9cf1385a2f940cfee GIT binary patch literal 1762 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142102.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142102.roa new file mode 100644 index 0000000000000000000000000000000000000000..1bcf0138fc6ce78d9f716b762168d43b43064af8 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qg#SDZE1X-9Em<+fLIGNcQ6d0L;namb6vD`3dV!2|_#Jpz#GZP~d zlSrb}maUi5k8Nl$zu_qTSB|;mb!&(LFWhoQZdL{ZFGEoSVK(Ma7G@qEM@vIjQx`Ks z0|Ns?Lqh|7kT9#ThJmS@v!%1ClZAz;ftj1Rvw@4Tn}wN?vxSAFsgtXVnYpW_n}w^B zqk)__uaTL7p^<@sp@FH9Nt8IRk-34Pp{0SLp@ES}lz}nKP-bBbCl?o2OGh_DH%n(z zLvvFX3s*;16LS+&LswTvBS&Ww3qu17BWE`kgC<5LWH&RiGB7tW@-rATF>*0AF)}io zJT+6H-fgX!XQbSL2vL;`L+-eXp%2|XmtH^MwEZpj=P#OWd;V;Czj^ja?(RfJQ4S5~ z$4z$6g@j*SIC7c)@eP}w`!|0VR_m#73yjjP7CFWhBV+UTU*Put2VL6Mnn?N;PIvgA z<57P+`*O;|gB4qCjYd6+*=`*6Lg z{~X&I@k!B9({|M7Mr$%CRZYAnGwt%tHOj^H>-IR`)r-yEw{Krg$BC?i?QT-t8J_8X zBcAE(xgKI5&BV;ez__@H@wh<~<6#3?Hs(-SJ{B<+k-hh3ef)V;JhpG0yQ|zQts{*b zI)4r1LDI@B5(Z)oBCLPrM0W(_*YMi6>2yrpcdc%I-!20_kOF>2#{VoV%uMVJ2FW14 zJWGs0ltILTumvG)K}E%tdC6A#`b7oVnR>~oMR}fO`bDV)`T7vPzJWfmX+|%( zD950VjYFG_k(HI5k&&gypuivx#y4PUOG2?Pu^=xq8E##1W=VcgrM{D?k-4jzsfD47 znVF%XtC5qFiJ66)xwE;En~R~Fn~}a#T4i#$Nk(9jak*cBNn~-RSGcZWo>^K}Q9j5A z27WO67`a)T3>*yXV0;7aHX{`KA^w9q0O4Q9U_%olLjxndqWnYy2~eOZfC7=vfX9Ff zW*Q%pff9_($PSVgHV`!62j^r&K1NRL+~CB{$PoO~x}{~sZ>_a^GuI^s<*!UJJ1{@g zQvWE2>idL+C*4bWC#T3P&+|5W?GjMbthKXFQ8qj;F=I_nsPnFa*BQP}TNj<4;xSMA zXz`)xuQuH6t#{weAK`!G|9*Y6A%RRWI}noRmy$~If2zpPGu zLFm4V_BR~gvD)4?|8yhR(%}2dcU>HJmivWz=FM2+YAyYs!Lj;V#M*>Y8C&uSsyf6D ztz&LoDX^!;H+4>E@VoCDv+M+Yu+-wbxF{+ba#J2zvY(?*8-g{%5EIz5TdwRyT-u;i6t6XPm_CdOqiVar6axxq8qLiZsG6*?VLw-b&1u3KS5wa|XN-PSq`B-dLc}r?*mM(tv zH~aZL))U+&SLbeYx%qL81!JS`a^&b@WMyD!Vq~z9^f{xv_jJ>xWBa3;b$KuMLBmlmFt<-S0t{t-|LxY!Cv{EcZI9x2e*&!pWS${?&~zY zh}mEMp7F`NEanukj#KIWqeY565yHljd&7e^&sTr0>_5e;m!scB0Nb zfw`%Li?frnn}Ly|fw8NZrICe+ftk6Xp{1FLu|X4~60(~aSs9p{82K3tni#p5niv@w zw%wfNJkno(qXPW8b`968K-opJ(>@D*;FNU7~He246l}GXrvwrk{#jA?(%#eOnHJb(YB;0| zPIESp2T3clNEnDUh_L>d6WtMzU&CwPrqeNX-?h5=eY*_!KnnO78UM4eFf*|?7$k%E z@+>h1Q3eqU!WM+I1r-%n<|SL{>lYPdXX+)V7UiXu=;fuB=oh6H!Fy ze&2rftHr{V_t|!&GH>giIcKhn-Or06^4T|yj%bzt+`_80E$MWEY`xT*okFYDGwM!u zQ4wWvIihtX@6Eb@#@4Hw8WL8EBpqBivo(CyCf&0Pca#LQEO`F@bX%m|o9i3(Ww(&( ztC@cv<+!i+rwl*mmbA3A;?b9g#aVUyB_upM~__~_p9~@ z)m~=ajP4gE%G|d~HqB70F;TFsth?#Ya&=*ExVo16%707VT)Ax6#JI|!iE$YdBXa}x zgw2gqa4yI;kYayeQ?Ufeb>9)sP=iWI@U(eS|EFp%RP2gj3J5bk3}rDkNvR z`v3alOY@d#&gu+i^+F>mVe?(VL zI{sU8hR~L(Z#UUe6|RK;nrrfY{kb@!CrL#~Jpsnfwj2bJ~BzKkEM4bvNSn zz5n+{ZN}9krumh9rrhb;2esnTB&G&8+r0XF^?83)DO>Z)87!;U+_DP|%bm3BqMPCC z6`Ur%t8#?JoR_+2`mfPB$)lgf=O@q{a6e;u4lB>12|QU->a-Qt*87F~hdT*qpPpUE tIeFtNmm}|Qo)vFvm-r%J`cI}Sr|oC{owASF#Z@cneqDFI(`>le5CDuHW5ECb literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142104.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142104.roa new file mode 100644 index 0000000000000000000000000000000000000000..106402a1b567b0e0087348dd3fd3af6b4d0063bd GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$QgB@BcO1X-9Em<+fLIGNcQ6d0L;nJgAGvD`3dV!2|_#Jpz#GZP~d zlZb!M!+dTfk0lD5g;x5RIu%K!_TRNLMSy-4Fn7Nrd8@L#|S(q6)TUc0{I=Q--nY&uLS-3hm z8pw(B8krdw8W|WE8kiaxM~U+qnHv}yS{fJ{8WuHZpQHGjVn@Xkt`Cb~7U@19KB2KZ8LNBNtN>BO}9; z6Ss`o(*Nr@AL8ha{FZ%Swl3G~D{mfc`|;-W!nL{GS+kns8@+Baok&iW|Dt4gY{pB@ z8sth-@H)2(8TZC{)0K9zM1>*lU01-84)0^Z7Vx2(Kr zxAGGs`?l-dTq-v&pE^~0;Qa*S!)xDlughJ$Y3XT(vTxEKe*ZWAVL5fua@jt;yKi;k zY<1$zW*xcdR1umsRjBvvJ%LSo)Z-K{B}@6Y+yDD@yyWHYIZt9!(jQ*ge@oWmd2v!! z=E2lil|Mol8y`-Q@czAAO!52fO-y%lKkb}w{CcO^3^kpFyw7)B%yH9JUT$*n4|m?D zh7*Dpu7%EAYS7BW%*epFxQX$&K@;O)16elaP+2|}F&2?qTW%kJb7`Ki=ld2}s}s4k zhjda-8_0vCm02VV#2Q3c|ICT*2*|JDwQtkun7Z#;-Tb~?27Dj|{EUqMSy-5v*c%Lz zL40|Z7=tK-hy`H_LfV3giYxPyt@QPa3bHfxl2eQFQcLvmQcLuUQVa6+A$)xUePYv$ zUUE^6K^+^1HX9==D?1}2OOZi=K^}~6z|@w6VqaoGUS=}fy5h`|{Gv*ICsQMHS2t4& zLl-kMLqk_1Cnpm#3paCTb0aqwLpL`geW$d_R`vp5+z7}&x12Hb5%DE34A2X_F%zmCC%CPsz^CVEBri3Sp&KvMt(BA)?| z0T;|PJ|+Vt7@LtDBrR+pXuuE7$%uT6oY=X+iJg(5PO>p?KVdo*Go#)4Q+VR!oXHVj;KVAQK z`E%Kw2feJeoxif_k@vR?!ngevXBzZ>K6rbnH-oOIms^gn_zA9M%z?ZXr%V*P_0wa_ z6n?(94r63ou^>&rNq17D|^Z=T4zMVwb+`sal%|-S$wUw#7=E?P%S&}ohqCEqVdepO&X0Wm-PIv6JIaK$T9ES z?DnHF3}R+4+;Y{slvn18wHBM}b$Ek}MXPu}u& z`s=;iKfXU&;;mEp-*)n+7pAx01vDK@saxP6b!*P8X;KQ0mg-)ebp65F*5(6qyP7p8 zuX%8ZJ!cCqD7h`?4tgBM_bwFrYv!;<%Xo#~z?avCc1*hyCS6AP@xhx_6{_pTd x@ylB{Bn18+In$Zbcpz(*tYC-RaTAva>!e$mGepJIT;Fqx{jZxfP5k%|0RX*8e9Zs= literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142105.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142105.roa new file mode 100644 index 0000000000000000000000000000000000000000..8397586bb3c2eaab83e192efc1a2877f4d2d2bfa GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$QgB@KiP1X-9Em<+fLIGNcQ6d0L;nJgDHvD`3dV!2|_#Jpz#GZP~d zlZef8^WV2`^v!(uC;MXZZj~2CUaQs{@WL%;>k7 zIU2}`^BS2M7#bNE7#f%wnnsE98krjy8d@3{8X6dyMj05x3}qJ9aCCGsFg0~GG&Z(0 zv9NG6C)$T z_FFR3JI?AY`^bN{*jYrtQ^2Kc-`D!TZ_j2|hJ98#y}sk|;){MRS0mp`&t7jVe6Rd~ z+tust9adu30V&=tUtYC?|#Lu8($QZekC4X z7P~=UiSx}vT7O#h>r@NNe6}s8u{=1ae))zB= zZQJrFBwAdbFWBm;-%SgLhWTrC%u7dJ5;H)vu!Y#__V94gDlBE}-JYD4Hl<0&1dG`gR;UFDfl z(K?ZLw}CuJTA4+{K&(N8_0OE>j)43cUi&tkj;Z^u)y?nQWxxkgz|Y9|pM`~)iM_!f z8N`=oi7|*Wh*%J|Afzp*sJJpO*-Br(s31F2FFCa+FSSH3FSSI!D77G8AHvr+&?h#{ z=p`5B7}T+GXtOc0va&NWvJ@E<805kD225>9DE1{5Fj4`v@DH;a>jgMl54Z@}GVgknF$e{csN{OcHOXkuh&V5(P?pJ*Tf3N!^!Ao3aT z7;wQ%<6|;Vg0UIdLDIqof(HEHoQ%lF$cddBoY)x|1k8{Aud%!7=)L~#1co2;XL0s; zFZ$E&>l=M=+xg%hrxz|><+kZ2v%JyCki~BmKC*WROLm$})LbV2_Qr{Tqu!-kEhIUM zHrzju?&((Jv-R+T-;Z_gEo%C`_V&_EMGw8_x3aX|KD4{rpV_r~zvDIOCw7b&1BB4Nv>7@to5`L?26Qf9^iVSjwto>fi#-d581D9pfq>BX08W8Gro-)PK8 zwe$ae>G;Irtl|rKM?Q1A%3h71{QukRx6d`iROW=VyPaBK6?6Bt)KdN@4C_vvc3#M} ztosl9@{fK`C6xl5Ue)ZpX6017z*R1dSz_L6rScOkt9@okwlW*ein?Uj#JI|!iE$Yd zBXa}xgpFKqF32{JVuO{ioXm#2DCMYu3__08kRMTGLCPq7ge;4p5{trWIqrK44mxPg zj=J^T^y}VZD|&vWsU~pe@i@HJTPerqj~rc$tPCtoj102OS`)Ms@2YEN*xh**^(4S; zW46G#&rxD5_t;PGxg_@>vz60*;`xH+`@uz0Ej7vxF`^O8IrU;Xt9F&7dfshdce(I5 z(Dm{qkvlURUu>Jnv(ZaR@#p40d0)Q27m#0dUpu#DseQuDJD*)ECJ1uh-+$dWW5q@Z zq1DAz^|vN??YWWg^lCuP@jK6R=e?+0^F)AiV~(I`h?D0gL5J&AtJRX!a@QRdTI3wU z{Gw;khI7S>0^GVzdKVp%Z#L3U4VvAOW$u@?XXm+M=7|&b98UHtHhXrV{?&!(9~)PG w6k4L{w$Jra_#gANrKv?CAI|)b<$H7Gp|)Dq@7qWA9+{Q#^R&9nnFAj40n`tCl>h($ literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142106.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142106.roa new file mode 100644 index 0000000000000000000000000000000000000000..e1b7960328f47cb4d1e1a2d25095648bc4fcf239 GIT binary patch literal 1762 zcmXqLV!Ox2snzDu_MMlJooPW6+j)Z~w$n_E%!a%M+-#f)Z61uN%q&cd2D)tAP-UC~ zj1mjvSY!;On3$Qgr3{1(1X-9Em<+fLIGNcQ6d0L;nH&~0vD`3dV!2|_#Jpz#GZP~d zlSra@dQs6aSBWBHh7G$^N@iRT++1V83%8t+o0Y-9%TUxnn2kA)Wyuu zz`(%J(9l31B+M$TVPNX!Z0T(3WMN@yVCH7-Y~W(-W?^RJY++$(>g4KTX6|a~X5s4O zXdoxfYh-3%Xk=huXkcn+8YRwaWNu(+XlY<*Xkcg>Wnc_5lv!BA+{Mho+|0z>(8$%y z!p+sq&CJrx$l1co+|0n$$;rjY(bT}r#lpnMpovil+0Bfs49rc8{0s(7j9g4jjEoF_ zR?1(fnjN?BPV=4KsiD_ogC7~jEoF>S^eTMQnaDo<^xnN^tMh~=vo4&{E^zkR`s>g5 zH~4uKSLPLTa56D7GB7S~Vmxlp#CX_1mW?@7mXAe@MWi;P%w6bN|NC$Ab=u1Kc3)b` zf5XW@9we>IB4HrbAj0}*PIN~=ehsgEn@-2neb?&d_w6#^11aEVWc<&WXZ2wM=+7F1MRnU`#(uU}Ml^43n`ZQq zi*gL=*f_M=7+G1_85voM3n$5)1M&li}7CXO`p_Rq8vL8kxJgnOYdS zn3)+Gx*9n-nV4C)nLC>sxw#m+xf$s@rBx<}n`8tg8JGJ7m_!z5dWGv6=9#5s73G6` zVBiO{kCB_j$-u$D4#qd&ZZkr$AL2i_0}%do3^p_|GBhyLE6PtakN^dm0w@sq40sH< zV5adg87RTnjO-w3VFN(}esE4kDTlx7lwUJHZ4Q3d9(&`w zoy>~MKVs~DpObu0e(T9+kHF>6gVg^8RnHgP6=zrJB>FQpjeF)=F44P33l42FwTV4` z$K|FdA;(?`rIt`X}jsI=43B{qz0y>MgzdxPy&TLe~B0I(wxlJ;-5F49CVP zS6;12RmuF5a7V1{P0{{e51iiqOgc6-Rp`lul&f}nMc2fdu5HP^COfg=M6TPe{d&?b zW4d@hao%)gICoOxhTL?{FGgpo=AHCVIh@bT@*vmX<++kCE}JSB&oyjfTxHP2xQvOB zxdD5^MlLuPWE)7a!Ae+8WwsMWJ+!rOeIZDCYkh z8_V7^Tv+{g-oafAM?Kx*kMO38G@9DJZ@=s7uy{3khgQZ^iAWy9&NzUz3jX1SY7f)?UOamxAkH^XmW6Ku9lyxR0#jRj=2%Y|48eWOI(^$uqt+;>RD9zwqvvjrEi3fVFt)3(nZaSBzQZMhsP2DH)J2svK0C75cGXMYp literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142650.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142650.roa new file mode 100644 index 0000000000000000000000000000000000000000..1e69010a29c7f9f011114cd983e02c310ccd4cab GIT binary patch literal 1758 zcmXqLV!Or0snzDu_MMlJooPW6+i8O)w&P5U%!a%M+-#f)Z61uN%q&cd2HI@gP-UC~ zj1miESfmUjn3$P#tqcSW_*s}3m<%`#*qK=wRJax}ENEi6X3)fP$)JgO*8*lHMkXc^ zjteXAuy4NbZ@vC!ZPn?szgf)I@-g6rTg}ML%3$DSC~6?g#vIDR%){eoY3OR|VrFPy zU|?uyXrK=gW);>jFm-dbbT)OeurM_+b2E1~a4~kXFf($tu&^|Ba&<8?ceQl0aCLGt zkQ3)MGBYqVGB7YSFf}xZ66ZBCH!w7`G%z$YFf@rWFoqe*EUaPRVs371;cVe-WNzu= z=IU&2S$`v#HfVqW=2*9<|amd27@L>E~X|%Mur!{ zp)D$|9sY$LZ!B&dXWsRVclmwoWm!`X|4#WkyHK;_!^G3N!Q0E$r4}{6-&Urc^Jn+Q zFD`o{>{qUx_d4d4GJozri+Uxpx;~XLmwufc+1gEgoY4$pc zf1GuAj;C#>o|~+~WESxaOAMFpy=SkvHG8eYtycxQxV+ ztEhoc*inwBFHW1kElw}qH%(-p{R0)|Lx*0i-mv91Z-L&%%T1!Pjn@>)%RW8zVw$$F zuH#(a>to$a%!~|-i<=ma8Z~Ou4wdC&5n~bIEw?yvsPg`sqUUq$tWKPm!M{ju zsewF5TA4+{K&(N8_0OE>j)43cUi&tkj;Z^u)y?nQWxxkgz|Y9|pM`~)iM_!f8N`=o zi7|*Wh*%J|Afzp*sJJpO*-Br(s31F2FFCa+FSSH3FSSI!D77G8AHvr+&?h#{=p`5B z7}T+GXtOc0va&NWvJ@E<805kD225>9DE1{5Fj z4`v@DH;a>jgMl54Z@}GVgknF$e{csN{OcHOXkuh$YM@t?pJ*Tf3N!^!Ao3aT7;wQ% z<6|;VfUz0bLDGT-{06+>d<@IQ$Vr_WoYWZ^&i3f96J=I5$gWsF?RAHKBvZ<)s451o z*QH9bpRcaEVkpuiG>`qGDF25ICwT3IDyB$@JQkLb2;IRWs=V@W^!(HRQ#n4BEtCGM zVHRwn!Cdhh(qCokH~}I_NeTn$>GNSBn zkL+kstN#`@`S{0ay4HoKOGN@XzMqv0=f2dpE^=COLgUFN?mGW=u{59UEMOFzUfg<0 zhg&yw&cd(>`xXPf3aTyaMa|8Bd zja+Ch$TpB-gO#qF%!a%uWvGD+LXOptA5maIN+^AVEQ_HMi^7J8E+^F~tw-HDKWpDC z_#K~cXt{z!w5V_Ry&_wt^Q-icql=N1fu)I&frTab>gsolhAO&InRUta-#AtulQpq+ z`{uqRWx>7_UNiXxDK?*ZQ*ERdoLsK9d-=gS_r*yaZl|2TtKTd7c5?om{fDB~S3lSv zbL51|jq9^lf8Bg>mPgTyrc39qX~$Q7Te>`1%5);1cvW!xX`fyTyA5$i+&@YFnq}rx zanOIp)urts=MwH_KlJ?MtoEX9`pe4;?8<~c{5{T*^!s=wtGn}tw;}bKKNmfHb~`Zr z=3=eNZ8;Y*=9C>|4$6CRTX6p8!1&i~fp2#SU06_^aoTV}ADjN4OfK>7%o1kNvsUr% svwWF8qjKlGh$NR+H`X6A=g?z|TW7vpylH3impYesrgc~Mc~pr300&ZVQ~&?~ literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142651.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142651.roa new file mode 100644 index 0000000000000000000000000000000000000000..824c1dee7895804119900918adb8485f97a778aa GIT binary patch literal 1758 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142653.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142653.roa new file mode 100644 index 0000000000000000000000000000000000000000..c79d7f56b6d5e2d2b749379617af7986185e9cda GIT binary patch literal 1758 zcmXqLV!Or0snzDu_MMlJooPW6+i8O)w&P5U%!a%M+-#f)Z61uN%q&cd2HI@gP-UC~ zj1miESfmUjn3$P#Z4Cqs_*s}3m<%`#*qK=wRJax}FKA-9X3)fP$)JgO*8*lHMkXc^ z{=CVj}$Bq8xml^QFt!CtAWiaqE6g3cLV-96u=HYR)G;}p}F*7tU zFfcSUG|&eLvkGe%n7TPzI-5FKSeP1^xtTi~xEQ-xm>D@+SXi1mxw@E{yIQ(gxH>r+ z$cghBnHd-w85kHEm>QWziSrtn8yFf|8WBg69< zrTuQt?amurKk_#}`MJAr`>&W&Q39uC<%>;sVt;c_;QgmvDt{-M1vbanzt&SVi8zvf z=h3Doe4FQ=pPbEGvst9?beko^=~t5z4(tke@v z9(c&!wWIrNh4a1n?-u>(b(2+*J=gq6%$Ti~p~@`d>SWo~PsB~my0{(nFZ_GwrORmv z$EBa%#|kTDetJJ;PjR5Z4-Z9yUDb~5r_TIcuUV8~yi*~U>)QdBdKZQhEn?pvnj91} z{B~*K!>97sy;d6WtMzU&CwPrqeNX-?h5=eY*_!KnnO78UM4eFf*|?7$k%E z@+>h1Q3eqU!WM+I1r-%n<|SL{>lYPdXX+)V7UiXu=;fuB=oh6H45ktD@T9KaTz75=z-G@t@0dP3NRa zH3e1UZO{K!o{BpYxc%lk1;!kK@Ml_!esWG>_Ojq(&}uLeQvUO-*=oTS&oBOIS3G#0 z|9bv<{(-$)nwNEMn-s9MW|iO34L8HrnK{>da<^jYifd>1RvJ*xn#&_s@>C{3@_|uA z%d7g2uWkuXo_LhEvG~Qs-%=j0#B$B-cdXbYl<1IP_JQ5%X;b)%s6S$Fw#!SZ99x*$ z+LrTJBCsv{m5|jM!x`(1?th9px;c+KQnETf&*9pNzB0Mq`fEoGn;2IaG%+q?Vq|W> zo~)4z%>~&8Qf#o&m6O?!7o`j}kU_|?8uB9wEJz8ZkC0_CRAN!^PI-ASv{ub@U!q;i zhiR4W&2H^)L^5CBF5#CceczO`4LQ0PSs7TG7#Vots>}p$2QK=>csXvSQ|`gv{RJMBapuVg8aDBnIIxc8|nGvf`PHQ#nD{CB`2?EZGcN%2#?0Yp@Kg8%>k literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142654.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142654.roa new file mode 100644 index 0000000000000000000000000000000000000000..ff5b1715b22229b6904f59845eb6484454dd18c2 GIT binary patch literal 1758 zcmXqLV!Or0snzDu_MMlJooPW6+i8O)w&P5U%!a%M+-#f)Z61uN%q&cd2HI@gP-UC~ zj1miESfmUjn3$P#?FC)v z7#JEF8t8+BS%ozWOx>IZl`kzvbv zp|_{c+SDhl{-1dy@Ft68l6HDuj{S#O*VUdYaA88tz}FV zyCWKuJh!Uj(FK!r_cldIsicLsHKZOC5Vp9x>4IQb&>F#puIERdbuuort=fIR=J4)c zDQ5$jrz_o7snM1Abzf?NufZFJs}l=@RxEh^W2LC6mhg>@OIf~L6030kSs1fR-^t|o z!pCVhlgd9lVDnYmk-4iYX7!CCf$I9r`%4p5-_^douUrtYymjrdU7wTRtFK}dZI;V& z?fd-UBGX($CT2zk#>GvHM-7@74;sj_F^9_Xv52vV#F#4HG59u>P47-4T#q!)xEB(=m15wYvFzyA1e13iufr|Ff_#GqE=qB!l?! zEHMUA1`!Lw7KF3~6%|+JC0pt17Zqe@>LsTZ<)xPB<)xPB7o`^D>qGeZ2KvON8NKA9 z9D_PG4sA9@R#tXKMwTLj0)spl-+-wt3B|s|g1pRRxOK&uCHX~_`c9@s=B{q07KScn zW`>5YMovy9W)^Pd&gMpLE{1MyM*2=^mC4~I8G%X0<$eJsk;R!_;kt%-W@%YP`5+${ z_`&RBLI71v)_m;zyDfs(*FK-l99By=i@y z_33|^0f*$jOL%9lO%ak^;N)LA;pH#aBgQ@NLRG)*x!m^3Or>l2T=%r5sli`DLgr3; zR>yc@&Ar&BeW@>74u%W6w?B|@-IKxTvxBK>ad>pT>E>zNVuDT!&)H4jwcGUg?@6{Q zPRRx8frTF}H#eBAH1Yj)cAn^>M&(<_F#~)s{>dX=kH8?Us zJZIC6zO34i;`QA-Ztv7ib;*Bn@_)RmbC5xC2yeH=db1wxhn(53}S}p9De9*_1=ck0_x3#9au#fP;1>ptVx^}h1e>tso` zea4pQDknFyu0J4nQm!xd+1u<#d~)*^#=K*Ae?0&B{cgbpe?!AfPVF;o&aIx8l9zew z-4{Uvu3cLtcTAZmD;8vVJtt8qe)@KUtC#D{WEgG;nisd|OJ@ad%e7W~eBqjs6t52R zjF5}dKDL^%iLx==p0%58!nGQGgPfpNqdlKyOw|qY4rFVIo0X+}eUlMS!g|(QkB=?7 zzxt(MGUh%$GfDAsIZt2?XXf+i9U_|Q r^4l05yS|qCk~jNN{Fds^%d%I#?_V9Y?D@+SXi1mxw@E{yIQ(gxH>r+ z$cghBnHd-w85kHEm>QWziSrtn8yFf|8WBg6b3 zf_t`kidX&;O>FLOy`g_0;pLXxs%1yAw*NV=znVS6$kmcbipe|b?=#n`K)dI8-d`5C z-kRnreJ%9TjmYC>cPEH{Tf0c-^LoxBC*zN>6f;CGJDZ=Zcj9n(#rB_vonEb)W&JZ? z`_=B>$Fc?Q>HoUy$6GJ|X0bJA`8t^_qs5!$J`|ox`PwE_JMC-k+SF?PVv~0@dc1Q( zt#ca6h4uS-#oixt+UcBdY2w-5Nf+7n@0P!~hkx0N&YNG;?rP;fc;CV#*H^sh&8Fk* z-jDW|JaPyWR4?$z$=m77*5zN-$=BZa@lgP`?yp~y67HJ%CoH@_GvHM-7@74;sj_F^9_Xv52vV94k26>}91nPtd$4_en(9nFSTi zX$JBjX=N4(1F;4X)<1KiI|A}+coNZ%=~GCABNBQVLh+%Lc+vN+Q#T-PwqEG?@jALIiA zKbU=t+$>H84hD8Gz5#ce5sLi~|G^!A@ULUAp^1^1si|I3exiW{D9{u@fyigTW55M7 zjgQGd0mf!z2T2PW@Eh=g^D!(JBPVrka8hSv*dQ!@Sx-<>w<rnx@ zS2;G^^-x(>owv4-=Sx~=UDw*bXEnM`m>;@Tr0Ms$WZ`<_Xo);VQcOr0syjGb_f6f literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142656.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142656.roa new file mode 100644 index 0000000000000000000000000000000000000000..7c832a77acd5d1a03d277b0b1aae1e684833a66d GIT binary patch literal 1758 zcmXqLV!Or0snzDu_MMlJooPW6+i8O)w&P5U%!a%M+-#f)Z61uN%q&cd2HI@gP-UC~ zj1miESfmUjn3$P#9Sj5w_*s}3m<%`#*qK=wRJazfEofr7X3)fP$)JgO*8*lHMkXea z$YZt*d+T-C=Z13Y^zWS@H@$5Nj{z^-YDR8W1_LicQ3GK%=1>-99v(+aLswH5GeZLd z14BbY1AUM%tFVTFshhK{Ib(x@p9h)rOlm2F3dMm zTPxPNUvG+A_U2r?+MJX(adH)*u{ZpVdi*Qjl$XPIpIPGDj;zZovbOr?tW~-YzhH7e z@~V)t4IYcN-_1(jC}Ml?0f&31NtW_%dA%!qRYF$c>cLKz`{y325MR3C(DJgnpCJ>r zr|N0G$PT~B#LURRxVVY&s6i9sK?7Mf=1^Ha7BLnPv*YJ(EZd`Qa8=M@qT6p6jTHXAaq1tOmTj{z6V zG(IK+1sI!=9V9Jiz;D0{&d0D^jGWZD!AYHw;cWaAufO}Bh}%x`>s@m5Of(p0^?WR9#omq7jtTppu>%D5|TEr#v<}44VgVikt;j7u{Wt#6@8&@3L z>8pFfQm35p_&@0#`_#h)xEG7951M&9X|I=wN8Uj$gB|fvx0VaO&fSn#(Rokl_Rk0Z zOxfGbcYkb%JjW?2Dcf>|eNpq(ME2LIoGT_ywS9E8^~0r#3-w#P_(R|S+ZFAq^eHc? ziTw$XT96zz5AG^bAPv#q>O@k zmxb54_DQSRq8IX}niOACUbb1Q%x9nBl^qT$Wj-a9SDLrUeXRYQdU>JszuKtaN=r5O z++SBY85XZxedzhN`!Dm1>JO_OX;s|MSHQgC-PtEiN5j?^Jq!Ig;ZQ!O<6TebTfg43 ztm}-;@IOB5OtSUW-E+&TC;n^RCKq;BWd4&m`?I~ujVr@s-pGBl-d23zAzS5MwJWoi s%rM&@bp1-^pWY8V8B9u_4DJZ8GT1r&*{_v9a$5g7KKtl1ZQnyt0MN8{djJ3c literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142657.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142657.roa new file mode 100644 index 0000000000000000000000000000000000000000..071ef555ea8164fbf459f4868632959cbb6e5ec6 GIT binary patch literal 1758 zcmXqLV!Or0snzDu_MMlJooPW6+i8O)w&P5U%!a%M+-#f)Z61uN%q&cd2HI@gP-UC~ zj1miESfmUjn3$P#9SsBx_*s}3m<%`#*qK=wRJazfFKA-9X3)fP$)JgO*8*lHMkXea z@)>%6Bd$pD-(AOLcKb#~1MOAL77Rx@(5G8lLniW&&BF^94+^YA!Y8oHXgm>C)v z7#JEF8t8+BS%ozWOx>IZl`kzsFL zyrWs>hTXgBEQyKcN;`|cxY5SJFj42lR_$$+`q1N{t@0NQT=k(Sy1y?_wr8)aW zLF922-#~xUN9%sAJ_r*o;|=9}6w5k*^j9d|U6h_<_}_P0=*bmcnm;tXj@rwM-V9iILFIE`r{KwZN>7CD zxf|?YI}(zg@l|YJRYO2n*<`28{#$2mDjaO9{a?}aY*pSu=8)c?MKjXatAZ$TMTToGPWnQwCzJ5_bcBWo(YEfQliC$i6iGERPLB2kOuWz7FY?{$aF3K^e zW8=_fV`ODzXJlk4GAJ;}gYgZR+LBQ0ODxFCOom%moLQ1zRH^S|YGm%}W@=&RVrFJ& z=xXHTWMXFFX6|fmZjuq0WL)kSU=mrJ=@qVPm}i!jRg@3%fq@^) zK1Oa9Cj$oqI~d=9yUhs2eu)3z4nX+VG1$<=$jsDSuP8s!KmrtK3ZOvbGvG1cf|-IyX3}Gcv6H)2?>^bIF`s#>sL|HPl#>+!c55I~snO zu=VnRsKC#A6dWfWIe(Sm%Iu{#r>*(4vUnYjYvIjVhYl@~>1Fx+rir&-R`0$=_S@Zt zCi6JvExo?#)Q{~BO2QL_rxr+i^E~?Cb9U16FDk38%%)Y_+&{DP+?Hy|RWl-&_n(<` zTs z_Z>xJ_OCn%`+v+lvSU^X>yA5_+*j7{Ei#qR>|bx=qxR}apg&)c>GX4sE(_8VgIM_E zmgvNZU7EV&bI*I0TNAA3P4{L`uWrh>-ZQD`Q-f#Q*KG#HFK!w(F|IObVqC_=$lQQE zStA#k3$hKQ*kGkAC$k|hN*QV(gOFo2+A%R2LZ`{=K=A<|PZX!4|P`{^u} zUPWGY>+JXLleL`ldIQ(3iATO`swy)}tew8%m4eeYsjAHlJ33#gJUPB+uEI&PBTg~1 z=X$S8x^z&6<9J29rXt&~&fRq?zm)x+)LNa{@@DnUpgit-GX(c;Tavr~vnpT2n)>CN zD(p*SpDx?9TT9@l%jtxkX%dgWHBL7UxHG^0_>y%qo0e2gRem1VZD<=+clfRMpQemV so*AmqNoR{A?>s%Z&1YlC;$-=wcODgPNY&Qd_+3reVJF}HH`DcP014A@DF6Tf literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142658.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142658.roa new file mode 100644 index 0000000000000000000000000000000000000000..564add2c7d36ec55785ed10214991649f9777993 GIT binary patch literal 1758 zcmXqLV!Or0snzDu_MMlJooPW6+i8O)w&P5U%!a%M+-#f)Z61uN%q&cd2HI@gP-UC~ zj1miESfmUjn3$P#oeTsG_*s}3m<%`#*qK=wRJay!ENEi6X3)fP$)JgO*8*lHMkXea zs2$obYCkMLxxhp3y3bYdX{MWPv<-OSRx@(5G8lLniW&&BF^94+^YA!Y8oHXgm>C)v z7#JEF8t8+BS%ozWOx>IZl`k>Sw4 zfA=_5vw7Ga8~v3sPU`tsTB#foEd1%D#hdlQCl7JRy$s?AI5_+Hr2r#A#e`)qH%xV2 z8e?L9@foj^sQW?ArNa6P{-*OASxnS>BlzmsI>okQ9~9eFp0iKMoqX$ky0L3dxr}6E zV&vtm6R*7yQJ!*EuuJ+yQi-NTW$}sV(2^isOas^TQk~c#?LX^(Ng&}_T!q) z__k<)tSuETrH6i+vWAAYR6n{W;ZpK|?NvI*h5u&L^c;0sJ9gb$$G$CZ&9bzcD~uu< z-vt{KZJMmj#LURRxVVY&s6i9sK?7Mf=1^Ha7BLo)$0qItX78?Q8HjA$viR@;=`5qK zZw%x?(#k9n24W2&tbgW2cLe0u@Y=WObWGiMt!{qbE(1Q00)9ru|12!bOzaH?$soQw zON>F3LBxWv1tD!gMa7kQ$yWOMMFrWJddaCpd8s9Od8sA(MX3e(`VhXpfj+TmMlZQ2 z$DodlLz|6}m6e^5k)_C>z#tFCH(+W@La{HgATKi+Ze4L^Nq$kKzLTkuxvQJ0g`ta? znW3Spk&}~&nT4CVv$>I*i=msFk-k$}WpcPlMqrY0xnF=uWO1ffxUONISz1<6KF9|K zelYtOxmlbH91QGWd;{(_BNY1~{)0OJ;a|sKLlYx2QwzPK{6qr@P@pM*0+G*v$AAlF z8XuE^0*uYb4w4o$;5Xm}=VMqdMo#M7;H1vT5V*ghNaj+9)P8MMwhO1&K0T^q%JQ9a zzDB3XasQ=#&t`P@eqF;Ab08%v@Q8Y%4l7XLTwI>(6^J!u92{?rS?wpH5F(*>f~@^5p5(N|vpgCuUA<+H}vZ zCH(gt-)T;4654l;sfYeQty=e+)3+(3tCUIJe#2+wJKlvl3-crsw(WXw?!>hA#U~3F zZ46$sdhr&sa?=xAcPZapI`3cEL9uOOA@-;8?q546-t+zXoIi`#Y1`zTwK7_k@X$kd zbIP_~0+SDHiC64(HD0?wJ78VI<-l8Mj!_|veu~=16@?WV86#T_n;2IaG%+q?Vq|W> zo~)4z%>~&8Qf#o&m6O?!7o`j}kU_|?8uB9wEJz8ZkC0_CRAN!c<+9kg$szpZU)KCp z(G0($3PMlDJ3Y5*DvIKWa1B|$7&*EaSs7TG7#XIobjVqk^0<6n{DnJm@8y*k7*{Lz z-gk^vRk^_>H>qU8fOb@l)N literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142659.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS142659.roa new file mode 100644 index 0000000000000000000000000000000000000000..5f96ec28986d0cc6ada4c19371ed9a111e6de682 GIT binary patch literal 1758 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144699.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144699.roa new file mode 100644 index 0000000000000000000000000000000000000000..6d8af430b11dfec88257a883ec66891a63894a0c GIT binary patch literal 1758 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144701.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144701.roa new file mode 100644 index 0000000000000000000000000000000000000000..3d9aff853be1e408f1956fc90cc49d7708e332f2 GIT binary patch literal 1758 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144706.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144706.roa new file mode 100644 index 0000000000000000000000000000000000000000..0a996101f297c74b753978d0d8f075a8207649c7 GIT binary patch literal 1758 zcmXqLV!Or0snzDu_MMlJooPW6+i8O)w&P5U%!a%M+-#f)Z61uN%q&cd2HI@gP-UC~ zj1miESfmUjn3$PNoeTsG_*s}3m<%`#*qK=wRJc}fENEi6X3)fP$)JgO*8*lHMkXea z6j#0T=W0Zz#;tx667h>8{JCRuh5;|!YDR8W1_LicQ3GK%=1>-99v(+aLswH5GeZLd z14BbY1AUM%tFVTFshhK8W6Hy2A6 zM-yXb7gJ|rM@Mr@XA?6sV+(UvHv=PQV*`UGMkQo7GqN%;H!<=v7&I|*F*PwVGTcr6 znmB*gYy%4wDPOxNCwUF`H;i`{NJ~$wWD~EM%ei>oW99v#hyUhpJ=nc5f0w?k+L45r zE5tr*sJeaoMd>-a^5XBENx!#+2|P4Wtq)p~Tv9q81lHsw?Fl({ z*~isqmH(@2;!pF_RG+4+{fK+X{^4!%kzDKW^CT2zk#>GvHM-7@74;sj_F^9_Xv52vVNP+ z$G|`yB(2OMVIbBZ!un@UbVopb4X=HhPRG=J*Xri??K0p4Dd1;h{LjL|%*5VckPPC> zv&0xg8AL1yTM*I~R8(AN}YlnY+4~S{S;R znHd_o8aX+cm|3`)JDVH1xfr^+8R6ayh3gvTnWbeF<%4`+ z;0Lphk(>z1D1AYTua6V>-=3?Ze&J9lLj11ef^)l|5W!@K^->g)#i`WKOlE$^PFCG#R9W!4X?XJ zW&I96v5xx~!fALr)a^!O=0%0gM=uHe@0dG%De@5n8@5mB`4 zw~uY^PszvGm4(0F-irLv>7ljrVrVE+OuVhS;rzh~HCA8q>&$jPNL8#` zssAqdO;6RYvlDLIxqRt!dE~mqRuva4eVD}J|E4qloT?vL{%+wayFOQu8y4@(c7K@C z<~wcL1pBRwzHFQMYCn1G(pu$edn;TpV^6Zo_EY=gIj_EJtb3Vx#IT8Rl|d8ZGA2gm z2JFcixzJpYZ6L)4D_uF64S7+@Py-o+9IGKeqQHWbQ2Gd27DFW#g<6pXtv09BR3=PT zXk>FbdwG_`p~U)>#~2XYkTw8 z^!nzlLMNl`Zz=Cu#>5_QLtg%ugGq_;Js;o6$28_x8P2NjOWpf(?{A@FYG33W_U#nD zc%?6}{&dodn$GS{nK@f@ujq0aTQ51C==X9_aZr!bJxfkEBcqJqby?C{j6dgVlz#bY zaA{N3hqJ%*53;oUvFe_m@iXp$OO#Y}yN_7*jP%JHXJkC~Q2X1fq`tFteTRkr%Y9Wh zc-QC!379rqiA*}$!ERx7x3_icgb(~4E4C(jUsxTp|H*W<=~7?ym7jRo?kJCZ&@8aF u>e%{73*#roTjho7*XjCY##yfusebqTl~wbpHQW7}j#Wy1Q+E!(?g;>++I(yP literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144707.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS144707.roa new file mode 100644 index 0000000000000000000000000000000000000000..57dba74558e56ee1d53e04989790af427d4f1c84 GIT binary patch literal 1758 zcmXqLV!Or0snzDu_MMlJooPW6+i8O)w&P5U%!a%M+-#f)Z61uN%q&cd2HI@gP-UC~ zj1miESfmUjn3$PNoecyH_*s}3m<%`#*qK=wRJc}fE@)!8X3)fP$)JgO*8*lHMkXc^ z;kQBO5B3~qa_6hhf2VI?E%5K8xdAWSYDR8W1_LicQ3GK%=1>-99v(+aLswH5GeZLd z14BbY1AUM%tFVTFshhK}RlD=ypg+2QQ5 z?Fpw&eE#Vix7%pGQlwdg-^nR=iUeC;wFUKWm^yKC2R94T-==?46;z$YZ{7LmY$tH{ zsYBx7QjG_UC#JDE#`wMM^eLWZVA}CIwdjZ%bFk*QhhK_L%zgiH!?gNEKOANqZ#Xmm zVBCH~=h>F-mQVV%r+05Zp|kJ#L*?*It$Ghx)tbIUebpp;MyK?$5thPEsl@ z{(G%%`SPXCfyWN%#$h@RLDI@B5(Z)oBCLPrM0W(_*YMi6>2yrpcdc%I-!20_kOF>2#{VoV%uMVJ2FW14 zJWGs0ltILTumvG)K}E%tdC6A#`b7oVnR>~oMR}fO`bDV)`T7vPzJWfmX+|%( zD950VjYFG_k(HI5k&&gypuivx#y4PUOG2?Pu^=xq8E##1W=VcgrM{D?k-4jzsfD47 znVF%XtC5qFiJ66)xwE;En~R~Fn~}a#T4i#$Nk(9jak*cBNn~-RSGcZWo>^K}Q9j5A z27WO67`a)T3>*yXV0;7aHX{`KA^w9q0O4Q9U_%oVa|3g|qWnYy2~eOZfC7=vfX9Ff zW*Q%pfdY)p$PSVgG~hSj1?OW}E=Er3+~B0n$gpL9s@nXD$mlm8N|#$&`}Xcyo&360 zE9T{)LsdM@@g;rx|4Z!8s`;xt_o?l(Sx1#RET8;vb=h;Ys$Dv6^O~ufgwxmW5Mnu) z@GnPtQP94QFeBM&?uDhyUCO%yd1fqZP>5c?bJ6UxTWVN30zWgSS?4@GRdS-`Q@t(M ztC=wizii6e?w-6st7)$C-{UJn9=W`0>D2X{YO#m;)`F;~wQCs9xcLSBjXA?EGa-Mc zYp7OW@yj!LX{}qm=BeCD_GmZQ-7lVe=+JwIpgyCVdk+Jry_ORFd-L%!Hy*chF$aE} z&2wLKYu}BQk~>E(d}7^ppXbkpupdmFOI@2MaIRR(dNGypwdvWrhE0sC44N31F)=bX zU{BV_h30~611UCG>B`A$$cs{j8pt5zSPl6R1s0@)(nrX$7%H(S%(J&p&z9aj^A^XU zrD}68hyP0p)T~X5e7b{Yz0i$$-~S*-7b7bJOA{kQx3*EXfA_2VVk=@f{fy7)wp5=! zJilyqYx``EzsJI*U!IW)$k+94{}i;j+->{nkVG#%!Jw=20(F)KP29B5$@btJCPtyh zyFaaCUYg@xvM@P(6GzaaKIv!YKDPaGcyUDB@mYZ6XO<}E|87S%8TPU)N}6)>&;B@d z4z{I-Qhz?2rq@(H(R@z=`-*oFOUm=B_DsySj<&J8mh#T=*3k`VZ?{>M+xdTsnYPsR zprf^r3h&VpHB`{Ut}U{ABc*rmPHAwhj0B?oQpXL_ucwj=ZZn`K?sz|4}Q((zEH?13b)cKiA2ZZ~y>hjDf-c literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS23910.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS23910.roa new file mode 100644 index 0000000000000000000000000000000000000000..85f592e0bac5b06072d3aa865e035e0a2a147540 GIT binary patch literal 1973 zcmXqLV&BNdsnzDu_MMlJooPW6`yzuT_IXT<%!a%M+-#f)Z61uN%q&cd28~bHxS{Ge z1sEk3G+tq8ylBvPj)^HY&7kqPLE{k?CI%*h#=QpY%&ZIwj7-5`h6>jL1{i}8#$bXm zm|+YS7=snYV1qH(VGIr!gA>YF0W*08%;Xg?lUKk@UI8b&k zBWDW>OH(IT7c+BLOE(KwCr1N0ab6=c14APN149E-L-QzcUL$h@LqkggLqh{Y^C$yj zn4!$V8cybphL&z7rk1YeMkX$1<`!;FCT30sPKK5iCdOvw7LG1PPL7V|#s*D{O2}?z zWMyD(V&rEqXkz4IYGPz$IAQnYW0#eTlx+N$)xSgnD+}tROJ{psSZUJTSmx8W#NB@R z_Tx($1WP$Q=6pSIZOzp6Z47n))}7L-aLgm;c(y6%C@HeY{d2K_pxt# zJu&5phDu zKM7J>oGQNZ&$$&P4>`H^{uNGLqMn%1)+i$=Xz(+C-m){S=XKv@y?RtEZ}jKltwaS0 zk!7#!cI@-apD%0t@jo7$g!nCiEGZ8F&M?QPyu$Xn~m>U#) zZ8Wc1`X_Rwm&oCw2(t=b!=JeqPN%%w{GW-Lk%4h>6XPR;CdPXPvTV$uvV1IJEF#+% z&Uc+xatAZ$TMTToGPWnQwCzJ5_bcBWo(YEfQliC$i6 ziGERPLB2kOuWz7FY?{$aF3K^eW8=_fV`ODzXJlk4GAJ;}gYgZR+LBQ0ODxFCOom%m zoLQ1zRH^S|YGm%}W@=&RVrFJ&=xXHTWMXFFX6|fmZjuq0WL)kS zU=mrJ=@qVPm}i!jRg@3%fq^f~K1Oa9M+18UTNvMfyUh^Aeu)3z4nX+VG1$o1($GM! zC_m9a0u*KnpfKb!;4$EW8OFzCU^n134dXgYy9+!(`UWU3zbKGu5`()~j9mwudv)XhOTql-EiNWwf2r zZiIQ;t`~jhBo^QmtC8@%fvM)v_18bGWFB?A(mHtQ2*YNPC#-xMFXu~7v*^tiuGwK| zy-{_Qd4Am5J$F7VsENB`D{SXjZh0aj;+CKe+c7CigNDVNQTP7u+#8x#_;J$phN{B% zYjQ(OUfDeU)wB0Xg17y-HIM&oXnwVIX_n~Z3kj~9T%O-%+0%2Zp*JBnW$tDlGtuQt z*4ivbu3P4uly>I2b}b^fbW5kk_SrMnEdS{us&#Xs$@SiF({SylE1l=>`+DK>l>I$U ziSxXF&k_3D!_IQNPfPpN{_Q93O?_5y^I`Y9yT=_2n;2IaG%+q?Vq|W>p5~G3f(6+I zQf#nFgOk~i7o}z}kU_|?8uBAbGf45JkC0_CRAN!MvbN!4s6=kz?8W`9>rB*(;`@r; z^k_u(2V1xE2XO|OB1ab^D+5atBSV+sop0hZ@-J+fvgT9h_JG@odwyL~vOO$$g;A!} z=GV#Nz5Mne4m zyyK>yQTj3OMp9Jxykenu8x`xfwRNlBc)}p8^DpSf)Gk-CUjimib{KlRPm|y{p!zx5 zv)5rC%bnwaGGR9_#ERN}OUo9!XQNoO_J-icL!Zqy^*k_%oqEVQF7nu>$71dpGTkrN z)`{t6om%YNAR%$H=9OBk%bdvnSFhDO&)RuSin-HAwLgF@;LRKRii3BR*wo}}7=>@O lOt`dH>21M|ef8}VPfXeBe%LT*=b=?PUkxAIJ;}Fg0s!^>m7D+o literal 0 HcmV?d00001 diff --git a/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa b/tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa new file mode 100644 index 0000000000000000000000000000000000000000..846e77702b49e21449b35f615c81dc0cdaa99287 GIT binary patch literal 1956 zcmXqLVqd_BZZ^(@HV?*BW)>z!gT~uz+)#C# z0*n$18c(w{o-k-U%ETnN%b; zRv3c~#$bmrIA9D;C}Rc8gjt0(3{2geEuBrBEG$e7%-qbK4P1=fEX<6YEi5ce zom^ea%v~+rEL@!&4dldmjm!)TjSLJ74NMKqqQrTP%nb|;Ee#9}4Ghhq42)rhG7D>% zx|q8e8@aifIy##gSr|GSxfqz5JDXV;I69fTm^eEbTDm&9ni!cIG%+e6yP1)dfw_s1 zpTVGsk&CH`k&$6K*9>DXgCaMHlZPigQNQaact*Cw!10i=kmDSof+ZRzjEkJy)l(Yv zK3`g^WF(;a$n5{8gQ2%=wY;w`$(?O;BztR!^2{qKpFCWJK3%snXr1HOdFrS{?CIy* z7-t%Mz47SPHIp~lM=JK7d!zkjYnT;h=(6f8)!my9_pIq|y!VoChT$ah2N`}#&K$4U zbp3R`yrTS{Zxerdy_r8hMKA3Dw?+4VE2nu(dPb2qJA)>%ZCv9zG2Q)(qQ|c?#)ljR zdLEql%xNk{sU~JVs)_|EziJ&bwx<7he?#5(&i2OF-S3af+_@cnShy{>hlTl{mKRI# zn@>Fz&#N^oU#>cmnV5OE%Jxbs6EhIYm_udxSj1RFV(X3mMIF_U z(Pgd4;M#uWwB+k2>IU*4X=N4(1F;4X)<1KiI|A}+coNZ%=~GCABNBQVLh+%Lc+vN+Q# zT-PwqEG?@jALIiAADDfN+$;_Tb_O;uz5#ce0gC+)|G^!A@ULUAiK(%LUQvFcfdnYX z6hJ}9XTW2?1v86}$-o@OW@HCRYZ#~*sDMixIRjp17FHFm1JoBQI+ z+zCzV8|#^6OLV6gDzxYvTZ03uiEgwa+&lowU`%N zHii4RLaTINHaF&cTu{g;zN$=W{(Hqu`ng z)!5H#g*jq)A}Z~kFPi$|VB37dCdO3;O^nN!7?~Ter*-6_e?hi^6dSCL;AA%BMX3l3 zWDs(!hWv<93{q_ABV<_&l~@$mb=8tNrXODN&T;;&TkpLK&ve|YKPrm;>K6azxw)Z{z{A6k;@jL7N)7mrTV0rw@-N6sibt(d!s#>G7 zZZFL`yLFaz?U%F(x|ORJeR{G)Kg?72Qrjl|t~K`8vl?tQuWGe;*Xv66*c8CZO=+eoKk`6N?sjd+jUTyvFjo<@@Zp+ka0G zEq@s?A>8uKS!dn-*`=BjnC-l+o;bJN5Hf#vIzV8e>w{BrayKg(pY2IC{uh6z@chn+ z2j0B&mgMl}Kc{oGbbcgfR!8xhYY$33Gim;Qt$b~1He0&;Lh0Wxgf=iMFPVBJ;N4|w Z&HWx}ns-n4T=f0A&+Y%x6=z&)O95EsjlBQ> literal 0 HcmV?d00001 diff --git a/tests/test_crl_decode.rs b/tests/test_crl_decode.rs new file mode 100644 index 0000000..f5055ff --- /dev/null +++ b/tests/test_crl_decode.rs @@ -0,0 +1,68 @@ +use std::path::PathBuf; + +use rpki::data_model::crl::RpkixCrl; +use rpki::data_model::crl::Asn1TimeEncoding; + +#[test] +fn decode_and_validate_crl_fixture() { + let path = PathBuf::from("tests/fixtures/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl"); + let der = std::fs::read(&path).expect("read CRL fixture"); + + let crl = RpkixCrl::decode_der(&der).expect("decode CRL"); + + assert_eq!(crl.version, 2); + assert_eq!(crl.signature_algorithm_oid, "1.2.840.113549.1.1.11"); + assert_eq!(crl.this_update.encoding, Asn1TimeEncoding::UtcTime); + assert_eq!(crl.next_update.encoding, Asn1TimeEncoding::UtcTime); + assert_eq!( + hex::encode_upper(&crl.extensions.authority_key_identifier), + "05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA" + ); + assert_eq!(crl.extensions.crl_number.bytes_be, vec![12]); + assert!(crl.revoked_certs.is_empty()); + + println!("{crl:#?}"); +} + +#[test] +fn crl_signature_verification_succeeds_with_issuer_cert() { + let crl_der = std::fs::read( + "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl", + ) + .expect("read CRL fixture"); + let issuer_cert_der = std::fs::read( + "tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer", + ) + .expect("read issuer certificate fixture"); + + let crl = RpkixCrl::decode_der(&crl_der).expect("decode CRL"); + crl.verify_signature_with_issuer_certificate_der(&issuer_cert_der) + .expect("CRL signature must verify with issuer certificate"); +} + +#[test] +fn decode_crl_with_revoked_entries() { + let der = + std::fs::read("tests/fixtures/0099DEAB073EFD74C250C0A382B25012B5082AEE.crl") + .expect("read CRL fixture with revoked entries"); + + let crl = RpkixCrl::decode_der(&der).expect("decode CRL"); + + assert_eq!(crl.revoked_certs.len(), 21); + for entry in &crl.revoked_certs { + assert!(!entry.serial_number.bytes_be.is_empty()); + // 0 should be encoded as [0], otherwise no leading zero bytes. + if entry.serial_number.bytes_be.len() > 1 { + assert_ne!(entry.serial_number.bytes_be[0], 0); + } + let year = entry.revocation_date.utc.year(); + let expected = if year <= 2049 { + Asn1TimeEncoding::UtcTime + } else { + Asn1TimeEncoding::GeneralizedTime + }; + assert_eq!(entry.revocation_date.encoding, expected); + } + + println!("{crl:#?}"); +}