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() else {
247 return Ok(None);
248 };
249 let at = identifier.offset()
250 + identifier
251 .parameter_start
252 .expect("written parameters")
253 .get() as u64;
254 let mut reader = execution
255 .read_scoped_nested(
256 identifier.parser,
257 parameters,
258 at,
259 identifier.encoding,
260 identifier.outer,
261 )
262 .field(field)?;
263 let element = reader
264 .next_element()
265 .field(field)?
266 .ok_or_else(|| Error::new(ErrorCode::MissingField, field, reader.offset()))?;
267 if !reader.is_empty() {
268 return Err(Error::new(ErrorCode::TrailingData, field, reader.offset()));
269 }
270 Ok(Some((reader, element)))
271}
272
273fn decode<'a>(
274 parent: &Reader<'a, '_>,
275 element: Element<'a>,
276 mut fault: impl FnMut(Error) -> Result<()>,
277) -> Result<Parameters<'a>> {
278 let mut fields = parent.enter(&element).field(FIELD)?;
279 let mut parameters = Parameters {
280 element,
281 hash: None,
282 mask: Mask::DefaultMgf1Sha1,
283 salt: Number::Default(20),
284 trailer: Number::Default(1),
285 };
286 let mut previous = None;
287 while let Some(element) = fields.next_element().field(FIELD)? {
288 fields.charge(1).field(FIELD)?;
289 let Some(number) = element.tag().number() else {
290 return Err(Error::new(
291 ErrorCode::UnexpectedField,
292 FIELD,
293 element.span().start,
294 ));
295 };
296 if number > 3
297 || element.tag() != Tag::context(true, number)
298 || previous.is_some_and(|last| number <= last)
299 {
300 return Err(Error::new(
301 ErrorCode::UnexpectedField,
302 FIELD,
303 element.span().start,
304 ));
305 }
306 previous = Some(number);
307 let mut inside = fields.enter(&element).field(FIELD)?;
308 let value = inside
309 .next_element()
310 .field(FIELD)?
311 .ok_or_else(|| Error::new(ErrorCode::MissingField, FIELD, inside.offset()))?;
312 if !inside.is_empty() {
313 return Err(Error::new(ErrorCode::TrailingData, FIELD, inside.offset()));
314 }
315 let defaulted = match number {
316 0 => {
317 let hash = super::read(&inside, &value, "algorithm.pss.hash")?;
318 parameters.hash = Some(Written {
319 element,
320 value: hash,
321 });
322 default_hash(&inside, hash)?
323 }
324 1 => {
325 let (mask, defaulted) = read_mask(&inside, element, value)?;
326 parameters.mask = mask;
327 defaulted
328 }
329 _ => {
330 if value.tag() != Tag::primitive(universal::INTEGER) {
331 return Err(Error::new(
332 ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
333 FIELD,
334 value.span().start,
335 ));
336 }
337 let integer = inside.integer(&value).field(FIELD)?;
338 if number == 2 && integer.is_negative() {
339 return Err(Error::new(
340 ErrorCode::MalformedValue,
341 FIELD,
342 value.span().start,
343 ));
344 }
345 charge(&inside, 9, value.span().start)?;
346 let written = Number::Written(Written {
347 element,
348 value: integer,
349 });
350 if number == 2 {
351 parameters.salt = written;
352 integer.as_u64() == Some(20)
353 } else {
354 parameters.trailer = written;
355 integer.as_u64() == Some(1)
356 }
357 }
358 };
359 if defaulted && fields.encoding().is_der() {
363 fault(Error::new(
364 ErrorCode::DefaultWritten,
365 FIELD,
366 element.span().start,
367 ))?;
368 }
369 }
370 Ok(parameters)
371}
372
373fn default_hash(parent: &Reader<'_, '_>, identifier: AlgorithmIdentifier<'_>) -> Result<bool> {
374 Ok(
379 oid_is(parent, identifier.algorithm(), SHA1, identifier.offset())?
380 && identifier.has_null_parameter(),
381 )
382}
383
384fn oid_is(parent: &Reader<'_, '_>, left: Oid<'_>, right: Oid<'_>, at: u64) -> Result<bool> {
385 charge(parent, 1, at)?;
386 if left.as_bytes().len() != right.as_bytes().len() {
387 return Ok(false);
388 }
389 charge(parent, left.as_bytes().len() as u64, at)?;
390 Ok(left == right)
391}
392
393fn charge(parent: &Reader<'_, '_>, amount: u64, at: u64) -> Result<()> {
394 parent
395 .charge(amount)
396 .map_err(|error| Error::new(ErrorCode::Encoding(error.code()), FIELD, at))
397}
398
399fn read_mask<'a>(
400 parent: &Reader<'a, '_>,
401 element: Element<'a>,
402 value: Element<'a>,
403) -> Result<(Mask<'a>, bool)> {
404 let algorithm = super::read(parent, &value, "algorithm.pss.mask")?;
405 let function = Written {
406 element,
407 value: algorithm,
408 };
409 if !oid_is(parent, algorithm.algorithm(), MGF1, algorithm.offset())? {
410 return Ok((Mask::Other(function), false));
411 }
412 let execution = parent.execution();
413 let (reader, element) =
414 open_parameter(algorithm, parent, &execution, "algorithm.pss.mask.hash")?.ok_or_else(
415 || {
416 Error::new(
417 ErrorCode::MissingField,
418 "algorithm.pss.mask.hash",
419 algorithm.offset(),
420 )
421 },
422 )?;
423 let hash = super::read(&reader, &element, "algorithm.pss.mask.hash")?;
424 Ok((Mask::Mgf1 { function, hash }, default_hash(&reader, hash)?))
425}