Skip to content

Error when AuthenticatorData contains both attested_credential and extensions #135

@jo-bitsch

Description

@jo-bitsch

Thanks for your very excellent work on bringing better webauthn support to the linux desktop!

I was trying out cargo run --example webauthn_extensions_hid and ran into the following issue:

Devices found: [HidDevice { backend: HidApiDevice(HidDeviceInfo { vendor_id: 14286, product_id: 514 }) }]
Selected HID authenticator: PONE Biometrics OFFPAD+ (r1280)
Please touch your device!
ERROR libwebauthn::proto::ctap2::protocol: Failed to parse Ctap2MakeCredentialResponse from CBOR-data provided by the device. Parsing error: SerdeCbor(ErrorImpl { code: Message("serde_cbor serialization error: trailing data at offset 78"), offset: 0 })

Debugging this, I had the following output from the authenticator:

a301667061636b65640258b9bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b5c50000000069700f79d1fb472ebd9ba3a3b9a9eda00010e92cfa7b351ced73cdb8b306b5005d43a5010203262001215820df2f676b42997470d6055a69ce6ce7a6925a2c59572ba8b6a0e8e69500a8a717225820caa45f5d6f798175a8abef72ab06b4987a19cb8bdd2b9d951e7a0fc166cd5d5aa36863726564426c6f62f56b6372656450726f74656374036b686d61632d736563726574f503a363616c672663736967584630440220563d8fcfe4c64743407a402017175f2295b72d23134fca1c1b30d112c449a829022019ccac58a664facff733b33fa3c19e807bc37e09dc9c53aaa9ad2ebbd3f31a7b637835638159021930820215308201bba003020102021403df6e574b6636c96a8d61c6ad76f14c04152728300a06082a8648ce3d04030230363118301606035504030c0f506f6e652042696f6d657472696373310b3009060355040613024e4f310d300b06035504070c044f736c6f301e170d3235303332363134353432325a170d3335303332343134353432325a30818c312d302b06035504030c24506f6e652042696f6d657472696373204f46465041442041757468656e74696361746f72310b3009060355040613024e4f310d300b06035504070c044f736c6f311b3019060355040a0c12506f6e652042696f6d65747269637320415331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e3059301306072a8648ce3d020106082a8648ce3d03010703420004955017625a36e7dd7762cd7c7a226a45de4b6c10542cbafdfcbf7a7f29afd03c35679ea763912ca5e6d54090dbbc21cda403bddbd961d494ffd32b35e8c7c151a350304e300c0603551d130101ff04023000301d0603551d0e0416041488f7ce107cd267f4fd76454f738da7b04dcbf79f301f0603551d23041830168014dc9f1783258274be4c546e56c2ee4c115944d14f300a06082a8648ce3d040302034800304502207105a01e74c10801cbebd87684ea1345865bcb61c7da99f57fd4adcde0afdc36022100de4b4c62b6925620f6780aa5d0513939b7b0b9c3ceae16e2a7525a62a54dcad4

Dissecting this a bit further, the AuthenticatorData is

BFABC37432958B063360D3AD6461C9C4735AE7F8EDD46592A5E0F01452B2E4B5C50000000069700F79D1FB472EBD9BA3A3B9A9EDA00010E92CFA7B351CED73CDB8B306B5005D43A5010203262001215820DF2F676B42997470D6055A69CE6CE7A6925A2C59572BA8B6A0E8E69500A8A717225820CAA45F5D6F798175A8ABEF72AB06B4987A19CB8BDD2B9D951E7A0FC166CD5D5AA36863726564426C6F62F56B6372656450726F74656374036B686D61632D736563726574F5

Dissecting this even further:

rpIdHash:
  BFABC37432958B063360D3AD6461C9C4735AE7F8EDD46592A5E0F01452B2E4B5
flags:
  C5 = (USER_PRESENT | USER_VERIFIED | ATTESTED_CREDENTIALS | EXTENSION_DATA)
signCount:
  00000000
attestedCredentialData:
  aaguid:
    69700F79D1FB472EBD9BA3A3B9A9EDA0
  credentialIdLength:
    0010
  credentialId:
    E92CFA7B351CED73CDB8B306B5005D43
  credentialPublicKey:
    A5010203262001215820DF2F676B42997470D6055A69CE6CE7A6925A2C59572BA8B6A0E8E69500A8A717225820CAA45F5D6F798175A8ABEF72AB06B4987A19CB8BDD2B9D951E7A0FC166CD5D5A
extensions:
  A36863726564426C6F62F56B6372656450726F74656374036B686D61632D736563726574F5

And this is where the error message actually starts to make a bit of sense:
The credentialPublicKey is 77 bytes long, so there is trailing data at offset 78. However, this trailing data is actually the extensions, as the attested credentials and extensions are allowed to both be present at the same time.

For reference see the note at the end of https://w3c.github.io/webauthn/#authenticator-data:

The authenticator data describes its own length: If the AT and ED flags are not set, it is always 37 bytes long. The attested credential data (which is only present if the AT flag is set) describes its own length. If the ED flag is set, then the total length is 37 bytes plus the length of the attested credential data (if the AT flag is set), plus the length of the extensions output (a CBOR map) that follows.
Determining attested credential data’s length, which is variable, involves determining credentialPublicKey’s beginning location given the preceding credentialId’s length, and then determining the credentialPublicKey’s length (see also Section 7 of [RFC9052]).

So looking into the code, the error seems to be thrown at

let credential_public_key: PublicKey =
cbor::from_reader(&mut cursor).map_err(DesError::custom)?;

In particular, inside from_reader, serde calls deserializer.end()?; which gives the trailing data error message.

The solution will probably involve manually creating a deserializer from the cursor instead of calling from_reader, but my knowledge here is limited.

Again, thanks for your excellent work!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions