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