Presumably this is to prevent a replay attack, but wouldn't a replay attack be prevented by TLS already?
I've asked around a lot about this and haven't been able to find a definitive answer. However, I think the challenge is needed for the following reason:
Replay attacks should mostly be prevented by TLS, but as mentioned here and here it is still possible to execute a replay attack even with TLS by fooling the user or the user's browser to retry a request. Thus, this challenge helps cover a gap in TLS's replay prevention mechanisms.
For example, an attacker could compromise a user's identity in the following scenario if the challenge wasn't required:
- A user tries registering a new credential.
- That request is held by a man in the middle and a TCP reset is sent to the user's browser.
- The user's browser retries the request and successfully registers the new credential.
- Within a short period of time, the user decides to deregister their credential.
Again within a short period of time, the man in the middle releases the original request to the server and thus, the credential is re-registered without the user's knowledge.
Sometime later, the man in the middle steals the user's FIDO2 authenticator.
- The man in the middle can now pose as the user.
After realizing that a replay attack doesn't have to occur as a result of a compromised node in the network but could also occur as a result of a compromised operating system or compromised browser, I thought of the following example that would be possible without a challenge during registration:
- An attacker gains control of a user's browser.
- A user registers a new credential and the compromised browser intercepts the PublicKeyCredential before sending it to the server.
- The attacker steals the user's FIDO2 authenticator.
- The user deregisters their credential.
- When the user goes to register a new credential, the compromised browser sends the old PublicKeyCredential instead of a new one.
- The attacker can now pose as the user.
A very similar scenario could occur if the user's operating system was compromised and a challenge wasn't used during registration.
Also, these scenarios would only be relevant if a relying party required that registration/authentication be executed with a particular device that the attacker couldn't easily crack.
This aspect comes essentially down to one form of challenge-response authentication.
As you've mentioned it does prevent replay attacks, as the relying party (RP) will (hopefully) choose a challenge based on a random value.
It is also a way of authentication: By signing the unpredictable random value the authenticator proofs in a cryptographically secure way to the relying party (RP) that he is actually in control of the private key belonging to the public key being presented.