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>;