Closed infinisil closed 2 years ago
I took a closer look at this today, and it turns out that the correct encoding/decoding is more complicated than it seems. Here are some notes:
Crypto.WebAuthn.Model.WebIDL
are tied to webauthn-json, which is not obvious from the names.Given the above, and some more thought, I think this is the best approach forward:
attestationObject
decoding, the encoding of ResidentialKeyRequirement
, etc. Really anything that doesn't depend on webauthn-json.The WebIDL module works both with the binary CBOR payload, and the JSON object that contains the payload. In my understanding, the CBOR handling is under Crypto.WebAuthn.Model.WebIDL.Internal.Binary
.
Yeah, we discussed before that it is fine to have the default JSON schema to be tied to webauthn-json. I agree that it can be more obvious. Maybe a module name can be changed.
After playing around with the library, I think that it may be better to drop the WebIDL abstraction. WebIDL aligns with the CTAP part of the spec, but this library isn't meant to work client-side with the browser API.
That indirection makes it hard to discover how to compose. For example, I want to get a Credential 'Registration 'True
from the client to pass to verifyRegistrationResponse
. The docs for Credential
has instances of ToJSON
, Convert
, Decode
, DecodeCreated
. The instances don't tell how to get the value from JSON. I only understood how to do this after reading the server example at the Main.hs
that calls decodeCredentialRegistration
.
It would be much simpler if we had something like this:
-- | ...
-- For decoding see the newtype `Crypto.WebAuthn.Model.WebauthnJSON.CredentialJSON` .
data Credential (c :: CeremonyKind) raw
...
newtype CredentialJSON (c :: CeremonyKind) raw = CredentialJSON (Credential (c :: CeremonyKind) raw)
instance FromJSON CredentialJSON ...
instance ToJSON CredentialJSON ...
Then I'd only need to know the helper newtypes and use the regular aeson types. There is SupportedAttestationStatementFormats
passed to decoding that does not map cleanly toFromJSON
. But I think it is easy to resolve if decoding is done in two stages - for the JSON payload with FromJSON, and with decode*
that takes a CBOR value and the statement formats. The decode*
functions not related to CBOR won't be necessary anymore.
After playing around with the library, I think that it may be better to drop the WebIDL abstraction. WebIDL aligns with the CTAP part of the spec, but this library isn't meant to work client-side with the browser API.
Yeah very much agreed after looking more closely at it. WebIDL isn't really very involved here, I'll rename this to be more webauthn-json specific.
There is
SupportedAttestationStatementFormats
passed to decoding that does not map cleanly toFromJSON
. But I think it is easy to resolve if decoding is done in two stages - for the JSON payload with FromJSON, and withdecode*
that takes a CBOR value and the statement formats.
I'm not entirely sure what you mean by this though, isn't this what is being done right now? Decoding is done with FromJSON IDLCredentialRegistration
in a first step, followed by a second decodeCredentialRegistration
step which takes the SupportedAttestationStatementFormats
.
In the future I believe we will also need the same pattern for supported extensions (and that for both registration and authentication responses), see #35.
What I can do is just make sure that the documentation is better, e.g. as you already suggested, referencing the decoding function from the Credential
type.
When I said that Credential c raw
doesn't map cleanly to FromJSON
, I meant that aCredential c raw
or a newtype over it cannot have a FromJSON
instance. They need the two steps for decoding that you described where SupportedAttestationStatementFormats
is supplied.
This is now being cleaned up a bit in #140, though it's mostly still the same scheme of having intermediate types, but now they're specifically for webauthn-json and not really exposed
Using these intermediate types allows directly deriving JSON instances, because the field names and types of the WebIDL model line up exactly with the spec. But the alternative of just wrapping the fully-decoded model types with
newtype
's and writing a manual encoding/decoding also sounds intriguing and would remove some mental overhead. Although it would require duplication in the encoding and decoding parts.Edit: Another motivation for these intermediate types is that they allow using other encoding/decoding schemas than webauthn-json.