1use base64urlsafedata::Base64UrlSafeData;
2use serde::{Deserialize, Serialize};
3use serde_cbor_2::{value::to_value, Value};
4use std::collections::BTreeMap;
5use webauthn_rs_proto::{PubKeyCredParams, PublicKeyCredentialDescriptor, RelyingParty, User};
6
7use crate::ctap2::commands::{value_to_map, value_to_vec_u8};
8
9use super::{value_to_bool, value_to_string, CBORCommand};
10
11#[derive(Deserialize, Serialize, Debug, Clone)]
15#[serde(into = "BTreeMap<u32, Value>", try_from = "BTreeMap<u32, Value>")]
16pub struct MakeCredentialRequest {
17 pub client_data_hash: Vec<u8>,
19 pub rp: RelyingParty,
22 pub user: User,
25 pub pub_key_cred_params: Vec<PubKeyCredParams>,
27 pub exclude_list: Vec<PublicKeyCredentialDescriptor>,
30 pub options: Option<BTreeMap<String, bool>>,
33 pub pin_uv_auth_param: Option<Vec<u8>>,
35 pub pin_uv_auth_proto: Option<u32>,
37 pub enterprise_attest: Option<u32>,
39}
40
41impl CBORCommand for MakeCredentialRequest {
42 const CMD: u8 = 0x01;
43 type Response = MakeCredentialResponse;
44}
45
46#[derive(Deserialize, Serialize, Debug, Clone, Default, PartialEq, Eq)]
62#[serde(rename_all = "camelCase")]
63pub struct MakeCredentialResponse {
64 pub fmt: Option<String>,
66 pub auth_data: Option<Value>,
68 pub att_stmt: Option<Value>,
70 pub epp_att: Option<bool>,
73 pub large_blob_key: Option<Value>,
78 }
80
81impl From<MakeCredentialRequest> for BTreeMap<u32, Value> {
82 fn from(value: MakeCredentialRequest) -> Self {
83 let MakeCredentialRequest {
84 client_data_hash,
85 rp,
86 user,
87 pub_key_cred_params,
88 exclude_list,
89 options,
90 pin_uv_auth_param,
91 pin_uv_auth_proto,
92 enterprise_attest: _,
93 } = value;
94
95 let mut keys = BTreeMap::new();
96
97 keys.insert(0x01, Value::Bytes(client_data_hash));
98
99 if let Ok(rp_value) = to_value(rp) {
100 keys.insert(0x2, rp_value);
101 }
102
103 let User {
106 id,
107 name,
108 display_name,
109 } = user;
110
111 let mut user_map = BTreeMap::new();
112 user_map.insert(Value::Text("id".to_string()), Value::Bytes(id.into()));
114 user_map.insert(Value::Text("name".to_string()), Value::Text(name));
115 user_map.insert(
116 Value::Text("displayName".to_string()),
117 Value::Text(display_name),
118 );
119
120 let user_value = Value::Map(user_map);
121 keys.insert(0x3, user_value);
123
124 if let Ok(ps) = to_value(pub_key_cred_params) {
125 keys.insert(0x4, ps);
126 }
127
128 if !exclude_list.is_empty() {
129 keys.insert(
130 0x05,
131 Value::Array(
132 exclude_list
133 .iter()
134 .map(|a| {
135 let mut m = BTreeMap::from([
136 (
137 Value::Text("type".to_string()),
138 Value::Text(a.type_.to_owned()),
139 ),
140 (Value::Text("id".to_string()), Value::Bytes(a.id.to_vec())),
141 ]);
142
143 if let Some(transports) = &a.transports {
144 let transports: Vec<Value> = transports
145 .iter()
146 .map(|t| Value::Text(t.to_string()))
147 .collect();
148
149 if !transports.is_empty() {
150 m.insert(
151 Value::Text("transports".to_string()),
152 Value::Array(transports),
153 );
154 }
155 }
156
157 Value::Map(m)
158 })
159 .collect(),
160 ),
161 );
162 }
163
164 if let Some(o) = options {
165 let mut options_map = BTreeMap::new();
166 for (option, value) in &o {
167 options_map.insert(Value::Text(option.to_string()), Value::Bool(*value));
168 }
169
170 let options_value = Value::Map(options_map);
171 keys.insert(0x7, options_value);
172 }
173
174 if let Some(p) = pin_uv_auth_param {
175 keys.insert(0x08, Value::Bytes(p));
176 }
177
178 if let Some(p) = pin_uv_auth_proto {
179 keys.insert(0x09, Value::Integer(p.into()));
180 }
181
182 keys
183 }
184}
185
186impl TryFrom<BTreeMap<u32, Value>> for MakeCredentialRequest {
187 type Error = &'static str;
188 fn try_from(mut raw: BTreeMap<u32, Value>) -> Result<Self, Self::Error> {
189 trace!("raw: {:?}", raw);
190 Ok(Self {
191 client_data_hash: raw
192 .remove(&0x01)
193 .and_then(|v| value_to_vec_u8(v, "0x01"))
194 .ok_or("parsing clientDataHash")?,
195 rp: raw
196 .remove(&0x02)
197 .and_then(|v| serde_cbor_2::value::from_value(v).ok())
198 .ok_or("parsing rp")?,
199 user: raw
200 .remove(&0x03)
201 .and_then(|v| if let Value::Map(v) = v { Some(v) } else { None })
202 .and_then(|mut v| {
203 Some(User {
204 id: Base64UrlSafeData::from(value_to_vec_u8(
205 v.remove(&Value::Text("id".to_string()))?,
206 "id",
207 )?),
208 name: value_to_string(v.remove(&Value::Text("name".to_string()))?, "name")?,
209 display_name: value_to_string(
210 v.remove(&Value::Text("displayName".to_string()))?,
211 "displayName",
212 )?,
213 })
214 })
215 .ok_or("parsing user")?,
216 pub_key_cred_params: raw
217 .remove(&0x04)
218 .and_then(|v| serde_cbor_2::value::from_value(v).ok())
219 .ok_or("parsing pubKeyCredParams")?,
220 exclude_list: raw
221 .remove(&0x05)
222 .and_then(|v| serde_cbor_2::value::from_value(v).ok())
223 .unwrap_or_default(),
224 options: raw
225 .remove(&0x07)
226 .and_then(|v| value_to_map(v, "0x07"))
227 .map(|v| {
228 v.into_iter()
229 .filter_map(|(key, value)| match (key, value) {
230 (Value::Text(key), Value::Bool(value)) => Some((key, value)),
231 _ => None,
232 })
233 .collect()
234 }),
235 pin_uv_auth_param: None,
237 pin_uv_auth_proto: None,
238 enterprise_attest: None,
239 })
240 }
241}
242
243impl From<MakeCredentialResponse> for BTreeMap<u32, Value> {
244 fn from(value: MakeCredentialResponse) -> Self {
245 let MakeCredentialResponse {
246 fmt,
247 auth_data,
248 att_stmt,
249 epp_att,
250 large_blob_key,
251 } = value;
252
253 let mut keys = BTreeMap::new();
254 if let Some(fmt) = fmt {
255 keys.insert(0x01, Value::Text(fmt));
256 }
257 if let Some(auth_data) = auth_data {
258 keys.insert(0x02, auth_data);
259 }
260 if let Some(att_stmt) = att_stmt {
261 keys.insert(0x03, att_stmt);
262 }
263 if let Some(epp_att) = epp_att {
264 keys.insert(0x04, epp_att.into());
265 }
266 if let Some(large_blob_key) = large_blob_key {
267 keys.insert(0x05, large_blob_key);
268 }
269 keys
270 }
271}
272
273impl TryFrom<BTreeMap<u32, Value>> for MakeCredentialResponse {
274 type Error = &'static str;
275 fn try_from(mut raw: BTreeMap<u32, Value>) -> Result<Self, Self::Error> {
276 trace!(?raw);
277 Ok(Self {
278 fmt: raw.remove(&0x01).and_then(|v| value_to_string(v, "0x01")),
279 auth_data: raw.remove(&0x02),
280 att_stmt: raw.remove(&0x03),
281 epp_att: raw.remove(&0x04).and_then(|v| value_to_bool(&v, "0x04")),
282 large_blob_key: raw.remove(&0x05),
283 })
284 }
285}
286
287crate::deserialize_cbor!(MakeCredentialRequest);
288crate::deserialize_cbor!(MakeCredentialResponse);
289
290#[cfg(test)]
291mod test {
292 use crate::ctap2::CBORResponse;
293
294 use super::*;
295 use base64urlsafedata::Base64UrlSafeData;
296 use serde_cbor_2::{from_slice, to_vec, Value};
297 use webauthn_rs_proto::{PubKeyCredParams, RelyingParty, User};
298
299 #[test]
300 fn sample_make_credential_request() {
301 let _ = tracing_subscriber::fmt::try_init();
302 let expected = vec![
320 1, 167, 1, 88, 32, 104, 113, 52, 150, 130, 34, 236, 23, 32, 46, 66, 80, 95, 142, 210, 177, 106,
326 226, 47, 22, 187, 5, 184, 140, 37, 219, 158, 96, 38, 69, 241, 65, 2, 162, 98, 105, 100, 105, 116, 101, 115, 116, 46, 99, 116, 97, 112, 100, 110, 97, 109,
329 101, 105, 116, 101, 115, 116, 46, 99, 116, 97, 112, 3, 163, 98, 105, 100, 88, 32, 43, 102, 137, 187, 24, 244, 22, 159, 6, 159, 188, 223, 80,
332 203, 110, 163, 198, 10, 134, 27, 154, 123, 99, 148, 105, 131, 224, 181, 119, 183, 140,
333 112, 100, 110, 97, 109, 101, 113, 116, 101, 115, 116, 99, 116, 97, 112, 64, 99, 116,
334 97, 112, 46, 99, 111, 109, 107, 100, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101,
335 105, 84, 101, 115, 116, 32, 67, 116, 97, 112, 4, 131, 162, 99, 97, 108, 103, 38, 100, 116, 121, 112, 101, 106, 112, 117, 98, 108, 105,
338 99, 45, 107, 101, 121, 162, 99, 97, 108, 103, 57, 1, 0, 100, 116, 121, 112, 101, 106,
339 112, 117, 98, 108, 105, 99, 45, 107, 101, 121, 162, 99, 97, 108, 103, 56, 36, 100, 116,
340 121, 112, 101, 106, 112, 117, 98, 108, 105, 99, 45, 107, 101, 121,
341 7, 161, 98, 114, 107, 245, 8, 80, 252, 67, 170, 164, 17, 217, 72, 204, 108, 55, 6, 139, 141, 161, 213, 8,
347 9, 1,
349 ];
350
351 let req = MakeCredentialRequest {
352 client_data_hash: vec![
353 104, 113, 52, 150, 130, 34, 236, 23, 32, 46, 66, 80, 95, 142, 210, 177, 106, 226,
354 47, 22, 187, 5, 184, 140, 37, 219, 158, 96, 38, 69, 241, 65,
355 ],
356 rp: RelyingParty {
357 name: "test.ctap".to_owned(),
358 id: "test.ctap".to_owned(),
359 },
360 user: User {
361 id: Base64UrlSafeData::from(vec![
362 43, 102, 137, 187, 24, 244, 22, 159, 6, 159, 188, 223, 80, 203, 110, 163, 198,
363 10, 134, 27, 154, 123, 99, 148, 105, 131, 224, 181, 119, 183, 140, 112,
364 ]),
365 name: "testctap@ctap.com".to_owned(),
366 display_name: "Test Ctap".to_owned(),
367 },
368 pub_key_cred_params: vec![
369 PubKeyCredParams {
370 type_: "public-key".to_owned(),
371 alg: -7,
372 },
373 PubKeyCredParams {
374 type_: "public-key".to_owned(),
375 alg: -257,
376 },
377 PubKeyCredParams {
378 type_: "public-key".to_owned(),
379 alg: -37,
380 },
381 ],
382 exclude_list: vec![],
383 options: Some(BTreeMap::from([("rk".to_owned(), true)])),
384 pin_uv_auth_param: Some(vec![
385 252, 67, 170, 164, 17, 217, 72, 204, 108, 55, 6, 139, 141, 161, 213, 8,
386 ]),
387 pin_uv_auth_proto: Some(1),
388 enterprise_attest: None,
389 };
390
391 assert_eq!(expected, req.cbor().expect("encode error"));
392
393 let decoded = <MakeCredentialRequest as CBORResponse>::try_from(&expected[1..]).unwrap();
394 trace!(?decoded);
395
396 let r = vec![
397 163, 1, 102, 112, 97, 99, 107, 101, 100, 2, 89, 0, 162, 0, 33, 245, 252, 11, 133, 205,
398 34, 230, 6, 35, 188, 215, 209, 202, 72, 148, 137, 9, 36, 155, 71, 118, 235, 81, 81, 84,
399 229, 123, 102, 174, 18, 197, 0, 0, 0, 85, 248, 160, 17, 243, 140, 10, 77, 21, 128, 6,
400 23, 17, 31, 158, 220, 125, 0, 16, 244, 213, 123, 35, 221, 12, 183, 133, 104, 12, 218,
401 167, 247, 228, 79, 96, 165, 1, 2, 3, 38, 32, 1, 33, 88, 32, 223, 1, 125, 11, 40, 103,
402 149, 190, 161, 83, 209, 102, 160, 161, 91, 79, 107, 103, 163, 175, 74, 16, 30, 16, 232,
403 73, 111, 61, 211, 197, 209, 169, 34, 88, 32, 148, 178, 37, 81, 230, 50, 93, 119, 51,
404 196, 27, 178, 245, 166, 66, 173, 238, 65, 124, 151, 224, 144, 97, 151, 181, 176, 205,
405 139, 141, 108, 107, 167, 161, 107, 104, 109, 97, 99, 45, 115, 101, 99, 114, 101, 116,
406 245, 3, 163, 99, 97, 108, 103, 38, 99, 115, 105, 103, 88, 71, 48, 69, 2, 32, 124, 202,
407 197, 122, 30, 67, 223, 36, 176, 132, 126, 235, 241, 25, 210, 141, 205, 197, 4, 143,
408 125, 205, 142, 221, 121, 231, 151, 33, 196, 27, 207, 45, 2, 33, 0, 216, 158, 199, 91,
409 146, 206, 143, 249, 228, 111, 231, 248, 200, 121, 149, 105, 74, 99, 229, 183, 138, 184,
410 92, 71, 185, 218, 28, 88, 10, 142, 200, 58, 99, 120, 53, 99, 129, 89, 1, 151, 48, 130,
411 1, 147, 48, 130, 1, 56, 160, 3, 2, 1, 2, 2, 9, 0, 133, 155, 114, 108, 178, 75, 76, 41,
412 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 48, 71, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19,
413 2, 85, 83, 49, 20, 48, 18, 6, 3, 85, 4, 10, 12, 11, 89, 117, 98, 105, 99, 111, 32, 84,
414 101, 115, 116, 49, 34, 48, 32, 6, 3, 85, 4, 11, 12, 25, 65, 117, 116, 104, 101, 110,
415 116, 105, 99, 97, 116, 111, 114, 32, 65, 116, 116, 101, 115, 116, 97, 116, 105, 111,
416 110, 48, 30, 23, 13, 49, 54, 49, 50, 48, 52, 49, 49, 53, 53, 48, 48, 90, 23, 13, 50,
417 54, 49, 50, 48, 50, 49, 49, 53, 53, 48, 48, 90, 48, 71, 49, 11, 48, 9, 6, 3, 85, 4, 6,
418 19, 2, 85, 83, 49, 20, 48, 18, 6, 3, 85, 4, 10, 12, 11, 89, 117, 98, 105, 99, 111, 32,
419 84, 101, 115, 116, 49, 34, 48, 32, 6, 3, 85, 4, 11, 12, 25, 65, 117, 116, 104, 101,
420 110, 116, 105, 99, 97, 116, 111, 114, 32, 65, 116, 116, 101, 115, 116, 97, 116, 105,
421 111, 110, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61,
422 3, 1, 7, 3, 66, 0, 4, 173, 17, 235, 14, 136, 82, 229, 58, 213, 223, 237, 134, 180, 30,
423 97, 52, 161, 142, 196, 225, 175, 143, 34, 26, 60, 125, 110, 99, 108, 128, 234, 19, 195,
424 213, 4, 255, 46, 118, 33, 27, 180, 69, 37, 177, 150, 196, 76, 180, 132, 153, 121, 207,
425 111, 137, 110, 205, 43, 184, 96, 222, 27, 244, 55, 107, 163, 13, 48, 11, 48, 9, 6, 3,
426 85, 29, 19, 4, 2, 48, 0, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 73, 0, 48, 70,
427 2, 33, 0, 233, 163, 159, 27, 3, 25, 117, 37, 247, 55, 62, 16, 206, 119, 231, 128, 33,
428 115, 27, 148, 208, 192, 63, 63, 218, 31, 210, 45, 179, 208, 48, 231, 2, 33, 0, 196,
429 250, 236, 52, 69, 168, 32, 207, 67, 18, 156, 219, 0, 170, 190, 253, 154, 226, 216, 116,
430 249, 197, 211, 67, 203, 47, 17, 61, 162, 55, 35, 243,
431 ];
432 let a = <MakeCredentialResponse as CBORResponse>::try_from(r.as_slice())
433 .expect("Failed to decode message");
434 info!("r = {}", hex::encode(r));
435
436 assert_eq!(
437 a,
438 MakeCredentialResponse {
439 fmt: Some("packed".to_owned()),
440 auth_data: Some(Value::Bytes(vec![
441 0, 33, 245, 252, 11, 133, 205, 34, 230, 6, 35, 188, 215, 209, 202, 72, 148,
442 137, 9, 36, 155, 71, 118, 235, 81, 81, 84, 229, 123, 102, 174, 18, 197, 0, 0,
443 0, 85, 248, 160, 17, 243, 140, 10, 77, 21, 128, 6, 23, 17, 31, 158, 220, 125,
444 0, 16, 244, 213, 123, 35, 221, 12, 183, 133, 104, 12, 218, 167, 247, 228, 79,
445 96, 165, 1, 2, 3, 38, 32, 1, 33, 88, 32, 223, 1, 125, 11, 40, 103, 149, 190,
446 161, 83, 209, 102, 160, 161, 91, 79, 107, 103, 163, 175, 74, 16, 30, 16, 232,
447 73, 111, 61, 211, 197, 209, 169, 34, 88, 32, 148, 178, 37, 81, 230, 50, 93,
448 119, 51, 196, 27, 178, 245, 166, 66, 173, 238, 65, 124, 151, 224, 144, 97, 151,
449 181, 176, 205, 139, 141, 108, 107, 167, 161, 107, 104, 109, 97, 99, 45, 115,
450 101, 99, 114, 101, 116, 245
451 ])),
452 att_stmt: Some(Value::Map(BTreeMap::from([
453 (Value::Text("alg".to_owned()), Value::Integer(-7)),
454 (
455 Value::Text("sig".to_owned()),
456 Value::Bytes(vec![
457 48, 69, 2, 32, 124, 202, 197, 122, 30, 67, 223, 36, 176, 132, 126, 235,
458 241, 25, 210, 141, 205, 197, 4, 143, 125, 205, 142, 221, 121, 231, 151,
459 33, 196, 27, 207, 45, 2, 33, 0, 216, 158, 199, 91, 146, 206, 143, 249,
460 228, 111, 231, 248, 200, 121, 149, 105, 74, 99, 229, 183, 138, 184, 92,
461 71, 185, 218, 28, 88, 10, 142, 200, 58
462 ])
463 ),
464 (
465 Value::Text("x5c".to_owned()),
466 Value::Array(vec![Value::Bytes(vec![
467 48, 130, 1, 147, 48, 130, 1, 56, 160, 3, 2, 1, 2, 2, 9, 0, 133, 155,
468 114, 108, 178, 75, 76, 41, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2,
469 48, 71, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 20, 48, 18,
470 6, 3, 85, 4, 10, 12, 11, 89, 117, 98, 105, 99, 111, 32, 84, 101, 115,
471 116, 49, 34, 48, 32, 6, 3, 85, 4, 11, 12, 25, 65, 117, 116, 104, 101,
472 110, 116, 105, 99, 97, 116, 111, 114, 32, 65, 116, 116, 101, 115, 116,
473 97, 116, 105, 111, 110, 48, 30, 23, 13, 49, 54, 49, 50, 48, 52, 49, 49,
474 53, 53, 48, 48, 90, 23, 13, 50, 54, 49, 50, 48, 50, 49, 49, 53, 53, 48,
475 48, 90, 48, 71, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 20,
476 48, 18, 6, 3, 85, 4, 10, 12, 11, 89, 117, 98, 105, 99, 111, 32, 84,
477 101, 115, 116, 49, 34, 48, 32, 6, 3, 85, 4, 11, 12, 25, 65, 117, 116,
478 104, 101, 110, 116, 105, 99, 97, 116, 111, 114, 32, 65, 116, 116, 101,
479 115, 116, 97, 116, 105, 111, 110, 48, 89, 48, 19, 6, 7, 42, 134, 72,
480 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 173,
481 17, 235, 14, 136, 82, 229, 58, 213, 223, 237, 134, 180, 30, 97, 52,
482 161, 142, 196, 225, 175, 143, 34, 26, 60, 125, 110, 99, 108, 128, 234,
483 19, 195, 213, 4, 255, 46, 118, 33, 27, 180, 69, 37, 177, 150, 196, 76,
484 180, 132, 153, 121, 207, 111, 137, 110, 205, 43, 184, 96, 222, 27, 244,
485 55, 107, 163, 13, 48, 11, 48, 9, 6, 3, 85, 29, 19, 4, 2, 48, 0, 48, 10,
486 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 73, 0, 48, 70, 2, 33, 0, 233,
487 163, 159, 27, 3, 25, 117, 37, 247, 55, 62, 16, 206, 119, 231, 128, 33,
488 115, 27, 148, 208, 192, 63, 63, 218, 31, 210, 45, 179, 208, 48, 231, 2,
489 33, 0, 196, 250, 236, 52, 69, 168, 32, 207, 67, 18, 156, 219, 0, 170,
490 190, 253, 154, 226, 216, 116, 249, 197, 211, 67, 203, 47, 17, 61, 162,
491 55, 35, 243
492 ])])
493 )
494 ]))),
495 ..Default::default()
496 }
497 );
498 }
499
500 #[test]
501 fn make_credential() {
502 let _ = tracing_subscriber::fmt().try_init();
503
504 let bytes = vec![
558 168, 1, 88, 32, 104, 113, 52, 150, 130, 34, 236, 23, 32, 46, 66, 80, 95, 142, 210, 177,
559 106, 226, 47, 22, 187, 5, 184, 140, 37, 219, 158, 96, 38, 69, 241, 65, 2, 162, 98, 105,
560 100, 105, 116, 101, 115, 116, 46, 99, 116, 97, 112, 100, 110, 97, 109, 101, 105, 116,
561 101, 115, 116, 46, 99, 116, 97, 112, 3, 163, 98, 105, 100, 88, 32, 43, 102, 137, 187,
562 24, 244, 22, 159, 6, 159, 188, 223, 80, 203, 110, 163, 198, 10, 134, 27, 154, 123, 99,
563 148, 105, 131, 224, 181, 119, 183, 140, 112, 100, 110, 97, 109, 101, 113, 116, 101,
564 115, 116, 99, 116, 97, 112, 64, 99, 116, 97, 112, 46, 99, 111, 109, 107, 100, 105, 115,
565 112, 108, 97, 121, 78, 97, 109, 101, 105, 84, 101, 115, 116, 32, 67, 116, 97, 112, 4,
566 131, 162, 99, 97, 108, 103, 38, 100, 116, 121, 112, 101, 106, 112, 117, 98, 108, 105,
567 99, 45, 107, 101, 121, 162, 99, 97, 108, 103, 57, 1, 0, 100, 116, 121, 112, 101, 106,
568 112, 117, 98, 108, 105, 99, 45, 107, 101, 121, 162, 99, 97, 108, 103, 56, 36, 100, 116,
569 121, 112, 101, 106, 112, 117, 98, 108, 105, 99, 45, 107, 101, 121, 6, 161, 107, 104,
570 109, 97, 99, 45, 115, 101, 99, 114, 101, 116, 245, 7, 161, 98, 114, 107, 245, 8, 80,
571 252, 67, 170, 164, 17, 217, 72, 204, 108, 55, 6, 139, 141, 161, 213, 8, 9, 1,
572 ];
573
574 let v: Result<Value, _> = from_slice(bytes.as_slice());
575 info!("got APDU Value response: {:?}", v);
576
577 let mc = MakeCredentialRequest {
578 client_data_hash: vec![0; 32],
579 rp: RelyingParty {
580 name: "test".to_string(),
581 id: "test".to_string(),
582 },
583 user: User {
584 id: Base64UrlSafeData::from(b"test"),
585 name: "test".to_string(),
586 display_name: "test".to_string(),
587 },
588 pub_key_cred_params: vec![PubKeyCredParams {
589 type_: "public-key".to_string(),
590 alg: -7,
591 }],
592 options: None,
593 exclude_list: vec![],
594 pin_uv_auth_param: None,
595 pin_uv_auth_proto: None,
596 enterprise_attest: None,
597 };
598
599 let b = to_vec(&mc).unwrap();
600
601 let v2: Result<Value, _> = from_slice(b.as_slice());
602 info!("got APDU Value encoded: {:?}", v2);
603
604 info!("got inner APDU: {}", hex::encode(b));
607 }
608}