@@ -267,6 +267,61 @@ pub enum AttestationStatement {
267267 Packed ( PackedAttestationStatement ) ,
268268}
269269
270+ // Hand-rolled Deserialize avoids serde's `#[serde(untagged)]` machinery,
271+ // which pulls in `serde::private::de::Content` (alloc-dependent) and
272+ // would force `serde/alloc` on the whole ctap-types crate. Distinguishes
273+ // variants by structural shape: `None` is an empty CBOR map; `Packed`
274+ // has `alg` + `sig` (+ optional `x5c`).
275+ #[ cfg( feature = "platform-serde" ) ]
276+ impl < ' de > Deserialize < ' de > for AttestationStatement {
277+ fn deserialize < D > ( deserializer : D ) -> core:: result:: Result < Self , D :: Error >
278+ where
279+ D : serde:: Deserializer < ' de > ,
280+ {
281+ struct V ;
282+ impl < ' de > serde:: de:: Visitor < ' de > for V {
283+ type Value = AttestationStatement ;
284+ fn expecting ( & self , f : & mut core:: fmt:: Formatter ) -> core:: fmt:: Result {
285+ f. write_str ( "a CBOR map for an attestation statement" )
286+ }
287+ fn visit_map < A > ( self , mut map : A ) -> core:: result:: Result < Self :: Value , A :: Error >
288+ where
289+ A : serde:: de:: MapAccess < ' de > ,
290+ {
291+ use serde:: de:: Error as _;
292+
293+ let mut alg: Option < i32 > = None ;
294+ let mut sig: Option < Bytes < ASN1_SIGNATURE_LENGTH > > = None ;
295+ let mut x5c: Option < Vec < Bytes < 1024 > , 1 > > = None ;
296+ let mut has_values = false ;
297+ while let Some ( key) = map. next_key :: < & str > ( ) ? {
298+ has_values = true ;
299+ match key {
300+ "alg" => alg = Some ( map. next_value ( ) ?) ,
301+ "sig" => sig = Some ( map. next_value ( ) ?) ,
302+ "x5c" => x5c = Some ( map. next_value ( ) ?) ,
303+ _ => {
304+ let _: serde:: de:: IgnoredAny = map. next_value ( ) ?;
305+ }
306+ }
307+ }
308+ if let Some ( ( alg, sig) ) = alg. zip ( sig) {
309+ Ok ( AttestationStatement :: Packed ( PackedAttestationStatement {
310+ alg,
311+ sig,
312+ x5c,
313+ } ) )
314+ } else if !has_values {
315+ Ok ( AttestationStatement :: None ( NoneAttestationStatement { } ) )
316+ } else {
317+ Err ( A :: Error :: custom ( "unsupported attestation statement format" ) )
318+ }
319+ }
320+ }
321+ deserializer. deserialize_map ( V )
322+ }
323+ }
324+
270325#[ derive( Copy , Clone , Debug , Eq , PartialEq , Serialize , Deserialize ) ]
271326#[ cfg_attr( feature = "arbitrary" , derive( arbitrary:: Arbitrary ) ) ]
272327#[ non_exhaustive]
@@ -303,9 +358,11 @@ impl TryFrom<&str> for AttestationStatementFormat {
303358}
304359
305360#[ derive( Clone , Debug , Eq , PartialEq , Serialize ) ]
361+ #[ cfg_attr( feature = "platform-serde" , derive( Deserialize ) ) ]
306362pub struct NoneAttestationStatement { }
307363
308364#[ derive( Clone , Debug , Eq , PartialEq , Serialize ) ]
365+ #[ cfg_attr( feature = "platform-serde" , derive( Deserialize ) ) ]
309366pub struct PackedAttestationStatement {
310367 pub alg : i32 ,
311368 pub sig : Bytes < ASN1_SIGNATURE_LENGTH > ,
@@ -329,6 +386,27 @@ impl AttestationFormatsPreference {
329386 }
330387}
331388
389+ #[ cfg( feature = "platform-serde" ) ]
390+ impl Serialize for AttestationFormatsPreference {
391+ fn serialize < S > ( & self , serializer : S ) -> core:: result:: Result < S :: Ok , S :: Error >
392+ where
393+ S : serde:: Serializer ,
394+ {
395+ use serde:: ser:: SerializeSeq ;
396+ // Wire format mirrors the Deserialize impl below: a CBOR array of
397+ // attestation-format strings. The `unknown` flag is a parse-time
398+ // marker — Deserialize sets it when it sees a string it doesn't
399+ // recognize. That source string isn't retained, so we can't round-
400+ // trip it; on the way out we only emit the recognized entries.
401+ let mut seq = serializer. serialize_seq ( Some ( self . known_formats . len ( ) ) ) ?;
402+ for format in & self . known_formats {
403+ let s: & str = ( * format) . into ( ) ;
404+ seq. serialize_element ( s) ?;
405+ }
406+ seq. end ( )
407+ }
408+ }
409+
332410impl < ' de > Deserialize < ' de > for AttestationFormatsPreference {
333411 fn deserialize < D > ( deserializer : D ) -> core:: result:: Result < Self , D :: Error >
334412 where
0 commit comments