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:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user