Make AuthenticatorAttestationResponseJSON.clientDataJSON a DOMString or USVString
zacknewman opened this issue · comments
JSON-compatible serialization must be used for clientDataJSON. This makes the ArrayBuffer
a USVString
for platforms whose native string encoding is UTF-8. For such platforms, it would be easier and faster to just send the data as is; and for non-UTF-8 platforms, encoding the ArrayBuffer
such that it is a USVString
/DOMString
is better than having to encode it as a Base64URLString
which itself is a subset of DOMString
anyway. Is the reason AuthenticatorAttestationResponseJSON.clientDataJSON
defined that way for consistency alone? Specifically that all ArrayBuffer
s are converted to that?
On the server side, the data needs to be decoded twice: first to transform the Base64URLString
into UTF-8 data and second to transform the UTF-8 data into a JSON map; however if the data were simply a USVString
/DOMString
, the server would only need to decode the data once as a JSON map.
Is the reason
AuthenticatorAttestationResponseJSON.clientDataJSON
defined that way for consistency alone? Specifically that allArrayBuffer
s are converted to that?
Yes, the intention was to use consistent encoding of ArrayBuffer
values to something that would survive transmission to the server. As clientDataJSON
is bytes it made sense to treat it like any other ArrayBuffer
, even though as is outlined in the spec it's handled as a UTF-8 string during response verification.
Fair enough.
Adding to what @MasterKale said - critically, the encoding of clientDataJSON
MUST remain byte-for-byte identical in transmission from authenticator to server so that the signature over it remains valid. Intermediate parties should not be led to believe that they can safely parse and re-serialize the JSON, because any change to it would break the signature even if the re-serialized JSON is semantically equivalent. Therefore clientDataJSON
is defined as a byte array rather than a DOMString
, to emphasize that intermediate parties should consider it as opaque. These are essentially the same reasons as why JWS also serializes everything as base64-encoded byte arrays even though many of the components are JSON data.
Adding to what @MasterKale said - critically, the encoding of
clientDataJSON
MUST remain byte-for-byte identical in transmission from authenticator to server so that the signature over it remains valid. Intermediate parties should not be led to believe that they can safely parse and re-serialize the JSON, because any change to it would break the signature even if the re-serialized JSON is semantically equivalent. ThereforeclientDataJSON
is defined as a byte array rather than aDOMString
, to emphasize that intermediate parties should consider it as opaque. These are essentially the same reasons as why JWS also serializes everything as base64-encoded byte arrays even though many of the components are JSON data.
clientDataJSON
is not the only item that must remain identical though. For example RP ID must also remain identical since a SHA-256 hash of it is matched with rpIdHash
in authData
; yet PublicKeyCredentialRpEntity.id
is modeled as a DOMString
and not ArrayBuffer
. I find it more likely RP ID gets altered in transit since an RP ID only needs to be a valid domain string. For example, www.EXample.com
very likely will be altered into www.example.com
when sent from the server to authenticator which will cause the registration to fail. Perhaps that is an issue with how RP ID is defined; but even if the definition were improved to require the RP ID to be the result of the domain-to-ascii algorithm, it would still be essential it does not get altered and thus be modeled as an ArrayBuffer
.