NodeCert
NodeCert: a cluster node's certificate (distributed-deploys build step 11a).
A certificate names one node, the protocol roles it may play and the raw primitives it may use, and is signed (ed25519) by the cluster's OPERATOR key. Nodes present certificates in the cert-mode handshake (NetKernel.handshake_auth); each side verifies the other's against the operator public key and the clock, then proves it holds the key the certificate names. See specs/lang/clustering.md, "Node certificates".
Names are SPIFFE-style URIs, so a service mesh can carry the same identities later (SPIFFE itself is not implemented): node spiffe://<trust-domain>/pool/<pool>/node/<name> issuer spiffe://<trust-domain>/operator/<first 16 hex digits of the operator key>
Roles are "Proto.Role:offer" / "Proto.Role:initiate"; the one flag so far is "raw_send". Step 11b checks them: roles at session formation (SessionAP.authorize, from SessionNode's access points and direct runner), raw_send on every raw send and registry lookup (ClusterNode, NodeSend, NodeCall). See specs/lang/clustering.md, "Authorization".
Wire form. The body is the canonical MessagePack array ["march-node-cert-v1", node, [role...], [flag...], not_after, issuer, pubkey_hex, serial] (Msgpack.encode's smallest-form encoding; forge's cluster cert writes the same bytes), and a signed certificate is [Bin(body), Bin(signature)]; its text form (MARCH_NODE_CERT, forge cluster cert's .cert file) is that, base64. The signature covers the body bytes exactly as sent, so verification never re-encodes. not_after is unix SECONDS, inclusive.
A revocation is signed by the same operator key: body ["march-revocation-v1", node, serial, issued_at] revoking one certificate (serial != "") or every certificate of a node (serial == ""). Revocations are gossiped between nodes (ClusterNode).
Types
Functions
The canonical MessagePack body of [c] (what the operator signs).
Has [c] expired at [now] (unix seconds)?
Parse wire bytes (does NOT verify: see verify).
Does [c] carry [flag] (e.g. \
Does [c] let its node play role [role] (\
Is [c] revoked by any of [rs]?
When [c] was issued (unix ms), if its serial says (ordered_serial); None for a serial with no order.
The issuer URI for an operator public key (hex): its first 16 hex digits.
A key (or signature) from its hex text, checking its length in bytes.
A fresh ed25519 secret key (64 bytes: seed || public key).
The secret key a 32-byte [seed] determines (RFC 8032); empty Bytes for a wrong length.
The node name a certificate's URI ends in (the segment after the last "/node/"), or "" when the URI has no node segment. The handshake requires it to equal the name the peer announces.
The SPIFFE-style URI of node [name] in [pool] under [trust_domain].
Why [next] may not replace [held] (supersedes), if it may not.
A serial carrying issue time [issued_ms] (unix ms): \
The 32-byte public key inside a 64-byte secret key.
A short identity for a revocation: the first 16 hex digits of the sha256 of its canonical body. Two copies of one revocation (from a release, from a peer's gossip, from MARCH_CLUSTER_REVOCATIONS) have the same id, so a node's report of the revocations it knows can be matched against a release's (Control, step 12b).
The text form of a signed revocation (base64): what forge cluster revoke prints.
Does [r] revoke [c]: the same serial, or (serial \
Sign [c] with the operator secret key [operator_sk].
Sign a revocation with the operator secret key.
May [next] replace [held], by issue order? Refused when [held] carries an issue time and [next] was issued before it, or carries none (a certificate from before ordered serials cannot replace one after). When [held] has no issue time there is no order to keep and the answer is yes (the release floor guards that case, Control). The same certificate again is yes.
The signed certificate's wire bytes: [Bin(body), Bin(signature)].
The text form (base64 of to_bytes): MARCH_NODE_CERT and forge's .cert files.
Verify a signed certificate against [operator_pubkey] (32 bytes) at [now] (unix seconds): the signature must cover the body, and [now] must not be past not_after. Returns the certificate, or why it is refused.
Verify a signed revocation against the operator key (a member cannot revoke another).