1use crate::{Error, Result};
4#[cfg(feature = "alloc")]
5use der::Any;
6use der::{
7 Decode, DecodeValue, Encode, EncodeValue, FixedTag, Length, Reader, Sequence, Tag, TagMode,
8 TagNumber, Writer,
9 asn1::{AnyRef, ContextSpecificRef, ObjectIdentifier},
10 oid::AssociatedOid,
11};
12use spki::{AlgorithmIdentifier, AlgorithmIdentifierRef, AsAlgorithmIdentifierRef};
13
14const OID_SHA_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26");
15const OID_MGF_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.8");
16const OID_PSPECIFIED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.9");
17
18const SHA_1_AI: AlgorithmIdentifierRef<'_> = AlgorithmIdentifierRef {
19 oid: OID_SHA_1,
20 parameters: Some(AnyRef::NULL),
21};
22
23#[derive(Clone, Debug, Copy, PartialEq, Eq)]
29#[repr(u8)]
30#[derive(Default)]
31pub enum TrailerField {
32 #[default]
34 BC = 1,
35}
36
37impl<'a> DecodeValue<'a> for TrailerField {
38 type Error = der::Error;
39
40 fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
41 match u8::decode_value(reader, header)? {
42 1 => Ok(TrailerField::BC),
43 _ => Err(reader.error(Self::TAG.value_error())),
44 }
45 }
46}
47
48impl EncodeValue for TrailerField {
49 fn value_len(&self) -> der::Result<Length> {
50 Ok(Length::ONE)
51 }
52
53 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
54 (*self as u8).encode_value(writer)
55 }
56}
57
58impl FixedTag for TrailerField {
59 const TAG: Tag = Tag::Integer;
60}
61
62pub type RsaPssParamsRef<'a> = RsaPssParams<AnyRef<'a>>;
64
65#[cfg(feature = "alloc")]
67pub type RsaPssParamsOwned = RsaPssParams<Any>;
68
69#[derive(Clone, Debug, Eq, PartialEq)]
85pub struct RsaPssParams<Params> {
86 pub hash: AlgorithmIdentifier<Params>,
88
89 pub mask_gen: AlgorithmIdentifier<AlgorithmIdentifier<Params>>,
91
92 pub salt_len: u8,
94
95 pub trailer_field: TrailerField,
97}
98
99impl<Params> RsaPssParams<Params> {
100 pub const SALT_LEN_DEFAULT: u8 = 20;
102
103 fn context_specific_salt_len(&self) -> Option<ContextSpecificRef<'_, u8>> {
104 if self.salt_len == Self::SALT_LEN_DEFAULT {
105 None
106 } else {
107 Some(ContextSpecificRef {
108 tag_number: TagNumber(2),
109 tag_mode: TagMode::Explicit,
110 value: &self.salt_len,
111 })
112 }
113 }
114
115 fn context_specific_trailer_field(&self) -> Option<ContextSpecificRef<'_, TrailerField>> {
116 if self.trailer_field == TrailerField::default() {
117 None
118 } else {
119 Some(ContextSpecificRef {
120 tag_number: TagNumber(3),
121 tag_mode: TagMode::Explicit,
122 value: &self.trailer_field,
123 })
124 }
125 }
126}
127
128impl<'a> RsaPssParamsRef<'a> {
129 pub fn new<D>(salt_len: u8) -> Self
131 where
132 D: AssociatedOid,
133 {
134 Self {
135 hash: AlgorithmIdentifierRef {
136 oid: D::OID,
137 parameters: Some(AnyRef::NULL),
138 },
139 mask_gen: AlgorithmIdentifier {
140 oid: OID_MGF_1,
141 parameters: Some(AlgorithmIdentifierRef {
142 oid: D::OID,
143 parameters: Some(AnyRef::NULL),
144 }),
145 },
146 salt_len,
147 trailer_field: Default::default(),
148 }
149 }
150}
151
152impl<Params> RsaPssParams<Params>
153where
154 AlgorithmIdentifier<Params>: AsAlgorithmIdentifierRef,
155 AlgorithmIdentifier<Params>: From<AlgorithmIdentifier<AnyRef<'static>>>,
156 Params: PartialEq,
157{
158 fn context_specific_hash(&self) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<Params>>> {
159 if self.hash.as_algo_ref() == SHA_1_AI {
160 None
161 } else {
162 Some(ContextSpecificRef {
163 tag_number: TagNumber(0),
164 tag_mode: TagMode::Explicit,
165 value: &self.hash,
166 })
167 }
168 }
169
170 fn context_specific_mask_gen(
171 &self,
172 ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<AlgorithmIdentifier<Params>>>> {
173 if self.mask_gen == default_mgf1_sha1::<Params>() {
174 None
175 } else {
176 Some(ContextSpecificRef {
177 tag_number: TagNumber(1),
178 tag_mode: TagMode::Explicit,
179 value: &self.mask_gen,
180 })
181 }
182 }
183}
184
185impl<Params> Default for RsaPssParams<Params>
186where
187 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
188{
189 fn default() -> Self {
190 Self {
191 hash: SHA_1_AI.into(),
192 mask_gen: default_mgf1_sha1(),
193 salt_len: RsaPssParams::<Params>::SALT_LEN_DEFAULT,
194 trailer_field: Default::default(),
195 }
196 }
197}
198
199impl<'a, Params> DecodeValue<'a> for RsaPssParams<Params>
200where
201 AlgorithmIdentifier<Params>: DecodeValue<'a, Error = der::Error> + FixedTag,
202 AlgorithmIdentifier<AlgorithmIdentifier<Params>>:
203 DecodeValue<'a, Error = der::Error> + FixedTag,
204 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
205 Params: 'a,
206{
207 type Error = der::Error;
208
209 fn decode_value<R: Reader<'a>>(reader: &mut R, _header: der::Header) -> der::Result<Self> {
210 Ok(Self {
211 hash: reader
212 .context_specific(TagNumber(0), TagMode::Explicit)?
213 .unwrap_or_else(|| SHA_1_AI.into()),
214 mask_gen: reader
215 .context_specific(TagNumber(1), TagMode::Explicit)?
216 .unwrap_or_else(default_mgf1_sha1),
217 salt_len: reader
218 .context_specific(TagNumber(2), TagMode::Explicit)?
219 .unwrap_or(RsaPssParams::<Params>::SALT_LEN_DEFAULT),
220 trailer_field: reader
221 .context_specific(TagNumber(3), TagMode::Explicit)?
222 .unwrap_or_default(),
223 })
224 }
225}
226
227impl<Params> EncodeValue for RsaPssParams<Params>
228where
229 AlgorithmIdentifier<Params>: AsAlgorithmIdentifierRef,
230 for<'b> Option<ContextSpecificRef<'b, AlgorithmIdentifier<Params>>>: Encode,
231 for<'b> Option<ContextSpecificRef<'b, AlgorithmIdentifier<AlgorithmIdentifier<Params>>>>:
232 Encode,
233 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
234 Params: PartialEq,
235{
236 fn value_len(&self) -> der::Result<Length> {
237 self.context_specific_hash().encoded_len()?
238 + self.context_specific_mask_gen().encoded_len()?
239 + self.context_specific_salt_len().encoded_len()?
240 + self.context_specific_trailer_field().encoded_len()?
241 }
242
243 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
244 self.context_specific_hash().encode(writer)?;
245 self.context_specific_mask_gen().encode(writer)?;
246 self.context_specific_salt_len().encode(writer)?;
247 self.context_specific_trailer_field().encode(writer)?;
248 Ok(())
249 }
250}
251
252impl<'a, Params> Sequence<'a> for RsaPssParams<Params> {}
253
254impl<'a, Params> TryFrom<&'a [u8]> for RsaPssParams<Params>
255where
256 AlgorithmIdentifier<Params>: DecodeValue<'a, Error = der::Error> + FixedTag,
257 AlgorithmIdentifier<AlgorithmIdentifier<Params>>:
258 DecodeValue<'a, Error = der::Error> + FixedTag,
259 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
260 Params: 'a,
261{
262 type Error = Error;
263
264 fn try_from(bytes: &'a [u8]) -> Result<Self> {
265 Ok(Self::from_der(bytes)?)
266 }
267}
268
269fn default_mgf1_sha1<Params>() -> AlgorithmIdentifier<AlgorithmIdentifier<Params>>
271where
272 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
273{
274 AlgorithmIdentifier::<AlgorithmIdentifier<Params>> {
275 oid: OID_MGF_1,
276 parameters: Some(SHA_1_AI.into()),
277 }
278}
279
280pub type RsaOaepParamsRef<'a> = RsaOaepParams<AnyRef<'a>>;
282
283#[cfg(feature = "alloc")]
285pub type RsaOaepParamsOwned = RsaOaepParams<Any>;
286
287#[derive(Clone, Debug, Eq, PartialEq)]
303pub struct RsaOaepParams<Params> {
304 pub hash: AlgorithmIdentifier<Params>,
306
307 pub mask_gen: AlgorithmIdentifier<AlgorithmIdentifier<Params>>,
309
310 pub p_source: AlgorithmIdentifier<Params>,
312}
313
314impl<Params> RsaOaepParams<Params>
315where
316 AlgorithmIdentifier<Params>: AsAlgorithmIdentifierRef,
317{
318 fn context_specific_hash(&self) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<Params>>> {
319 if self.hash.as_algo_ref() == SHA_1_AI {
320 None
321 } else {
322 Some(ContextSpecificRef {
323 tag_number: TagNumber(0),
324 tag_mode: TagMode::Explicit,
325 value: &self.hash,
326 })
327 }
328 }
329
330 fn context_specific_p_source(
331 &self,
332 ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<Params>>> {
333 if self.p_source.as_algo_ref() == default_pempty_string() {
334 None
335 } else {
336 Some(ContextSpecificRef {
337 tag_number: TagNumber(2),
338 tag_mode: TagMode::Explicit,
339 value: &self.p_source,
340 })
341 }
342 }
343}
344
345impl<Params> RsaOaepParams<Params>
346where
347 AlgorithmIdentifier<Params>: AsAlgorithmIdentifierRef,
348 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
349 Params: PartialEq,
350{
351 fn context_specific_mask_gen(
352 &self,
353 ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<AlgorithmIdentifier<Params>>>> {
354 if self.mask_gen == default_mgf1_sha1::<Params>() {
355 None
356 } else {
357 Some(ContextSpecificRef {
358 tag_number: TagNumber(1),
359 tag_mode: TagMode::Explicit,
360 value: &self.mask_gen,
361 })
362 }
363 }
364}
365
366impl<'a> RsaOaepParamsRef<'a> {
367 pub fn new<D>() -> Self
369 where
370 D: AssociatedOid,
371 {
372 Self::new_with_label::<D>(&[])
373 }
374
375 pub fn new_with_label<D>(label: &'a impl AsRef<[u8]>) -> RsaOaepParamsRef<'a>
377 where
378 D: AssociatedOid,
379 {
380 Self {
381 hash: AlgorithmIdentifier {
382 oid: D::OID,
383 parameters: Some(AnyRef::NULL),
384 },
385 mask_gen: AlgorithmIdentifier {
386 oid: OID_MGF_1,
387 parameters: Some(AlgorithmIdentifier {
388 oid: D::OID,
389 parameters: Some(AnyRef::NULL),
390 }),
391 },
392 p_source: pspecified_algorithm_identifier(label),
393 }
394 }
395}
396
397impl<Params> Default for RsaOaepParams<Params>
398where
399 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
400{
401 fn default() -> Self {
402 Self {
403 hash: SHA_1_AI.into(),
404 mask_gen: default_mgf1_sha1(),
405 p_source: default_pempty_string().into(),
406 }
407 }
408}
409
410impl<'a, Params> DecodeValue<'a> for RsaOaepParams<Params>
411where
412 AlgorithmIdentifier<Params>: DecodeValue<'a, Error = der::Error> + FixedTag,
413 AlgorithmIdentifier<AlgorithmIdentifier<Params>>:
414 DecodeValue<'a, Error = der::Error> + FixedTag,
415 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
416 Params: 'a,
417{
418 type Error = der::Error;
419
420 fn decode_value<R: Reader<'a>>(reader: &mut R, _header: der::Header) -> der::Result<Self> {
421 Ok(Self {
422 hash: reader
423 .context_specific(TagNumber(0), TagMode::Explicit)?
424 .unwrap_or_else(|| SHA_1_AI.into()),
425 mask_gen: reader
426 .context_specific(TagNumber(1), TagMode::Explicit)?
427 .unwrap_or_else(default_mgf1_sha1),
428 p_source: reader
429 .context_specific(TagNumber(2), TagMode::Explicit)?
430 .unwrap_or_else(|| default_pempty_string().into()),
431 })
432 }
433}
434
435impl<Params> EncodeValue for RsaOaepParams<Params>
436where
437 AlgorithmIdentifier<Params>: AsAlgorithmIdentifierRef,
438 for<'b> Option<ContextSpecificRef<'b, AlgorithmIdentifier<Params>>>: Encode,
439 for<'b> Option<ContextSpecificRef<'b, AlgorithmIdentifier<AlgorithmIdentifier<Params>>>>:
440 Encode,
441 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
442 Params: PartialEq,
443{
444 fn value_len(&self) -> der::Result<Length> {
445 self.context_specific_hash().encoded_len()?
446 + self.context_specific_mask_gen().encoded_len()?
447 + self.context_specific_p_source().encoded_len()?
448 }
449
450 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
451 self.context_specific_hash().encode(writer)?;
452 self.context_specific_mask_gen().encode(writer)?;
453 self.context_specific_p_source().encode(writer)?;
454 Ok(())
455 }
456}
457
458impl<'a, Params> Sequence<'a> for RsaOaepParams<Params> {}
459
460impl<'a, Params> TryFrom<&'a [u8]> for RsaOaepParams<Params>
461where
462 AlgorithmIdentifier<Params>: DecodeValue<'a, Error = der::Error> + FixedTag,
463 AlgorithmIdentifier<AlgorithmIdentifier<Params>>:
464 DecodeValue<'a, Error = der::Error> + FixedTag,
465 AlgorithmIdentifier<Params>: From<AlgorithmIdentifierRef<'static>>,
466 Params: 'a,
467{
468 type Error = Error;
469
470 fn try_from(bytes: &'a [u8]) -> Result<Self> {
471 Ok(Self::from_der(bytes)?)
472 }
473}
474
475fn pspecified_algorithm_identifier(label: &impl AsRef<[u8]>) -> AlgorithmIdentifierRef<'_> {
476 AlgorithmIdentifierRef {
477 oid: OID_PSPECIFIED,
478 parameters: Some(
479 AnyRef::new(Tag::OctetString, label.as_ref()).expect("error creating OAEP params"),
480 ),
481 }
482}
483
484fn default_pempty_string<'a>() -> AlgorithmIdentifierRef<'a> {
486 pspecified_algorithm_identifier(&[])
487}