Skip to content

Refactor PKI parsing and prepare v0.1.3-rc.8#38

Merged
vansour merged 4 commits intomainfrom
feat/rasn-pki-rc8-prep
Apr 11, 2026
Merged

Refactor PKI parsing and prepare v0.1.3-rc.8#38
vansour merged 4 commits intomainfrom
feat/rasn-pki-rc8-prep

Conversation

@vansour
Copy link
Copy Markdown
Owner

@vansour vansour commented Apr 11, 2026

Summary

  • replace x509-parser usage in the rginx-http production path with rasn/webpki-based parsing and OCSP verification
  • add staged migration docs and stage-0 baseline notes for the PKI refactor
  • bump workspace version and README references to v0.1.3-rc.8

Validation

  • ./scripts/test-fast.sh
  • cargo test -p rginx --test check -- --test-threads=1
  • cargo test -p rginx --test ocsp -- --test-threads=1
  • cargo test -p rginx --test downstream_mtls -- --test-threads=1

Copilot AI review requested due to automatic review settings April 11, 2026 04:17
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 11, 2026

Warning

Rate limit exceeded

@vansour has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 56 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 19 minutes and 56 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 09f104c8-0856-4b5e-a827-99f4e0eec055

📥 Commits

Reviewing files that changed from the base of the PR and between b2ea6cd and 32e3139.

📒 Files selected for processing (2)
  • crates/rginx-http/src/pki/certificate.rs
  • crates/rginx-http/src/tls/ocsp/mod.rs
📝 Walkthrough

Walkthrough

将工作区从基于 x509-parser 的解析迁移为以 rasn/rasn-pkixwebpki 为核心的 PKI 管理;新增 pki 模块实现证书链检测、TLS 客户端身份解析和 CRL DER 验证;相应地替换/清理多个 crate 的依赖与原有 x509_parser 调用并补充测试与文档,版本升级至 v0.1.3-rc.8。

Changes

Cohort / File(s) Summary
版本与根依赖
Cargo.toml, README.md
工作区版本 0.1.3-rc.70.1.3-rc.8;移除 x509-parser workspace 依赖,新增 webpki(来自 rustls-webpki,禁用默认特性,启用 stdaws-lc-rs)。
依赖清理(各 crate)
crates/rginx-app/Cargo.toml, crates/rginx-http/Cargo.toml
删除 x509-parser.workspace = true 引用;rcgen 特性去除对 x509-parser 的依赖(保留版本)。
新增 PKI 模块
crates/rginx-http/src/pki/mod.rs, crates/rginx-http/src/pki/certificate.rs, crates/rginx-http/src/pki/crl.rs
新增 pki 子模块;实现 InspectedCertificateParsedClientIdentityinspect_certificate()parse_tls_client_identity()validate_der_certificate_revocation_list(),全部基于 rasn/rasn-pkix 解码并输出诊断与元数据。
库集成
crates/rginx-http/src/lib.rs
新增 mod pki; 模块声明,使 pki 模块纳入编译。
服务器层集成
crates/rginx-http/src/server/connection.rs
将原地实现的 TLS 客户端身份解析替换为对 crate::pki::parse_tls_client_identity 的委托(去除 x509_parser 直接使用)。
运行时证书检查迁移
crates/rginx-http/src/state/tls_runtime/certificates.rs, crates/rginx-http/src/state/tls_runtime/mod.rs
移除模块本地的证书检查实现并改为调用 crate::pki::inspect_certificate;测试导出由本地实现改为 crate::pki
CRL 验证迁移
crates/rginx-http/src/tls/certificates.rs
将 DER CRL 校验委托给 pki::validate_der_certificate_revocation_list(基于 rasn 解码并校验无余留数据);添加针对尾随字节的单元测试。
OCSP 逻辑迁移
crates/rginx-http/src/tls/ocsp/mod.rs
将 OCSP/CertId 构造、AIA 提取、签名/授权/有效性校验从 x509_parser 迁移到 rasn_pkix::Certificatewebpki 验证;新增 AIA/OCSP 相关测试与证书生成辅助。
测试与样例更新
crates/rginx-app/tests/ocsp.rs, crates/rginx-http/src/server/tests.rs
将 DER 解码从 x509_parser 切换为 rasn::der::decode;新增 TLS 链保序与字段保留性的单元测试。
导入清理
crates/rginx-http/src/state/mod.rs
移除未使用的 x509_parser 及相关导入。
迁移文档
docs/x509-parser-stage0-baseline.md, docs/x509-parser-to-rasn-plan.md
新增两份文档:Stage0 行为基线与分阶段迁移计划/门禁(包含测试要求与风险说明)。

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server as rginx Server
    participant PKI as crate::pki
    participant CRL_FS as CRL/FileSystem
    participant WebPKI as webpki

    Client->>Server: 建立 TLS 连接 (带证书链)
    Server->>PKI: parse_tls_client_identity(der_chain)
    PKI->>PKI: 使用 rasn 解码每个 Certificate,提取字段与 SAN
    PKI->>Server: 返回 ParsedClientIdentity (leaf fields, chain_subjects)
    Server->>CRL_FS: 读取 CRL 文件 (.crl)
    Server->>PKI: validate_der_certificate_revocation_list(path, der)
    PKI->>PKI: rasn::der::decode CertificateList,检查无尾随字节
    PKI->>Server: 验证结果 OK / Err
    Server->>WebPKI: (在 OCSP/签名验证中) verify_signature(...)
    WebPKI-->>Server: 签名验证结果
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 分钟

