1use crate::algorithm::{self, AlgorithmIdentifier};
9use crate::error::{Error, ErrorCode, Located, Result};
10use structured_asn1::memory::Work;
11use structured_asn1::{BitString, Element, Oid, ScopedReader, Tag, universal};
12
13pub mod dsa;
14pub mod dstu4145;
15pub mod ec;
16pub mod effective;
17pub mod ml_dsa;
18pub mod rfc8410;
19pub mod rsa;
20
21#[derive(Debug, Clone, Copy)]
23pub struct PublicKeyInfo<'a> {
24 algorithm: AlgorithmIdentifier<'a>,
25 key: BitString<'a>,
26 der: &'a [u8],
27 key_offset: u64,
29}
30
31impl<'a> PublicKeyInfo<'a> {
32 pub fn execution_in<'operation, W: structured_asn1::memory::Work>(
35 &self,
36 work: &'operation W,
37 ) -> structured_asn1::memory::Execution<'operation>
38 where
39 'a: 'operation,
40 {
41 self.algorithm.query_in(work)
42 }
43
44 #[must_use]
46 pub fn algorithm(self) -> AlgorithmIdentifier<'a> {
47 self.algorithm
48 }
49
50 #[must_use]
52 pub fn key(self) -> BitString<'a> {
53 self.key
54 }
55
56 #[must_use]
59 pub fn key_octets(self) -> Option<&'a [u8]> {
60 self.key.octets()
61 }
62
63 #[must_use]
65 pub fn key_offset(self) -> u64 {
66 self.key_offset
67 }
68
69 pub(crate) fn whole_octets(self, field: &'static str) -> Result<&'a [u8]> {
71 self.key_octets()
72 .ok_or_else(|| Error::new(ErrorCode::MalformedValue, field, self.key_offset))
73 }
74
75 #[must_use]
81 pub fn as_bytes(self) -> &'a [u8] {
82 self.der
83 }
84 pub fn read_element(
95 parent: &ScopedReader<'a, '_>,
96 element: &Element<'a>,
97 field: &'static str,
98 ) -> Result<PublicKeyInfo<'a>> {
99 let fail = |code| Error::new(code, field, element.span().start);
100
101 if element.tag() != Tag::constructed(universal::SEQUENCE) {
102 return Err(fail(ErrorCode::Encoding(
103 structured_asn1::ErrorCode::UnexpectedTag,
104 )));
105 }
106
107 let mut inside = parent.enter(element).field(field)?;
108 let algorithm_element = inside
109 .next_element()
110 .field(field)?
111 .ok_or_else(|| fail(ErrorCode::MissingField))?;
112 let algorithm = algorithm::read(&inside, &algorithm_element, field)?;
113 let key_element = inside
114 .expect(Tag::primitive(universal::BIT_STRING))
115 .field(field)?;
116 let key = inside.bit_string(&key_element).field(field)?;
117
118 if !inside.is_empty() {
119 return Err(fail(ErrorCode::TrailingData));
120 }
121
122 Ok(PublicKeyInfo {
123 algorithm,
124 key,
125 der: element.as_bytes(),
126 key_offset: key_element.contents_span().start + 1,
128 })
129 }
130}
131
132pub(crate) fn same_oid<W: Work>(
134 left: Oid<'_>,
135 right: Oid<'_>,
136 execution: &W,
137 field: &'static str,
138 at: u64,
139) -> Result<bool> {
140 let charge = |amount| {
141 execution
142 .charge_work(amount)
143 .map_err(|reason| Error::resource(reason, field, at))
144 };
145 charge(1)?;
146 if left.as_bytes().len() != right.as_bytes().len() {
147 return Ok(false);
148 }
149 charge(left.as_bytes().len() as u64)?;
150 Ok(left == right)
151}
152
153#[cfg(test)]
154mod tests;