• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! X.509 `AlgorithmIdentifier`
2 
3 use crate::{Error, Result};
4 use core::cmp::Ordering;
5 use der::asn1::{AnyRef, ObjectIdentifier};
6 use der::{Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd};
7 
8 /// X.509 `AlgorithmIdentifier` as defined in [RFC 5280 Section 4.1.1.2].
9 ///
10 /// ```text
11 /// AlgorithmIdentifier  ::=  SEQUENCE  {
12 ///      algorithm               OBJECT IDENTIFIER,
13 ///      parameters              ANY DEFINED BY algorithm OPTIONAL  }
14 /// ```
15 ///
16 /// [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2
17 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
18 pub struct AlgorithmIdentifier<'a> {
19     /// Algorithm OID, i.e. the `algorithm` field in the `AlgorithmIdentifier`
20     /// ASN.1 schema.
21     pub oid: ObjectIdentifier,
22 
23     /// Algorithm `parameters`.
24     pub parameters: Option<AnyRef<'a>>,
25 }
26 
27 impl<'a> AlgorithmIdentifier<'a> {
28     /// Assert the `algorithm` OID is an expected value.
assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier>29     pub fn assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier> {
30         if self.oid == expected_oid {
31             Ok(expected_oid)
32         } else {
33             Err(Error::OidUnknown { oid: expected_oid })
34         }
35     }
36 
37     /// Assert `parameters` is an OID and has the expected value.
assert_parameters_oid( &self, expected_oid: ObjectIdentifier, ) -> Result<ObjectIdentifier>38     pub fn assert_parameters_oid(
39         &self,
40         expected_oid: ObjectIdentifier,
41     ) -> Result<ObjectIdentifier> {
42         let actual_oid = self.parameters_oid()?;
43 
44         if actual_oid == expected_oid {
45             Ok(actual_oid)
46         } else {
47             Err(Error::OidUnknown { oid: expected_oid })
48         }
49     }
50 
51     /// Assert the values of the `algorithm` and `parameters` OIDs.
assert_oids( &self, algorithm: ObjectIdentifier, parameters: ObjectIdentifier, ) -> Result<()>52     pub fn assert_oids(
53         &self,
54         algorithm: ObjectIdentifier,
55         parameters: ObjectIdentifier,
56     ) -> Result<()> {
57         self.assert_algorithm_oid(algorithm)?;
58         self.assert_parameters_oid(parameters)?;
59         Ok(())
60     }
61 
62     /// Get the `parameters` field as an [`AnyRef`].
63     ///
64     /// Returns an error if `parameters` are `None`.
parameters_any(&self) -> Result<AnyRef<'a>>65     pub fn parameters_any(&self) -> Result<AnyRef<'a>> {
66         self.parameters.ok_or(Error::AlgorithmParametersMissing)
67     }
68 
69     /// Get the `parameters` field as an [`ObjectIdentifier`].
70     ///
71     /// Returns an error if it is absent or not an OID.
parameters_oid(&self) -> Result<ObjectIdentifier>72     pub fn parameters_oid(&self) -> Result<ObjectIdentifier> {
73         Ok(ObjectIdentifier::try_from(self.parameters_any()?)?)
74     }
75 
76     /// Convert to a pair of [`ObjectIdentifier`]s.
77     ///
78     /// This method is helpful for decomposing in match statements. Note in
79     /// particular that `NULL` parameters are treated the same as missing
80     /// parameters.
81     ///
82     /// Returns an error if parameters are present but not an OID.
oids(&self) -> der::Result<(ObjectIdentifier, Option<ObjectIdentifier>)>83     pub fn oids(&self) -> der::Result<(ObjectIdentifier, Option<ObjectIdentifier>)> {
84         Ok((
85             self.oid,
86             match self.parameters {
87                 None => None,
88                 Some(p) => match p {
89                     AnyRef::NULL => None,
90                     _ => Some(p.oid()?),
91                 },
92             },
93         ))
94     }
95 }
96 
97 impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> {
decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self>98     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
99         reader.read_nested(header.length, |reader| {
100             Ok(Self {
101                 oid: reader.decode()?,
102                 parameters: reader.decode()?,
103             })
104         })
105     }
106 }
107 
108 impl<'a> Sequence<'a> for AlgorithmIdentifier<'a> {
fields<F, T>(&self, f: F) -> der::Result<T> where F: FnOnce(&[&dyn Encode]) -> der::Result<T>,109     fn fields<F, T>(&self, f: F) -> der::Result<T>
110     where
111         F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
112     {
113         f(&[&self.oid, &self.parameters])
114     }
115 }
116 
117 impl<'a> TryFrom<&'a [u8]> for AlgorithmIdentifier<'a> {
118     type Error = Error;
119 
try_from(bytes: &'a [u8]) -> Result<Self>120     fn try_from(bytes: &'a [u8]) -> Result<Self> {
121         Ok(Self::from_der(bytes)?)
122     }
123 }
124 
125 impl ValueOrd for AlgorithmIdentifier<'_> {
value_cmp(&self, other: &Self) -> der::Result<Ordering>126     fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
127         match self.oid.der_cmp(&other.oid)? {
128             Ordering::Equal => self.parameters.der_cmp(&other.parameters),
129             other => Ok(other),
130         }
131     }
132 }
133