Possibly related PRs

🐰 旧解析换新装,rasn 披甲上战场。
PKI 成群理证章,CRL、OCSP 齐声唱。
版本跃一阶,测试证实安康。

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确概括了主要变更——将PKI解析逻辑从x509-parser迁移到rasn/webpki,并准备v0.1.3-rc.8版本发布。
Description check ✅ Passed 描述清晰关联到变更集,列出了三个主要内容:替换x509-parser、添加迁移文档和版本升级,并包含验证命令。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rasn-pki-rc8-prep

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors rginx-http’s PKI/X.509 handling away from x509-parser toward rasn-based parsing and webpki signature verification (notably in the OCSP validation path), adds migration/baseline documentation for the staged refactor, and bumps the workspace/release version to v0.1.3-rc.8.

Changes:

  • Replace x509-parser usage in OCSP/certificate parsing paths with rasn-pkix decoding and rustls-webpki signature verification.
  • Introduce an internal pki module to centralize certificate inspection, mTLS identity extraction, and CRL DER validation.
  • Add migration plan + stage-0 baseline docs; bump version references to v0.1.3-rc.8.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
README.md Updates referenced current version/tag to v0.1.3-rc.8.
docs/x509-parser-to-rasn-plan.md Adds detailed staged migration plan for replacing x509-parser with rasn/webpki.
docs/x509-parser-stage0-baseline.md Adds stage-0 baseline behavior + required test gates for regression-proof refactor.
crates/rginx-http/src/tls/ocsp/mod.rs Refactors OCSP parsing/verification to rasn + webpki; adds AIA responder URL test; removes x509-parser bridges.
crates/rginx-http/src/tls/certificates.rs Moves CRL DER validation behind crate::pki API and adds CRL characterization tests.
crates/rginx-http/src/state/tls_runtime/mod.rs Re-exports certificate inspection from crate::pki for tests.
crates/rginx-http/src/state/tls_runtime/certificates.rs Switches certificate inspection to crate::pki::inspect_certificate and removes local implementation.
crates/rginx-http/src/state/mod.rs Removes no-longer-needed x509-parser and related parsing imports after refactor.
crates/rginx-http/src/server/tests.rs Adds characterization test ensuring mTLS identity extraction preserves chain order/leaf fields.
crates/rginx-http/src/server/connection.rs Switches mTLS client identity parsing to crate::pki implementation.
crates/rginx-http/src/pki/mod.rs Introduces internal PKI module entrypoints.
crates/rginx-http/src/pki/crl.rs Adds rasn-based DER CRL validation with trailing-data rejection.
crates/rginx-http/src/pki/certificate.rs Adds rasn-pkix based certificate inspection + mTLS identity parsing utilities.
crates/rginx-http/src/lib.rs Registers the new internal pki module.
crates/rginx-http/Cargo.toml Removes x509-parser, adds rustls-webpki, and drops rcgen’s x509-parser feature.
crates/rginx-app/tests/ocsp.rs Updates test helper certificate parsing away from x509-parser.
crates/rginx-app/Cargo.toml Removes x509-parser and rcgen feature usage.
Cargo.toml Bumps workspace version and adds workspace webpki dependency.
Cargo.lock Updates lockfile for version bump and dependency graph changes (webpki, untrusted, etc.).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/rginx-http/src/tls/ocsp/mod.rs
Comment thread crates/rginx-http/src/pki/crl.rs
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
docs/x509-parser-to-rasn-plan.md (1)

