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
//! Original `MessageImprint` fields, without a concrete digest backend.
use super::record;
use crate::{Error, ErrorCode, Octets, Result};
use structured_asn1::memory::{OwnedVec, Work};
use structured_asn1::{Element, Oid, Reader, Span, Tag, universal};
use structured_pkix::AlgorithmIdentifier;
#[derive(Debug, Clone, Copy)]
pub(super) struct ImprintFields {
pub enclosing: &'static str,
pub algorithm: &'static str,
pub hashed: &'static str,
}
const TOKEN: ImprintFields = ImprintFields {
enclosing: "tstInfo.messageImprint",
algorithm: "tstInfo.messageImprint.hashAlgorithm",
hashed: "tstInfo.messageImprint.hashedMessage",
};
/// A written identifier versus uniquely bounded malformed algorithm syntax.
#[derive(Debug)]
pub enum HashAlgorithmReading<'a> {
/// Original `AlgorithmIdentifier`, with original parameter/depth provenance.
Identifier(AlgorithmIdentifier<'a>),
/// No identifier may be dispatched as if its syntax were conforming.
Malformed {
/// Whole original malformed field, never retagged or re-encoded.
element: Element<'a>,
/// Bare OID only when the shared OID decoder actually read it.
kind: Option<Oid<'a>>,
},
}
/// Borrowed algorithm/hash fields and independently accounted diagnostics.
/// Reading is independent of algorithm support, output width and token trust.
#[derive(Debug)]
pub struct MessageImprint<'a> {
algorithm: HashAlgorithmReading<'a>,
hashed: Octets<'a>,
faults: OwnedVec<Error>,
span: Span,
fields: ImprintFields,
}
impl<'a> MessageImprint<'a> {
/// Reads the two original fields of RFC3161 ยง2.4.1 `MessageImprint`.
///
/// The normative algorithm is `AlgorithmIdentifier`. Inspection retains a
/// uniquely bounded malformed first field and readable OCTET STRING, with
/// faults; a bare OID does not become a fabricated valid identifier. This
/// recovery is not specified by RFC3161. Missing/unreadable hash refuses.
/// The selected provider resolves written identifiers and their full
/// parameter/output semantics separately; no fixed hash registry is assumed.
/// <https://www.rfc-editor.org/rfc/rfc3161#section-2.4.1>
pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
Self::read_fields(parent, element, TOKEN)
}
pub(super) fn read_fields(
parent: &Reader<'a>,
element: &Element<'a>,
fields: ImprintFields,
) -> Result<Self> {
if element.tag() != Tag::constructed(universal::SEQUENCE) {
return Err(Error::schema(
ErrorCode::UnexpectedTag,
fields.enclosing,
element.span().start,
));
}
let mut inside = parent
.enter(element)
.map_err(|error| Error::encoding(error, fields.enclosing))?;
let written = crate::signer::required(&mut inside, fields.algorithm)?;
let execution = parent.execution();
let mut faults = execution.vector();
let algorithm = if written.tag() == Tag::constructed(universal::SEQUENCE) {
match structured_pkix::algorithm::read(&inside, &written, fields.algorithm)
.map_err(Error::pkix)
{
Ok(identifier) => HashAlgorithmReading::Identifier(identifier),
Err(error) if error.is_terminal() => return Err(error),
Err(error) => {
record(&mut faults, error)?;
HashAlgorithmReading::Malformed {
element: written,
kind: None,
}
}
}
} else {
let kind = if written.tag() == Tag::primitive(universal::OID) {
match inside
.oid(&written)
.map_err(|error| Error::encoding(error, fields.algorithm))
{
Ok(kind) => Some(kind),
Err(error) if error.is_terminal() => return Err(error),
Err(error) => {
record(&mut faults, error)?;
None
}
}
} else {
None
};
record(
&mut faults,
Error::schema(
ErrorCode::MalformedValue,
fields.algorithm,
written.span().start,
),
)?;
HashAlgorithmReading::Malformed {
element: written,
kind,
}
};
let hashed = crate::signer::required(&mut inside, fields.hashed)?;
let hashed = Octets::read(&inside, &hashed, fields.hashed)?;
if !inside.is_empty() {
record(
&mut faults,
Error::schema(ErrorCode::TrailingData, fields.enclosing, inside.offset()),
)?;
}
Ok(Self {
algorithm,
hashed,
faults: faults.into_owned(),
span: element.span(),
fields,
})
}
/// Original written algorithm or explicit unreadable/malformed alternative.
#[must_use]
pub fn algorithm(&self) -> &HashAlgorithmReading<'a> {
&self.algorithm
}
/// Original logical hash bytes, including original BER fragment spans.
#[must_use]
pub fn hashed(&self) -> &Octets<'a> {
&self.hashed
}
/// Original complete `MessageImprint` range.
#[must_use]
pub fn span(&self) -> Span {
self.span
}
/// Readable faults, which cannot be silently ignored for proof acceptance.
#[must_use]
pub fn faults(&self) -> &[Error] {
&self.faults
}
pub(super) fn fields(&self) -> ImprintFields {
self.fields
}
}