Copyright © 2013-2018 FIDO Alliance All Rights Reserved.
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.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current FIDO Alliance publications and the latest revision of this technical report can be found in the FIDO Alliance specifications index at https://www.fidoalliance.org/specifications/.
This document was published by the FIDO Alliance as a Implementation Draft. This document is intended to become a FIDO Alliance Proposed Standard. If you wish to make comments regarding this document, please Contact Us. All comments are welcome.
This Implementation Draft Specification has been prapared by FIDO Alliance, Inc. Permission is hereby granted to use the Specification solely for the purpose of implementing the Specification. No rights are granted to prepare derivative works of this Specification. Entities seeking permission to reproduce portions of this Specification for other uses must contact the FIDO Alliance to determine whether an appropriate license for such use is available.
Implementation of certain elements of this Specification may require licenses under third party intellectual property rights, including without limitation, patent rights. The FIDO Alliance, Inc. and its Members and any other contributors to the Specification are not, and shall not be held, responsible in any manner for identifying or failing to identify any or all such third party intellectual property rights.
THIS FIDO ALLIANCE SPECIFICATION IS PROVIDED “AS IS” AND WITHOUT ANY WARRANTY OF ANY KIND, INCLUDING, WITHOUT LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
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].
This section is non-normative.
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 Base64 encoded SHA-256 (or SHA-1) hash of the APK signing certificate [APK-Signing]:
android:apk-key-hash-sha256:<base64_encoded_sha256_hash-of-apk-signing-cert>
android:apk-key-hash:<base64_encoded_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 <alias-of-entry> \ -keystore <path-to-apk-signing-keystore> &>2 /dev/null | \ openssl sha256 -binary | \ openssl base64 | \ sed 's/=//g'
# Export the signing certificate in DER format, hash, base64 encode and trim '=' keytool -exportcert \ -alias <alias-of-entry> \ -keystore <path-to-apk-signing-keystore> &>2 /dev/null | \ openssl sha1 -binary | \ openssl base64 | \ sed 's/=//g'
The Base64 encoding is the the "Base 64 Encoding" from Section 4 in [RFC4648], with padding characters removed.
If compatibility with older versions of FIDO Clients (i.e. the ones not yet supporting SHA-256 for FacetIDs) is required, both entries should be specified.
In the iOS [iOS] case, the FacetID MUST be the BundleID [BundleID] URI of the application:
ios:bundle-id:<ios-bundle-id-of-app>
The Trusted Facets JSON resource is a serialized TrustedFacetList
hosted at the
AppID URL. It consists of a dictionary containing
a single member, trustedFacets
which is an
array of TrustedFacets
dictionaries.
dictionary TrustedFacetList {
required TrustedFacets[] trustedFacets;
};
TrustedFacetList
MemberstrustedFacets
of type array of required TrustedFacetsdictionary TrustedFacets {
required Version version;
required DOMString[] ids;
};
TrustedFacets
Membersversion
of type required Versionversion
structure.
ids
of type array of required DOMString{ "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 ] }] }
{ "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 ] }] }
This section is non-normative.
The following code demonstrates how a FIDO Client can obtain and construct the FacetID of a calling Android native application.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("SHA256"); return "android:apk-key-hash-sha256:" + 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; }
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.
This section is non-normative.
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.