Skip to main content

spki/
algorithm.rs

1//! X.509 `AlgorithmIdentifier`
2
3use crate::{Error, Result};
4use core::cmp::Ordering;
5use der::{
6    Decode, DecodeValue, DerOrd, Encode, EncodeValue, Header, Length, Reader, Sequence, ValueOrd,
7    Writer,
8    asn1::{AnyRef, Choice, ObjectIdentifier},
9};
10
11#[cfg(feature = "alloc")]
12use 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, Hash, PartialEq, PartialOrd, Ord)]
25pub 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
34impl<'a, Params> DecodeValue<'a> for AlgorithmIdentifier<Params>
35where
36    Params: Choice<'a, Error = der::Error>,
37{
38    type Error = der::Error;
39
40    fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
41        Ok(Self {
42            oid: reader.decode()?,
43            parameters: reader.decode()?,
44        })
45    }
46}
47
48impl<Params> EncodeValue for AlgorithmIdentifier<Params>
49where
50    Params: Encode,
51{
52    fn value_len(&self) -> der::Result<Length> {
53        self.oid.encoded_len()? + self.parameters.encoded_len()?
54    }
55
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
63impl<'a, Params> Sequence<'a> for AlgorithmIdentifier<Params> where
64    Params: Choice<'a, Error = der::Error> + Encode
65{
66}
67
68impl<'a, Params> TryFrom<&'a [u8]> for AlgorithmIdentifier<Params>
69where
70    Params: Choice<'a, Error = der::Error> + Encode,
71{
72    type Error = Error;
73
74    fn try_from(bytes: &'a [u8]) -> Result<Self> {
75        Ok(Self::from_der(bytes)?)
76    }
77}
78
79impl<Params> ValueOrd for AlgorithmIdentifier<Params>
80where
81    Params: DerOrd,
82{
83    fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
84        match self.oid.der_cmp(&other.oid)? {
85            Ordering::Equal => self.parameters.der_cmp(&other.parameters),
86            other => Ok(other),
87        }
88    }
89}
90
91/// `AlgorithmIdentifier` reference which has `AnyRef` parameters.
92pub type AlgorithmIdentifierRef<'a> = AlgorithmIdentifier<AnyRef<'a>>;
93
94/// `AlgorithmIdentifier` with `ObjectIdentifier` parameters.
95pub type AlgorithmIdentifierWithOid = AlgorithmIdentifier<ObjectIdentifier>;
96
97/// `AlgorithmIdentifier` reference which has `Any` parameters.
98#[cfg(feature = "alloc")]
99pub type AlgorithmIdentifierOwned = AlgorithmIdentifier<Any>;
100
101impl<Params> AlgorithmIdentifier<Params> {
102    /// Assert the `algorithm` OID is an expected value.
103    ///
104    /// # Errors
105    /// Returns [`Error::OidUnknown`] if `self` does not match `expected_oid`.
106    pub fn assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier> {
107        if self.oid == expected_oid {
108            Ok(expected_oid)
109        } else {
110            Err(Error::OidUnknown { oid: self.oid })
111        }
112    }
113}
114
115impl<'a> AlgorithmIdentifierRef<'a> {
116    /// Assert `parameters` is an OID and has the expected value.
117    ///
118    /// # Errors
119    /// Returns [`Error::OidUnknown`] if `self.parameters_oid()` doesn't match `expected_oid`.
120    pub fn assert_parameters_oid(
121        &self,
122        expected_oid: ObjectIdentifier,
123    ) -> Result<ObjectIdentifier> {
124        let actual_oid = self.parameters_oid()?;
125
126        if actual_oid == expected_oid {
127            Ok(actual_oid)
128        } else {
129            Err(Error::OidUnknown { oid: actual_oid })
130        }
131    }
132
133    /// Assert the values of the `algorithm` and `parameters` OIDs.
134    ///
135    /// # Errors
136    /// Returns [`Error::OidUnknown`] if `algorithm` and/or `parameters` aren't the expected values.
137    pub fn assert_oids(
138        &self,
139        algorithm: ObjectIdentifier,
140        parameters: ObjectIdentifier,
141    ) -> Result<()> {
142        self.assert_algorithm_oid(algorithm)?;
143        self.assert_parameters_oid(parameters)?;
144        Ok(())
145    }
146
147    /// Get the `parameters` field as an [`AnyRef`].
148    ///
149    /// # Errors
150    /// Returns [`Error::AlgorithmParametersMissing`] error if `self.parameters` are `None`.
151    pub fn parameters_any(&self) -> Result<AnyRef<'a>> {
152        self.parameters.ok_or(Error::AlgorithmParametersMissing)
153    }
154
155    /// Get the `parameters` field as an [`ObjectIdentifier`].
156    ///
157    /// # Errors
158    /// - Returns [`Error::AlgorithmParametersMissing`] error if `self.parameters` are `None`.
159    /// - Returns [`Error::Asn1`] if `self.parameters` is not an OID.
160    pub fn parameters_oid(&self) -> Result<ObjectIdentifier> {
161        Ok(ObjectIdentifier::try_from(self.parameters_any()?)?)
162    }
163
164    /// Convert to a pair of [`ObjectIdentifier`]s.
165    ///
166    /// This method is helpful for decomposing in match statements. Note in
167    /// particular that `NULL` parameters are treated the same as missing
168    /// parameters.
169    ///
170    /// # Errors
171    /// Returns an error if parameters are present but not an OID.
172    pub fn oids(&self) -> der::Result<(ObjectIdentifier, Option<ObjectIdentifier>)> {
173        Ok((
174            self.oid,
175            match self.parameters {
176                None => None,
177                Some(p) => {
178                    if p.is_null() {
179                        None
180                    } else {
181                        Some(p.decode_as::<ObjectIdentifier>()?)
182                    }
183                }
184            },
185        ))
186    }
187}
188
189#[cfg(feature = "alloc")]
190mod allocating {
191    use super::*;
192    use der::referenced::*;
193
194    impl<'a> RefToOwned<'a> for AlgorithmIdentifierRef<'a> {
195        type Owned = AlgorithmIdentifierOwned;
196        fn ref_to_owned(&self) -> Self::Owned {
197            AlgorithmIdentifier {
198                oid: self.oid,
199                parameters: self.parameters.ref_to_owned(),
200            }
201        }
202    }
203
204    impl OwnedToRef for AlgorithmIdentifierOwned {
205        type Borrowed<'a> = AlgorithmIdentifierRef<'a>;
206        fn owned_to_ref(&self) -> Self::Borrowed<'_> {
207            AlgorithmIdentifier {
208                oid: self.oid,
209                parameters: self.parameters.owned_to_ref(),
210            }
211        }
212    }
213}