1use std::{convert::TryFrom, str::FromStr};
6use thiserror::Error;
7use tpm2_protocol::data::TpmHt;
8
9#[derive(Debug, Error)]
10pub enum HandleError {
11 #[error("invalid handle")]
12 InvalidHandle,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum HandleClass {
18 Tpm,
19 Vtpm,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct Handle(pub (HandleClass, u32));
25
26impl Handle {
27 #[must_use]
29 pub fn class(&self) -> HandleClass {
30 self.0 .0
31 }
32
33 #[must_use]
35 pub fn value(&self) -> u32 {
36 self.0 .1
37 }
38}
39
40impl std::fmt::Display for Handle {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 let value = self.value();
43 match self.class() {
44 HandleClass::Tpm => write!(f, "tpm:{value:08x}"),
45 HandleClass::Vtpm => write!(f, "vtpm:{value:08x}"),
46 }
47 }
48}
49
50impl FromStr for Handle {
51 type Err = HandleError;
52
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 let (scheme_str, value_str) = s.split_once(':').ok_or(HandleError::InvalidHandle)?;
55
56 let class = match scheme_str {
57 "tpm" => HandleClass::Tpm,
58 "vtpm" => HandleClass::Vtpm,
59 _ => return Err(HandleError::InvalidHandle),
60 };
61
62 let value = u32::from_str_radix(value_str, 16).map_err(|_| HandleError::InvalidHandle)?;
63
64 Ok(Handle((class, value)))
65 }
66}
67
68impl TryFrom<Handle> for TpmHt {
69 type Error = HandleError;
70
71 fn try_from(handle: Handle) -> Result<Self, Self::Error> {
72 let raw_handle = handle.value();
73 let ht_byte = (raw_handle >> 24) as u8;
74 TpmHt::try_from(ht_byte).map_err(|()| HandleError::InvalidHandle)
75 }
76}
77
78#[derive(Debug, Error, PartialEq, Eq)]
79pub enum HandlePatternError {
80 #[error("handle pattern is not a valid hex string")]
81 InvalidHexString,
82 #[error("handle pattern has less than eight characters")]
83 TooFewDigits,
84 #[error("handle pattern has more than one '*'")]
85 TooManyAsterisks,
86 #[error("handle pattern has more than eight characters")]
87 TooManyDigits,
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub struct HandlePattern(u32, u32);
99
100impl HandlePattern {
101 pub fn new(query: &str) -> Result<Self, HandlePatternError> {
107 if query == "*" {
108 return Ok(Self(0, 0));
109 }
110
111 let mut mask: u32 = 0;
112 let mut value: u32 = 0;
113
114 let (prefix, suffix) = if let Some((p, s)) = query.split_once('*') {
115 if s.contains('*') {
116 return Err(HandlePatternError::TooManyAsterisks);
117 }
118 if p.len() + s.len() > 8 {
119 return Err(HandlePatternError::TooManyDigits);
120 }
121 (p, s)
122 } else {
123 if query.len() < 8 {
124 return Err(HandlePatternError::TooFewDigits);
125 }
126 if query.len() > 8 {
127 return Err(HandlePatternError::TooManyDigits);
128 }
129 (query, "")
130 };
131
132 for (i, c) in prefix.chars().enumerate() {
133 let shift = (7 - i) * 4;
134 match c.to_digit(16) {
135 Some(v) => {
136 mask |= 0xF << shift;
137 value |= v << shift;
138 }
139 None if c == '?' => {}
140 None => return Err(HandlePatternError::InvalidHexString),
141 }
142 }
143
144 for (i, c) in suffix.chars().rev().enumerate() {
145 let shift = i * 4;
146 match c.to_digit(16) {
147 Some(v) => {
148 mask |= 0xF << shift;
149 value |= v << shift;
150 }
151 None if c == '?' => {}
152 None => return Err(HandlePatternError::InvalidHexString),
153 }
154 }
155
156 Ok(Self(mask, value))
157 }
158
159 #[must_use]
161 pub fn matches(&self, handle: u32) -> bool {
162 if self.0 == 0 && self.1 == 0 {
163 return true;
164 }
165 (handle & self.0) == self.1
166 }
167}