/* * Copyright 2023 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ syntax = "proto3"; option java_multiple_files = true; package org.signal.chat.keys; import "google/protobuf/empty.proto"; import "org/signal/chat/common.proto"; import "org/signal/chat/errors.proto"; import "org/signal/chat/require.proto"; import "org/signal/chat/tag.proto"; // Provides methods for working with pre-keys. service Keys { option (require.auth) = AUTH_ONLY_AUTHENTICATED; // Retrieves an approximate count of the number of the various kinds of // pre-keys stored for the authenticated device. rpc GetPreKeyCount (GetPreKeyCountRequest) returns (GetPreKeyCountResponse) {} // Retrieves a set of pre-keys for establishing a session with the targeted // device or devices. Note that callers with an unidentified access key for // the targeted account should use the version of this method in // `KeysAnonymous` instead. rpc GetPreKeys(GetPreKeysRequest) returns (GetPreKeysResponse) {} // Uploads a new set of one-time EC pre-keys for the authenticated device, // clearing any previously-stored pre-keys. Note that all keys submitted via // a single call to this method _must_ have the same identity type (i.e. if // the first key has an ACI identity type, then all other keys in the same // stream must also have an ACI identity type). The provided list of pre-keys // must be non-empty. rpc SetOneTimeEcPreKeys (SetOneTimeEcPreKeysRequest) returns (SetPreKeyResponse) {} // Uploads a new set of one-time KEM pre-keys for the authenticated device, // clearing any previously-stored pre-keys. Note that all keys submitted via // a single call to this method _must_ have the same identity type (i.e. if // the first key has an ACI identity type, then all other keys in the same // stream must also have an ACI identity type). The provided list of pre-keys // must be non-empty. rpc SetOneTimeKemSignedPreKeys (SetOneTimeKemSignedPreKeysRequest) returns (SetPreKeyResponse) {} // Sets the signed EC pre-key for one identity (i.e. ACI or PNI) associated // with the authenticated device. rpc SetEcSignedPreKey (SetEcSignedPreKeyRequest) returns (SetPreKeyResponse) {} // Sets the last-resort KEM pre-key for one identity (i.e. ACI or PNI) // associated with the authenticated device. rpc SetKemLastResortPreKey (SetKemLastResortPreKeyRequest) returns (SetPreKeyResponse) {} } // Provides methods for working with pre-keys using "unidentified access" // credentials. service KeysAnonymous { option (require.auth) = AUTH_ONLY_ANONYMOUS; // Retrieves a set of pre-keys for establishing a session with the targeted // device or devices. Callers must not submit any self-identifying credentials // when calling this method and must instead present the targeted account's // unidentified access key as an anonymous authentication mechanism. Callers // without an unidentified access key should use the equivalent, authenticated // method in `Keys` instead. rpc GetPreKeys(GetPreKeysAnonymousRequest) returns (GetPreKeysAnonymousResponse) {} // Checks identity key fingerprints of the target accounts. // // Returns a stream of elements, each one representing an account that had a mismatched // identity key fingerprint with the server and the corresponding identity key stored by the server. rpc CheckIdentityKeys(stream CheckIdentityKeyRequest) returns (stream CheckIdentityKeyResponse) {} } message GetPreKeyCountRequest { } message GetPreKeyCountResponse { // The approximate number of one-time EC pre-keys stored for the // authenticated device and associated with the caller's ACI. uint32 aci_ec_pre_key_count = 1; // The approximate number of one-time Kyber pre-keys stored for the // authenticated device and associated with the caller's ACI. uint32 aci_kem_pre_key_count = 2; // The approximate number of one-time EC pre-keys stored for the // authenticated device and associated with the caller's PNI. 0 if // the account does not possess a phone number. uint32 pni_ec_pre_key_count = 3; // The approximate number of one-time KEM pre-keys stored for the // authenticated device and associated with the caller's PNI. 0 if // the account does not possess a phone number. uint32 pni_kem_pre_key_count = 4; } message GetPreKeysRequest { // The service identifier of the account for which to retrieve pre-keys. common.ServiceIdentifier target_identifier = 1; // The ID of the device associated with the targeted account for which to // retrieve pre-keys. If not set, pre-keys are returned for all devices // associated with the targeted account. optional uint32 device_id = 2; } message GetPreKeysAnonymousRequest { // The request to retrieve pre-keys for a specific account/device(s). GetPreKeysRequest request = 1; // A means to authorize the request. oneof authorization { // The unidentified access key (UAK) for the targeted account. bytes unidentified_access_key = 2; // A group send endorsement token for the targeted account. bytes group_send_token = 3; // The destination account allows unrestricted unidentified access google.protobuf.Empty unrestricted_access = 4; } } message DevicePreKeyBundle { // The EC signed pre-key associated with the targeted // account/device/identity. common.EcSignedPreKey ec_signed_pre_key = 1; // A one-time EC pre-key for the targeted account/device/identity. May not // be set if no one-time EC pre-keys are available. common.EcPreKey ec_one_time_pre_key = 2; // A one-time KEM pre-key (or a last-resort KEM pre-key) for the targeted // account/device/identity. common.KemSignedPreKey kem_one_time_pre_key = 3; // The registration ID for the targeted account/device/identity. uint32 registration_id = 4; } message AccountPreKeyBundles { // The identity key associated with the targeted account/identity. bytes identity_key = 1; // A map of device IDs to pre-key "bundles" for the targeted account. map device_pre_keys = 2; // Whether the account has enabled sealed sender from anyone. Always false // if the request was for a PNI, which does not allow any unidentified access. bool unrestricted_unidentified_access = 3; // If the target supports unidentified access and has an unidentified access // key, a fingerprint of the target's UAK. This may be used to detect a change // in the UAK that the sender has for the target before actually sending a message. Otherwise, empty. bytes unidentified_access_key_fingerprint = 4; } message GetPreKeysResponse { oneof response { // The requested pre-key bundles AccountPreKeyBundles pre_keys = 1; // Either the target account was not found, no active device with the given // ID (if specified) was found on the target account. errors.NotFound target_not_found = 2 [(tag.reason) = "not_found"]; } } message GetPreKeysAnonymousResponse { oneof response { // The requested pre-key bundles AccountPreKeyBundles pre_keys = 1; // Either the target account was not found, no active device with the given // ID (if specified) was found on the target account. errors.NotFound target_not_found = 2 [(tag.reason) = "not_found"]; // The provided unidentified authorization credential was invalid errors.FailedUnidentifiedAuthorization failed_unidentified_authorization = 3 [(tag.reason) = "failed_unidentified_authorization"]; } } message SetOneTimeEcPreKeysRequest { // The identity type (i.e. ACI/PNI) with which the keys in this request are // associated. common.IdentityType identity_type = 1; // The unsigned EC pre-keys to be stored. repeated common.EcPreKey pre_keys = 2 [(require.size) = {min: 1, max: 100}]; } message SetOneTimeKemSignedPreKeysRequest { // The identity type (i.e. ACI/PNI) with which the keys in this request are // associated. common.IdentityType identity_type = 1; // The KEM pre-keys to be stored. repeated common.KemSignedPreKey pre_keys = 2 [(require.size) = {min: 1, max: 100}]; } message SetEcSignedPreKeyRequest { // The identity type (i.e. ACI/PNI) with which this key is associated. common.IdentityType identity_type = 1; // The signed EC pre-key itself. common.EcSignedPreKey signed_pre_key = 2 [(require.present) = true]; } message SetKemLastResortPreKeyRequest { // The identity type (i.e. ACI/PNI) with which this key is associated. common.IdentityType identity_type = 1; // The signed KEM pre-key itself. common.KemSignedPreKey signed_pre_key = 2 [(require.present) = true]; } message SetPreKeyResponse { } message CheckIdentityKeyRequest { // The service identifier of the account for which we want to check the associated identity key fingerprint. common.ServiceIdentifier target_identifier = 1; // The most significant 4 bytes of the SHA-256 hash of the identity key associated with the target account/identity type. bytes fingerprint = 2 [(require.exactlySize) = 4]; } message CheckIdentityKeyResponse { // The service identifier of the account for which there is a mismatch between the client and server identity key fingerprints. common.ServiceIdentifier target_identifier = 1; // The identity key that is stored by the server for the target account/identity type. bytes identity_key = 2; }