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