561-567: “当前建议”段落与文档状态存在时态冲突。

Line 561–567 在“阶段 0-6 已完成”的前提下仍使用“如果现在开始执行”的表述,容易让读者误解迁移尚未落地。建议改成“复盘建议/可复用方法”。

✏️ 建议改写
-## 当前建议
+## 迁移后复盘建议

-如果现在开始执行,建议先落地两个最小动作:
+若后续在其他子系统复用该迁移方法,建议优先落地两个最小动作:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/x509-parser-to-rasn-plan.md` around lines 561 - 567, Update the "当前建议"
section heading and its opening sentence to remove present-tense conditional
phrasing; rename the heading to "复盘建议/可复用方法" (or similar) and change
"如果现在开始执行,建议先落地两个最小动作:" to a retrospective phrasing such as "建议先落地两个最小动作:" or
"复盘建议:先落地两个最小动作:" while keeping the two bullet items unchanged; locate the
paragraph by the heading text "当前建议" in docs/x509-parser-to-rasn-plan.md and
adjust the wording accordingly.
crates/rginx-http/src/pki/crl.rs (1)

9-12: 错误信息与函数职责略有不一致。

错误消息提到 "as PEM or DER CRL",但此函数 validate_der_certificate_revocation_list 仅处理 DER 格式。调用方 validate_der_crl 在 PEM 解析失败后才调用此函数,因此 "PEM or" 部分可能会误导用户。

🔧 建议修正错误信息
     let (_crl, remaining) = rasn::der::decode_with_remainder::<CertificateList>(der).map_err(
         |error| {
         Error::Server(format!(
-            "failed to parse certificate revocation list `{}` as PEM or DER CRL: {error}",
+            "failed to parse certificate revocation list `{}` as DER CRL: {error}",
             path.display()
         ))
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/pki/crl.rs` around lines 9 - 12, The error message in
validate_der_certificate_revocation_list is misleading because it mentions "as
PEM or DER CRL" while the function only handles DER; update the Error::Server
message in validate_der_certificate_revocation_list to state that parsing failed
as a DER CRL (remove "PEM or"), keep including the path.display() and the
{error} details so callers get the file path and underlying error, and ensure
the change is made inside the validate_der_certificate_revocation_list function
referenced in crl.rs.
crates/rginx-http/src/tls/ocsp/mod.rs (1)

239-241: AIA 扩展提取逻辑在找到首个有效扩展后立即返回。

