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