Signal-Server/service/src/main/proto/KeyTransparencyService.proto

368 lines
12 KiB
Protocol Buffer

/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.signal.keytransparency.client";
package kt_query;
/**
* An external-facing, read-only key transparency service used by Signal's chat server
* to look up and monitor identifiers.
* There are three types of identifier mappings stored by the key transparency log:
* - An ACI which maps to an ACI identity key
* - An E164-formatted phone number which maps to an ACI
* - A username hash which also maps to an ACI
* Separately, the log also stores and periodically updates a fixed value known as the `distinguished` key.
* Clients use the verified tree head from looking up this key for future calls to the Search and Monitor endpoints.
*/
service KeyTransparencyQueryService {
/**
* An endpoint used by clients to retrieve the most recent distinguished tree
* head, which should be used to derive consistency parameters for
* subsequent Search and Monitor requests. It should be the first key
* transparency RPC a client calls.
*/
rpc Distinguished(DistinguishedRequest) returns (DistinguishedResponse) {}
/**
* An endpoint used by clients to search for one or more identifiers in the transparency log.
* The server returns proof that the identifier(s) exist in the log.
*/
rpc Search(SearchRequest) returns (SearchResponse) {}
/**
* An endpoint that allows users to monitor a set of identifiers by returning proof that the log continues to be
* constructed correctly in later entries for those identifiers.
*/
rpc Monitor(MonitorRequest) returns (MonitorResponse) {}
}
message SearchRequest {
/**
* The ACI to look up in the log.
*/
bytes aci = 1;
/**
* The ACI identity key that the client thinks the ACI maps to in the log.
*/
bytes aci_identity_key = 2;
/**
* The username hash to look up in the log.
*/
optional bytes username_hash = 3;
/**
* The E164 to look up in the log along with associated data.
*/
optional E164SearchRequest e164_search_request = 4;
/**
* The tree head size(s) to prove consistency against.
*/
ConsistencyParameters consistency = 5;
}
/**
* E164SearchRequest contains the data that the user must provide when looking up an E164.
*/
message E164SearchRequest {
/**
* The E164 that the client wishes to look up in the transparency log.
*/
string e164 = 1;
/**
* The unidentified access key of the account associated with the provided E164.
*/
bytes unidentified_access_key = 2;
}
/**
* SearchResponse contains search proofs for each of the requested identifiers.
* Callers should use the top-level `FullTreeHead` for verification;
* the `FullTreeHead` field on the individual `TreeSearchResponse`s will be empty.
*/
message SearchResponse {
/**
* A signed representation of the log tree's current state along with some
* additional information necessary for validation such as a consistency proof and an auditor-signed tree head.
*/
FullTreeHead tree_head = 1;
/**
* The ACI search response is always provided.
*/
TreeSearchResponse aci = 2;
/**
* This response is only provided if all of the conditions are met:
* - the E164 exists in the log
* - its mapped ACI matches the one provided in the request
* - the account associated with the ACI is discoverable
* - the unidentified access key provided in E164SearchRequest matches the one on the account
*/
optional TreeSearchResponse e164 = 3;
/**
* This response is only provided if the username hash exists in the log and
* its mapped ACI matches the one provided in the request.
*/
optional TreeSearchResponse username_hash = 4;
}
/**
* The tree head size(s) to prove consistency against. A client's very first
* key transparency request should be looking up the "distinguished" key;
* in this case, both fields will be omitted since the client has no previous
* tree heads to prove consistency against.
*/
message ConsistencyParameters {
/**
* The non-distinguished tree head size to prove consistency against.
* This field may be omitted if the client is looking up an identifier
* for the first time.
*/
optional uint64 last = 1;
/**
* The distinguished tree head size to prove consistency against.
* This field may be omitted when the client is looking up the
* "distinguished" key for the very first time.
*/
optional uint64 distinguished = 2;
}
/**
* DistinguishedRequest looks up the most recent distinguished key in the
* transparency log.
*/
message DistinguishedRequest {
/**
* The tree size of the client's last verified distinguished request. With the
* exception of a client's very first request, this field should always be
* set.
*/
optional uint64 last = 1;
}
/**
* DistinguishedResponse contains the tree head and search proof for the most
* recent `distinguished` key in the log. Callers should use the top-level
* `FullTreeHead` for verification; the `FullTreeHead` field on
* `TreeSearchResponse` will be empty.
*/
message DistinguishedResponse {
/**
* A signed representation of the log tree's current state along with some
* additional information necessary for validation such as a consistency proof and an auditor-signed tree head.
*/
FullTreeHead tree_head = 1;
/**
* This search response is always provided.
*/
TreeSearchResponse distinguished = 2;
}
message TreeSearchResponse {
/**
* A signed representation of the log tree's current state along with some
* additional information necessary for validation such as a consistency proof and an auditor-signed tree head.
*/
FullTreeHead tree_head = 1;
/**
* A proof that is combined with the original requested identifier and the VRF public key
* and outputs whether the proof is valid, and if so, the commitment index.
*/
bytes vrf_proof = 2;
/**
* A proof that the binary search for the given identifier was done correctly.
*/
SearchProof search = 3;
/**
* A 32-byte value computed based on the log position of the identifier
* and a random 32 byte key that is only known by the key transparency service.
* It is provided so that clients can recompute and verify the commitment.
*/
bytes opening = 4;
/**
* The new or updated value that the identifier maps to.
*/
UpdateValue value = 5;
}
message FullTreeHead {
/**
* A representation of the log tree's current state signed by the key transparency service.
*/
TreeHead tree_head = 1;
/**
* A consistency proof between the current tree size and the requested distinguished tree size.
*/
repeated bytes distinguished = 2;
/**
* A consistency proof between the current tree size and the requested tree size.
*/
repeated bytes consistency = 3;
/**
* A tree head signed by a third-party auditor.
*/
optional AuditorTreeHead auditor_tree_head = 4;
}
message TreeHead {
/**
* The number of entries in the log tree.
*/
uint64 tree_size = 1;
/**
* The time in milliseconds since epoch when the tree head signature was generated.
*/
int64 timestamp = 2;
/**
* A signature computed over the log tree's current state and long-term log configuration.
*/
bytes signature = 3;
}
message AuditorTreeHead {
/**
* A representation of the log tree state signed by a third-party auditor.
*/
TreeHead tree_head = 1;
/**
* Provided if the auditor tree head size is smaller than the size of the most recent
* tree head provided to the user.
* The root hash of the log tree when the auditor produced the tree head signature.
*/
optional bytes root_value = 2;
/**
* Provided if the auditor tree head size is smaller than the size of the most recent
* tree head provided by the key transparency service to the user.
* A consistency proof between the auditor tree head and the most recent tree head.
*/
repeated bytes consistency = 3;
}
/**
* A ProofStep represents one "step" or log entry in the binary search
* and can be used to calculate a log tree leaf hash.
*/
message ProofStep {
/**
* Provides the data needed to recompute the prefix tree root hash corresponding to the given log entry.
*/
PrefixSearchResult prefix = 1;
/**
* A cryptographic hash of the update used to calculate the log tree leaf hash.
*/
bytes commitment = 2;
}
message SearchProof {
/**
* The position in the log tree of the first occurrence of the requested identifier.
*/
uint64 pos = 1;
/**
* The steps of a binary search through the entries of the log tree for the given identifier version.
* Each ProofStep corresponds to a log entry and provides the information necessary to recompute a log tree
* leaf hash.
*/
repeated ProofStep steps = 2;
/**
* A batch inclusion proof for all log tree leaves involved in the binary search for the given identifier.
*/
repeated bytes inclusion = 3;
}
message UpdateValue {
/**
* TODO: Update KT server to remove this field since it's only relevant to third-party management and we're not doing that.
*/
// optional bytes signature = 1;
/**
* The new value for a identifier.
*/
bytes value = 2;
}
message PrefixSearchResult {
/**
* A proof from a prefix tree that indicates a search was done correctly for a given identifier.
* The elements of this array are the copath of the prefix tree leaf node in bottom-to-top order.
*/
repeated bytes proof = 1;
/**
* The version of the requested identifier in the prefix tree.
*/
uint32 counter = 2;
}
message MonitorKey {
/**
* The key to search for in the log tree.
*/
bytes search_key = 1;
/**
* A list of log tree positions maintained by a client for the identifier being monitored.
* Each position is in the direct path to a key version and corresponds to a tree head
* that has been verified to contain that version or greater.
* The key transparency server uses this list to compute which log entries to return
* in the corresponding MonitorProof.
*/
repeated uint64 entries = 2;
/**
* The commitment index for the identifier. This is derived from vrf_proof in
* the SearchResponse.
*/
bytes commitment_index = 3;
}
message MonitorRequest {
/**
* TODO: Remove this protobuf field in the KT server
*/
repeated MonitorKey owned_keys = 1;
/**
* The list of identifiers that the client would like to monitor.
* All identifiers *must* belong to the same user.
*/
repeated MonitorKey contact_keys = 2;
/**
* The tree head size(s) to prove consistency against.
*/
ConsistencyParameters consistency = 3;
}
message MonitorProof {
/**
* Generated based on the monitored entries provided in MonitorKey.entries. Each ProofStep
* corresponds to a log tree entry that exists in the search path to each monitored entry
* and that came *after* that monitored entry. It proves that the log tree has been constructed
* correctly at that later entry. This list also includes any remaining entries
* along the "frontier" of the log tree which proves that the very last entry in the log
* has been constructed correctly.
*/
repeated ProofStep steps = 1;
}
message MonitorResponse {
/**
* A signed representation of the log tree's current state along with some
* additional information necessary for validation such as a consistency proof and an auditor-signed tree head.
*/
FullTreeHead tree_head = 1;
/**
* TODO: Remove this protobuf field in the KT server
*/
repeated MonitorProof owned_proofs = 2;
/**
* A list of proofs, one for each identifier in MonitorRequest.contact_keys, each proving that the given identifier
* continues to be constructed correctly in later entries of the log tree.
*/
repeated MonitorProof contact_proofs = 3;
/**
* A batch inclusion proof that the log entries involved in the binary search for each of the entries
* being monitored in MonitorKey.entries are included in the current log tree.
*/
repeated bytes inclusion = 4;
}