use alloc::string::String;
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProfileError {
KeyIdLength {
actual: usize,
},
MessageIdLength {
actual: usize,
},
EmptySubject,
ContentTypeForm,
EmptyPartyIdentity,
EmptySignature,
}
impl fmt::Display for ProfileError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::KeyIdLength { actual } => {
write!(f, "key id must be 1..=128 bytes, got {actual}")
}
Self::MessageIdLength { actual } => {
write!(f, "message id must be 1..=64 bytes, got {actual}")
}
Self::EmptySubject => write!(f, "subject string must be non-empty"),
Self::ContentTypeForm => write!(
f,
"content type must be of type/subtype form without surrounding whitespace"
),
Self::EmptyPartyIdentity => write!(f, "party identity must be non-empty when present"),
Self::EmptySignature => write!(f, "signature must be non-empty"),
}
}
}
impl core::error::Error for ProfileError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DecodeError {
Malformed,
NotTagged,
WrongTag {
expected: u64,
actual: u64,
},
IndefiniteLength,
NonMinimalEncoding,
NonDeterministicEncoding,
DuplicateLabel,
UnknownLabel {
label: i64,
},
TextLabel,
WrongType {
label: i64,
},
MissingHeader {
label: i64,
},
UnknownAlgorithm {
alg: i64,
},
CritMissing,
CritIncomplete {
label: i64,
},
CritUnexpected {
label: i64,
},
ClaimsInUnprotected,
UnknownClaim {
claim: i64,
},
FractionalTime,
MissingClaim {
claim: i64,
},
RecipientCount {
count: usize,
},
NestedRecipients,
RecipientCiphertextPresent,
MissingPayload,
EmbeddedNotEncrypt,
EphemeralKeyShape,
InvalidLength {
label: i64,
expected: usize,
actual: usize,
},
Identifier(ProfileError),
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Malformed => write!(f, "malformed CBOR input"),
Self::NotTagged => write!(f, "top-level item is not tagged"),
Self::WrongTag { expected, actual } => {
write!(f, "wrong COSE tag: expected {expected}, got {actual}")
}
Self::IndefiniteLength => write!(f, "indefinite-length item"),
Self::NonMinimalEncoding => write!(f, "non-minimal integer encoding"),
Self::NonDeterministicEncoding => write!(f, "non-deterministic encoding"),
Self::DuplicateLabel => write!(f, "duplicate map label"),
Self::UnknownLabel { label } => write!(f, "unknown label {label}"),
Self::TextLabel => write!(f, "text label outside the integer-labelled profile"),
Self::WrongType { label } => write!(f, "wrong CBOR type for label {label}"),
Self::MissingHeader { label } => write!(f, "missing required header {label}"),
Self::UnknownAlgorithm { alg } => write!(f, "algorithm {alg} outside the profile"),
Self::CritMissing => write!(f, "missing crit header"),
Self::CritIncomplete { label } => write!(f, "label {label} not listed in crit"),
Self::CritUnexpected { label } => write!(f, "unexpected crit entry {label}"),
Self::ClaimsInUnprotected => write!(f, "claims in unprotected header"),
Self::UnknownClaim { claim } => write!(f, "unknown CWT claim {claim}"),
Self::FractionalTime => write!(f, "fractional CWT timestamp"),
Self::MissingClaim { claim } => write!(f, "missing required CWT claim {claim}"),
Self::RecipientCount { count } => {
write!(f, "expected exactly one recipient, got {count}")
}
Self::NestedRecipients => write!(f, "nested recipients are not in the profile"),
Self::RecipientCiphertextPresent => {
write!(
f,
"recipient ciphertext must be nil for direct key agreement"
)
}
Self::MissingPayload => write!(f, "payload is absent"),
Self::EmbeddedNotEncrypt => {
write!(f, "sealed payload is not a tagged COSE_Encrypt")
}
Self::EphemeralKeyShape => {
write!(f, "ephemeral key is not the profile OKP/X25519 shape")
}
Self::InvalidLength {
label,
expected,
actual,
} => write!(f, "field {label} must be {expected} bytes, got {actual}"),
Self::Identifier(e) => write!(f, "invalid identifier: {e}"),
}
}
}
impl core::error::Error for DecodeError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Identifier(e) => Some(e),
_ => None,
}
}
}
impl From<ProfileError> for DecodeError {
fn from(e: ProfileError) -> Self {
Self::Identifier(e)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClaimsError {
IssuedInFuture,
Expired,
TtlTooLong {
seconds: i64,
},
NonPositiveTtl,
AudienceRejected,
MissingClaim {
label: i64,
},
ForbiddenClaim {
label: i64,
},
}
impl fmt::Display for ClaimsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::IssuedInFuture => write!(f, "issued-at is in the future beyond allowed skew"),
Self::Expired => write!(f, "message expired"),
Self::TtlTooLong { seconds } => {
write!(f, "explicit ttl of {seconds}s exceeds the maximum")
}
Self::NonPositiveTtl => write!(f, "expiry is not after issued-at"),
Self::AudienceRejected => write!(f, "audience not allowed"),
Self::MissingClaim { label } => write!(f, "role requires claim {label}"),
Self::ForbiddenClaim { label } => write!(f, "role forbids claim {label}"),
}
}
}
impl core::error::Error for ClaimsError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SignError {
AlgorithmUnsupported,
Provider {
message: String,
},
}
impl fmt::Display for SignError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AlgorithmUnsupported => write!(f, "signer does not support the algorithm"),
Self::Provider { message } => write!(f, "signing provider failed: {message}"),
}
}
}
impl core::error::Error for SignError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BuildError {
SenderKeyMismatch,
RoleShape(ClaimsError),
ResponseKeyNotText,
Rng,
SealFailed,
Sign(SignError),
Codec,
}
impl fmt::Display for BuildError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SenderKeyMismatch => {
write!(f, "claims sender key id does not match the signer key id")
}
Self::RoleShape(e) => write!(f, "claims do not fit the message role: {e}"),
Self::ResponseKeyNotText => write!(f, "response key id must be UTF-8"),
Self::Rng => write!(f, "randomness unavailable"),
Self::SealFailed => write!(f, "seal failed"),
Self::Sign(e) => write!(f, "signing failed: {e}"),
Self::Codec => write!(f, "structure encoding failed"),
}
}
}
impl core::error::Error for BuildError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::RoleShape(e) => Some(e),
Self::Sign(e) => Some(e),
_ => None,
}
}
}
impl From<SignError> for BuildError {
fn from(e: SignError) -> Self {
Self::Sign(e)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VerifyError {
Decode(DecodeError),
SignatureInvalid,
UnknownKeyId,
AlgorithmMismatch,
SenderKeyMismatch,
Claims(ClaimsError),
ClaimsPresenceMismatch,
Provider {
message: String,
},
}
impl fmt::Display for VerifyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Decode(e) => write!(f, "strict decode failed: {e}"),
Self::SignatureInvalid => write!(f, "signature verification failed"),
Self::UnknownKeyId => write!(f, "unknown signing key id"),
Self::AlgorithmMismatch => write!(f, "algorithm does not match the pinned key"),
Self::SenderKeyMismatch => {
write!(f, "sender key id claim does not match the outer kid")
}
Self::Claims(e) => write!(f, "claim validation failed: {e}"),
Self::ClaimsPresenceMismatch => write!(
f,
"claims presence does not match the validation expectation"
),
Self::Provider { message } => write!(f, "verification provider failed: {message}"),
}
}
}
impl core::error::Error for VerifyError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Decode(e) => Some(e),
Self::Claims(e) => Some(e),
_ => None,
}
}
}
impl From<DecodeError> for VerifyError {
fn from(e: DecodeError) -> Self {
Self::Decode(e)
}
}
impl From<ClaimsError> for VerifyError {
fn from(e: ClaimsError) -> Self {
Self::Claims(e)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OpenError {
Decode(DecodeError),
RecipientKeyMismatch,
PartyMismatch,
OpenFailed,
Provider {
message: String,
},
}
impl fmt::Display for OpenError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Decode(e) => write!(f, "strict decode failed: {e}"),
Self::RecipientKeyMismatch => write!(f, "message is for a different recipient key"),
Self::PartyMismatch => write!(f, "KDF party identities do not match expectation"),
Self::OpenFailed => write!(f, "open failed"),
Self::Provider { message } => write!(f, "open provider failed: {message}"),
}
}
}
impl core::error::Error for OpenError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Decode(e) => Some(e),
_ => None,
}
}
}
impl From<DecodeError> for OpenError {
fn from(e: DecodeError) -> Self {
Self::Decode(e)
}
}