当前实现在找到第一个包含 OCSP URL 的 AIA 扩展后就返回。如果证书包含多个 AIA 扩展(虽然不常见),后续扩展将被忽略。这可能是预期行为,但建议确认是否符合需求。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/tls/ocsp/mod.rs` around lines 239 - 241, 当前代码在遍历 AIA
扩展时遇到第一个包含 OCSP URL 的扩展就通过 if !urls.is_empty() { return urls; } 立即返回,导致证书中后续的
AIA 扩展被忽略。请修改遍历逻辑(查找产生 urls 的循环处,涉及变量 urls 和早期 return 的分支)以继续扫描所有 AIA 扩展并将所有发现的
OCSP URL 收集到 urls 中(可选去重),然后在循环结束后统一返回;如果确实只想要第一个有效 URL,添加明确注释或开关以表明该行为。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/rginx-http/src/pki/certificate.rs`:
- Around line 137-140: Parsing failures for cert entries (decode_certificate
returning None) are causing later adjacency checks to use wrong indices because
chain_entries is compressed; update the logic so that when decode_certificate
fails for a chain element (the block that currently does let Some(cert) =
decode_certificate(...) else { chain_diagnostics.push(...); continue; }) you
also ensure no adjacency/neighbor checks run for that position — either by
preserving the original index mapping (store original_index alongside compressed
entries) or by gating all adjacency validation paths with a check that the
parsed cert (cert variable) exists/was successfully decoded before any neighbor
comparisons; apply the same fix for the other affected region (around the code
handling entries 212-242) and ensure chain_diagnostics uses the correct original
index in messages.
- Around line 145-147: The current days calculation using (not_after - now_secs)
/ 86_400 truncates toward zero and maps negative seconds like -1..-86399 to 0,
so expired certs may appear as 0 days remaining; change the computation in
expires_in_days (where
time_to_unix_secs(cert.tbs_certificate.validity.not_after) is mapped) to perform
floor division for negatives (e.g., compute seconds = not_after - now_secs and
then convert to days with proper rounding: if seconds >= 0 { seconds / 86_400 }
else { -(((-seconds) + 86_400 - 1) / 86_400) } or use a floating-point division
with .floor()) so that values like -1 second become -1 day; apply the same fix
to the analogous calculation in the 153-158 region.
- Around line 229-233: The current check uses chain_entries[index + 2..] to
count CA certs upstream of the current entry, which is reversed; change it to
count downstream CA certificates closer to the leaf by iterating over
chain_entries[..index] (i.e., entries before the current index) when computing
remaining_ca_certs used with path_len_constraint; update the slice used in the
iterator that computes remaining_ca_certs (the code around chain_entries, index,
path_len_constraint, and remaining_ca_certs) so the filter still checks
entry.is_ca == Some(true) but over the preceding entries instead of the
following ones.

---

Nitpick comments:
In `@crates/rginx-http/src/pki/crl.rs`:
- Around line 9-12: The error message in
validate_der_certificate_revocation_list is misleading because it mentions "as
PEM or DER CRL" while the function only handles DER; update the Error::Server
message in validate_der_certificate_revocation_list to state that parsing failed
as a DER CRL (remove "PEM or"), keep including the path.display() and the
{error} details so callers get the file path and underlying error, and ensure
the change is made inside the validate_der_certificate_revocation_list function
referenced in crl.rs.

In `@crates/rginx-http/src/tls/ocsp/mod.rs`:
- Around line 239-241: 当前代码在遍历 AIA 扩展时遇到第一个包含 OCSP URL 的扩展就通过 if
!urls.is_empty() { return urls; } 立即返回,导致证书中后续的 AIA 扩展被忽略。请修改遍历逻辑(查找产生 urls
的循环处,涉及变量 urls 和早期 return 的分支)以继续扫描所有 AIA 扩展并将所有发现的 OCSP URL 收集到 urls
中(可选去重),然后在循环结束后统一返回;如果确实只想要第一个有效 URL,添加明确注释或开关以表明该行为。

