[webauthn] Proposal for password-only authentication using ES256 (#2091)

dolda2000 has just created a new issue for https://github.com/w3c/webauthn:

== Proposal for password-only authentication using ES256 ==
I would like to propose there being a standardized format for password-only (that is, effectively single-factor authentication) keys using WebAuthn.

I understand there may be some reluctance among the WebAuthn community to such low-security uses of WebAuthn, so to make my case for it, I'd like to assert that there are, for the foreseeable future, cases where one might one to use password-only authentication instead of implementation-bound keys for a variety of reasons (I think this assertion should be uncontroversial enough to not have to bring up examples), and in such cases, strictly *if you are going to use a password anyway*:
 * It is better to use a challenge-response-based protocol where the password never has to leave the user-agent; and
 * Password authentication would stand to benefit a lot from the strong anti-phishing protections that WebAuthn offers.

---

My proposal, such as it is, then, wouldn't extend the WebAuthn protocol as such, but rather offer a standardized format for such keys that can be used across independent implementations, and which wouldn't require any changes on the part of RPs. The basic idea is to run the password through some sort of PRF with 32 bytes of output, and derive an ES256 key from said output, and to identify keys thus generated with a standardized format for the credential ID, which would also specify parameters for the PRF.

I propose a credential-ID format consisting of the following parts, in order:
 * The first 8 bytes are a checksum of the rest of the ID data. It is calculated by calculating the SHA-256 hash of the ASCII string "`pwkey`", concatenated with the rest of the credential-ID data, and taking the first 8 bytes thereof. As far as I can tell, the checksum shouldn't be security-critical, so it's mostly just a tag for recognizing a password-based key.
 * A NUL-terminated string naming the PRF to be used.
 * Any parameters for the PRF, in a format specific to each PRF.

To start out with, I only propose one PRF, its name being "`pbkdf2-sha256`". Obviously, this would be using PBKDF2 with the SNA-256 hash function, except that to preserve the anti-phishing strength, the RPID needs to be combined with the password. The parameters for this PRF would consist of the the following parts, in order:
 * A single unsigned byte, *n*, specifying the 2log of the iteration count, and
 * 32 bytes, *salt*, to be used for the PBKDF2 salt.

To incorporate the RPID, the actual password used as input for PBKDF2 should be the concatenation of the RPID hash with the password as input by the user (the hash is used instead of the text RPID to avoid any potential extension attacks). Thus, the output of this PRF, given a *password* to hash, would be PBKDF2(SHA-256, SHA-256(*RPID*) | *password*, *salt*, 1 << *n*, 32). As an example, then, a `pbkdf2-sha256` credential might be, in hex-encoded form:
 * `92F9795026B3B7A570626B6466322D7368613235360014ED3035C6AB2A060BF3C73D96678084F5FDDD0C419B5D89415ABE8D2E1BE273F9`

When used with the password "`123`" on RP "`example.com`*, it would produce the following output:
 * `75E7E2F671172E740D45BA1CFC7B316C58878444D0EA151A6B5888CCF896AB51`

---

In order to generate an ES256 key from the PRF output, then, as far as my knowledge of ECDSA goes, it should be fine to more or less use the PRF output as it is as the *d* value for a P-256 key (the *x* and *y* coordinates would of course just be calculated from the *d* value), the only caveat being that its numerical value cannot be greater than the generator order of the curve (the *n* value in standardized curve parameters). As how to deal with this limitation, that is where the limits of my knowledge of elliptic curve mathematics are hit:
 * The obvious proposition would be to simply use the remainder of the PRF output with the *n* number of the curve. However, a small subset of PRF outputs (those that overflow *n*) would then result in a low numerical value and low Hamming weight for *d*, which I don't know if it should be considered a problem. If it is, then;
 * The slightly more complex proposition would be to take a PRF-output number that overflows *n* and simply rotate the bits left until it no longer does.

If anyone is interested in this proposal, I would appreciate input on which method to use, but my inclination (not knowing better) would be to go the perhaps somewhat safer route and use the latter.

---

Finally, as for the various metadata produced for the WebAuthn protocol:
 * Decent user-agents should probably set the UV bit if the password was freshly input, and clear it if a saved password was used.
 * The `rk` property should not be set.
 * The `BS` and `BE` bits should probably reflect whether the password is stored in a password-manager with backup capabilities, though I don't know why anyone would use these keys in favor of properly randomly generated keys with a WebAuthn-aware password-manager.

---

I think that should be all that is relevant for the proposal.

Is anyone interested in this, and if so, any thoughts?

Please view or discuss this issue at https://github.com/w3c/webauthn/issues/2091 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Tuesday, 2 July 2024 19:03:54 UTC