pub struct SharedSecurityGate { /* private fields */ }Expand description
Thread-safe security gate. Clone gives a second reference to the same plugin instance — all clones operate on the same key store.
Implementations§
Sourcepub fn new(
domain_id: u32,
governance: Governance,
crypto: Box<dyn CryptographicPlugin>,
) -> Self
pub fn new( domain_id: u32, governance: Governance, crypto: Box<dyn CryptographicPlugin>, ) -> Self
Constructor. The plugin is owned by the gate (Box).
Sourcepub fn domain_id(&self) -> Result<u32, SecurityGateError>
pub fn domain_id(&self) -> Result<u32, SecurityGateError>
Returns the domain id the gate runs for.
Sourcepub fn message_protection(&self) -> Result<ProtectionKind, SecurityGateError>
pub fn message_protection(&self) -> Result<ProtectionKind, SecurityGateError>
ProtectionKind for the message level — derived from the first
matching <domain_rule>.
Sourcepub fn data_protection(&self) -> Result<ProtectionLevel, SecurityGateError>
pub fn data_protection(&self) -> Result<ProtectionLevel, SecurityGateError>
ProtectionLevel for user DATA — derived from the
data_protection_kind of the domain’s first <topic_rule>
(FU2 S3). Used by the user outbound path as a fallback when
the matched reader has not announced an explicit security_info level via
SEDP — this way ZeroDDS↔ZeroDDS encrypts user data
according to its own governance, while SPDP/SEDP metatraffic
bootstraps plaintext via rtps_protection_kind=NONE.
§Errors
Mutex poison.
Sourcepub fn metadata_protection(&self) -> Result<ProtectionLevel, SecurityGateError>
pub fn metadata_protection(&self) -> Result<ProtectionLevel, SecurityGateError>
ProtectionLevel for submessage metadata — from the
metadata_protection_kind of the domain’s first <topic_rule>.
Controls (together with Self::data_protection) the
endpoint_security_attributes that ZeroDDS announces via SEDP —
cross-vendor the mask must match cyclone/OpenDDS byte-exactly
(otherwise “security_attributes mismatch” → no endpoint match).
§Errors
Mutex poison.
Sourcepub fn discovery_protection(&self) -> Result<ProtectionLevel, SecurityGateError>
pub fn discovery_protection(&self) -> Result<ProtectionLevel, SecurityGateError>
ProtectionLevel for protected discovery — from the DOMAIN-wide
discovery_protection_kind (DDS-Security §8.4.2.4 is_discovery_ protected). != None ⟹ secured endpoints are announced via the secure SEDP
(DCPSPublicationsSecure/DCPSSubscriptionsSecure) instead of plaintext SEDP;
the DATA/HEARTBEAT/GAP of the secure-SEDP writers are protected with the
participant data key via encode_datawriter_submessage.
§Errors
Mutex poison.
Sourcepub fn topic_discovery_protected(&self) -> Result<bool, SecurityGateError>
pub fn topic_discovery_protected(&self) -> Result<bool, SecurityGateError>
true if the domain’s first <topic_rule> sets
enable_discovery_protection. Controls the endpoint bit
IS_DISCOVERY_PROTECTED of the EndpointSecurityAttributes
(§9.4.2.4) — this is a TOPIC-level flag, NOT the domain-wide
Self::discovery_protection (= discovery_protection_kind, which
only protects the SEDP channel). cyclone derives the endpoint mask from
this boolean; ZeroDDS must announce byte-exactly the same,
otherwise “security_attributes mismatch” → no endpoint match.
§Errors
Mutex poison.
Sourcepub fn topic_read_protected(&self) -> Result<bool, SecurityGateError>
pub fn topic_read_protected(&self) -> Result<bool, SecurityGateError>
true if the domain’s first <topic_rule> sets
enable_read_access_control → endpoint bit IS_READ_PROTECTED
(0x01) of the EndpointSecurityAttributes (§9.4.2.4). cyclone sets it for
access-control topics; ZeroDDS must announce byte-exactly the same mask.
§Errors
Mutex poison.
Sourcepub fn topic_write_protected(&self) -> Result<bool, SecurityGateError>
pub fn topic_write_protected(&self) -> Result<bool, SecurityGateError>
true if the domain’s first <topic_rule> sets
enable_write_access_control → endpoint bit IS_WRITE_PROTECTED
(0x02) of the EndpointSecurityAttributes (§9.4.2.4).
§Errors
Mutex poison.
Sourcepub fn rtps_protection(&self) -> Result<ProtectionLevel, SecurityGateError>
pub fn rtps_protection(&self) -> Result<ProtectionLevel, SecurityGateError>
ProtectionLevel for the whole RTPS message — DOMAIN-wide
rtps_protection_kind (§8.4.2.4 is_rtps_protected). Flows into the
ParticipantSecurityAttributes mask (§9.4.2.4) that ZeroDDS announces via
SPDP.
§Errors
Mutex poison.
Sourcepub fn liveliness_protection(
&self,
) -> Result<ProtectionLevel, SecurityGateError>
pub fn liveliness_protection( &self, ) -> Result<ProtectionLevel, SecurityGateError>
ProtectionLevel for liveliness (BuiltinParticipantMessageSecure) —
DOMAIN-wide liveliness_protection_kind (§8.4.2.4).
§Errors
Mutex poison.
Sourcepub fn ensure_local(&self) -> Result<CryptoHandle, SecurityGateError>
pub fn ensure_local(&self) -> Result<CryptoHandle, SecurityGateError>
Registers the local participant with the crypto plugin (idempotent).
§Errors
CryptoSetup if the plugin does not accept the identity handle.
Sourcepub fn local_token(&self) -> Result<Vec<u8>, SecurityGateError>
pub fn local_token(&self) -> Result<Vec<u8>, SecurityGateError>
Sourcepub fn register_remote_with_token(
&self,
remote_identity: IdentityHandle,
shared_secret: SharedSecretHandle,
token: &[u8],
) -> Result<CryptoHandle, SecurityGateError>
pub fn register_remote_with_token( &self, remote_identity: IdentityHandle, shared_secret: SharedSecretHandle, token: &[u8], ) -> Result<CryptoHandle, SecurityGateError>
Registers a remote peer and installs its token.
The returned CryptoHandle identifies the slot in
which the remote key is stored — needed again at decode_inbound_message.
§Errors
See SecurityGateError.
Sourcepub fn register_remote_by_guid(
&self,
peer_key: PeerKey,
remote_identity: IdentityHandle,
shared_secret: SharedSecretHandle,
token: &[u8],
) -> Result<CryptoHandle, SecurityGateError>
pub fn register_remote_by_guid( &self, peer_key: PeerKey, remote_identity: IdentityHandle, shared_secret: SharedSecretHandle, token: &[u8], ) -> Result<CryptoHandle, SecurityGateError>
Registers a remote peer with peer-key mapping. After
this call Self::transform_inbound_from can find the peer
by its PeerKey (GuidPrefix).
Idempotent: a repeated call with the same key does not overwrite the
old slot — the caller must explicitly call
Self::forget_remote to be able to rotate.
§Errors
See SecurityGateError.
Sourcepub fn register_remote_by_guid_from_secret(
&self,
peer_key: PeerKey,
remote_identity: IdentityHandle,
shared_secret: SharedSecretHandle,
) -> Result<CryptoHandle, SecurityGateError>
pub fn register_remote_by_guid_from_secret( &self, peer_key: PeerKey, remote_identity: IdentityHandle, shared_secret: SharedSecretHandle, ) -> Result<CryptoHandle, SecurityGateError>
FU2 S1.2: Registers a remote peer only with the Kx key
(from the handshake SharedSecret), WITHOUT a data token. The data
key is installed later via Self::set_remote_data_token_by_guid from
the received ParticipantCryptoToken.
Maps peer_key → slot; idempotent (a repeated call with the
same key returns the existing slot).
§Errors
CryptoSetup if the plugin does not accept the secret.
Sourcepub fn set_remote_data_token_by_guid(
&self,
peer_key: &PeerKey,
token: &[u8],
) -> Result<(), SecurityGateError>
pub fn set_remote_data_token_by_guid( &self, peer_key: &PeerKey, token: &[u8], ) -> Result<(), SecurityGateError>
FU2 S1.2: Installs the data key of a peer already registered via
Self::register_remote_by_guid_from_secret
from its received ParticipantCryptoToken (token exchange).
§Errors
PolicyViolation if the peer is not registered; Crypto
on an invalid token.
Sourcepub fn transform_kx_outbound_for(
&self,
peer_key: &PeerKey,
plaintext: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn transform_kx_outbound_for( &self, peer_key: &PeerKey, plaintext: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
FU2 S1.2: Encrypts a VolatileSecure payload (e.g. a
ParticipantCryptoToken) with the peer’s Kx key
(encode_kx_submessage). The peer must be registered via
Self::register_remote_by_guid_from_secret.
§Errors
PolicyViolation (unknown peer) / Crypto.
Sourcepub fn transform_kx_inbound_from(
&self,
peer_key: &PeerKey,
wire: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn transform_kx_inbound_from( &self, peer_key: &PeerKey, wire: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
FU2 S1.2: Decrypts a Kx-protected VolatileSecure
payload of a peer (decode_kx_submessage).
§Errors
PolicyViolation (unknown peer) / Crypto (tag mismatch).
Sourcepub fn encode_kx_datawriter_for(
&self,
peer_key: &PeerKey,
data_submessage: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn encode_kx_datawriter_for( &self, peer_key: &PeerKey, data_submessage: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Cross-vendor VolatileSecure: protects a DATA submessage as a
cyclone-conform SEC_PREFIX/SEC_BODY/SEC_POSTFIX sequence with the
peer’s Kx key (encode_kx_datawriter_submessage).
§Errors
PolicyViolation (unknown peer) / Crypto.
Sourcepub fn decode_kx_datawriter_from(
&self,
peer_key: &PeerKey,
wire: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn decode_kx_datawriter_from( &self, peer_key: &PeerKey, wire: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Counterpart: decodes a peer’s SEC_PREFIX/SEC_BODY/SEC_POSTFIX sequence
back to the original DATA submessage (decode_kx_datawriter_submessage).
§Errors
PolicyViolation (unknown peer) / Crypto (tag mismatch).
Sourcepub fn encode_data_datawriter_local(
&self,
data_submessage: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn encode_data_datawriter_local( &self, data_submessage: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Cross-vendor user DATA (send): protects a DATA submessage with the
local data key as a cyclone-conform SEC_PREFIX/BODY/POSTFIX sequence
(encode_data_datawriter_submessage). cyclone decodes it with the
(= local) key sent by ZeroDDS via datawriter_crypto_tokens.
§Errors
CryptoSetup (no local slot) / Crypto.
Sourcepub fn register_local_endpoint(
&self,
is_writer: bool,
) -> Result<CryptoHandle, SecurityGateError>
pub fn register_local_endpoint( &self, is_writer: bool, ) -> Result<CryptoHandle, SecurityGateError>
Registers a local endpoint crypto slot with its own key material.
is_writer = DataWriter (else DataReader). Returns the endpoint handle.
§Errors
CryptoSetup (no local participant) / plugin error.
Sourcepub fn create_endpoint_token(
&self,
endpoint: CryptoHandle,
) -> Result<Vec<u8>, SecurityGateError>
pub fn create_endpoint_token( &self, endpoint: CryptoHandle, ) -> Result<Vec<u8>, SecurityGateError>
Serializes the per-endpoint datawriter/datareader_crypto_token
(the key material of the local endpoint slot), to be sent to the matched
remote endpoint via VolatileSecure.
§Errors
Crypto (unknown endpoint handle).
Sourcepub fn endpoint_payload_token(&self, endpoint: CryptoHandle) -> Option<Vec<u8>>
pub fn endpoint_payload_token(&self, endpoint: CryptoHandle) -> Option<Vec<u8>>
Installs a received per-endpoint token. The key material is
indexed via its transformation_key_id (remote_by_key_id), so that
Self::decode_data_by_key_id maps the submessages of this remote endpoint
— independent of the participant key.
§Errors
CryptoSetup (no local slot) / Crypto.
Optional second (payload) token of a DataWriter endpoint for the
cyclone dual-key model (metadata != data, e.g. meta-sign-data). None
= single key (all other profiles).
Sourcepub fn install_remote_endpoint_token(
&self,
token: &[u8],
) -> Result<(), SecurityGateError>
pub fn install_remote_endpoint_token( &self, token: &[u8], ) -> Result<(), SecurityGateError>
Installs a remote endpoint crypto token (volatile key exchange):
passes the received token via set_remote_participant_crypto_tokens to
the crypto plugin (participant handle CryptoHandle(0) = per-endpoint).
Sourcepub fn encode_data_datawriter_by_handle(
&self,
endpoint: CryptoHandle,
data_submessage: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn encode_data_datawriter_by_handle( &self, endpoint: CryptoHandle, data_submessage: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Encodes a DATA submessage with the per-endpoint key (not the
participant). Wire-identical to cyclone encode_datawriter_submessage.
§Errors
Crypto (unknown endpoint handle / encode error).
Sourcepub fn decode_data_datawriter_from(
&self,
peer_key: &PeerKey,
wire: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn decode_data_datawriter_from( &self, peer_key: &PeerKey, wire: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Cross-vendor user DATA (recv): decodes a SEC_* sequence with the sender’s data key (peer slot, filled via token exchange).
§Errors
PolicyViolation (unknown peer) / Crypto (tag mismatch).
Sourcepub fn decode_data_by_key_id(
&self,
wire: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn decode_data_by_key_id( &self, wire: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Cross-vendor (recv) by key_id: decodes a SEC_* submessage without
knowing the endpoint handle — the plugin looks up the remote key material
by the transformation_key_id in the CryptoHeader (§9.5.2.1.1). Needed
for protected discovery, where a peer has its own key per secure builtin
endpoint.
§Errors
Crypto (no key for the key_id / tag mismatch).
Sourcepub fn encode_serialized_payload(
&self,
endpoint: CryptoHandle,
payload: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn encode_serialized_payload( &self, endpoint: CryptoHandle, payload: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
§9.5.3.3.1 data_protection (send): encrypts the SerializedPayload
of ONE endpoint (per-endpoint writer key) as the inner layer. Cross-vendor
needed: with data_protection_kind=ENCRYPT cyclone expects the
encrypted payload (decode_serialized_payload).
§Errors
Crypto (no key / seal error).
Sourcepub fn decode_serialized_payload(
&self,
encoded: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn decode_serialized_payload( &self, encoded: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
§9.5.3.3.1 data_protection (recv): key via transformation_key_id.
§Errors
Crypto (no key for key_id / tag mismatch).
Sourcepub fn authenticated_peer_prefixes(&self) -> Vec<PeerKey> ⓘ
pub fn authenticated_peer_prefixes(&self) -> Vec<PeerKey> ⓘ
Prefixes of all peers with which a data key is installed (participant
slot table). STABLE — unlike completed_peer_prefixes (derived from the
handshake entries GC’d after completion), this entry persists. Source for
re-sending per-endpoint crypto tokens to
late-matching user endpoints.
Sourcepub fn decode_serialized_payload_from(
&self,
peer_key: &PeerKey,
encoded: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn decode_serialized_payload_from( &self, peer_key: &PeerKey, encoded: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
§9.5.3.3.1 data_protection (recv) fallback: key via the sender prefix
(GuidPrefix slot table, token exchange) instead of key_id. zero↔zero indexes
the remote key material via the peer slot, not necessarily via a
unique transformation_key_id — analogous to decode_data_datawriter_from.
§Errors
PolicyViolation (unknown peer) / Crypto (tag mismatch).
Sourcepub fn decode_serialized_payload_kx(
&self,
peer_key: &PeerKey,
encoded: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn decode_serialized_payload_kx( &self, peer_key: &PeerKey, encoded: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
§9.5.3.3.1 data_protection (recv) fallback with the Kx/participant key
of the peer slot (transformation_key_id=0). cyclone encrypts the
data_protection payload with the SharedSecret-derived participant key
instead of the per-endpoint DataWriter key — the same handle indexes the
Kx key material in kx_slots (§10.5.2.1.2 Tab. 73).
§Errors
PolicyViolation (unknown peer) / Crypto (tag mismatch).
Sourcepub fn forget_remote(&self, peer_key: &PeerKey) -> Result<(), SecurityGateError>
pub fn forget_remote(&self, peer_key: &PeerKey) -> Result<(), SecurityGateError>
Removes the peer-key → slot mapping. The slot itself stays in the plugin (key cleanup is the plugin’s job on re-register).
Sourcepub fn slot_for(
&self,
peer_key: &PeerKey,
) -> Result<Option<CryptoHandle>, SecurityGateError>
pub fn slot_for( &self, peer_key: &PeerKey, ) -> Result<Option<CryptoHandle>, SecurityGateError>
Returns the slot for a peer key, if registered.
Sourcepub fn transform_inbound_from(
&self,
peer_key: &PeerKey,
wire: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn transform_inbound_from( &self, peer_key: &PeerKey, wire: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Inbound transform with peer-key lookup. The RTPS header
contains the sender’s GuidPrefix on bytes 8..20 — the
caller must pass this here as peer_key.
If the peer is not registered and the message
looks encrypted: PolicyViolation (unknown sender
sends SRTPS).
§Errors
See SecurityGateError.
Sourcepub fn transform_outbound(
&self,
message: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn transform_outbound( &self, message: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Sourcepub fn transform_outbound_group(
&self,
peer_keys: &[PeerKey],
plaintext: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn transform_outbound_group( &self, peer_keys: &[PeerKey], plaintext: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Group outbound with receiver-specific MACs.
Uses encode_secured_submessage_multi when all receivers
are already registered in the gate via peer keys. Returns a
single wire datagram with a multi-MAC SEC_POSTFIX; the
caller can unicast the same datagram to all matched readers.
The resulting wire is NOT an RTPS message-level wrapper —
it is a submessage sequence (SEC_PREFIX/BODY/POSTFIX). The
caller must put the RTPS header in front itself or use the
transform_outbound_multi_wrapped variant (follows if
needed — for stage 7 the submessage sequence suffices).
§Errors
Cryptopassed through.PolicyViolationif a peer key is not registered.
Sourcepub fn transform_inbound_group(
&self,
sender_peer_key: &PeerKey,
own_peer_key: &PeerKey,
wire: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn transform_inbound_group( &self, sender_peer_key: &PeerKey, own_peer_key: &PeerKey, wire: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Group inbound: decodes a multi-MAC submessage sequence and validates our own MAC.
sender_peer_key is the sender’s GuidPrefix (as registered in
Self::register_remote_by_guid). The receiver
MAC key comes from ensure_local() — at encoding the sender set
exactly this slot handle as a remote_list entry
(via register_remote_by_guid(our_prefix, our_local_token)).
§Errors
PolicyViolationifsender_peer_keyis not registered.Crypto/Wrapperon a tag/MAC mismatch.
Sourcepub fn transform_outbound_for(
&self,
_peer_key: &PeerKey,
message: &[u8],
level: ProtectionLevel,
) -> Result<Vec<u8>, SecurityGateError>
pub fn transform_outbound_for( &self, _peer_key: &PeerKey, message: &[u8], level: ProtectionLevel, ) -> Result<Vec<u8>, SecurityGateError>
Peer-specific outbound transform.
Unlike Self::transform_outbound, this
method ignores the domain rule and instead applies the
caller-given ProtectionLevel. This is the API that
the heterogeneous-security writer tick (per-reader serializer)
calls per matched reader.
ProtectionLevel::None→ plaintext passthroughProtectionLevel::Sign→ RTPS message wrap (HMAC/GCM tag)ProtectionLevel::Encrypt→ RTPS message wrap (AEAD ciphertext)
The sign/encrypt distinction today uses the same encoder
as Self::transform_outbound — the current
AesGcmCryptoPlugin does not differentiate. Receiver-specific MACs
and further extensions retrofit the distinction. The
peer_key is carried along (for future per-peer crypto
handles) but not yet passed to the plugin.
§Errors
See SecurityGateError. Never an error in the None path.
Sourcepub fn allow_unauthenticated(&self) -> Result<bool, SecurityGateError>
pub fn allow_unauthenticated(&self) -> Result<bool, SecurityGateError>
Returns the allow_unauthenticated_participants flag from the
domain rule. Default false if no rule exists for the domain
— conservative-safe stance.
Sourcepub fn classify_inbound(
&self,
bytes: &[u8],
iface: &NetInterface,
) -> InboundVerdict
pub fn classify_inbound( &self, bytes: &[u8], iface: &NetInterface, ) -> InboundVerdict
Classifies an incoming RTPS datagram against the domain rule, peer registration, wire format and network interface .
Decision matrix:
bytes.len() < 20→Malformed.- Extract
peer_keyfrombytes[8..20]. - If the packet is SRTPS-wrapped → standard unwrap path
(
transform_inbound_from). On a crypto errorCryptoError, on an unknown peerPolicyViolation. - If the packet is plain AND the domain requires ProtectionKind::None
→
Accept. - If the packet is plain AND the domain requires protection:
- the interface is
LoopbackorLocalHost→Accept(bytes do not leave the host kernel — spec-conform plaintext on host-local transport) allow_unauthenticated_participants = true→Accept- otherwise →
LegacyBlocked
- the interface is
The iface context is currently consulted in the rules only for the
loopback fast path; the finer per-interface peer/topic
classification is handled by the PolicyEngine
from stage 8 on (governance-XML <interface_bindings>).
Sourcepub fn transform_inbound(
&self,
remote_slot: CryptoHandle,
wire: &[u8],
) -> Result<Vec<u8>, SecurityGateError>
pub fn transform_inbound( &self, remote_slot: CryptoHandle, wire: &[u8], ) -> Result<Vec<u8>, SecurityGateError>
Inbound message: unwrap if SRTPS_PREFIX is detected, otherwise passthrough or PolicyViolation.
remote_slot points to the slot in which the sender key
is stored (from Self::register_remote_with_token).
§Errors
See SecurityGateError.
Trait Implementations§
Source§fn clone(&self) -> SharedSecurityGate
fn clone(&self) -> SharedSecurityGate
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more