darkbio_crypto/cwt/claims/
mod.rs1pub mod eat;
12
13use crate::cbor::{
14 self, Cbor, Decode, Encode, MapDecode, MapEncode, MapEncodeBuffer, MapEntryAccess,
15};
16use crate::cose;
17use crate::xdsa;
18use crate::xhpke;
19
20#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
22pub struct Issuer {
23 #[cbor(key = 1)]
25 pub iss: String,
26}
27
28#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
30pub struct Subject {
31 #[cbor(key = 2)]
33 pub sub: String,
34}
35
36#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
38pub struct Audience {
39 #[cbor(key = 3)]
41 pub aud: String,
42}
43
44#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
46pub struct Expiration {
47 #[cbor(key = 4)]
49 pub exp: u64,
50}
51
52#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
54pub struct NotBefore {
55 #[cbor(key = 5)]
57 pub nbf: u64,
58}
59
60#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
62pub struct IssuedAt {
63 #[cbor(key = 6)]
65 pub iat: u64,
66}
67
68#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
70pub struct TokenId {
71 #[cbor(key = 7)]
73 pub cti: Vec<u8>,
74}
75
76mod sealed {
79 use crate::cbor;
80
81 pub trait ConfirmKeySealed {
82 const ALGORITHM: i64;
83 fn to_confirm_bytes(&self) -> Vec<u8>;
84 fn from_confirm_bytes(bytes: &[u8]) -> Result<Self, cbor::Error>
85 where
86 Self: Sized;
87 }
88}
89
90pub trait ConfirmKey: sealed::ConfirmKeySealed + Clone + std::fmt::Debug {}
94
95impl sealed::ConfirmKeySealed for xdsa::PublicKey {
96 const ALGORITHM: i64 = cose::ALGORITHM_ID_XDSA;
97
98 fn to_confirm_bytes(&self) -> Vec<u8> {
99 self.to_bytes().to_vec()
100 }
101
102 fn from_confirm_bytes(bytes: &[u8]) -> Result<Self, cbor::Error> {
103 let arr: [u8; xdsa::PUBLIC_KEY_SIZE] = bytes.try_into().map_err(|_| {
104 cbor::Error::DecodeFailed(format!(
105 "cnf: unexpected key size {}, want {}",
106 bytes.len(),
107 xdsa::PUBLIC_KEY_SIZE,
108 ))
109 })?;
110 xdsa::PublicKey::from_bytes(&arr).map_err(|e| cbor::Error::DecodeFailed(e.to_string()))
111 }
112}
113
114impl ConfirmKey for xdsa::PublicKey {}
115
116impl sealed::ConfirmKeySealed for xhpke::PublicKey {
117 const ALGORITHM: i64 = cose::ALGORITHM_ID_XHPKE;
118
119 fn to_confirm_bytes(&self) -> Vec<u8> {
120 self.to_bytes().to_vec()
121 }
122
123 fn from_confirm_bytes(bytes: &[u8]) -> Result<Self, cbor::Error> {
124 let arr: [u8; xhpke::PUBLIC_KEY_SIZE] = bytes.try_into().map_err(|_| {
125 cbor::Error::DecodeFailed(format!(
126 "cnf: unexpected key size {}, want {}",
127 bytes.len(),
128 xhpke::PUBLIC_KEY_SIZE,
129 ))
130 })?;
131 xhpke::PublicKey::from_bytes(&arr).map_err(|e| cbor::Error::DecodeFailed(e.to_string()))
132 }
133}
134
135impl ConfirmKey for xhpke::PublicKey {}
136
137#[derive(Clone, Debug)]
144pub struct Confirm<T: ConfirmKey> {
145 key: T,
146}
147
148impl<T: ConfirmKey> Confirm<T> {
149 pub fn new(key: T) -> Self {
151 Self { key }
152 }
153
154 pub fn key(&self) -> &T {
156 &self.key
157 }
158}
159
160#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
162struct CnfMap {
163 #[cbor(key = 1)]
164 cose_key: CoseKey,
165}
166
167#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
170struct CoseKey {
171 #[cbor(key = 1)]
172 kty: i64,
173 #[cbor(key = -2)]
174 x: Vec<u8>,
175}
176
177impl<T: ConfirmKey> Encode for Confirm<T> {
178 fn encode_cbor_to(&self, buf: &mut Vec<u8>) -> Result<(), cbor::Error> {
179 let mut enc = MapEncodeBuffer::new(1);
180 <Self as MapEncode>::encode_map(self, &mut enc)?;
181 enc.finish_to(buf)
182 }
183}
184
185impl<T: ConfirmKey> Decode for Confirm<T> {
186 fn decode_cbor(data: &[u8]) -> Result<Self, cbor::Error> {
187 let mut dec = cbor::Decoder::new(data);
188 let result = Self::decode_cbor_notrail(&mut dec)?;
189 dec.finish()?;
190 Ok(result)
191 }
192
193 fn decode_cbor_notrail(dec: &mut cbor::Decoder<'_>) -> Result<Self, cbor::Error> {
194 let entries = cbor::decode_map_entries_slices_notrail(dec)?;
195 let mut remaining = cbor::MapEntries::new(entries);
196 let value = <Self as MapDecode>::decode_map(&mut remaining)?;
197 if !remaining.is_empty() {
198 let unknown: Vec<i64> = remaining.remaining_keys();
199 return Err(cbor::Error::DecodeFailed(format!(
200 "unknown CBOR map keys: {unknown:?}"
201 )));
202 }
203 Ok(value)
204 }
205}
206
207impl<T: ConfirmKey> MapEncode for Confirm<T> {
208 fn encode_map(&self, enc: &mut MapEncodeBuffer) -> Result<(), cbor::Error> {
209 let cnf = CnfMap {
210 cose_key: CoseKey {
211 kty: T::ALGORITHM,
212 x: self.key.to_confirm_bytes(),
213 },
214 };
215 enc.push(8, &cnf)
216 }
217}
218
219impl<T: ConfirmKey> MapDecode for Confirm<T> {
220 fn cbor_map_keys() -> &'static [i64] {
221 &[8]
222 }
223
224 fn decode_map<'a, E: MapEntryAccess<'a>>(entries: &mut E) -> Result<Self, cbor::Error> {
225 let raw = entries.take(8).ok_or(cbor::Error::DecodeFailed(
226 "missing required key 8 (cnf)".into(),
227 ))?;
228 let cnf = CnfMap::decode_cbor(raw)?;
229
230 if cnf.cose_key.kty != T::ALGORITHM {
232 return Err(cbor::Error::DecodeFailed(format!(
233 "cnf: unexpected key type {}, want {}",
234 cnf.cose_key.kty,
235 T::ALGORITHM,
236 )));
237 }
238 let key = T::from_confirm_bytes(&cnf.cose_key.x)?;
239 Ok(Self { key })
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 #[test]
249 fn test_confirm_xdsa() {
250 let key = xdsa::SecretKey::generate().public_key();
251
252 #[derive(Debug, Cbor)]
253 struct Token {
254 #[cbor(embed)]
255 cnf: Confirm<xdsa::PublicKey>,
256 }
257 let orig = Token {
258 cnf: Confirm::new(key.clone()),
259 };
260 let data = cbor::encode(&orig).expect("encode");
261 let got = Token::decode_cbor(&data).expect("decode");
262
263 assert_eq!(got.cnf.key().to_bytes(), key.to_bytes());
264 }
265
266 #[test]
268 fn test_confirm_xhpke() {
269 let key = xhpke::SecretKey::generate().public_key();
270
271 #[derive(Debug, Cbor)]
272 struct Token {
273 #[cbor(embed)]
274 cnf: Confirm<xhpke::PublicKey>,
275 }
276 let orig = Token {
277 cnf: Confirm::new(key.clone()),
278 };
279 let data = cbor::encode(&orig).expect("encode");
280 let got = Token::decode_cbor(&data).expect("decode");
281
282 assert_eq!(got.cnf.key().to_bytes(), key.to_bytes());
283 }
284
285 #[test]
287 fn test_composite_claims() {
288 let key = xdsa::SecretKey::generate().public_key();
289
290 #[derive(Debug, Cbor)]
291 struct DeviceCert {
292 #[cbor(embed)]
293 sub: Subject,
294 #[cbor(embed)]
295 exp: Expiration,
296 #[cbor(embed)]
297 nbf: NotBefore,
298 #[cbor(embed)]
299 cnf: Confirm<xdsa::PublicKey>,
300 #[cbor(key = 256)]
301 ueid: Vec<u8>,
302 }
303 let orig = DeviceCert {
304 sub: Subject {
305 sub: "device-abc-123".into(),
306 },
307 exp: Expiration { exp: 1000000 },
308 nbf: NotBefore { nbf: 100 },
309 cnf: Confirm::new(key.clone()),
310 ueid: b"SN-12345".to_vec(),
311 };
312 let data = cbor::encode(&orig).expect("encode");
313 let got = DeviceCert::decode_cbor(&data).expect("decode");
314
315 assert_eq!(got.sub.sub, "device-abc-123");
316 assert_eq!(got.exp.exp, 1000000);
317 assert_eq!(got.nbf.nbf, 100);
318 assert_eq!(got.cnf.key().to_bytes(), key.to_bytes());
319 assert_eq!(got.ueid, b"SN-12345");
320 }
321
322 #[test]
324 fn test_confirm_wrong_key_type() {
325 let key = xdsa::SecretKey::generate().public_key();
326
327 #[derive(Debug, Cbor)]
328 struct XdsaToken {
329 #[cbor(embed)]
330 cnf: Confirm<xdsa::PublicKey>,
331 }
332 #[derive(Debug, Cbor)]
333 struct XhpkeToken {
334 #[cbor(embed)]
335 cnf: Confirm<xhpke::PublicKey>,
336 }
337 let orig = XdsaToken {
338 cnf: Confirm::new(key),
339 };
340 let data = cbor::encode(&orig).expect("encode");
341
342 let err = XhpkeToken::decode_cbor(&data).expect_err("should fail with wrong key type");
344 let msg = err.to_string();
345 assert!(
346 msg.contains("unexpected key type"),
347 "expected key type error, got: {msg}"
348 );
349 }
350}