1use crate::Bytes;
2use bitflags::bitflags;
3use cosey::EcdhEsHkdf256PublicKey;
4use serde_indexed::{DeserializeIndexed, SerializeIndexed};
5use serde_repr::{Deserialize_repr, Serialize_repr};
6
7#[derive(Clone, Debug, Eq, PartialEq, Serialize_repr, Deserialize_repr)]
8#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
9#[non_exhaustive]
10#[repr(u8)]
11pub enum PinV1Subcommand {
12 GetRetries = 0x01,
13 GetKeyAgreement = 0x02,
14 SetPin = 0x03,
15 ChangePin = 0x04,
16 GetPinToken = 0x05,
17 GetPinUvAuthTokenUsingUvWithPermissions = 0x06,
18 GetUVRetries = 0x07,
19 GetPinUvAuthTokenUsingPinWithPermissions = 0x09,
20}
21
22bitflags! {
23 #[derive(Default)]
24 pub struct Permissions: u8 {
25 const MAKE_CREDENTIAL = 0x01;
26 const GET_ASSERTION = 0x02;
27 const CREDENTIAL_MANAGEMENT = 0x04;
28 const BIO_ENROLLMENT = 0x08;
29 const LARGE_BLOB_WRITE = 0x10;
30 const AUTHENTICATOR_CONFIGURATION = 0x20;
31 }
32}
33
34#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
39#[non_exhaustive]
40#[serde_indexed(offset = 1)]
41pub struct Request<'a> {
42 pub pin_protocol: u8,
46
47 pub sub_command: PinV1Subcommand,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
55 pub key_agreement: Option<EcdhEsHkdf256PublicKey>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
61 pub pin_auth: Option<&'a serde_bytes::Bytes>,
62
63 #[serde(skip_serializing_if = "Option::is_none")]
67 pub new_pin_enc: Option<&'a serde_bytes::Bytes>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
72 pub pin_hash_enc: Option<&'a serde_bytes::Bytes>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub(crate) _placeholder07: Option<()>,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub(crate) _placeholder08: Option<()>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
85 pub permissions: Option<u8>,
86
87 #[serde(skip_serializing_if = "Option::is_none")]
90 pub rp_id: Option<&'a str>,
91}
92
93#[derive(Clone, Debug, Default, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
94#[non_exhaustive]
95#[serde_indexed(offset = 1)]
96pub struct Response {
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub key_agreement: Option<EcdhEsHkdf256PublicKey>,
100
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub pin_token: Option<Bytes<48>>,
104
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub retries: Option<u8>,
108
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub power_cycle_state: Option<bool>,
112
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub uv_retries: Option<u8>,
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use hex_literal::hex;
122 use serde_test::{assert_de_tokens, assert_ser_tokens, assert_tokens, Token};
123
124 const KEY_AGREEMENT: &[u8] = &hex!("b174bc49c7ca254b70d2e5c207cee9cf174820ebd77ea3c65508c26da51b657c1cc6b952f8621697936482da0a6d3d3826a59095daf6cd7c03e2e60385d2f6d9");
125 const NEW_PIN_ENC: &[u8] = &[0xde; 64];
126 const PIN_AUTH: &[u8] = &[0xad; 32];
127 const PIN_HASH_ENC: &[u8] = &[0xda; 16];
128 const PIN_TOKEN: &[u8] = &[0xed; 32];
129
130 #[test]
131 fn test_de_request_get_retries() {
132 let request = Request {
133 pin_protocol: 1,
134 sub_command: PinV1Subcommand::GetRetries,
135 key_agreement: None,
136 pin_auth: None,
137 new_pin_enc: None,
138 pin_hash_enc: None,
139 _placeholder07: None,
140 _placeholder08: None,
141 permissions: None,
142 rp_id: None,
143 };
144 assert_tokens(
145 &request,
146 &[
147 Token::Map { len: Some(2) },
148 Token::U64(0x01),
150 Token::U8(1),
151 Token::U64(0x02),
153 Token::U8(0x01),
154 Token::MapEnd,
155 ],
156 );
157 }
158
159 #[test]
160 fn test_de_request_get_key_agreement() {
161 let request = Request {
162 pin_protocol: 1,
163 sub_command: PinV1Subcommand::GetKeyAgreement,
164 key_agreement: None,
165 pin_auth: None,
166 new_pin_enc: None,
167 pin_hash_enc: None,
168 _placeholder07: None,
169 _placeholder08: None,
170 permissions: None,
171 rp_id: None,
172 };
173 assert_tokens(
174 &request,
175 &[
176 Token::Map { len: Some(2) },
177 Token::U64(0x01),
179 Token::U8(1),
180 Token::U64(0x02),
182 Token::U8(0x02),
183 Token::MapEnd,
184 ],
185 );
186 }
187
188 #[test]
189 fn test_de_request_set_pin() {
190 let key_agreement = EcdhEsHkdf256PublicKey {
191 x: Bytes::from_slice(&KEY_AGREEMENT[..32]).unwrap(),
192 y: Bytes::from_slice(&KEY_AGREEMENT[32..]).unwrap(),
193 };
194 let request = Request {
195 pin_protocol: 1,
196 sub_command: PinV1Subcommand::SetPin,
197 key_agreement: Some(key_agreement),
198 pin_auth: Some(serde_bytes::Bytes::new(PIN_AUTH)),
199 new_pin_enc: Some(serde_bytes::Bytes::new(NEW_PIN_ENC)),
200 pin_hash_enc: None,
201 _placeholder07: None,
202 _placeholder08: None,
203 permissions: None,
204 rp_id: None,
205 };
206 assert_de_tokens(
207 &request,
208 &[
209 Token::Map { len: Some(5) },
210 Token::U64(0x01),
212 Token::U8(1),
213 Token::U64(0x02),
215 Token::U8(0x03),
216 Token::U64(0x03),
218 Token::Map { len: Some(5) },
219 Token::I8(1),
221 Token::I8(2),
222 Token::I8(3),
224 Token::I8(-25),
225 Token::I8(-1),
227 Token::I8(1),
228 Token::I8(-2),
230 Token::BorrowedBytes(&KEY_AGREEMENT[..32]),
231 Token::I8(-3),
233 Token::BorrowedBytes(&KEY_AGREEMENT[32..]),
234 Token::MapEnd,
235 Token::U64(0x04),
237 Token::BorrowedBytes(PIN_AUTH),
238 Token::U64(0x05),
240 Token::BorrowedBytes(NEW_PIN_ENC),
241 Token::MapEnd,
242 ],
243 );
244 }
245
246 #[test]
247 fn test_de_request_change_pin() {
248 let key_agreement = EcdhEsHkdf256PublicKey {
249 x: Bytes::from_slice(&KEY_AGREEMENT[..32]).unwrap(),
250 y: Bytes::from_slice(&KEY_AGREEMENT[32..]).unwrap(),
251 };
252 let request = Request {
253 pin_protocol: 1,
254 sub_command: PinV1Subcommand::ChangePin,
255 key_agreement: Some(key_agreement),
256 pin_auth: Some(serde_bytes::Bytes::new(PIN_AUTH)),
257 new_pin_enc: Some(serde_bytes::Bytes::new(NEW_PIN_ENC)),
258 pin_hash_enc: Some(serde_bytes::Bytes::new(PIN_HASH_ENC)),
259 _placeholder07: None,
260 _placeholder08: None,
261 permissions: None,
262 rp_id: None,
263 };
264 assert_de_tokens(
265 &request,
266 &[
267 Token::Map { len: Some(6) },
268 Token::U64(0x01),
270 Token::U8(1),
271 Token::U64(0x02),
273 Token::U8(0x04),
274 Token::U64(0x03),
276 Token::Map { len: Some(5) },
277 Token::I8(1),
279 Token::I8(2),
280 Token::I8(3),
282 Token::I8(-25),
283 Token::I8(-1),
285 Token::I8(1),
286 Token::I8(-2),
288 Token::BorrowedBytes(&KEY_AGREEMENT[..32]),
289 Token::I8(-3),
291 Token::BorrowedBytes(&KEY_AGREEMENT[32..]),
292 Token::MapEnd,
293 Token::U64(0x04),
295 Token::BorrowedBytes(PIN_AUTH),
296 Token::U64(0x05),
298 Token::BorrowedBytes(NEW_PIN_ENC),
299 Token::U64(0x06),
301 Token::BorrowedBytes(PIN_HASH_ENC),
302 Token::MapEnd,
303 ],
304 );
305 }
306
307 #[test]
308 fn test_de_get_pin_token() {
309 let key_agreement = EcdhEsHkdf256PublicKey {
310 x: Bytes::from_slice(&KEY_AGREEMENT[..32]).unwrap(),
311 y: Bytes::from_slice(&KEY_AGREEMENT[32..]).unwrap(),
312 };
313 let request = Request {
314 pin_protocol: 1,
315 sub_command: PinV1Subcommand::GetPinToken,
316 key_agreement: Some(key_agreement),
317 pin_auth: None,
318 new_pin_enc: None,
319 pin_hash_enc: Some(serde_bytes::Bytes::new(PIN_HASH_ENC)),
320 _placeholder07: None,
321 _placeholder08: None,
322 permissions: None,
323 rp_id: None,
324 };
325 assert_de_tokens(
326 &request,
327 &[
328 Token::Map { len: Some(4) },
329 Token::U64(0x01),
331 Token::U8(1),
332 Token::U64(0x02),
334 Token::U8(0x05),
335 Token::U64(0x03),
337 Token::Map { len: Some(5) },
338 Token::I8(1),
340 Token::I8(2),
341 Token::I8(3),
343 Token::I8(-25),
344 Token::I8(-1),
346 Token::I8(1),
347 Token::I8(-2),
349 Token::BorrowedBytes(&KEY_AGREEMENT[..32]),
350 Token::I8(-3),
352 Token::BorrowedBytes(&KEY_AGREEMENT[32..]),
353 Token::MapEnd,
354 Token::U64(0x06),
356 Token::BorrowedBytes(PIN_HASH_ENC),
357 Token::MapEnd,
358 ],
359 );
360 }
361
362 #[test]
363 fn test_de_get_pin_token_with_permissions() {
364 let key_agreement = EcdhEsHkdf256PublicKey {
365 x: Bytes::from_slice(&KEY_AGREEMENT[..32]).unwrap(),
366 y: Bytes::from_slice(&KEY_AGREEMENT[32..]).unwrap(),
367 };
368 let request = Request {
369 pin_protocol: 1,
370 sub_command: PinV1Subcommand::GetPinUvAuthTokenUsingPinWithPermissions,
371 key_agreement: Some(key_agreement),
372 pin_auth: None,
373 new_pin_enc: None,
374 pin_hash_enc: Some(serde_bytes::Bytes::new(PIN_HASH_ENC)),
375 _placeholder07: None,
376 _placeholder08: None,
377 permissions: Some(0x04),
378 rp_id: Some("example.com"),
379 };
380 assert_de_tokens(
381 &request,
382 &[
383 Token::Map { len: Some(6) },
384 Token::U64(0x01),
386 Token::U8(1),
387 Token::U64(0x02),
389 Token::U8(0x09),
390 Token::U64(0x03),
392 Token::Map { len: Some(5) },
393 Token::I8(1),
395 Token::I8(2),
396 Token::I8(3),
398 Token::I8(-25),
399 Token::I8(-1),
401 Token::I8(1),
402 Token::I8(-2),
404 Token::BorrowedBytes(&KEY_AGREEMENT[..32]),
405 Token::I8(-3),
407 Token::BorrowedBytes(&KEY_AGREEMENT[32..]),
408 Token::MapEnd,
409 Token::U64(0x06),
411 Token::BorrowedBytes(PIN_HASH_ENC),
412 Token::U64(0x09),
414 Token::U8(0x04),
415 Token::U64(0x0A),
417 Token::BorrowedStr("example.com"),
418 Token::MapEnd,
419 ],
420 );
421 }
422
423 #[test]
424 fn test_ser_response_get_retries() {
425 let response = Response {
426 retries: Some(3),
427 ..Default::default()
428 };
429 assert_ser_tokens(
430 &response,
431 &[
432 Token::Map { len: Some(1) },
433 Token::U64(0x03),
435 Token::Some,
436 Token::U8(3),
437 Token::MapEnd,
438 ],
439 );
440 }
441
442 #[test]
443 fn test_ser_response_get_key_agreement() {
444 let key_agreement = EcdhEsHkdf256PublicKey {
445 x: Bytes::from_slice(&KEY_AGREEMENT[..32]).unwrap(),
446 y: Bytes::from_slice(&KEY_AGREEMENT[32..]).unwrap(),
447 };
448 let response = Response {
449 key_agreement: Some(key_agreement),
450 ..Default::default()
451 };
452 assert_ser_tokens(
453 &response,
454 &[
455 Token::Map { len: Some(1) },
456 Token::U64(0x01),
458 Token::Some,
459 Token::Map { len: Some(5) },
460 Token::I8(1),
462 Token::I8(2),
463 Token::I8(3),
465 Token::I8(-25),
466 Token::I8(-1),
468 Token::I8(1),
469 Token::I8(-2),
471 Token::BorrowedBytes(&KEY_AGREEMENT[..32]),
472 Token::I8(-3),
474 Token::BorrowedBytes(&KEY_AGREEMENT[32..]),
475 Token::MapEnd,
476 Token::MapEnd,
477 ],
478 );
479 }
480
481 #[test]
482 fn test_ser_response_get_pin_token() {
483 let response = Response {
484 pin_token: Some(Bytes::from_slice(PIN_TOKEN).unwrap()),
485 ..Default::default()
486 };
487 assert_ser_tokens(
488 &response,
489 &[
490 Token::Map { len: Some(1) },
491 Token::U64(0x02),
493 Token::Some,
494 Token::BorrowedBytes(PIN_TOKEN),
495 Token::MapEnd,
496 ],
497 );
498 }
499
500 #[test]
501 fn pin_v1_subcommand() {
502 let mut buf = [0u8; 64];
510 let example = PinV1Subcommand::GetKeyAgreement;
511 let ser = crate::serde::cbor_serialize(&example, &mut buf).unwrap();
512 assert_eq!(ser, &[0x02]);
513 }
514}