1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! Located processing failures, retaining the original ASN.1 diagnostic.
use core::fmt;
use structured_asn1::memory::MemoryError;
/// A processing failure, distinct from a provider's signature answer.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorCode {
/// The producing ASN.1 reader refused the encoding or its resources.
Encoding(structured_asn1::ErrorCode),
/// A shared PKIX semantic or conformance mechanism refused.
Pkix(structured_pkix::ErrorCode),
/// An element has the wrong tag for the selected schema field.
UnexpectedTag,
/// The logical content length cannot be represented.
LengthOverflow,
/// A required schema component was not present.
MissingField,
/// A container includes an additional component beyond its schema.
TrailingData,
/// A required nonempty attribute collection is empty.
EmptyAttributes,
/// An attribute that requires one value holds none or several.
AttributeCardinality,
/// Another instance was written where the selected type requires uniqueness.
DuplicateAttribute,
/// Signed attribute encodings are not in DER SET OF order.
AttributeOrder,
/// The numeric schema version does not fit its representation.
ValueTooLarge,
/// The declared version disagrees with the encoded schema choices.
VersionMismatch,
/// `ContentInfo` selected a type other than the requested protocol schema.
UnexpectedContentType,
/// A DER SET OF catalogue is not ordered by original encodings.
SetOrder,
/// The content-type attribute disagrees with its enclosing signed content.
ContentTypeMismatch,
/// A recognized attribute is in a placement its protocol forbids.
AttributePlacement,
/// A recognized attribute value violates its selected type or profile syntax.
AttributeSyntax,
/// A fixed digest identity cannot produce the declared message-digest width.
DigestWidth,
/// The selected algorithm's identifier violates its own parameter syntax.
AlgorithmSyntax,
/// Protected algorithms disagree under the selected provider's full semantics.
AlgorithmProtection,
/// A request uses another provider, or lacks a stable selection owner.
ProviderMismatch,
/// A readable schema default was explicitly encoded where DER omits it.
DefaultWritten,
/// A bounded schema container has an unrecognized field.
UnknownField,
/// A field is repeated; readable identical recovery retains a fault.
DuplicateField,
/// Recognized fields were written outside their required SEQUENCE order.
FieldOrder,
/// A readable value violates the selected schema's scalar bounds.
MalformedValue,
/// The written protocol version has no implemented schema interpretation.
UnsupportedVersion,
/// A readable open encoding needs a schema-specific DER projection codec.
UnsupportedEncoding,
/// A caller supplied a location outside the reader's source window.
InvalidLocation,
/// A timestamp token has no signer or conflicting multiple signer values.
SignerCount,
/// Timestamp information was detached instead of carried in the token.
DetachedContent,
/// An additional timestamp signature was retained for readable inspection.
ExtraSignature,
}
#[derive(Debug)]
enum Detail {
Schema { code: ErrorCode, offset: u64 },
Encoding(structured_asn1::Error),
Pkix(structured_pkix::Error),
}
/// A source-located failure with independently retained diagnostic storage.
#[derive(Debug)]
pub struct Error {
field: &'static str,
detail: Detail,
}
impl Error {
pub(crate) fn schema(code: ErrorCode, field: &'static str, offset: u64) -> Self {
Self {
field,
detail: Detail::Schema { code, offset },
}
}
pub(crate) fn encoding(source: structured_asn1::Error, field: &'static str) -> Self {
Self {
field,
detail: Detail::Encoding(source),
}
}
pub(crate) fn pkix(source: structured_pkix::Error) -> Self {
Self {
field: source.field(),
detail: Detail::Pkix(source),
}
}
pub(crate) fn resource(reason: MemoryError, field: &'static str, offset: u64) -> Self {
Self::encoding(structured_asn1::Error::resource(reason, offset), field)
}
/// The processing failure category.
#[must_use]
pub fn code(&self) -> ErrorCode {
match &self.detail {
Detail::Schema { code, .. } => *code,
Detail::Encoding(source) => ErrorCode::Encoding(source.code()),
Detail::Pkix(source) => ErrorCode::Pkix(source.code()),
}
}
/// The schema field being processed.
#[must_use]
pub fn field(&self) -> &'static str {
self.field
}
/// The original source position where processing refused.
#[must_use]
pub fn offset(&self) -> u64 {
match &self.detail {
Detail::Schema { offset, .. } => *offset,
Detail::Encoding(source) => source.offset(),
Detail::Pkix(source) => source.offset(),
}
}
/// The original reader diagnostic, including any available path.
#[must_use]
pub fn encoding_source(&self) -> Option<&structured_asn1::Error> {
match &self.detail {
Detail::Encoding(source) => Some(source),
_ => None,
}
}
/// Whether processing refused resources rather than document syntax.
#[must_use]
pub fn is_resource(&self) -> bool {
match &self.detail {
Detail::Encoding(source) => source.is_resource(),
Detail::Pkix(source) => source.is_resource(),
Detail::Schema { .. } => false,
}
}
/// An inspection recovery must abort instead of retaining a document fault.
/// Resource refusals and a foreign producing reader are operation failures;
/// neither can establish a malformed value, mismatch or successful absence.
#[must_use]
pub fn is_terminal(&self) -> bool {
self.is_resource()
|| self.code() == ErrorCode::Pkix(structured_pkix::ErrorCode::ForeignReader)
|| self.code() == ErrorCode::InvalidLocation
|| self.code() == ErrorCode::UnsupportedEncoding
}
}
impl fmt::Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"{} at {}: {:?}",
self.field,
self.offset(),
self.code()
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.detail {
Detail::Encoding(source) => Some(source),
Detail::Pkix(source) => Some(source),
Detail::Schema { .. } => None,
}
}
}
/// A fallible CMS processing operation.
pub type Result<T> = core::result::Result<T, Error>;