The FIDO family of protocols introduce a new security concept, Application Facets, to describe the scope of user credentials and how a trusted computing base which supports application isolation may make access control decisions about which keys can be used by which applications and web origins.
This document describes the motivations for and requirements for implementing the Application Facet concept and how it applies to the FIDO protocols.
Type names, attribute names and element names are written as code
.
String literals are enclosed in “”, e.g. “UAF-TLV”.
In formulas we use “|” to denote byte wise concatenation operations.
This document applies to both the U2F protocol and the UAF protocol. UAF specific terminology used in this document is defined in [[!FIDOGlossary]].
All diagrams, examples, notes in this specification are non-normative.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [[!RFC2119]].
Modern networked applications typically present several ways that a user can interact with them. This document introduces the concept of an Application Facet to describe the identities of a single logical application across various platforms. For example, the application MyBank may have an Android app, an iOS app, and a Web app accessible from a browser. These are all facets of the MyBank application.
The FIDO architecture provides for simpler and stronger authentication than traditional username and password approaches while avoiding many of the shortfalls of alternative authentication schemes. At the core of the FIDO protocols are challenge and response operations performed with a public/private keypair that serves as a user's credential.
To minimize frequently-encountered issues around privacy, entanglements with concepts of "identity", and the necessity for trusted third parties, keys in FIDO are tightly scoped and dynamically provisioned between the user and each Relying Party and only optionally associated with a server-assigned username. This approach contrasts with, for example, traditional PKIX client certificates as used in TLS, which introduce a trusted third party, mix in their implementation details identity assertions with holder-of-key cryptographic proofs, lack audience restrictions, and may even be sent in the cleartext portion of a protocol handshake without the user's notification or consent.
While the FIDO approach is preferable for many reasons, it introduces several challenges.
This document describes how FIDO addresses these goals (where adequate platform mechanisms exist for enforcement) by allowing an application to declare a credential scope that crosses all the various facets it presents to the user.
FIDO conceptually sets a scope for registered keys to the tuple of (Username, Authenticator, Relying Party). But what constitutes a Relying Party? It is quite common for a user to access the same set of services from a Relying Party, on the same device, in one or more web browsers as well as one or more dedicated apps. As the Relying Party may require the user to perform a costly ceremony in order to prove her identity and register a new FIDO key, it is undesirable that the user should have to repeat this ceremony multiple times on the same device, once for each browser or app.
FIDO provides for user-friendly verification ceremonies to allow access to registered keys, such as entering a simple PIN code and touching a device, or scanning a finger. It should not matter for security purposes if the user re-uses the same verification inputs across Relying Parties, and in the case of a biometric, she may have no choice.
Modern operating systems that use an "app store" distribution model often make a promise to the user that it is "safe to try" any app. They do this by providing strong isolation between applications, so that they may not read each others' data or mutually interfere, and by requiring explicit user permission to access shared system resources.
If a user were to download a maliciously constructed game that instructs her to activate her FIDO authenticator in order to "save your progress" but actually unlocks her banking credential and takes over her account, FIDO has failed, because the risk of phishing has only been moved from the password to an app download. FIDO must not violate a platform's promise that any app is "safe to try" by keeping good custody of the high-value shared state that a registered key represents.
The OAuth and OAuth2 of protocols were designed for a server-to-server security model with the assumption that each application instance can be issued, and keep, an "application secret". This approach is ill-suited to the "app store" security model. Although it is common for services to provision an OAuth-style application secret into their apps in an attempt to allow only authorized/official apps to connect, any such "secret" is in fact shared among everyone with access to the app store and can be trivially recovered thorough basic reverse engineering.
In contrast, FIDO's facet concept is designed for the "app store" model from the start. It relies on client-side platform isolation features to make sure that a key registered by a user with a member of a well-behaved "trusted club" stays within that trusted club, even if the user later installs a malicious app, and does not require any secrets hard-coded into a shared package to do so. The user must, however, still make good decisions about which apps and browsers they are willing to preform a registration ceremony with. App store policing can assist here by removing applications which solicit users to register FIDO keys to for Relying Parties in order to make illegitmate or fraudulent use of them.
The Application Facet concept does not attempt to strongly identify the calling application to a service across a network. Remote attestation of an application identity is an explicit non-goal.
If an unauthorized app can convince a user to provide all the information to it required to register a new FIDO key, the Relying Party cannot use FIDO protocols or the Facet concept to recognize as unauthorized, or deny such an application from performing FIDO operations, and an application that a user has chosen to trust in such a manner can also share access to a key outside of the mechanisms described in this document.
The facet mechanism provides a way for registered keys to maintain their proper scope when created and accessed from a Trusted Computing Base (TCB) that provides isolation of malicious apps. A user can also roam their credentials between multiple devices with user-friendly TCBs and credentials will retain their proper scope if this mechanism is correctly implemented by each. However, no guarantees can be made in environments where the TCB is user-hostile, such as a device with malicious code operating with "root" level permissions. On environments that do not provide application isolation but run all code with the privileges of the user, (e.g. traditional desktop operating systems) an intact TCB, including web browsers, may successfully enforce scoping of credentials for web origins only, but cannot meaningfully enforce application scoping.
When a user performs a Registration operation [[UAFArchOverview]] a new private key is created
by their authenticator, and the public key is sent to the Relying Party. As part of this process,
each key is associated with an AppID
. The AppID
is a URL carried as part
of the protocol message sent by the server and indicates the target for this credential. By default,
the audience of the credential is restricted to the Same Origin of the AppID
.
In some circumstances, a Relying Party may desire to apply a larger scope to a key. If
that AppID
URL has the https
scheme, a FIDO client may be able to
dereference and process it as a TrustedFacetList
that designates a scope or audience
restriction that includes multiple facets, such as other web origins within the same DNS zone of
control of the AppID's origin, or URLs indicating the identity of other types of trusted facets
such as mobile apps.
Users may also register multiple keys on a single authenticator for an
AppID
, such as for cases where they have multiple accounts. Such registrations may
have a Relying Party assigned username or local nicknames associated to allow them to be distinguished
by the user, or they may not (e.g. for 2nd factor use cases, the user account associated with a key
may be communicated out-of-band to what is specified by FIDO protocols). All registrations
that share an AppID
, also share these same audience restriction.
In the Web case, the FacetID MUST be the Web Origin [[!RFC6454]] of the web page triggering the FIDO operation, written as a URI with an empty path. Default ports are omitted and any path component is ignored.
An example FacetID is shown below:
https://login.mycorp.com/
In the Android [[ANDROID]] case, the FacetID MUST be a URI derived from the SHA-1 hash of the APK signing certificate [[APK-Signing]], such as:
android:apk-key-hash:<sha1_hash-of-apk-signing-cert>
The SHA-1 hash can be computed as follows:
# Export the signing certificate in DER format, hash, base64 encode and trim '=' keytool -exportcert -alias androiddebugkey -keystore \ <path-to-apk-signing-keystore> &>2 /dev/null | openssl sha1 \ -binary | openssl base64 | sed 's/=//g'
In the iOS [[iOS]] case, the FacetID MUST be the BundleID [[BundleID]] URI of the application:
ios:bundle-id:<ios-bundle-id-of-app>
https://
Origin sharing the same host as the AppID,
(e.g. if an application hosted at https://fido.example.com/myApp
set
an AppID of https://fido.example.com/myAppId
), no additional processing
is necessary and the operation may proceed. This algorithm MAY be continued
asynchronously for purposes of caching the Trusted Facet List, if desired.FIDO-AppID-Redirect-Authorized: true
and the client MUST verify the presence
of such a header before following the redirect. This protects against abuse of open
redirectors within the target domain by unauthorized parties. If this check has passed,
restart this algorithm from step 4.trustedFacet
array, select the one with
the version
matching that of the protocol message version.ids
MUST identify either an application
identity (e.g. using the apk:
, ios:
or similar scheme) or an https:
Web Origin [[RFC6454]].ids
using the https://
scheme MUST contain only scheme,
host and port components, with an optional trailing /. Any path, query string, username/password,
or fragment information MUST be discarded.trustedFacets
entry of the correct
version
and removing any invalid entries, if the
caller's FacetID matches one listed in ids
, the operation is allowed.The JSON resource hosted at the AppID URL consists of a dictionary containing
a single member, trustedFacets
which is an
array of TrustedFacets
dictionaries.
version
structure.
{ "trustedFacets" : [{ "version": { "major": 1, "minor" : 0 }, "ids": [ "https://register.example.com", // VALID, shares "example.com" label "https://fido.example.com", // VALID, shares "example.com" label "http://www.example.com", // DISCARD, scheme is not https: "http://www.example-test.com", // DISCARD, "example-test.com" does not match "https://www.example.com:444" // VALID, port is not significant ] }] }For this policy, "https://www.example.com" and "https://register.example.com" would have access to the keys registered for this AppID, and "https://user1.example.com" would not.
{ "trustedFacets" : [{ "version": { "major": 1, "minor" : 0 }, "ids": [ "https://register.example.com", // DISCARD, does not share "companyA.hosting.example.com" label "https://fido.companyA.hosting.example.com", // VALID, shares "companyA.hosting.example.com" label "https://xyz.companyA.hosting.example.com", // VALID, shares "companyA.hosting.example.com" label "https://companyB.hosting.example.com" // DISCARD, "companyB.hosting.example.com" does not match ] }] }For this policy, "https://fido.companyA.hosting.example.com" would have access to the keys registered for this AppID, and "https://register.example.com" and "https://companyB.hosting.example.com" would not as a public-suffix exists between these DNS names and the AppID's.
private String getFacetID(Context aContext, int callingUid) { String packageNames[] = aContext.getPackageManager().getPackagesForUid(callingUid); if (packageNames == null) { return null; } try { PackageInfo info = aContext.getPackageManager().getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES); byte[] cert = info.signatures[0].toByteArray(); InputStream input = new ByteArrayInputStream(cert); CertificateFactory cf = CertificateFactory.getInstance("X509"); X509Certificate c = (X509Certificate) cf.generateCertificate(input); MessageDigest md = MessageDigest.getInstance("SHA1"); return "android:apk-key-hash:" + Base64.encodeToString(md.digest(c.getEncoded()), Base64.DEFAULT | Base64.NO_WRAP | Base64.NO_PADDING); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (CertificateEncodingException e) { e.printStackTrace(); } return null; }
The UAF protocol supports passing FacetID to the FIDO Server and including the FacetID in the computation of the authentication response.
Trusting a web origin facet implicitly trusts all subdomains under the named entity because web user agents do not provide a security barrier between such origins. So, in AppID Example 1, although not explicitly listed, "https://foobar.register.example.com" would still have effective access to credentials registered for the AppID "https://www.example.com/appID" because it can effectively act as "https://register.example.com".
The component implementing the controls described here must reliably identify callers to securely enforce the mechanisms. Platform inter-process communication mechanisms which allow such identification SHOULD be used when available.
It is unlikely that the component implementing the controls described here can verify
the integrity and intent of the entries on a TrustedFacetList
. If a trusted
facet can be compromised or enlisted as a confused deputy [[FIDOGlossary]] by a malicious party, it may
be possible to trick a user into completing an authentication ceremony under the control
of that malicious party.
Wildcards are not supported in TrustedFacet identifiers. This follows the advice of RFC6125 [[!RFC6125]], section 7.2.
FacetIDs are URIs that uniquely identify specific security principals that are trusted to interact with a given registered credential. Wildcards introduce undesirable ambiguitiy in the defintion of the principal, as there is no consensus syntax for what wildcards mean, how they are expanded and where they can occur across different applications and protocols in common use. For schemes indicating application identities, it is not clear that wildcarding is appropriate in any fashion. For Web Origins, it broadly increases the scope of the credential to potentially include rogue or buggy hosts.
Taken together, these ambiguities might introduce exploitable differences in identity checking behavior among client implementations and would necessitate overly complex and inefficient identity checking algorithms.