Skip to main content

zerodds_security/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! Security error types. OMG DDS-Security 1.1 §8.1.2 `SecurityException`.
5//!
6//! A common error type across all plugins — so that call sites do not
7//! have to handle five different result variants. The `Kind`
8//! variants match the spec error codes.
9
10extern crate alloc;
11
12use alloc::borrow::Cow;
13use core::fmt;
14
15/// Security operation error.
16#[derive(Debug, Clone, PartialEq, Eq)]
17#[non_exhaustive]
18pub struct SecurityError {
19    /// Error category.
20    pub kind: SecurityErrorKind,
21    /// Human-readable hint (not for end users — internal).
22    pub detail: Cow<'static, str>,
23}
24
25/// Category of the security error.
26///
27/// Spec reference OMG DDS-Security 1.1 §8.1.2. The codes are kept
28/// open (`#[non_exhaustive]`) so that v1.4 can add additional variants
29/// without a breaking change.
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31#[non_exhaustive]
32pub enum SecurityErrorKind {
33    /// Identity handshake failed (certificate invalid,
34    /// signature wrong, peer not in the trust store).
35    AuthenticationFailed,
36    /// The peer has no permission for this operation.
37    AccessDenied,
38    /// Cryptographic operation failed (AES-GCM tag verify,
39    /// HMAC mismatch, key unknown).
40    CryptoFailed,
41    /// Missing or implausible configuration (e.g. cert missing,
42    /// permissions XML does not parse).
43    InvalidConfiguration,
44    /// Invalid argument (None where Some expected, empty key, etc.).
45    BadArgument,
46    /// Feature not implemented. The v1.3 plugin SPI signals this way
47    /// when a method is planned for v1.4.
48    NotImplemented,
49    /// Internal unexpected error — plugin bug.
50    Internal,
51}
52
53impl SecurityError {
54    /// Constructor.
55    #[must_use]
56    pub fn new(kind: SecurityErrorKind, detail: impl Into<Cow<'static, str>>) -> Self {
57        Self {
58            kind,
59            detail: detail.into(),
60        }
61    }
62
63    /// Shortcut for `NotImplemented`.
64    #[must_use]
65    pub fn not_implemented(detail: impl Into<Cow<'static, str>>) -> Self {
66        Self::new(SecurityErrorKind::NotImplemented, detail)
67    }
68
69    /// Shortcut for `BadArgument`.
70    #[must_use]
71    pub fn bad_argument(detail: impl Into<Cow<'static, str>>) -> Self {
72        Self::new(SecurityErrorKind::BadArgument, detail)
73    }
74}
75
76impl fmt::Display for SecurityError {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        write!(f, "security error [{:?}]: {}", self.kind, self.detail)
79    }
80}
81
82#[cfg(feature = "std")]
83impl std::error::Error for SecurityError {}
84
85/// Plugin operation result.
86pub type SecurityResult<T> = core::result::Result<T, SecurityError>;