signstar_yubihsm2/object/
id.rs1use std::{
4 fmt::Display,
5 num::{NonZeroU16, NonZeroUsize},
6 str::FromStr,
7};
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11use yubihsm::object::{Handle, Type};
12
13#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
23#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
24#[cfg_attr(feature = "serde", serde(into = "u16", try_from = "NonZeroU16"))]
25pub struct Id(NonZeroU16);
26
27impl Id {
28 pub fn new(num: NonZeroU16) -> Result<Self, crate::Error> {
30 if num.get() > 256 {
31 return Err(crate::object::Error::InvalidId {
32 reason: "an ID must be a number between 1-256".to_string(),
33 id: num.to_string(),
34 }
35 .into());
36 }
37
38 Ok(Self(num))
39 }
40
41 pub fn get(&self) -> NonZeroU16 {
43 self.0
44 }
45}
46
47impl AsRef<NonZeroU16> for Id {
48 fn as_ref(&self) -> &NonZeroU16 {
49 &self.0
50 }
51}
52
53impl Display for Id {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 self.get().fmt(f)
56 }
57}
58
59impl TryFrom<u16> for Id {
60 type Error = crate::Error;
61
62 fn try_from(value: u16) -> Result<Self, Self::Error> {
63 Self::new(
64 NonZeroU16::new(value).ok_or(crate::object::Error::InvalidId {
65 reason: "it must not be 0".to_string(),
66 id: value.to_string(),
67 })?,
68 )
69 }
70}
71
72impl TryFrom<NonZeroU16> for Id {
73 type Error = crate::Error;
74
75 fn try_from(value: NonZeroU16) -> Result<Self, Self::Error> {
76 Self::new(value)
77 }
78}
79
80impl TryFrom<NonZeroUsize> for Id {
81 type Error = crate::Error;
82
83 fn try_from(value: NonZeroUsize) -> Result<Self, Self::Error> {
84 Self::try_from(NonZeroU16::try_from(value).map_err(|source| {
85 crate::object::Error::InvalidId {
86 reason: source.to_string(),
87 id: value.to_string(),
88 }
89 })?)
90 }
91}
92
93impl TryFrom<usize> for Id {
94 type Error = crate::Error;
95
96 fn try_from(value: usize) -> Result<Self, Self::Error> {
97 Self::try_from(NonZeroUsize::try_from(value).map_err(|source| {
98 crate::object::Error::InvalidId {
99 reason: source.to_string(),
100 id: value.to_string(),
101 }
102 })?)
103 }
104}
105
106impl FromStr for Id {
107 type Err = crate::Error;
108
109 fn from_str(s: &str) -> Result<Self, Self::Err> {
110 Self::new(
111 NonZeroU16::from_str(s).map_err(|source| crate::object::Error::InvalidId {
112 reason: source.to_string(),
113 id: s.to_string(),
114 })?,
115 )
116 }
117}
118
119impl From<&Id> for u16 {
120 fn from(value: &Id) -> Self {
121 value.get().get()
122 }
123}
124
125impl From<Id> for u16 {
126 fn from(value: Id) -> Self {
127 value.get().get()
128 }
129}
130
131#[derive(Debug)]
137#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
138#[cfg_attr(
139 feature = "serde",
140 serde(tag = "object_type", content = "object_id", rename_all = "kebab-case")
141)]
142pub enum ObjectId {
143 AsymmetricKey(Id),
145
146 AuthenticationKey(Id),
148
149 WrappingKey(Id),
151
152 Opaque(Id),
154
155 Hmac(Id),
157
158 Template(Id),
160
161 Otp(Id),
163}
164
165impl ObjectId {
166 pub fn id(&self) -> Id {
168 match self {
169 ObjectId::AsymmetricKey(id) => *id,
170 ObjectId::AuthenticationKey(id) => *id,
171 ObjectId::WrappingKey(id) => *id,
172 ObjectId::Opaque(id) => *id,
173 ObjectId::Hmac(id) => *id,
174 ObjectId::Template(id) => *id,
175 ObjectId::Otp(id) => *id,
176 }
177 }
178
179 pub fn object_type(&self) -> Type {
181 match self {
182 ObjectId::AsymmetricKey(_) => Type::AsymmetricKey,
183 ObjectId::AuthenticationKey(_) => Type::AuthenticationKey,
184 ObjectId::WrappingKey(_) => Type::WrapKey,
185 ObjectId::Opaque(_) => Type::Opaque,
186 ObjectId::Hmac(_) => Type::HmacKey,
187 ObjectId::Template(_) => Type::Template,
188 ObjectId::Otp(_) => Type::OtpAeadKey,
189 }
190 }
191}
192
193impl TryFrom<Handle> for ObjectId {
194 type Error = crate::Error;
195
196 fn try_from(value: Handle) -> Result<Self, Self::Error> {
197 let id = Id::try_from(value.object_id)?;
198
199 Ok(match value.object_type {
200 Type::Opaque => ObjectId::Opaque(id),
201 Type::AuthenticationKey => ObjectId::AuthenticationKey(id),
202 Type::AsymmetricKey => ObjectId::AsymmetricKey(id),
203 Type::WrapKey => ObjectId::WrappingKey(id),
204 Type::HmacKey => ObjectId::Hmac(id),
205 Type::Template => ObjectId::Template(id),
206 Type::OtpAeadKey => ObjectId::Otp(id),
207 })
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use rstest::rstest;
214
215 use super::*;
216
217 #[test]
218 fn id_new_too_large() {
219 assert!(Id::new(NonZeroU16::new(257u16).unwrap()).is_err());
220 }
221
222 #[test]
223 fn id_from_str_too_large() {
224 assert!(Id::from_str("257").is_err());
225 }
226
227 #[test]
228 fn id_try_from_str_invalid_nonzero_u16() {
229 assert!(Id::from_str("foo").is_err());
230 }
231
232 #[test]
233 fn id_try_from_non_zero_usize_too_large() {
234 assert!(Id::try_from(NonZeroUsize::new(257).unwrap()).is_err());
235 }
236
237 #[test]
238 fn id_try_from_non_zero_usize_invalid_non_zero_u16() {
239 assert!(Id::try_from(NonZeroUsize::new(65536).unwrap()).is_err());
240 }
241
242 #[rstest]
243 #[case::zero(0usize)]
244 #[case::too_large(257usize)]
245 fn id_from_usize_fails(#[case] input: usize) {
246 assert!(Id::try_from(input).is_err());
247 }
248}