// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module ash.secure_channel.mojom;
import "chromeos/ash/components/multidevice/mojom/multidevice_types.mojom";
import "chromeos/ash/services/secure_channel/public/mojom/nearby_connector.mojom";
import "chromeos/ash/services/secure_channel/public/mojom/secure_channel_types.mojom";
import "mojo/public/mojom/base/time.mojom";
// Keep in sync with SecureChannelConnectionAttemptFailureReason in
// tools/metrics/histograms/enums.xml
enum ConnectionAttemptFailureReason {
// The local device could not authenticate with the remote device. This likely
// means that one (or both) devices have not synced their keys recently.
AUTHENTICATION_ERROR = 0,
// An advertisement could not be generated for this connection. This likely
// means that one (or both) devices have not synced their BeaconSeeds
// recently.
COULD_NOT_GENERATE_ADVERTISEMENT = 1,
// GATT connections were attempted, but they failed. This could be caused by
// errors creating GATT connections, dropped GATT connections, or an issue
// relating to GATT services being unavailable.
GATT_CONNECTION_ERROR = 2,
// A Nearby Connection was attempted, but it failed. Potential causes include
// internal API errors and flaky Bluetooth/WebRTC connections.
NEARBY_CONNECTION_ERROR = 3,
// The provided local device does not have a public key set.
LOCAL_DEVICE_INVALID_PUBLIC_KEY = 4,
// The provided local device does not have a persistent symmetric key set.
LOCAL_DEVICE_INVALID_PSK = 5,
// The provided local device does not have a valid Bluetooth address.
LOCAL_DEVICE_INVALID_BLUETOOTH_ADDRESS = 6,
// The provided remote device does not have a public key set.
REMOTE_DEVICE_INVALID_PUBLIC_KEY = 7,
// The provided remote device does not have a persistent symmetric key set.
REMOTE_DEVICE_INVALID_PSK = 8,
// The provided remote device does not have a valid Bluetooth address.
REMOTE_DEVICE_INVALID_BLUETOOTH_ADDRESS = 9,
// Timeouts occurred trying to contact the remote device.
TIMEOUT_FINDING_DEVICE = 10,
// The local Bluetooth adapter is disabled (turned off).
ADAPTER_DISABLED = 11,
// The local Bluetooth adapter is not present.
ADAPTER_NOT_PRESENT = 12,
// Tried to connect using a role which is unsupported for the connection
// medium (e.g., Nearby Connections only supports the listener role, not the
// initiator role).
UNSUPPORTED_ROLE_FOR_MEDIUM = 13,
// Tried requesting a connection via Nearby Connections, but no
// NearbyConnector was provided.
MISSING_NEARBY_CONNECTOR = 14,
// The attempt was intentionally interrupted.
CONNECTION_CANCELLED = 15,
};
enum ConnectionCreationDetail {
REMOTE_DEVICE_USED_BACKGROUND_BLE_ADVERTISING,
REMOTE_DEVICE_USED_FOREGROUND_BLE_ADVERTISING
};
// Determines the order in which connections are attempted when system resources
// must be shared. For example, a device can only register a limited number of
// BLE advertisements at a given time due to hardware constraints; in this
// situation, a connection attempt with a higher priority will be allowed to
// register an advertisement before an attempt with a lower priority.
//
// For connection mediums which do not require use of limited system resources,
// ConnectionPriority is ignored.
enum ConnectionPriority {
// Should be used for connection attempts which do not have latency
// requirements (e.g., background scans for nearby devices).
LOW,
// Should be used when the connection attempt should complete in a reasonable
// amount of time but is not urgent (e.g., heartbeat/keep-alive messages).
MEDIUM,
// Should be used when the user is directly waiting on the result of the
// connection (e.g., the user clicks a button and sees a spinner in the UI
// until the connection succeeds).
HIGH
};
enum ConnectionMedium {
// Connection occurs using GATT over Bluetooth Low Energy (BLE).
kBluetoothLowEnergy,
// Connection occurs using the Nearby Connections library, which bootstraps
// a connection via Bluetooth Classic, then "upgrades" bandwidth to a WebRTC
// connection.
kNearbyConnections
};
enum DiscoveryResult {
// Failed to discovered device. A DiscoveryErrorCode will be appended\
// when logging.
kFailure,
// Successfully discovered device.
kSuccess
};
// Possible error code happened during BLE discovery process. Should be
// associated with DiscoveryResult.
enum DiscoveryErrorCode {
kBluetoothTurnedOff,
kFilterCreationFailed,
kErrorStartingDiscovery,
kBleSessionInvalidated,
kDeviceNotInScanRequest,
kTimeout
};
// Different state during Secure Channel authentication process.
enum SecureChannelState {
kGeneratingSessionKeys,
kSendingHello,
kSentHello,
kReceivedResponderAuth,
kValidatedResponderAuth,
kSentInitiatorAuth,
kAuthenticationSuccess,
kFailureNotConnectedToRemoteDevice,
kFailedToGenerateSessionKeys,
kFailedToGenerateHelloMessage,
kFailedToSendHelloMessage,
kFailedToWaitForResponderAuth,
kReceivedUnexpectedMessage,
kFailedToValidateReponderAuth,
kFailedToGenerateInitiatorAuth,
kFailedToSendInitiatorAuth,
kFailureDisconnectDuringAuthentication
};
struct BluetoothConnectionMetadata {
// RSSI at the exact time that this metadata was requested. Note that RSSI
// may change drastically in a short period; this is only a snapshot.
int32 current_rssi;
};
struct ConnectionMetadata {
// Details which describe how the connection was created. If no
// ConnectionCreationDetails apply to this connection, the array is empty.
array<ConnectionCreationDetail> creation_details;
// Only available for connections over Bluetooth.
BluetoothConnectionMetadata? bluetooth_connection_metadata;
// The responder auth message returned by the other device during the
// cryptographic handshake that established the channel. These are serialized
// bytes of a proto which contains an encrypted message, returned by the
// remote device in the last step of a 3-step cryptographic handshake. These
// bytes were publicly visible over BLE when the connection with the remote
// device was being established. It is used by some clients for further
// cryptographic communication.
// Defined by //chromeos/ash/services/device_sync/proto/securemessage.proto.
string channel_binding_data;
};
// Allows clients to send messages to a remote device, or registers local files
// to receive incoming files transferred from a remote device. Can also be used
// to get metadata of the underlying connection. Called from Secure Channel
// client side API implementation.
interface Channel {
// If the connection is dropped (e.g., by the remote device or due to
// connection instability), this reason is supplied to the
// connection_error_with_reason_handler.
const int32 kConnectionDroppedReason = 1;
// Sends an encrypted message over the connection. The message is sent
// along with metadata indicating the feature used to create this
// connection. The callback is invoked when the message has been sent
// successfully. If the message fails to be sent, the entire Channel is
// disconnected with reason |kConnectionDroppedReason|, and the SendMessage()
// callback is never invoked.
SendMessage(string message) => ();
// Registers |payload_files| to receive an incoming file transfer with
// the given |payload_id|. Callers can listen to progress information about
// the transfer through the |listener|. Returns whether the file was
// successfully registered. The |listener| will be disconnected after the file
// transfer is complete.
RegisterPayloadFile(int64 payload_id,
PayloadFiles payload_files,
pending_remote<FilePayloadListener> listener)
=> (bool success);
GetConnectionMetadata() => (ConnectionMetadata metadata);
};
interface MessageReceiver {
// Invoked when a message is received over the connection. Only messages
// corresponding to the feature used when creating the connection are
// passed to this callback.
OnMessageReceived(string message);
};
// Delegate interface used to handle connection attempt successes/failures. Note
// that this interface is intended to be implemented by clients of the
// DeviceSync service.
interface ConnectionDelegate {
// Invoked when a connection attempt failed (i.e., the failure occurred before
// a connection could be established).
OnConnectionAttemptFailure(ConnectionAttemptFailureReason reason);
// Invoked when a connection is established. The channel is authenticated
// with account credentials, and all messages sent over the channel are
// encrypted. Client should set a connection_error_with_reason_handler on
// |channel| to be notified when it has been invalidated due to a dropped
// connection. Note that clients are expected to hold the reference to
// |channel| until they are done using the connection.
// |nearby_connection_state_listener_receiver| will only be invoked if the
// channel is over Nearby Connection.
OnConnection(pending_remote<Channel> channel,
pending_receiver<MessageReceiver> message_receiver_receiver,
pending_receiver<NearbyConnectionStateListener>
nearby_connection_state_listener_receiver);
};
// The interface used to log state of each step during Secure Channel connection
// establishment.
interface SecureChannelStructuredMetricsLogger {
// Invoked when BLE discovery step of Secure Channel connection attempt has an
// result. And if the result is a failure result, an error code will also be
// passed in.
LogDiscoveryAttempt(DiscoveryResult result, DiscoveryErrorCode? error_code);
// Invoked when there is a state change during Nearby Connection process.
LogNearbyConnectionState(NearbyConnectionStep step,
NearbyConnectionStepResult status);
// Invoked when there is a state change during Secure Channel authentication
// process.
LogSecureChannelState(SecureChannelState state);
};
// Brokers connections between the current Chromebook and remote devices,
// allowing the sending/receiving of messages. All channels created via this API
// are authenticated and all messages sent are encrypted via account-specific
// keys.
//
// If multiple connections are requested to the same device, this service
// creates only one connection and shares it among all clients; likewise, if
// multiple clients are sharing a single connection and one client drops its
// reference to the connection, the connection will stay active until each
// client has invalidated its reference to the channel.
//
// All connections require metadata about the local device (i.e., the device on
// which this code is running) in order to perform a cryptographic handshake
// which ensures that both devices are owned by the same underlying account.
// Note that each logged-in user on Chrome OS has its own set of keys; thus, the
// provided local device is not the same each time the call is made. For
// instance, at the sign-in (i.e., account-choosing) screen, EasyUnlock tries to
// establish connections to phones belonging to each account on the device, so
// each of these connection attempts uses a different local device.
//
// If a Nearby-based connection is requested, clients must first invoke
// SetNearbyConnector().
//
// Note: Each API function results in either one connection (success case)
// or zero connections (failure case). Clients wishing to initiate another
// connection after the first one has completed should invoke the API again.
interface SecureChannel {
// Starts listening for an incoming connection attempt from |device|.
// This function listens indefinitely until a connection is formed, at
// which time |delegate|'s OnConnection() is invoked. |delegate|'s
// OnConnectionFailure() is only invoked if the connection could not be
// attempted at all (e.g., if |device| did not contain valid metadata). To
// cancel a connection attempt (i.e., to stop listening for incoming
// connections), disconnect |delegate|.
ListenForConnectionFromDevice(
ash.multidevice.mojom.RemoteDevice device_to_connect,
ash.multidevice.mojom.RemoteDevice local_device,
string feature,
ConnectionMedium connection_medium,
ConnectionPriority connection_priority,
pending_remote<ConnectionDelegate> delegate);
// Initiates a connection to |device|, which is presumed to be listening
// for incoming connections. This function attempts to create a connection
// until it has succeeded or until it has failed several attempts.
// |delegate|'s OnConnection() is called in the success case, and
// OnConnectionFailure() is called if a connection could not be attempted or
// if a connection was attempted and failed several retry attempts. To cancel
// the connection attempt, disconnect |delegate|.
InitiateConnectionToDevice(
ash.multidevice.mojom.RemoteDevice device_to_connect,
ash.multidevice.mojom.RemoteDevice local_device,
string feature,
ConnectionMedium connection_medium,
ConnectionPriority connection_priority,
pending_remote<ConnectionDelegate> delegate,
pending_remote<SecureChannelStructuredMetricsLogger>?
secure_channel_structured_metrics_logger);
// Sets a NearbyConnector to be used by future connection requests. Must be
// called before requesting a connection with
// ConnectionMedium::kNearbyConnections. Should only be called once.
SetNearbyConnector(pending_remote<NearbyConnector> nearby_connector);
// Retrieves the timestamp of the last successful discovery for the given
// |remote_device_id|, or null if we haven't seen this remote device during
// the current Chrome session.
GetLastSeenTimestamp(string remote_device_id) => (mojo_base.mojom.Time? time);
};