barrel_p2p_dist_auth (barrel_p2p v0.1.0)
View SourceSummary
Functions
Cache the SHA-256 of the effective listener TLS certificate, for use as the handshake channel binding. Called once at listen time, after the quic.dist config is projected, so the hash matches exactly the cert quic_dist serves. Reads cert_file from the merged config (honours -barrel_p2p_dist_cert_dir and a user-supplied cert), not the default path. Best-effort: logs and continues on failure (the auth path then fails closed when it cannot resolve the binding).
Build a fresh challenge. The wall-clock timestamp is what the peer signs and what is compared cross-host. The monotonic start lets the responder measure the handshake duration without an NTP-induced spurious failure.
Ensure a node keypair exists, generating one if needed.
Generate a fresh Ed25519 keypair.
Read the node's Ed25519 private key from disk.
Read the node's Ed25519 public key from disk.
Initialize the authentication subsystem.
Check if a node may bypass the Ed25519 handshake on the strength of the Erlang dist cookie alone (c-nodes, legacy tools). Accepts a node atom or a (peer-supplied) name binary. The binary form is matched without atomising, so the cookie-only check that runs before Ed25519 verification cannot mint atoms.
Load a keypair from disk. Verifies that the public key on disk is the one derived from the private key: a crash between the two file renames in save_keypair/3 could otherwise leave a mismatched pair, and load would silently return inconsistent material.
Save a keypair to disk atomically. Each file goes through the barrel_p2p_file:write_secure/2 chmod-before-write+rename helper, so neither key is ever world-readable mid-write. Two separate renames are not collectively atomic, but load_keypair/1 detects the mismatched-pair window and refuses to load.
The server-side channel binding: SHA-256 of the listener cert. Returns the cached value, recomputing from the effective config if the cache is cold (e.g. the auth path runs before listen cached it).
Sign a challenge built locally. The message format Nonce | Timestamp | OwnPubKey | Binding binds the signature to the signer's own identity and to the QUIC TLS channel: Binding is the SHA-256 of the server's TLS certificate (H1). A relayed signature computed over a different channel's cert no longer verifies.
Reject a peer-supplied wall timestamp that is too far from local wall time. Defense-in-depth against an attacker replaying an old peer CHALLENGE: the nonce alone protects against replay within a single signing session, this widens that to gross clock skew.
Verify a peer's response. Rebuilds the signed message as Nonce | WallTs | ResponderPubKey and checks the signature. The handshake-elapsed window is measured against the monotonic clock captured by create_challenge/0, so an NTP step during the handshake cannot spuriously fail (or pass) the duration check.
Functions
-spec cache_server_cert_binding() -> ok.
Cache the SHA-256 of the effective listener TLS certificate, for use as the handshake channel binding. Called once at listen time, after the quic.dist config is projected, so the hash matches exactly the cert quic_dist serves. Reads cert_file from the merged config (honours -barrel_p2p_dist_cert_dir and a user-supplied cert), not the default path. Best-effort: logs and continues on failure (the auth path then fails closed when it cannot resolve the binding).
Build a fresh challenge. The wall-clock timestamp is what the peer signs and what is compared cross-host. The monotonic start lets the responder measure the handshake duration without an NTP-induced spurious failure.
-spec ensure_keypair() -> ok | {error, term()}.
Ensure a node keypair exists, generating one if needed.
Generate a fresh Ed25519 keypair.
Read the node's Ed25519 private key from disk.
Read the node's Ed25519 public key from disk.
-spec init() -> ok | {error, term()}.
Initialize the authentication subsystem.
Check if a node may bypass the Ed25519 handshake on the strength of the Erlang dist cookie alone (c-nodes, legacy tools). Accepts a node atom or a (peer-supplied) name binary. The binary form is matched without atomising, so the cookie-only check that runs before Ed25519 verification cannot mint atoms.
Load a keypair from disk. Verifies that the public key on disk is the one derived from the private key: a crash between the two file renames in save_keypair/3 could otherwise leave a mismatched pair, and load would silently return inconsistent material.
Save a keypair to disk atomically. Each file goes through the barrel_p2p_file:write_secure/2 chmod-before-write+rename helper, so neither key is ever world-readable mid-write. Two separate renames are not collectively atomic, but load_keypair/1 detects the mismatched-pair window and refuses to load.
The server-side channel binding: SHA-256 of the listener cert. Returns the cached value, recomputing from the effective config if the cache is cold (e.g. the auth path runs before listen cached it).
Sign a challenge built locally. The message format Nonce | Timestamp | OwnPubKey | Binding binds the signature to the signer's own identity and to the QUIC TLS channel: Binding is the SHA-256 of the server's TLS certificate (H1). A relayed signature computed over a different channel's cert no longer verifies.
-spec validate_peer_ts(integer()) -> ok | {error, peer_ts_skew}.
Reject a peer-supplied wall timestamp that is too far from local wall time. Defense-in-depth against an attacker replaying an old peer CHALLENGE: the nonce alone protects against replay within a single signing session, this widens that to gross clock skew.
Verify a peer's response. Rebuilds the signed message as Nonce | WallTs | ResponderPubKey and checks the signature. The handshake-elapsed window is measured against the monotonic clock captured by create_challenge/0, so an NTP step during the handshake cannot spuriously fail (or pass) the duration check.