1 //! X.509 `AlgorithmIdentifier`
2 
3 use crate::{Error, Result};
4 use core::cmp::Ordering;
5 use der::{
6     asn1::{AnyRef, Choice, ObjectIdentifier},
7     Decode, DecodeValue, DerOrd, Encode, EncodeValue, Header, Length, Reader, Sequence, ValueOrd,
8     Writer,
9 };
10 
11 #[cfg(feature = "alloc")]
12 use der::asn1::Any;
13 
14 /// X.509 `AlgorithmIdentifier` as defined in [RFC 5280 Section 4.1.1.2].
15 ///
16 /// ```text
17 /// AlgorithmIdentifier  ::=  SEQUENCE  {
18 ///      algorithm               OBJECT IDENTIFIER,
19 ///      parameters              ANY DEFINED BY algorithm OPTIONAL  }
20 /// ```
21 ///
22 /// [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2
23 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
24 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
25 pub struct AlgorithmIdentifier<Params> {
26     /// Algorithm OID, i.e. the `algorithm` field in the `AlgorithmIdentifier`
27     /// ASN.1 schema.
28     pub oid: ObjectIdentifier,
29 
30     /// Algorithm `parameters`.
31     pub parameters: Option<Params>,
32 }
33 
34 impl<'a, Params> DecodeValue<'a> for AlgorithmIdentifier<Params>
35 where
36     Params: Choice<'a>,
37 {
decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self>38     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
39         reader.read_nested(header.length, |reader| {
40             Ok(Self {
41                 oid: reader.decode()?,
42                 parameters: reader.decode()?,
43             })
44         })
45     }
46 }
47 
48 impl<Params> EncodeValue for AlgorithmIdentifier<Params>
49 where
50     Params: Encode,
51 {
value_len(&self) -> der::Result<Length>52     fn value_len(&self) -> der::Result<Length> {
53         self.oid.encoded_len()? + self.parameters.encoded_len()?
54     }
55 
encode_value(&self, writer: &mut impl Writer) -> der::Result<()>56     fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
57         self.oid.encode(writer)?;
58         self.parameters.encode(writer)?;
59         Ok(())
60     }
61 }
62 
63 impl<'a, Params> Sequence<'a> for AlgorithmIdentifier<Params> where Params: Choice<'a> + Encode {}
64 
65 impl<'a, Params> TryFrom<&'a [u8]> for AlgorithmIdentifier<Params>
66 where
67     Params: Choice<'a> + Encode,
68 {
69     type Error = Error;
70 
try_from(bytes: &'a [u8]) -> Result<Self>71     fn try_from(bytes: &'a [u8]) -> Result<Self> {
72         Ok(Self::from_der(bytes)?)
73     }
74 }
75 
76 impl<Params> ValueOrd for AlgorithmIdentifier<Params>
77 where
78     Params: DerOrd,
79 {
value_cmp(&self, other: &Self) -> der::Result<Ordering>80     fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
81         match self.oid.der_cmp(&other.oid)? {
82             Ordering::Equal => self.parameters.der_cmp(&other.parameters),
83             other => Ok(other),
84         }
85     }
86 }
87 
88 /// `AlgorithmIdentifier` reference which has `AnyRef` parameters.
89 pub type AlgorithmIdentifierRef<'a> = AlgorithmIdentifier<AnyRef<'a>>;
90 
91 /// `AlgorithmIdentifier` with `ObjectIdentifier` parameters.
92 pub type AlgorithmIdentifierWithOid = AlgorithmIdentifier<ObjectIdentifier>;
93 
94 /// `AlgorithmIdentifier` reference which has `Any` parameters.
95 #[cfg(feature = "alloc")]
96 pub type AlgorithmIdentifierOwned = AlgorithmIdentifier<Any>;
97 
98 impl<Params> AlgorithmIdentifier<Params> {
99     /// Assert the `algorithm` OID is an expected value.
assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier>100     pub fn assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier> {
101         if self.oid == expected_oid {
102             Ok(expected_oid)
103         } else {
104             Err(Error::OidUnknown { oid: expected_oid })
105         }
106     }
107 }
108 
109 impl<'a> AlgorithmIdentifierRef<'a> {
110     /// Assert `parameters` is an OID and has the expected value.
assert_parameters_oid( &self, expected_oid: ObjectIdentifier, ) -> Result<ObjectIdentifier>111     pub fn assert_parameters_oid(
112         &self,
113         expected_oid: ObjectIdentifier,
114     ) -> Result<ObjectIdentifier> {
115         let actual_oid = self.parameters_oid()?;
116 
117         if actual_oid == expected_oid {
118             Ok(actual_oid)
119         } else {
120             Err(Error::OidUnknown { oid: expected_oid })
121         }
122     }
123 
124     /// Assert the values of the `algorithm` and `parameters` OIDs.
assert_oids( &self, algorithm: ObjectIdentifier, parameters: ObjectIdentifier, ) -> Result<()>125     pub fn assert_oids(
126         &self,
127         algorithm: ObjectIdentifier,
128         parameters: ObjectIdentifier,
129     ) -> Result<()> {
130         self.assert_algorithm_oid(algorithm)?;
131         self.assert_parameters_oid(parameters)?;
132         Ok(())
133     }
134 
135     /// Get the `parameters` field as an [`AnyRef`].
136     ///
137     /// Returns an error if `parameters` are `None`.
parameters_any(&self) -> Result<AnyRef<'a>>138     pub fn parameters_any(&self) -> Result<AnyRef<'a>> {
139         self.parameters.ok_or(Error::AlgorithmParametersMissing)
140     }
141 
142     /// Get the `parameters` field as an [`ObjectIdentifier`].
143     ///
144     /// Returns an error if it is absent or not an OID.
parameters_oid(&self) -> Result<ObjectIdentifier>145     pub fn parameters_oid(&self) -> Result<ObjectIdentifier> {
146         Ok(ObjectIdentifier::try_from(self.parameters_any()?)?)
147     }
148 
149     /// Convert to a pair of [`ObjectIdentifier`]s.
150     ///
151     /// This method is helpful for decomposing in match statements. Note in
152     /// particular that `NULL` parameters are treated the same as missing
153     /// parameters.
154     ///
155     /// Returns an error if parameters are present but not an OID.
oids(&self) -> der::Result<(ObjectIdentifier, Option<ObjectIdentifier>)>156     pub fn oids(&self) -> der::Result<(ObjectIdentifier, Option<ObjectIdentifier>)> {
157         Ok((
158             self.oid,
159             match self.parameters {
160                 None => None,
161                 Some(p) => match p {
162                     AnyRef::NULL => None,
163                     _ => Some(p.decode_as::<ObjectIdentifier>()?),
164                 },
165             },
166         ))
167     }
168 }
169 
170 #[cfg(feature = "alloc")]
171 mod allocating {
172     use super::*;
173     use der::referenced::*;
174 
175     impl<'a> RefToOwned<'a> for AlgorithmIdentifierRef<'a> {
176         type Owned = AlgorithmIdentifierOwned;
ref_to_owned(&self) -> Self::Owned177         fn ref_to_owned(&self) -> Self::Owned {
178             AlgorithmIdentifier {
179                 oid: self.oid,
180                 parameters: self.parameters.ref_to_owned(),
181             }
182         }
183     }
184 
185     impl OwnedToRef for AlgorithmIdentifierOwned {
186         type Borrowed<'a> = AlgorithmIdentifierRef<'a>;
owned_to_ref(&self) -> Self::Borrowed<'_>187         fn owned_to_ref(&self) -> Self::Borrowed<'_> {
188             AlgorithmIdentifier {
189                 oid: self.oid,
190                 parameters: self.parameters.owned_to_ref(),
191             }
192         }
193     }
194 }
195