What's wrong
The end-to-end tests in libwebauthn-tests drive the virtual authenticator (get_virtual_device() in libwebauthn-tests/src/virt/mod.rs) through make-credential and get-assertion, but never cryptographically verify a signature. tests/basic_ctap2.rs and tests/prf.rs only assert that the ceremony completes and extension outputs are present.
There is also no golden-vector test pinning the canonical CTAP2 wire bytes. Ctap2MakeCredentialRequest and Ctap2GetAssertionRequest (libwebauthn/src/proto/ctap2/model/) are encoded with serde-indexed through the canonical encoder in cbor/serde.rs, and public keys with cosey, but no test pins the exact bytes. Existing tests in cose.rs and model/make_credential.rs check read_alg / to_spki and relative key order only.
Why it matters
The client returns the device's authenticatorData verbatim (AuthenticatorData::raw / to_response_bytes() in libwebauthn/src/fido.rs, #249) and emits make-credential extensions in canonical CBOR order (#243), because re-encoding or reordering the signed bytes makes a relying party reject a valid signature. A regression in either path, or a byte-layout change in cosey or serde-indexed, would silently break verification while every current test still passes. The virtual authenticator embeds a real attestation cert and key (fido-cert.der, fido-key.trussed) and signs in-process, so the round-trip needs no hardware. Its default ES256 is verifiable with the already-present p256 crate.
What to do
Pointers
- attestationObject assembly:
build_attestation_object / to_idl_model in ops/webauthn/make_credential.rs.
- Assertion signature:
Assertion in ops/webauthn/get_assertion.rs.
- Attestation statement shapes:
Ctap2AttestationStatement / PackedAttestationStmt in proto/ctap2/model/get_assertion.rs.
What's wrong
The end-to-end tests in
libwebauthn-testsdrive the virtual authenticator (get_virtual_device()inlibwebauthn-tests/src/virt/mod.rs) through make-credential and get-assertion, but never cryptographically verify a signature.tests/basic_ctap2.rsandtests/prf.rsonly assert that the ceremony completes and extension outputs are present.There is also no golden-vector test pinning the canonical CTAP2 wire bytes.
Ctap2MakeCredentialRequestandCtap2GetAssertionRequest(libwebauthn/src/proto/ctap2/model/) are encoded with serde-indexed through the canonical encoder incbor/serde.rs, and public keys withcosey, but no test pins the exact bytes. Existing tests incose.rsandmodel/make_credential.rscheckread_alg/to_spkiand relative key order only.Why it matters
The client returns the device's
authenticatorDataverbatim (AuthenticatorData::raw/to_response_bytes()inlibwebauthn/src/fido.rs, #249) and emits make-credential extensions in canonical CBOR order (#243), because re-encoding or reordering the signed bytes makes a relying party reject a valid signature. A regression in either path, or a byte-layout change incoseyor serde-indexed, would silently break verification while every current test still passes. The virtual authenticator embeds a real attestation cert and key (fido-cert.der,fido-key.trussed) and signs in-process, so the round-trip needs no hardware. Its default ES256 is verifiable with the already-presentp256crate.What to do
libwebauthn-tests: register a credential, take the COSE public key from the registrationauthenticatorData, run an assertion, recomputeSHA-256(clientDataJSON), and verify the assertion signature overauthenticatorData || clientDataHash(WebAuthn L3 §6.3.3).authenticatorData. hmac-secret (PRF) already works end to end and returns its output in the assertionauthData. credProtect at registration is an alternative. Use whichever GetInfo advertises.attestationObject, verify the packedattStmtsignature overauthData || clientDataHashwith the embedded cert's public key (WebAuthn L3 §8.2), and confirm itsauthDatais byte-identical to the surfacedauthenticatorData.libwebauthnpinning, as fixed hex, the canonical CBOR of a fixedCtap2MakeCredentialRequestandCtap2GetAssertionRequest(the publicCborRequestpath incbor/request.rs) and the COSE_Key of a fixedcosey::PublicKey. They must fail if map ordering drifts or either dependency changes its byte layout.ecdsafeature onp256andsha2. The attestation cert parses withx509-parser, already a core-crate dependency.Pointers
build_attestation_object/to_idl_modelinops/webauthn/make_credential.rs.Assertioninops/webauthn/get_assertion.rs.Ctap2AttestationStatement/PackedAttestationStmtinproto/ctap2/model/get_assertion.rs.