Skip to main content

structured_cades/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![doc = include_str!("../README.md")]
3
4extern crate alloc;
5#[cfg(test)]
6extern crate std;
7
8pub mod baseline;
9pub mod basic;
10pub mod counters;
11pub mod credential;
12pub mod evidence;
13pub mod material;
14pub mod participants;
15pub mod prepare;
16pub mod preservation;
17pub mod properties;
18pub mod source;
19pub mod timestamp;
20
21/// Terminal processing refusal, distinct from a completed format finding.
22#[derive(Debug)]
23pub enum Error {
24    /// Original common CMS failure, preserving all underlying diagnostics.
25    Cms(structured_cms::Error),
26    /// Original ASN.1 failure, without changing its coordinates or cause.
27    Encoding {
28        /// Original protocol field whose decoding refused.
29        field: &'static str,
30        /// Original ASN.1 cause, including its retained diagnostic path.
31        cause: structured_asn1::Error,
32    },
33    /// Shared PKIX schema/DER refusal, preserving its field and location.
34    Pkix(structured_pkix::Error),
35    /// Format schema failure at an actual original value.
36    Syntax {
37        /// Exact format/schema category.
38        code: structured_cms::ErrorCode,
39        /// Original protocol field.
40        field: &'static str,
41        /// Original source offset.
42        at: u64,
43    },
44    /// Current work/storage refused before use at this original position.
45    Resource {
46        /// Actual original source position.
47        at: u64,
48        /// Exact refusal, never converted to missing material.
49        cause: structured_asn1::memory::MemoryError,
50        /// Original operation field.
51        field: &'static str,
52    },
53    /// A receipt or selected model belongs to another original source.
54    Foreign {
55        /// Actual selecting position, never a fabricated decode offset.
56        at: u64,
57    },
58}
59
60impl Error {
61    pub(crate) fn resource(
62        cause: structured_asn1::memory::MemoryError,
63        field: &'static str,
64        at: u64,
65    ) -> Self {
66        Self::Resource { at, cause, field }
67    }
68    pub(crate) fn encoding(cause: structured_asn1::Error, field: &'static str) -> Self {
69        Self::Encoding { cause, field }
70    }
71    /// A refusal of the run, rather than a recoverable document finding.
72    #[must_use]
73    pub fn is_terminal(&self) -> bool {
74        match self {
75            Self::Cms(error) => error.is_terminal(),
76            Self::Encoding { cause, .. } => {
77                cause.is_resource() || cause.code() == structured_asn1::ErrorCode::TagTooLarge
78            }
79            Self::Pkix(error) => {
80                error.is_resource() || error.code() == structured_pkix::ErrorCode::ForeignReader
81            }
82            Self::Resource { .. } | Self::Foreign { .. } => true,
83            Self::Syntax { .. } => false,
84        }
85    }
86    /// Original source position of the failure.
87    #[must_use]
88    pub fn offset(&self) -> u64 {
89        match self {
90            Self::Cms(error) => error.offset(),
91            Self::Encoding { cause, .. } => cause.offset(),
92            Self::Pkix(error) => error.offset(),
93            Self::Resource { at, .. } | Self::Foreign { at } | Self::Syntax { at, .. } => *at,
94        }
95    }
96    /// Original protocol field, when this failure originates in document
97    /// processing. A foreign receipt is caller misuse and has no invented field.
98    #[must_use]
99    pub fn field(&self) -> Option<&'static str> {
100        match self {
101            Self::Cms(cause) => Some(cause.field()),
102            Self::Pkix(cause) => Some(cause.field()),
103            Self::Encoding { field, .. }
104            | Self::Syntax { field, .. }
105            | Self::Resource { field, .. } => Some(*field),
106            Self::Foreign { .. } => None,
107        }
108    }
109}
110
111impl From<structured_cms::Error> for Error {
112    fn from(cause: structured_cms::Error) -> Self {
113        Self::Cms(cause)
114    }
115}
116
117/// Complete operation or terminal processing refusal; never a successful prefix.
118pub type Result<T> = core::result::Result<T, Error>;
119
120/// Explicitly requested format profile, never inferred from unsigned attributes.
121#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
122pub enum Level {
123    /// Mandatory signed baseline fields and signer association.
124    Basic,
125    /// Basic plus the complete signature-timestamp obligations.
126    Timestamped,
127    /// Timestamped plus all required incorporated validation material.
128    LongTerm,
129    /// Long-term plus every original archive's protected validation material.
130    Archival,
131}
132
133/// Issuer of source-derived `CAdES` receipts in the format-neutral LTV core.
134/// Only this crate constructs it, after selecting the original CMS source.
135#[derive(Debug, Clone, Copy)]
136pub struct Cades(());
137
138pub(crate) const ISSUER: Cades = Cades(());