In `@docs/x509-parser-to-rasn-plan.md`:
- Around line 561-567: Update the "当前建议" section heading and its opening
sentence to remove present-tense conditional phrasing; rename the heading to
"复盘建议/可复用方法" (or similar) and change "如果现在开始执行,建议先落地两个最小动作:" to a retrospective
phrasing such as "建议先落地两个最小动作:" or "复盘建议:先落地两个最小动作:" while keeping the two
bullet items unchanged; locate the paragraph by the heading text "当前建议" in
docs/x509-parser-to-rasn-plan.md and adjust the wording accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 3250d722-d411-4b28-b544-43b71653dd55

📥 Commits

Reviewing files that changed from the base of the PR and between b98503b and c025b6e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • Cargo.toml
  • README.md
  • crates/rginx-app/Cargo.toml
  • crates/rginx-app/tests/ocsp.rs
  • crates/rginx-http/Cargo.toml
  • crates/rginx-http/src/lib.rs
  • crates/rginx-http/src/pki/certificate.rs
  • crates/rginx-http/src/pki/crl.rs
  • crates/rginx-http/src/pki/mod.rs
  • crates/rginx-http/src/server/connection.rs
  • crates/rginx-http/src/server/tests.rs
  • crates/rginx-http/src/state/mod.rs
  • crates/rginx-http/src/state/tls_runtime/certificates.rs
  • crates/rginx-http/src/state/tls_runtime/mod.rs
  • crates/rginx-http/src/tls/certificates.rs
  • crates/rginx-http/src/tls/ocsp/mod.rs
  • docs/x509-parser-stage0-baseline.md
  • docs/x509-parser-to-rasn-plan.md
💤 Files with no reviewable changes (1)
  • crates/rginx-http/src/state/mod.rs

Comment thread crates/rginx-http/src/pki/certificate.rs
Comment thread crates/rginx-http/src/pki/certificate.rs
Comment thread crates/rginx-http/src/pki/certificate.rs Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (3)
crates/rginx-http/src/pki/certificate.rs (3)

227-233: ⚠️ Potential issue | 🟠 Major

pathLenConstraint 统计方向反了,应统计“下游(靠近 leaf) CA 数”

Line 229 当前统计 index + 2..(上游/更靠近 root)会导致误报或漏报。对 cert[index+1] 应统计其下游 CA(..index+1)。

