1use super::AlgorithmIdentifier;
9use crate::error::{Error, ErrorCode, Located, Result};
10use structured_asn1::memory::{OwnedVec, Work};
11use structured_asn1::{Element, Integer, Oid, ScopedReader as Reader, Tag, universal};
12
13const SHA1: Oid<'static> = Oid::from_bytes(&[0x2b, 0x0e, 3, 2, 0x1a]);
14const MGF1: Oid<'static> = Oid::from_bytes(&[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 1, 1, 8]);
15const FIELD: &str = "algorithm.pss";
16
17#[derive(Debug, Clone, Copy)]
19pub struct Written<'a, T> {
20 element: Element<'a>,
21 value: T,
22}
23
24impl<'a, T: Copy> Written<'a, T> {
25 #[must_use]
27 pub fn element(self) -> Element<'a> {
28 self.element
29 }
30
31 #[must_use]
33 pub fn value(self) -> T {
34 self.value
35 }
36}
37
38#[derive(Debug, Clone, Copy)]
40pub enum Number<'a> {
41 Default(u64),
43 Written(Written<'a, Integer<'a>>),
45}
46
47impl Number<'_> {
48 #[must_use]
50 pub fn as_u64(self) -> Option<u64> {
51 match self {
52 Self::Default(value) => Some(value),
53 Self::Written(value) => value.value.as_u64(),
54 }
55 }
56}
57
58#[derive(Debug, Clone, Copy)]
60pub enum Mask<'a> {
61 DefaultMgf1Sha1,
63 Mgf1 {
65 function: Written<'a, AlgorithmIdentifier<'a>>,
67 hash: AlgorithmIdentifier<'a>,
69 },
70 Other(Written<'a, AlgorithmIdentifier<'a>>),
72}
73
74#[derive(Debug, Clone, Copy)]
76pub struct Parameters<'a> {
77 element: Element<'a>,
78 hash: Option<Written<'a, AlgorithmIdentifier<'a>>>,
79 mask: Mask<'a>,
80 salt: Number<'a>,
81 trailer: Number<'a>,
82}
83
84impl<'a> Parameters<'a> {
85 #[must_use]
87 pub fn element(self) -> Element<'a> {
88 self.element
89 }
90
91 #[must_use]
93 pub fn hash(self) -> Option<Written<'a, AlgorithmIdentifier<'a>>> {
94 self.hash
95 }
96
97 #[must_use]
99 pub fn mask(self) -> Mask<'a> {
100 self.mask
101 }
102
103 #[must_use]
107 pub fn salt(self) -> Number<'a> {
108 self.salt
109 }
110
111 #[must_use]
114 pub fn trailer(self) -> Number<'a> {
115 self.trailer
116 }
117}
118
119#[derive(Debug)]
121pub struct Reading<'a> {
122 parameters: Parameters<'a>,
123 faults: OwnedVec<Error>,
124}
125
126impl<'a> Reading<'a> {
127 #[must_use]
129 pub fn parameters(&self) -> Parameters<'a> {
130 self.parameters
131 }
132
133 #[must_use]
136 pub fn faults(&self) -> &[Error] {
137 &self.faults
138 }
139}
140
141pub fn read_in<'a>(
163 identifier: AlgorithmIdentifier<'a>,
164 parent: &Reader<'a, '_>,
165) -> Result<Option<Parameters<'a>>> {
166 let execution = parent.execution();
167 let Some((reader, element)) = open(identifier, parent, &execution)? else {
168 return Ok(None);
169 };
170 decode(&reader, element, Err).map(Some)
171}
172
173pub fn inspect_in<'a>(
181 identifier: AlgorithmIdentifier<'a>,
182 parent: &Reader<'a, '_>,
183) -> Result<Option<Reading<'a>>> {
184 let execution = parent.execution();
185 let Some((reader, element)) = open(identifier, parent, &execution)? else {
186 return Ok(None);
187 };
188 let mut faults = execution.vector();
189 let parameters = decode(&reader, element, |fault| {
190 let at = fault.offset();
191 let field = fault.field();
192 faults
193 .try_push(fault)
194 .map_err(|reason| Error::resource(reason, field, at))
195 })?;
196 Ok(Some(Reading {
197 parameters,
198 faults: faults.into_owned(),
199 }))
200}
201
202fn open<'a: 'operation, 'operation, W: Work>(
203 identifier: AlgorithmIdentifier<'a>,
204 parent: &Reader<'a, '_>,
205 execution: &'operation W,
206) -> Result<Option<(Reader<'a, 'operation>, Element<'a>)>> {
207 if !identifier.same_session(parent) {
208 return Err(Error::new(
209 ErrorCode::ForeignReader,
210 FIELD,
211 identifier.offset(),
212 ));
213 }
214 if !oid_is(
215 parent,
216 identifier.algorithm(),
217 crate::oid::RSASSA_PSS,
218 identifier.offset(),
219 )? {
220 return Err(Error::new(
221 ErrorCode::UnexpectedField,
222 FIELD,
223 identifier.offset(),
224 ));
225 }
226 let value = open_parameter(identifier, parent, execution, FIELD)?;
227 if let Some((_, element)) = &value
228 && element.tag() != Tag::constructed(universal::SEQUENCE)
229 {
230 return Err(Error::new(
231 ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
232 FIELD,
233 element.span().start,
234 ));
235 }
236 Ok(value)
237}
238
239fn open_parameter<'a: 'operation, 'operation, W: Work>(
240 identifier: AlgorithmIdentifier<'a>,
241 parent: &Reader<'a, '_>,
242 execution: &'operation W,
243 field: &'static str,
244) -> Result<Option<(Reader<'a, 'operation>, Element<'a>)>> {
245 charge(parent, 1, identifier.offset())?;
246 let Some(parameters) = identifier.parameters_nested() else {
247 return Ok(None);
248 };
249 parameters.open(execution, field).map(Some)
250}
251
252fn decode<'a>(
253 parent: &Reader<'a, '_>,
254 element: Element<'a>,
255 mut fault: impl FnMut(Error) -> Result<()>,
256) -> Result<Parameters<'a>> {
257 let mut fields = parent.enter(&element).field(FIELD)?;
258 let mut parameters = Parameters {
259 element,
260 hash: None,
261 mask: Mask::DefaultMgf1Sha1,
262 salt: Number::Default(20),
263 trailer: Number::Default(1),
264 };
265 let mut previous = None;
266 while let Some(element) = fields.next_element().field(FIELD)? {
267 fields.charge(1).field(FIELD)?;
268 let Some(number) = element.tag().number() else {
269 return Err(Error::new(
270 ErrorCode::UnexpectedField,
271 FIELD,
272 element.span().start,
273 ));
274 };
275 if number > 3
276 || element.tag() != Tag::context(true, number)
277 || previous.is_some_and(|last| number <= last)
278 {
279 return Err(Error::new(
280 ErrorCode::UnexpectedField,
281 FIELD,
282 element.span().start,
283 ));
284 }
285 previous = Some(number);
286 let mut inside = fields.enter(&element).field(FIELD)?;
287 let value = inside
288 .next_element()
289 .field(FIELD)?
290 .ok_or_else(|| Error::new(ErrorCode::MissingField, FIELD, inside.offset()))?;
291 if !inside.is_empty() {
292 return Err(Error::new(ErrorCode::TrailingData, FIELD, inside.offset()));
293 }
294 let defaulted = match number {
295 0 => {
296 let hash = super::read(&inside, &value, "algorithm.pss.hash")?;
297 parameters.hash = Some(Written {
298 element,
299 value: hash,
300 });
301 default_hash(&inside, hash)?
302 }
303 1 => {
304 let (mask, defaulted) = read_mask(&inside, element, value)?;
305 parameters.mask = mask;
306 defaulted
307 }
308 _ => {
309 if value.tag() != Tag::primitive(universal::INTEGER) {
310 return Err(Error::new(
311 ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
312 FIELD,
313 value.span().start,
314 ));
315 }
316 let integer = inside.integer(&value).field(FIELD)?;
317 if number == 2 && integer.is_negative() {
318 return Err(Error::new(
319 ErrorCode::MalformedValue,
320 FIELD,
321 value.span().start,
322 ));
323 }
324 charge(&inside, 9, value.span().start)?;
325 let written = Number::Written(Written {
326 element,
327 value: integer,
328 });
329 if number == 2 {
330 parameters.salt = written;
331 integer.as_u64() == Some(20)
332 } else {
333 parameters.trailer = written;
334 integer.as_u64() == Some(1)
335 }
336 }
337 };
338 if defaulted && fields.encoding().is_der() {
342 fault(Error::new(
343 ErrorCode::DefaultWritten,
344 FIELD,
345 element.span().start,
346 ))?;
347 }
348 }
349 Ok(parameters)
350}
351
352fn default_hash(parent: &Reader<'_, '_>, identifier: AlgorithmIdentifier<'_>) -> Result<bool> {
353 Ok(
358 oid_is(parent, identifier.algorithm(), SHA1, identifier.offset())?
359 && identifier.has_null_parameter(),
360 )
361}
362
363fn oid_is(parent: &Reader<'_, '_>, left: Oid<'_>, right: Oid<'_>, at: u64) -> Result<bool> {
364 charge(parent, 1, at)?;
365 if left.as_bytes().len() != right.as_bytes().len() {
366 return Ok(false);
367 }
368 charge(parent, left.as_bytes().len() as u64, at)?;
369 Ok(left == right)
370}
371
372fn charge(parent: &Reader<'_, '_>, amount: u64, at: u64) -> Result<()> {
373 parent
374 .charge(amount)
375 .map_err(|error| Error::new(ErrorCode::Encoding(error.code()), FIELD, at))
376}
377
378fn read_mask<'a>(
379 parent: &Reader<'a, '_>,
380 element: Element<'a>,
381 value: Element<'a>,
382) -> Result<(Mask<'a>, bool)> {
383 let algorithm = super::read(parent, &value, "algorithm.pss.mask")?;
384 let function = Written {
385 element,
386 value: algorithm,
387 };
388 if !oid_is(parent, algorithm.algorithm(), MGF1, algorithm.offset())? {
389 return Ok((Mask::Other(function), false));
390 }
391 let execution = parent.execution();
392 let (reader, element) =
393 open_parameter(algorithm, parent, &execution, "algorithm.pss.mask.hash")?.ok_or_else(
394 || {
395 Error::new(
396 ErrorCode::MissingField,
397 "algorithm.pss.mask.hash",
398 algorithm.offset(),
399 )
400 },
401 )?;
402 let hash = super::read(&reader, &element, "algorithm.pss.mask.hash")?;
403 Ok((Mask::Mgf1 { function, hash }, default_hash(&reader, hash)?))
404}