Projects/SPAKE security key support
The SPAKE pre-authentication mechanism provides protection against dictionary attacks when used with traditional password-based long-term keys alone. It also includes optional support for an additional second factor. The goal of this project is to support a second factor using security keys adhering to the FIDO Alliance standards.
There are two versions of the access protocol for security keys, CTAP 1 and CTAP 2. CTAP 2 is more complicated and uses different terminology from CTAP 1. This writeup will use CTAP 1 terms for now, but will need to be updated for CTAP 2 as the library we want to use (libfido2) uses CTAP 2 terminology.
An important feature of security keys is that a single key can be used with multiple servers or applications. Properly designed client software will prevent phishing (where one service obtains a valid access credential for another service) and correlation of users across services.
There are two steps to using a security token, registration and signature. Registration produces a key handle and public key, which must be associated with the principal entry in the KDB to bind the token to the principal. Signing produces a one-time access credential in response to a challenge. Both steps require the client software to provide a consistent application parameter to the security key. To prevent phishing, the client must not simply accept the server's assertion of an application parameter. Web browsers will typically use the web origin (RFC 6454) as the application parameter.
There are numerous options for how to handle registration in this project within the CTAP 1 framework, some of them less satisfactory than others:
- Registration is performed out of band via a web server and browser. The KDC provides the origin of the web server to the client in the SPAKE factor challenge, and the client simply accepts any value. This turns the client into a signing oracle which could be used by a rogue KDC (or an attacker who knows the client's password) to attack other applications.
- Registration is performed out of band via a web server and browser. The web server serves a list of "facet IDs" which must include one derived from the realm name (e.g. "krb5realm:KRBTEST.COM"; this is not currently a registered URI scheme). The KDC provides the https URL to the facet ID list to the client in the SPAKE factor challenge; the client queries the server for the list and verifies that it contains the required facet ID for the realm being authenticated to. After verification, the client uses the URI's origin as the application parameter. (As an optimization, client configuration could be used to remove the need for the HTTPS query.)
- Registration is performed out of band via a web server and browser. The web server origin is constrained to be a fixed function of the realm name, or to be set for the realm in client configuration.
- Registration is performed out of band via a pair of utilities on the client and KDC, using an application ID like "krb5realm:KRBTEST.COM". This option would not be very usable without additional site-specific infrastructure.
- Registration is performed out of band via HTTPS, but with a Kerberos-specific client utility that registers the key with an appliation ID like "krb5realm:KRBTEST.COM" using a realm supplied by the user.
- Registration is performed out of band using a Kerberos-specific protocol. The commonly-used password change protocol is probably too simple to work. The proposed set-password protocol (https://tools.ietf.org/html/draft-ietf-krb-wg-kerberos-set-passwd-08) might be able to accomodate it, but this proposal did not achieve traction and is not implemented in any Kerberos software.
- Registration is performed in band. The KDC administrator flags the principal entry as requiring token registration, causing the KDC to issue a special challenge asking for token registration. The client supplies the output of registration to the KDC in the response. The KDC records the key handle and public key in the KDB so that future authentications must use the same token. This option is difficult to implement in the current architecture; kdcpreauth modules are not really expected to modify the KDB, and the KDC serving the authentication response could be a replica server. This option is also somewhat inflexible; it would not allow sites to require any corroborating information (beyond the Kerberos password) to verify that the intended user is registering a token. This option requires the kdcpreauth module to implement attestation policy, or precludes having an attestation policy.
- As a variant of the above, the KDC could allow token registration by any user whenever the principal entry doesn't already have an associated security key. KDC administrator action would only be required to deassociate a token with the principal entry to allow a new security key to be registered. The same implementation obstacles apply.
The FIDO v2 standards replace the application parameter with a relying party identifier or "rpId". The rpID is required to be an immediate subdomain of a public DNS suffix (https://publicsuffix.org/), also known as a "PS+1". Although facets are still part of the terminology in the v2 standards, there is no longer a described mechanism to query a list of facets from an https URL; instead, platform implementations are required to somehow map native applications to rpId values. This architecture does not necessarily fit well with Kerberos, which makes no assumptions about realms named after PS+1s having similar trust domains. Nonetheless, we could have the client compute a PS+1 value from the realm name and use it as the rpID. The public suffix list is a changing resource, but is available as a system file on some platforms.
References:
- https://www.imperialviolet.org/2018/03/27/webauthn.html (this primarily uses the terminology of CTAP 1 and U2F)
- https://fidoalliance.org/specs/fido-v2.0-rd-20161004/fido-client-to-authenticator-protocol-v2.0-rd-20161004.html
- https://fidoalliance.org/specs/fido-u2f-v1.0-ps-20141009/fido-appid-and-facets-ps-20141009.html