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