1use crate::algorithm::{self, AlgorithmIdentifier};
8use crate::error::{Error, ErrorCode, Located, Result};
9use structured_asn1::memory::Work;
10use structured_asn1::{BitString, Element, Oid, Reader, Tag, universal};
11
12pub mod dsa;
13pub mod ec;
14pub mod rsa;
15
16#[derive(Debug, Clone, Copy)]
18pub struct PublicKeyInfo<'a> {
19 algorithm: AlgorithmIdentifier<'a>,
20 key: BitString<'a>,
21 der: &'a [u8],
22 key_offset: u64,
24}
25
26impl<'a> PublicKeyInfo<'a> {
27 #[must_use]
29 pub fn algorithm(self) -> AlgorithmIdentifier<'a> {
30 self.algorithm
31 }
32
33 #[must_use]
35 pub fn key(self) -> BitString<'a> {
36 self.key
37 }
38
39 #[must_use]
42 pub fn key_octets(self) -> Option<&'a [u8]> {
43 self.key.octets()
44 }
45
46 #[must_use]
48 pub fn key_offset(self) -> u64 {
49 self.key_offset
50 }
51
52 pub(crate) fn whole_octets(self, field: &'static str) -> Result<&'a [u8]> {
54 self.key_octets()
55 .ok_or_else(|| Error::new(ErrorCode::MalformedValue, field, self.key_offset))
56 }
57
58 #[must_use]
64 pub fn as_bytes(self) -> &'a [u8] {
65 self.der
66 }
67 pub fn read_element(
78 parent: &Reader<'a>,
79 element: &Element<'a>,
80 field: &'static str,
81 ) -> Result<PublicKeyInfo<'a>> {
82 let fail = |code| Error::new(code, field, element.span().start);
83
84 if element.tag() != Tag::constructed(universal::SEQUENCE) {
85 return Err(fail(ErrorCode::Encoding(
86 structured_asn1::ErrorCode::UnexpectedTag,
87 )));
88 }
89
90 let mut inside = parent.enter(element).field(field)?;
91 let algorithm_element = inside
92 .next_element()
93 .field(field)?
94 .ok_or_else(|| fail(ErrorCode::MissingField))?;
95 let algorithm = algorithm::read(&inside, &algorithm_element, field)?;
96 let key_element = inside
97 .expect(Tag::primitive(universal::BIT_STRING))
98 .field(field)?;
99 let key = inside.bit_string(&key_element).field(field)?;
100
101 if !inside.is_empty() {
102 return Err(fail(ErrorCode::TrailingData));
103 }
104
105 Ok(PublicKeyInfo {
106 algorithm,
107 key,
108 der: element.as_bytes(),
109 key_offset: key_element.contents_span().start + 1,
111 })
112 }
113}
114
115pub(crate) fn same_oid<W: Work>(
117 left: Oid<'_>,
118 right: Oid<'_>,
119 execution: &W,
120 field: &'static str,
121 at: u64,
122) -> Result<bool> {
123 let charge = |amount| {
124 execution
125 .charge_work(amount)
126 .map_err(|reason| Error::resource(reason, field, at))
127 };
128 charge(1)?;
129 if left.as_bytes().len() != right.as_bytes().len() {
130 return Ok(false);
131 }
132 charge(left.as_bytes().len() as u64)?;
133 Ok(left == right)
134}
135
136#[cfg(test)]
137mod tests;