1 //! PKCS#1 RSA parameters.
2 
3 use crate::{Error, Result};
4 use der::{
5     asn1::{AnyRef, ContextSpecificRef, ObjectIdentifier},
6     oid::AssociatedOid,
7     Decode, DecodeValue, Encode, EncodeValue, FixedTag, Length, Reader, Sequence, Tag, TagMode,
8     TagNumber, Writer,
9 };
10 use spki::{AlgorithmIdentifier, AlgorithmIdentifierRef};
11 
12 const OID_SHA_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26");
13 const OID_MGF_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.8");
14 const OID_PSPECIFIED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.9");
15 
16 const SHA_1_AI: AlgorithmIdentifierRef<'_> = AlgorithmIdentifierRef {
17     oid: OID_SHA_1,
18     parameters: Some(AnyRef::NULL),
19 };
20 
21 /// `TrailerField` as defined in [RFC 8017 Appendix 2.3].
22 /// ```text
23 /// TrailerField ::= INTEGER { trailerFieldBC(1) }
24 /// ```
25 /// [RFC 8017 Appendix 2.3]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3
26 #[derive(Clone, Debug, Copy, PartialEq, Eq)]
27 #[repr(u8)]
28 pub enum TrailerField {
29     /// the only supported value (0xbc, default)
30     BC = 1,
31 }
32 
33 impl Default for TrailerField {
default() -> Self34     fn default() -> Self {
35         Self::BC
36     }
37 }
38 
39 impl<'a> DecodeValue<'a> for TrailerField {
decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self>40     fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
41         match u8::decode_value(decoder, header)? {
42             1 => Ok(TrailerField::BC),
43             _ => Err(Self::TAG.value_error()),
44         }
45     }
46 }
47 
48 impl EncodeValue for TrailerField {
value_len(&self) -> der::Result<Length>49     fn value_len(&self) -> der::Result<Length> {
50         Ok(Length::ONE)
51     }
52 
encode_value(&self, writer: &mut impl Writer) -> der::Result<()>53     fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
54         (*self as u8).encode_value(writer)
55     }
56 }
57 
58 impl FixedTag for TrailerField {
59     const TAG: Tag = Tag::Integer;
60 }
61 
62 /// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3]
63 ///
64 /// ASN.1 structure containing a serialized RSASSA-PSS parameters:
65 /// ```text
66 /// RSASSA-PSS-params ::= SEQUENCE {
67 ///     hashAlgorithm      [0] HashAlgorithm      DEFAULT sha1,
68 ///     maskGenAlgorithm   [1] MaskGenAlgorithm   DEFAULT mgf1SHA1,
69 ///     saltLength         [2] INTEGER            DEFAULT 20,
70 ///     trailerField       [3] TrailerField       DEFAULT trailerFieldBC
71 /// }
72 /// HashAlgorithm ::= AlgorithmIdentifier
73 /// MaskGenAlgorithm ::= AlgorithmIdentifier
74 /// ```
75 ///
76 /// [RFC 8017 Appendix 2.3]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3
77 #[derive(Clone, Debug, Eq, PartialEq)]
78 pub struct RsaPssParams<'a> {
79     /// Hash Algorithm
80     pub hash: AlgorithmIdentifierRef<'a>,
81 
82     /// Mask Generation Function (MGF)
83     pub mask_gen: AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>,
84 
85     /// Salt length
86     pub salt_len: u8,
87 
88     /// Trailer field (i.e. [`TrailerField::BC`])
89     pub trailer_field: TrailerField,
90 }
91 
92 impl<'a> RsaPssParams<'a> {
93     /// Default RSA PSS Salt length in RsaPssParams
94     pub const SALT_LEN_DEFAULT: u8 = 20;
95 
96     /// Create new RsaPssParams for the provided digest and salt len
new<D>(salt_len: u8) -> Self where D: AssociatedOid,97     pub fn new<D>(salt_len: u8) -> Self
98     where
99         D: AssociatedOid,
100     {
101         Self {
102             hash: AlgorithmIdentifierRef {
103                 oid: D::OID,
104                 parameters: Some(AnyRef::NULL),
105             },
106             mask_gen: AlgorithmIdentifier {
107                 oid: OID_MGF_1,
108                 parameters: Some(AlgorithmIdentifierRef {
109                     oid: D::OID,
110                     parameters: Some(AnyRef::NULL),
111                 }),
112             },
113             salt_len,
114             trailer_field: Default::default(),
115         }
116     }
117 
context_specific_hash(&self) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>>118     fn context_specific_hash(&self) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>> {
119         if self.hash == SHA_1_AI {
120             None
121         } else {
122             Some(ContextSpecificRef {
123                 tag_number: TagNumber::N0,
124                 tag_mode: TagMode::Explicit,
125                 value: &self.hash,
126             })
127         }
128     }
129 
context_specific_mask_gen( &self, ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>>>130     fn context_specific_mask_gen(
131         &self,
132     ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>>> {
133         if self.mask_gen == default_mgf1_sha1() {
134             None
135         } else {
136             Some(ContextSpecificRef {
137                 tag_number: TagNumber::N1,
138                 tag_mode: TagMode::Explicit,
139                 value: &self.mask_gen,
140             })
141         }
142     }
143 
context_specific_salt_len(&self) -> Option<ContextSpecificRef<'_, u8>>144     fn context_specific_salt_len(&self) -> Option<ContextSpecificRef<'_, u8>> {
145         if self.salt_len == RsaPssParams::SALT_LEN_DEFAULT {
146             None
147         } else {
148             Some(ContextSpecificRef {
149                 tag_number: TagNumber::N2,
150                 tag_mode: TagMode::Explicit,
151                 value: &self.salt_len,
152             })
153         }
154     }
155 
context_specific_trailer_field(&self) -> Option<ContextSpecificRef<'_, TrailerField>>156     fn context_specific_trailer_field(&self) -> Option<ContextSpecificRef<'_, TrailerField>> {
157         if self.trailer_field == TrailerField::default() {
158             None
159         } else {
160             Some(ContextSpecificRef {
161                 tag_number: TagNumber::N3,
162                 tag_mode: TagMode::Explicit,
163                 value: &self.trailer_field,
164             })
165         }
166     }
167 }
168 
169 impl<'a> Default for RsaPssParams<'a> {
default() -> Self170     fn default() -> Self {
171         Self {
172             hash: SHA_1_AI,
173             mask_gen: default_mgf1_sha1(),
174             salt_len: RsaPssParams::SALT_LEN_DEFAULT,
175             trailer_field: Default::default(),
176         }
177     }
178 }
179 
180 impl<'a> DecodeValue<'a> for RsaPssParams<'a> {
decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self>181     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
182         reader.read_nested(header.length, |reader| {
183             Ok(Self {
184                 hash: reader
185                     .context_specific(TagNumber::N0, TagMode::Explicit)?
186                     .unwrap_or(SHA_1_AI),
187                 mask_gen: reader
188                     .context_specific(TagNumber::N1, TagMode::Explicit)?
189                     .unwrap_or_else(default_mgf1_sha1),
190                 salt_len: reader
191                     .context_specific(TagNumber::N2, TagMode::Explicit)?
192                     .unwrap_or(RsaPssParams::SALT_LEN_DEFAULT),
193                 trailer_field: reader
194                     .context_specific(TagNumber::N3, TagMode::Explicit)?
195                     .unwrap_or_default(),
196             })
197         })
198     }
199 }
200 
201 impl EncodeValue for RsaPssParams<'_> {
value_len(&self) -> der::Result<Length>202     fn value_len(&self) -> der::Result<Length> {
203         self.context_specific_hash().encoded_len()?
204             + self.context_specific_mask_gen().encoded_len()?
205             + self.context_specific_salt_len().encoded_len()?
206             + self.context_specific_trailer_field().encoded_len()?
207     }
208 
encode_value(&self, writer: &mut impl Writer) -> der::Result<()>209     fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
210         self.context_specific_hash().encode(writer)?;
211         self.context_specific_mask_gen().encode(writer)?;
212         self.context_specific_salt_len().encode(writer)?;
213         self.context_specific_trailer_field().encode(writer)?;
214         Ok(())
215     }
216 }
217 
218 impl<'a> Sequence<'a> for RsaPssParams<'a> {}
219 
220 impl<'a> TryFrom<&'a [u8]> for RsaPssParams<'a> {
221     type Error = Error;
222 
try_from(bytes: &'a [u8]) -> Result<Self>223     fn try_from(bytes: &'a [u8]) -> Result<Self> {
224         Ok(Self::from_der(bytes)?)
225     }
226 }
227 
228 /// Default Mask Generation Function (MGF): SHA-1.
default_mgf1_sha1<'a>() -> AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>229 fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier<AlgorithmIdentifierRef<'a>> {
230     AlgorithmIdentifier::<AlgorithmIdentifierRef<'a>> {
231         oid: OID_MGF_1,
232         parameters: Some(SHA_1_AI),
233     }
234 }
235 
236 /// PKCS#1 RSAES-OAEP parameters as defined in [RFC 8017 Appendix 2.1]
237 ///
238 /// ASN.1 structure containing a serialized RSAES-OAEP parameters:
239 /// ```text
240 /// RSAES-OAEP-params ::= SEQUENCE {
241 ///     hashAlgorithm      [0] HashAlgorithm     DEFAULT sha1,
242 ///     maskGenAlgorithm   [1] MaskGenAlgorithm  DEFAULT mgf1SHA1,
243 ///     pSourceAlgorithm   [2] PSourceAlgorithm  DEFAULT pSpecifiedEmpty
244 /// }
245 /// HashAlgorithm ::= AlgorithmIdentifier
246 /// MaskGenAlgorithm ::= AlgorithmIdentifier
247 /// PSourceAlgorithm ::= AlgorithmIdentifier
248 /// ```
249 ///
250 /// [RFC 8017 Appendix 2.1]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.1
251 #[derive(Clone, Debug, Eq, PartialEq)]
252 pub struct RsaOaepParams<'a> {
253     /// Hash Algorithm
254     pub hash: AlgorithmIdentifierRef<'a>,
255 
256     /// Mask Generation Function (MGF)
257     pub mask_gen: AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>,
258 
259     /// The source (and possibly the value) of the label L
260     pub p_source: AlgorithmIdentifierRef<'a>,
261 }
262 
263 impl<'a> RsaOaepParams<'a> {
264     /// Create new RsaPssParams for the provided digest and default (empty) label
new<D>() -> Self where D: AssociatedOid,265     pub fn new<D>() -> Self
266     where
267         D: AssociatedOid,
268     {
269         Self::new_with_label::<D>(&[])
270     }
271 
272     /// Create new RsaPssParams for the provided digest and specified label
new_with_label<D>(label: &'a impl AsRef<[u8]>) -> Self where D: AssociatedOid,273     pub fn new_with_label<D>(label: &'a impl AsRef<[u8]>) -> Self
274     where
275         D: AssociatedOid,
276     {
277         Self {
278             hash: AlgorithmIdentifierRef {
279                 oid: D::OID,
280                 parameters: Some(AnyRef::NULL),
281             },
282             mask_gen: AlgorithmIdentifier {
283                 oid: OID_MGF_1,
284                 parameters: Some(AlgorithmIdentifierRef {
285                     oid: D::OID,
286                     parameters: Some(AnyRef::NULL),
287                 }),
288             },
289             p_source: pspecicied_algorithm_identifier(label),
290         }
291     }
292 
context_specific_hash(&self) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>>293     fn context_specific_hash(&self) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>> {
294         if self.hash == SHA_1_AI {
295             None
296         } else {
297             Some(ContextSpecificRef {
298                 tag_number: TagNumber::N0,
299                 tag_mode: TagMode::Explicit,
300                 value: &self.hash,
301             })
302         }
303     }
304 
context_specific_mask_gen( &self, ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>>>305     fn context_specific_mask_gen(
306         &self,
307     ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>>> {
308         if self.mask_gen == default_mgf1_sha1() {
309             None
310         } else {
311             Some(ContextSpecificRef {
312                 tag_number: TagNumber::N1,
313                 tag_mode: TagMode::Explicit,
314                 value: &self.mask_gen,
315             })
316         }
317     }
318 
context_specific_p_source( &self, ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>>319     fn context_specific_p_source(
320         &self,
321     ) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>> {
322         if self.p_source == default_pempty_string() {
323             None
324         } else {
325             Some(ContextSpecificRef {
326                 tag_number: TagNumber::N2,
327                 tag_mode: TagMode::Explicit,
328                 value: &self.p_source,
329             })
330         }
331     }
332 }
333 
334 impl<'a> Default for RsaOaepParams<'a> {
default() -> Self335     fn default() -> Self {
336         Self {
337             hash: SHA_1_AI,
338             mask_gen: default_mgf1_sha1(),
339             p_source: default_pempty_string(),
340         }
341     }
342 }
343 
344 impl<'a> DecodeValue<'a> for RsaOaepParams<'a> {
decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self>345     fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
346         reader.read_nested(header.length, |reader| {
347             Ok(Self {
348                 hash: reader
349                     .context_specific(TagNumber::N0, TagMode::Explicit)?
350                     .unwrap_or(SHA_1_AI),
351                 mask_gen: reader
352                     .context_specific(TagNumber::N1, TagMode::Explicit)?
353                     .unwrap_or_else(default_mgf1_sha1),
354                 p_source: reader
355                     .context_specific(TagNumber::N2, TagMode::Explicit)?
356                     .unwrap_or_else(default_pempty_string),
357             })
358         })
359     }
360 }
361 
362 impl EncodeValue for RsaOaepParams<'_> {
value_len(&self) -> der::Result<Length>363     fn value_len(&self) -> der::Result<Length> {
364         self.context_specific_hash().encoded_len()?
365             + self.context_specific_mask_gen().encoded_len()?
366             + self.context_specific_p_source().encoded_len()?
367     }
368 
encode_value(&self, writer: &mut impl Writer) -> der::Result<()>369     fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
370         self.context_specific_hash().encode(writer)?;
371         self.context_specific_mask_gen().encode(writer)?;
372         self.context_specific_p_source().encode(writer)?;
373         Ok(())
374     }
375 }
376 
377 impl<'a> Sequence<'a> for RsaOaepParams<'a> {}
378 
379 impl<'a> TryFrom<&'a [u8]> for RsaOaepParams<'a> {
380     type Error = Error;
381 
try_from(bytes: &'a [u8]) -> Result<Self>382     fn try_from(bytes: &'a [u8]) -> Result<Self> {
383         Ok(Self::from_der(bytes)?)
384     }
385 }
386 
pspecicied_algorithm_identifier(label: &impl AsRef<[u8]>) -> AlgorithmIdentifierRef<'_>387 fn pspecicied_algorithm_identifier(label: &impl AsRef<[u8]>) -> AlgorithmIdentifierRef<'_> {
388     AlgorithmIdentifierRef {
389         oid: OID_PSPECIFIED,
390         parameters: Some(
391             AnyRef::new(Tag::OctetString, label.as_ref()).expect("error creating OAEP params"),
392         ),
393     }
394 }
395 
396 /// Default Source Algorithm, empty string
default_pempty_string<'a>() -> AlgorithmIdentifierRef<'a>397 fn default_pempty_string<'a>() -> AlgorithmIdentifierRef<'a> {
398     pspecicied_algorithm_identifier(&[])
399 }
400