建议修复
-        if let Some(path_len_constraint) = chain_entries[index + 1].path_len_constraint {
-            let remaining_ca_certs =
-                chain_entries[index + 2..].iter().filter(|entry| entry.is_ca == Some(true)).count()
-                    as u32;
-            if remaining_ca_certs > path_len_constraint {
+        if let Some(path_len_constraint) = chain_entries[index + 1].path_len_constraint {
+            let descendant_ca_certs = chain_entries[..index + 1]
+                .iter()
+                .filter(|entry| entry.is_ca == Some(true))
+                .count() as u32;
+            if descendant_ca_certs > path_len_constraint {
                 chain_diagnostics.push(format!(
-                    "cert[{}] path_len_constraint_exceeded remaining_ca_certs={} path_len_constraint={}",
+                    "cert[{}] path_len_constraint_exceeded descendant_ca_certs={} path_len_constraint={}",
                     index + 1,
-                    remaining_ca_certs,
+                    descendant_ca_certs,
                     path_len_constraint
                 ));
             }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/pki/certificate.rs` around lines 227 - 233, The
path_len_constraint check is counting the wrong direction: change the CA count
slice for cert at chain_entries[index + 1] from chain_entries[index + 2..]
(upstream/root side) to the downstream/leaf side chain_entries[..index + 1],
then recompute remaining_ca_certs as the number of entries with is_ca ==
Some(true) in that slice and compare it to path_len_constraint before pushing to
chain_diagnostics; update the reference to chain_entries, path_len_constraint,
remaining_ca_certs, index and chain_diagnostics accordingly.

144-145: ⚠️ Potential issue | 🟠 Major

expires_in_days 的负值取整方向错误,会漏报“已过期不足1天”

Line 145 使用 / 86_400 会向 0 截断,-1..-86399 秒会变成 0,从而不触发 expired。应使用欧几里得除法。

建议修复
-        let expires_in_days = time_to_unix_secs(cert.tbs_certificate.validity.not_after)
-            .map(|not_after| (not_after - now_secs) / 86_400);
+        let expires_in_days = time_to_unix_secs(cert.tbs_certificate.validity.not_after)
+            .map(|not_after| (not_after - now_secs).div_euclid(86_400));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/pki/certificate.rs` around lines 144 - 145,
expires_in_days 目前用 (not_after - now_secs) / 86_400 会对负数向 0 截断,导致 “已过期不足1天” 被误判为
0;在计算 expires_in_days 时把除法改为欧几里得除法(div_euclid)或等价的向下取整处理,例如对差值使用
.div_euclid(86_400)(确保差值是有符号整数类型),也就是修改计算在
time_to_unix_secs(cert.tbs_certificate.validity.not_after).map(...) 中将 `/
86_400` 替换为 `.div_euclid(86_400)`(或等价实现),以正确处理负秒数边界。

136-140: ⚠️ Potential issue | 🟠 Major

解析失败后链索引映射已失真,且可能把中间证书当作 leaf 返回

Line 136-140 发生解析失败后 chain_entries 被压缩,Line 210+ 的邻接校验与 Line 242+ 的链完整性/leaf 选择会基于错误位置运行;若 cert[0] 解析失败,当前实现还可能返回非叶子证书。建议在叶子不可解析时直接返回 None,并在存在不可解析条目时跳过邻接校验。

建议修复(最小改动)
@@
-    for (index, der) in certs.iter().enumerate() {
+    let mut leaf_parsed = false;
+    for (index, der) in certs.iter().enumerate() {
@@
         let Some(cert) = decode_certificate(der.as_ref()) else {
             chain_diagnostics.push(format!("cert[{index}] could_not_be_parsed_as_x509"));
             continue;
         };
+        if index == 0 {
+            leaf_parsed = true;
+        }
@@
-    for index in 0..chain_entries.len().saturating_sub(1) {
-        let issuer = chain_entries[index].issuer.as_deref();
-        let next_subject = chain_entries[index + 1].subject.as_deref();
-        if issuer != next_subject {
-            chain_diagnostics.push(format!(
-                "chain_link_mismatch cert[{index}]_issuer_to_cert[{}]_subject",
-                index + 1
-            ));
-        }
-        if let (Some(aki), Some(ski)) = (
-            chain_entries[index].authority_key_identifier.as_deref(),
-            chain_entries[index + 1].subject_key_identifier.as_deref(),
-        ) && aki != ski
-        {
-            chain_diagnostics
-                .push(format!("chain_aki_ski_mismatch cert[{index}]_to_cert[{}]", index + 1));
-        }
-        ...
-    }
+    if chain_entries.len() == certs.len() {
+        for index in 0..chain_entries.len().saturating_sub(1) {
+            let issuer = chain_entries[index].issuer.as_deref();
+            let next_subject = chain_entries[index + 1].subject.as_deref();
+            if issuer != next_subject {
+                chain_diagnostics.push(format!(
+                    "chain_link_mismatch cert[{index}]_issuer_to_cert[{}]_subject",
+                    index + 1
+                ));
+            }
+            if let (Some(aki), Some(ski)) = (
+                chain_entries[index].authority_key_identifier.as_deref(),
+                chain_entries[index + 1].subject_key_identifier.as_deref(),
+            ) && aki != ski
+            {
+                chain_diagnostics.push(format!(
+                    "chain_aki_ski_mismatch cert[{index}]_to_cert[{}]",
+                    index + 1
+                ));
+            }
+            // 其余链路邻接检查保持不变
+        }
+    } else {
+        chain_diagnostics.push(
+            "chain_link_checks_skipped_due_to_unparseable_certificate".to_string(),
+        );
+    }
@@
-    let leaf = chain_entries.into_iter().next()?;
+    if !leaf_parsed {
+        return None;
+    }
+    let leaf = chain_entries.into_iter().next()?;

Also applies to: 210-226, 242-255

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/rginx-http/src/pki/certificate.rs` around lines 136 - 140, The parsing
loop currently compresses chain_entries on decode_certificate failures which
corrupts index mapping and can lead to returning a non-leaf as the leaf; change
the logic so that if decode_certificate fails for cert[0] (the leaf) the
function returns None immediately, and for other entries push the diagnostic but
set a flag (e.g., skip_adjacency_checks) instead of removing entries; then guard
the adjacency verification and chain integrity/leaf-selection code (the blocks
that reference chain_entries later) to skip adjacency checks when that flag is
set so index mapping and leaf selection remain consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@crates/rginx-http/src/pki/certificate.rs`:
- Around line 227-233: The path_len_constraint check is counting the wrong
direction: change the CA count slice for cert at chain_entries[index + 1] from
chain_entries[index + 2..] (upstream/root side) to the downstream/leaf side
chain_entries[..index + 1], then recompute remaining_ca_certs as the number of
entries with is_ca == Some(true) in that slice and compare it to
path_len_constraint before pushing to chain_diagnostics; update the reference to
chain_entries, path_len_constraint, remaining_ca_certs, index and
chain_diagnostics accordingly.
- Around line 144-145: expires_in_days 目前用 (not_after - now_secs) / 86_400 会对负数向
0 截断,导致 “已过期不足1天” 被误判为 0;在计算 expires_in_days
时把除法改为欧几里得除法(div_euclid)或等价的向下取整处理,例如对差值使用
.div_euclid(86_400)(确保差值是有符号整数类型),也就是修改计算在
time_to_unix_secs(cert.tbs_certificate.validity.not_after).map(...) 中将 `/
86_400` 替换为 `.div_euclid(86_400)`(或等价实现),以正确处理负秒数边界。
- Around line 136-140: The parsing loop currently compresses chain_entries on
decode_certificate failures which corrupts index mapping and can lead to
returning a non-leaf as the leaf; change the logic so that if decode_certificate
fails for cert[0] (the leaf) the function returns None immediately, and for
other entries push the diagnostic but set a flag (e.g., skip_adjacency_checks)
instead of removing entries; then guard the adjacency verification and chain
integrity/leaf-selection code (the blocks that reference chain_entries later) to
skip adjacency checks when that flag is set so index mapping and leaf selection
remain consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 29c3df85-b51e-47f7-b3f5-010c0c30dbaa

📥 Commits

Reviewing files that changed from the base of the PR and between c025b6e and b2ea6cd.

📒 Files selected for processing (6)
  • crates/rginx-app/tests/ocsp.rs
  • crates/rginx-http/src/lib.rs
  • crates/rginx-http/src/pki/certificate.rs
  • crates/rginx-http/src/pki/crl.rs
  • crates/rginx-http/src/server/tests.rs
  • crates/rginx-http/src/tls/ocsp/mod.rs
✅ Files skipped from review due to trivial changes (2)
  • crates/rginx-http/src/lib.rs
  • crates/rginx-app/tests/ocsp.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/rginx-http/src/server/tests.rs
  • crates/rginx-http/src/pki/crl.rs
  • crates/rginx-http/src/tls/ocsp/mod.rs

@vansour vansour merged commit ac3ac0c into main Apr 11, 2026
6 checks passed
@vansour vansour deleted the feat/rasn-pki-rc8-prep branch April 11, 2026 05:33
@coderabbitai coderabbitai Bot mentioned this pull request Apr 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants