blob: b4a379a3fa8321b896bb908bdce5674b3721e2ef [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.identity.internal;
using fuchsia.auth;
using fuchsia.identity.account;
using fuchsia.identity.authentication;
using fuchsia.identity.external;
using fuchsia.kms;
const uint32 HASH_SIZE = 32;
const uint32 HASH_SALT_SIZE = 32;
alias GlobalIdHash = array<byte>:HASH_SIZE;
alias HashSalt = array<byte>:HASH_SALT_SIZE;
/// The control channel for an AccountHandler component.
///
/// This interface is intended only for use by the AccountManager component that
/// starts instances of AccountHandler. We define which account the handler
/// should be handling one time via this channel rather than via startup flags to
/// provide additional flexibility given the range of scenarios:
/// * The account is completely new
/// * The account is being added to the current device for the first time
/// * Account information is already present on the local disk and is readable
/// * Account information is already present on the local disk but is not yet
/// readable because the disk is not yet decrypted.
///
/// A given Account Handler progresses through the following state machine:
/// ```
/// |
/// V
/// +---------------+
/// +--------------| Uninitialized |------------+
/// | +---------------+ |
/// | | |
/// | PrepareForTransfer | | Preload
/// V | V
/// +------------------+ | +------------------+
/// | PendingTransfer | | | Locked |
/// +------------------+ | +------------------+
/// | | ^
/// | PerformTransfer | |
/// V | |
/// +------------------+ | | LockAccount /
/// | Transferred | | CreateAccount | UnlockAccount
/// +------------------+ | |
/// | | |
/// | FinalizeTransfer | |
/// | V |
/// | +---------------+ |
/// +------------->| Initialized |<-----------+
/// +---------------+
/// |
/// | Terminate
/// V
/// +---------------+
/// | Finished |
/// +---------------+
/// ```
///
/// * `Uninitialized` - the handler has just been instantiated and contains no
/// account information.
/// * `PendingTranfer` - the handler is awaiting an account transfer. It has
/// created a public key pair that will be associated with the account on this
/// device, but contains no other account information.
/// * `Transferred` - the handler has received transferred account information
/// and is holding it in memory. In this state, the account transfer is not
/// yet known to be valid, and is pending further validation from account
/// manager. The account is not available for use, and regardless of the
/// intended lifetime of the account on this device, the account is not
/// saved to disk.
/// * `Locked` - the handler has loaded pre-authentication data, which lets it
/// unlock the account subsequently.
/// * `Initialized` - the handler has loaded account information and is ready
/// to serve requests for the `Account` interface. If the account is
/// persistent on this device, then it is saved to disk.
/// * `Finished` - the handler is in the process of shutting down and will soon
/// terminate.
// TODO(fxbug.dev/42836): Supply UI for system authentication.
[Discoverable]
protocol AccountHandlerControl {
/// Creates a completely new Fuchsia account, optionally protecting the
/// account with a single enrollment of an authentication mechanism.
///
/// `auth_mechanism_id` An `AuthMechanismId` for a storage
/// unlock-capable authentication mechanism. If
/// provided, a single enrollment of that
/// mechanism will be created for storage
/// unlock.
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in the `Uninitialized`
/// state.
CreateAccount(
fuchsia.identity.account.AuthMechanismId? auth_mechanism_id)
-> () error fuchsia.identity.account.Error;
/// Loads pre-auth data, which allows the account to be unlocked later.
///
/// This moves the AccountHandler from the `Uninitialized` state to the `Locked` state.
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in the `Uninitialized`
/// state.
Preload() -> () error fuchsia.identity.account.Error;
/// Reach the `Initialized` state, attempting authentication and unlocking the account where
/// necessary.
///
/// Fails with
/// - FAILED_PRECONDITION if the AccountHandler is not in the `Locked` or `Initialized` state.
/// - FAILED_AUTH_ATTEMPT if the authentication attempt failed.
UnlockAccount()
-> () error fuchsia.identity.account.Error;
/// Reach the `Locked` state, closing any open `Account` and `Persona` channels for the account.
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in the `Initialized` or
/// `Locked` state.
LockAccount() -> () error fuchsia.identity.account.Error;
/// Prepares the AccountHandler to receive an account from another device through
/// direct transfer. This moves the AccountHandler from the `Uninitialized`
/// state to the `PendingTransfer` state.
///
/// `PrepareForAccountTransfer` should be used in conjunction with
/// `PerformAccountTransfer`, `FinalizeAccountTransfer`, and
/// `EncryptAccountData` to provision an existing account on another device
/// (source) to this device (target).
///
/// The expected sequence of calls to setup an AccountHandler with a transferred
/// account is as follows:
/// 1. `PrepareForAccountTransfer` is called on the target device.
/// 2. The public key for the target device is retrieved using `GetPublicKey`
/// and handed to the source device.
/// 3. Account data is encrypted on the source device using the public key
/// with `EncryptAccountData`.
/// 4. The encrypted account data is passed in to AccountHandler on the target
/// device with `PerformAccountTransfer`.
/// 5. After any validation, the transfer is finalized on the target device
/// with a call to `FinalizeAccountTransfer`.
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in the `Uninitialized`
/// state.
PrepareForAccountTransfer() -> () error fuchsia.identity.account.Error;
// TODO(satsukiu): investigate using VMOs or pagination over Overnet for
// when account size exceeds what FIDL can handle.
/// Loads the encrypted account into memory, but does not make it available
/// for use yet. The account data passed in is expected to be serialized as
/// an `AccountTransferContainer` and encrypted using the public key
/// retrieved from `GetPublicKey`. This format of account data is provided
/// by `EncryptAccountData` on the source device.
///
/// Moves the AccountHandler from the `PendingTransfer` state to the
/// `Transferred` state.
///
/// `encrypted_account_data` Account data retrieved on the source device
/// using `EncryptAccountData`.
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in the
/// `PendingTransfer` state.
PerformAccountTransfer(EncryptedAccountData encrypted_account_data)
-> () error fuchsia.identity.account.Error;
/// Completes the account transfer started through
/// `PrepareForAccountTransfer` and `PerformAccountTransfer`. This saves
/// the account to disk if the account is persistent and makes it available
/// for use.
///
/// Moves the AccountHandler from the `Transferred` state to the
/// `Initialized` state.
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in the `Transferred`
/// state.
FinalizeAccountTransfer()
-> () error fuchsia.identity.account.Error;
// TODO(fxr/37227) - update encrypt/decrypt APIs to handle data given by KMS.
/// Serializes and encrypts the account contained in the AccountHandler for
/// transfer. The account will be serialized as `AccountData` and
/// encrypted using `target_public_key`. The resulting
/// `EncryptedAccountData` should be passed to AccountHandler on the target
/// device using `PerformAccountTransfer`.
///
/// `target_public_key` The public key used to encrypt the account data.
///
/// Returns: `encrypted_account_data` Bytes containing the encrypted account
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in the `Initialized`
/// state.
EncryptAccountData(fuchsia.kms.PublicKey target_public_key)
-> (EncryptedAccountData encrypted_account_data) error fuchsia.identity.account.Error;
/// Deletes all persistent information about the Fuchsia account handled by
/// this handler, including all credentials and global identifiers.
/// Credential revocation is attempted before deletion. After a
/// successful call to RemoveAccount, all other open interfaces for this
/// account handler will be closed and any subsequent calls on the current
/// interface will fail.
///
/// `force` If true, continues removing the account even if revocation of
/// credentials fails. If false, any revocation failure will result
/// in an error and the account will remain. In this case, a subset
/// of the credentials may have been deleted.
RemoveAccount(bool force) -> () error fuchsia.identity.account.Error;
// TODO(jsankey): Add methods to cover adding an existing account and
// handling an account where the disk is not yet decrypted.
/// Connects an interface to read properties of and perform operations on
/// the account handled by this handler. The AccountHandler must be in the
/// `Initialized` state.
///
/// `context_provider` An `AuthenticationContextProvider` capable of
/// supplying UI contexts used for interactive
/// authentication on this account
/// `account` The server end of an `Account` channel
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in the `Initialized`
/// state.
GetAccount(
fuchsia.auth.AuthenticationContextProvider auth_context_provider,
request<fuchsia.identity.account.Account> account)
-> () error fuchsia.identity.account.Error;
/// Retrieves the public key associated with this account on this device.
/// The public key is exposed so that the target AccountHandler's key can
/// be distributed to the source AccountHandler during an account transfer.
/// This allows the source AccountHandler to encrypt account data such that
/// only the target AccountHandler can decrypt the data.
///
/// Returns: `public_key` Public key in an asymmetric key pair associated
/// with this account on this device.
///
/// Fails with FAILED_PRECONDITION is the AccountHandler is not in one of
/// `PendingTransfer`, `Transferred`, or `Initialized` states.
GetPublicKey() -> (fuchsia.kms.PublicKey public_key) error fuchsia.identity.account.Error;
/// Generates a hash of the global account ID using the provided salt.
/// Returning a hash of the global ID lets the account system determine
/// whether two locally provisioned accounts represent the same account
/// without storing every account's global ID. A salt is added so that
/// accounts cannot be easily correlated across devices.
///
/// The AccountHandler must be in either the `Transferred` or `Initialized`
/// states.
///
/// `salt` Bytes used as a salt while hashing global ID.
///
/// Returns: `id_hash` A hash of the global ID of the contained account
///
/// Fails with FAILED_PRECONDITION if the AccountHandler is not in one of
/// `Transferred` or `Initialized` states.
GetGlobalIdHash(HashSalt salt) -> (GlobalIdHash id_hash) error fuchsia.identity.account.Error;
/// Signals that the AccountHandler should tear itself down. After the
/// receiver responds by closing its handle, the caller may terminate the
/// component if it hasn't already exited.
Terminate();
};
/// An interface that supplies the account and authentication services that
/// an AccountHandler needs to perform its role in the system.
///
/// This service is supplied into the namespace of AccountHandler by the
/// component that launches it (i.e. the AccountManager).
[Discoverable]
protocol AccountHandlerContext {
/// Connects to the `Oauth` implementation for a particular service provider,
/// launching it if necessary.
///
/// `auth_provider_type` An OAuth identity provider matching a configuration
/// set in an AuthProviderConfig.auth_provider_type
/// `oauth` The server end of an `Oauth` channel
GetOauth(string auth_provider_type,
request<fuchsia.identity.external.Oauth> oauth)
-> () error fuchsia.identity.account.Error;
/// Connects to the `OpenIdConnect` implementation for a particular service
/// provider, launching it if necessary.
///
/// `auth_provider_type` An OpenID Connect identity provider matching a
/// configuration set in an
/// AuthProviderConfig.auth_provider_type
/// `open_id_connect` The server end of an `OpenIDConnect` channel
GetOpenIdConnect(string auth_provider_type,
request<fuchsia.identity.external.OpenIdConnect> open_id_connect)
-> () error fuchsia.identity.account.Error;
/// Connects to the `OauthOpenIdConnect` implementation for a particular
/// service provider, launching it if necessary.
///
/// `auth_provider_type` An OpenID Connect identity provider matching a
/// configuration set in an
/// AuthProviderConfig.auth_provider_type
/// `oauth_open_id_connect` The server end of an `OauthOpenIDConnect` channel
GetOauthOpenIdConnect(string auth_provider_type,
request<fuchsia.identity.external.OauthOpenIdConnect>
oauth_open_id_connect)
-> () error fuchsia.identity.account.Error;
/// Connects to a `StorageUnlockMechanism` implementation identified by its
/// auth mechanism ID, launching the associated Authenticator if necessary.
///
/// `auth_mechanism_id` An identifier matching an authentication mechanism
/// configured by the account system.
/// `storage_unlock_mechanism` The server end of an `StorageUnlockMechanism` channel
GetStorageUnlockAuthMechanism(
fuchsia.identity.account.AuthMechanismId auth_mechanism_id,
request<fuchsia.identity.authentication.StorageUnlockMechanism> storage_unlock_mechanism)
-> () error fuchsia.identity.account.Error;
};
/// Contents of an account, used for serialization during account transfer.
table AccountData {
/// A globally unique identifier for the account.
1: fuchsia.identity.account.GlobalAccountId global_id;
};
/// Encrypted form of AccountData.
alias EncryptedAccountData = bytes:16000;