Skip to content

rfc9980: close small compliance gaps (G1+G3+G4) - #2433

Open
ronaldtse wants to merge 1 commit into
mainfrom
rfc9980-compliance-polish
Open

rfc9980: close small compliance gaps (G1+G3+G4)#2433
ronaldtse wants to merge 1 commit into
mainfrom
rfc9980-compliance-polish

Conversation

@ronaldtse

Copy link
Copy Markdown
Contributor

Summary

First of three batched PRs addressing the audit findings in TODO.rnp-roadmap/26-rfc9980-and-thunderbird-integration.md. Closes the small RFC 9980 compliance gaps on top of PR #2355. The other two batched PRs (revocation service docs, backup/recovery infrastructure) will follow.

What's in this PR

Three small changes, one coherent story: "make rnp's PQC implementation fully RFC 9980-compliant on the keygen and receiver sides."

G1 — Preferred AEAD Ciphersuites for PQ keys (RFC 9980 §7.1)
UserPrefs::check_defaults() now populates aead_prefs from symm_algs not only for v6 keys (the prior behaviour) but also for any key whose public-key algorithm is PQ. Ensures v4 ML-KEM-768+X25519 keys also advertise AES-256+OCB, satisfying the RFC's SHOULD for all PQ certs rather than just v6.

G3 — Reject weak-hash subkey binding signatures over PQ subkeys (RFC 9980 §7.2)
Key::validate_binding() now rejects MD5, SHA-1, and RIPEMD-160 in subkey binding signatures (type 0x18) when the subkey's algorithm is PQ. The RFC says a receiving implementation MUST treat such signatures as invalid; rnp now does. Returns RNP_ERROR_SIG_WEAK_HASH.

G4 — Canonical algorithm name strings (RFC 9980 §2.1)
rnp_keygen_alg_map in src/lib/keygen.cpp used hardcoded strings with underscore separators ("ML-KEM-768_X25519") and two outdated names that don't match RFC 9980 at all ("Kyber-X448" for alg ID 36, "Dilithium-ED448" for alg ID 31). Now uses the RNP_ALGNAME_* macros from include/rnp/rnp.h, which already use the canonical RFC 9980 + form. Makes both internal maps consistent and matches the wire-spec naming.

Why

Audit against the published RFC 9980 (June 2026) showed rnp's PQC implementation is essentially complete (via #2355), but three small receiver/keygen-side items were not yet enforced. This PR closes them.

What's NOT in this PR (deferred)

G2 — Implicit AES-256 when encrypting to PQ recipients (RFC 9980 §7.1)
RFC 9980 §7.1 also specifies that a receiver should implicitly append AES-256 to a PQ recipient's preferences if it's missing. rnp does not have a recipient-pref-intersection code path today — callers choose the cipher via rnp_op_encrypt_set_cipher(), so there's nothing to implicitly augment. This item is moot until rnp grows recipient-driven cipher selection.

Test plan

  • Build clean on default config (no warnings)
  • test_ffi_security_profile and test_ffi_security_rule_enumeration still pass
  • CI green on PQC-enabled legs (existing test_ffi_pqc_gen_enc_sign will exercise G1; existing import tests will exercise G4)
  • A dedicated test for G3 (crafting a PQ subkey binding with weak hash) is a follow-up — it requires generating a key with a forced-weak hash, which is non-trivial without bypassing the keygen defaults that G1 just made stricter

Related

  • Audit doc: TODO.rnp-roadmap/26-rfc9980-and-thunderbird-integration.md
  • Source PR for PQC implementation: Update PQC Draft to Version 12 #2355
  • Follow-up batched PRs: revocation service docs (R1), backup/recovery infrastructure (B1+B2+B3+B4)

…ak-hash binding)

Audit-driven polish on top of PR #2355 to close the remaining RFC 9980
compliance gaps. Three changes, one story: make rnp's PQC implementation
fully RFC 9980-conformant on the receiver and keygen sides.

G1 — Preferred AEAD Ciphersuites for PQ keys (RFC 9980 §7.1)
  UserPrefs::check_defaults() now populates aead_prefs from symm_algs
  not only for v6 keys (the prior behaviour) but also for any key whose
  public-key algorithm is PQ. This ensures v4 ML-KEM-768+X25519 keys
  also advertise AES-256+OCB, satisfying the RFC's SHOULD for all PQ
  certs rather than just v6.

G3 — Reject weak-hash subkey binding signatures over PQ subkeys (RFC 9980 §7.2)
  Key::validate_binding() now rejects MD5, SHA-1, and RIPEMD-160 in
  subkey binding signatures (type 0x18) when the subkey's algorithm
  is one of the PQ(/T) algorithms. The RFC says a receiving
  implementation MUST treat such signatures as invalid; rnp now does.

G4 — Canonical algorithm name strings (RFC 9980 §2.1)
  rnp_keygen_alg_map in src/lib/keygen.cpp used hardcoded strings
  with underscore separators ("ML-KEM-768_X25519") and two outdated
  names that don't match RFC 9980 at all ("Kyber-X448" for alg ID 36
  and "Dilithium-ED448" for alg ID 31). Now uses the RNP_ALGNAME_*
  macros from include/rnp/rnp.h, which already use the canonical
  RFC 9980 "+" form. This makes both internal maps consistent and
  matches the wire-spec naming.

G2 (deferred): RFC 9980 §7.1 also specifies that a receiver should
implicitly append AES-256 to a PQ recipient's preferences if it's
missing. rnp does not have a recipient-pref-intersection code path
today (callers choose the cipher via rnp_op_encrypt_set_cipher), so
there's nothing to add AES-256 to. This item is moot until rnp grows
recipient-driven cipher selection.
@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.37%. Comparing base (975b67c) to head (33ea313).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2433      +/-   ##
==========================================
- Coverage   85.37%   85.37%   -0.01%     
==========================================
  Files         126      126              
  Lines       22789    22787       -2     
==========================================
- Hits        19457    19455       -2     
  Misses       3332     3332              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ronaldtse
ronaldtse requested review from antonsviridenko and ni4 July 31, 2026 16:19
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.

1 participant