pub enum LeafError {
Show 14 variants
Storage(String),
NotProvisioned,
AlreadyProvisioned,
Crypto(String),
Mls(String),
MalformedFrame(String),
ControlFrameRefused(String),
StaleControlFrame(String),
IdentityBinding(String),
NoSession(String),
UnsolicitedWelcome(String),
StaleKeyPackage(String),
TooManyPeers,
Sealed(String),
}Expand description
What can go wrong on a leaf node.
Deliberately not #[non_exhaustive], for the reason
ADR 0022
gives for SealedError: firmware that maps these onto its own error space
should get a compile error when a variant is added, rather than a wildcard
arm that silently renders a new failure as an old one.
Variants§
Storage(String)
The backing store failed.
NotProvisioned
The device has no identity yet, and an operation needed one.
AlreadyProvisioned
The device already has an identity, and provisioning would replace it.
Overwriting an identity is not a recoverable state: the device’s address changes, every peer’s paired record names a device that no longer exists, and nothing on the wire says why.
Crypto(String)
A cryptographic operation failed.
Mls(String)
MLS refused an operation.
MalformedFrame(String)
A frame did not parse.
ControlFrameRefused(String)
A control frame arrived unsigned, or its signature did not verify.
Unsigned is a refusal rather than a downgrade: every control frame in this protocol carries a signature, and one that does not is either an implementation that skipped the step or an injection.
StaleControlFrame(String)
A control frame’s signature verified, and the frame is too old, too far ahead of this device’s clock, or built on the payload that states neither.
Its own variant rather than a Self::ControlFrameRefused with
different text, because firmware has to be able to tell these apart and
the two mean opposite things about what to do. A signature that does
not verify accuses the sender. This one, in bulk and across peers,
accuses this device’s clock: the signed timestamp is judged against
it, so a device whose time source is wrong or has not been set refuses
every honest peer and reports it as though it were under attack.
A leaf gets a time source at pairing and is expected to keep one; see the provisioning chapter of the specification for what that obligation is and why it is not optional.
IdentityBinding(String)
A presented key did not derive to the address that claimed it, or the claimed identifier is not an address at all.
Both are the same refusal on purpose. An identifier that does not parse as an address has no derivation to check, and answering “acceptable” for it is the bypass rather than a lenience.
NoSession(String)
No session exists with this peer.
UnsolicitedWelcome(String)
A Welcome asked this device to join on a key package it did not mint for the peer that sent it.
A key package is a bearer token. It rides in a frame that is signed but not encrypted, so anyone in radio range copies one off the air, and every other gate on a Welcome then passes for them honestly: they do hold the key their own address derives from, and they did build the group this pair’s id names. Only this refusal separates the peer the package was minted for from whoever else heard it.
Its own variant rather than an identity binding, because the two send firmware to different places. An identity binding failure says a peer is not who it claims; this says the peer is exactly who it claims and is spending something that was never given to it.
StaleKeyPackage(String)
A Welcome spends the key package this device minted for its sender, and that package is no longer held.
Neither an attack nor an identity failure: the peer is exactly who it claims and is spending exactly what it was given. The package is simply gone, because an earlier join consumed it (an init key is single use, so a Welcome is not replayable) or because later mints pushed it out of the bounded ring.
Its own variant because the repair is a fresh package rather than a retry, and because the alternative is the same condition arriving from inside MLS as a Welcome that will not decode, which reads as a broken peer and sends a bench to the wire.
TooManyPeers
The device already holds as many peers as it keeps room for, and none of them is an incomplete pairing that could be recycled.
Refusing rather than evicting an established peer is deliberate. A
device with a full table is one a stranger cannot displace the owner
from; the owner clears a slot with
LeafDevice::unpair.
Sealed(String)
The sealed layer refused a value.
Trait Implementations§
impl Eq for LeafError
Source§impl Error for LeafError
impl Error for LeafError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl From<SealedError> for LeafError
impl From<SealedError> for LeafError
Source§fn from(e: SealedError) -> Self
fn from(e: SealedError) -> Self
impl StructuralPartialEq for LeafError
Auto Trait Implementations§
impl Freeze for LeafError
impl RefUnwindSafe for LeafError
impl Send for LeafError
impl Sync for LeafError
impl Unpin for LeafError
impl UnsafeUnpin for LeafError
impl UnwindSafe for LeafError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more