feat(proto,pki,cli): in-band CRL push (closes last v2 limitation)

Server now pushes its signed CRL to each connecting client right after the
handshake; the client verifies the signature against the CA and applies the
revocation list to its verifier (and caches it on disk for restarts).
Removes the v1 "CRL distributed out-of-band" honest limitation.

Wire (multiplexed over existing PacketConnection, no trait change):
control envelope = MAGIC[4]=[0xAA,0xAA,0xC0,0x01] || kind(u8) || u32_be(len)
  || payload. IPv4/IPv6 start with 0x4X/0x6X, so 0xAA cannot collide; an old
peer just drops it as a junk packet in the TUN — back-compat preserved.

- aura-proto: ControlKind { CrlPush, CrlAck, Unknown }, encode/decode_control_
  envelope, CONTROL_ENVELOPE_MAGIC; 7 frame tests.
- aura-pki: CrlStore::{encode_signed, save_signed, decode_signed_verified,
  load_signed_verified} — ECDSA-P256/SHA-256 from the CA private key against
  a textual "CRL-Aura-v1" body + --SIGNATURE--; 7 signing tests. ring 0.17
  added crate-local (already in lockfile via rustls-webpki).
- aura-cli: crl_push module — server pushes via conn.send_packet on accept;
  client wraps the Arc<dyn PacketConnection> in AcceptPushedCrlConn which
  sniffs the magic in recv_packet, verifies the signature, updates the
  AuraCertVerifier, caches to disk. PkiSection gets ca_key, crl_push (default
  true), accept_pushed_crl (default true).
- 5 in_band_crl integration tests via mock PacketConnection.

Workspace: 235 tests passed (+28), clippy -D warnings clean, fmt clean. v2
COMPLETE — all 9 honest v1 limitations resolved (except sing-box, per user).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
xah30
2026-05-27 12:35:16 +03:00
parent 8f0cf1f017
commit 35d94dee33
14 changed files with 1453 additions and 4 deletions
+29
View File
@@ -328,6 +328,35 @@ pub struct PkiSection {
pub cert: String,
/// Path to this peer's PKCS#8 private key PEM.
pub key: String,
/// Optional CRL file path.
///
/// On the **server** side this is the CRL the operator maintains via `aura pki revoke` and
/// (when [`PkiSection::crl_push`] is true) is signed and pushed to every freshly handshaked
/// client. On the **client** side this is the on-disk location where pushed CRLs are cached
/// so revocations survive a restart even without a fresh server push.
///
/// Optional — when omitted the v1 behaviour applies (server: nobody is revoked at the
/// post-handshake check; client: pushed CRLs are applied to the live verifier only).
#[serde(default)]
pub crl: Option<String>,
/// Path to the CA **private** key, used by the server to sign the CRL before pushing it. Only
/// read on the server when [`PkiSection::crl_push`] is true. Optional — when omitted and
/// `crl_push` is true the server logs a warning and does not push (the v1 behaviour).
#[serde(default)]
pub ca_key: Option<String>,
/// Server-side toggle: push the CRL to every authenticated client right after the handshake.
/// Default `true` in v2.
#[serde(default = "default_true")]
pub crl_push: bool,
/// Client-side toggle: accept CRL pushes from the server and apply them to the live verifier.
/// Default `true` in v2.
#[serde(default = "default_true")]
pub accept_pushed_crl: bool,
}
/// Default helper for serde: `true`.
fn default_true() -> bool {
true
}
/// `[transport]` section shared by both config files: the set/order of transports and their ports.