1use crate::{Error, Result};
4use core::cmp::Ordering;
5use 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")]
12use der::asn1::Any;
13
14#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
24#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
25pub struct AlgorithmIdentifier<Params> {
26    pub oid: ObjectIdentifier,
29
30    pub parameters: Option<Params>,
32}
33
34impl<'a, Params> DecodeValue<'a> for AlgorithmIdentifier<Params>
35where
36    Params: Choice<'a>,
37{
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
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 Params: Choice<'a> + Encode {}
64
65impl<'a, Params> TryFrom<&'a [u8]> for AlgorithmIdentifier<Params>
66where
67    Params: Choice<'a> + Encode,
68{
69    type Error = Error;
70
71    fn try_from(bytes: &'a [u8]) -> Result<Self> {
72        Ok(Self::from_der(bytes)?)
73    }
74}
75
76impl<Params> ValueOrd for AlgorithmIdentifier<Params>
77where
78    Params: DerOrd,
79{
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
88pub type AlgorithmIdentifierRef<'a> = AlgorithmIdentifier<AnyRef<'a>>;
90
91pub type AlgorithmIdentifierWithOid = AlgorithmIdentifier<ObjectIdentifier>;
93
94#[cfg(feature = "alloc")]
96pub type AlgorithmIdentifierOwned = AlgorithmIdentifier<Any>;
97
98impl<Params> AlgorithmIdentifier<Params> {
99    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
109impl<'a> AlgorithmIdentifierRef<'a> {
110    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    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    pub fn parameters_any(&self) -> Result<AnyRef<'a>> {
139        self.parameters.ok_or(Error::AlgorithmParametersMissing)
140    }
141
142    pub fn parameters_oid(&self) -> Result<ObjectIdentifier> {
146        Ok(ObjectIdentifier::try_from(self.parameters_any()?)?)
147    }
148
149    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")]
171mod allocating {
172    use super::*;
173    use der::referenced::*;
174
175    impl<'a> RefToOwned<'a> for AlgorithmIdentifierRef<'a> {
176        type Owned = AlgorithmIdentifierOwned;
177        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>;
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}