feat(api): Add get entries endpoint

This commit is contained in:
Tyler Beckman 2024-10-27 16:35:34 -06:00
parent 7e51c915bc
commit 70a83d4b9e
Signed by: Ty
GPG key ID: 2813440C772555A4
3 changed files with 98 additions and 0 deletions

View file

@ -125,3 +125,49 @@ pub const GET_STH_CONSISTENCY: Endpoint =
/// ```
pub const GET_PROOF_BY_HASH: Endpoint =
(reqwest::Method::GET, "/ct/v1/get-proof-by-hash");
/// Reference: https://datatracker.ietf.org/doc/html/rfc6962#section-4.4
/// ```txt
/// GET https://<log server>/ct/v1/get-entries
///
/// Inputs:
///
/// start: 0-based index of first entry to retrieve, in decimal.
///
/// end: 0-based index of last entry to retrieve, in decimal.
///
/// Outputs:
///
/// entries: An array of objects, each consisting of
///
/// leaf_input: The base64-encoded MerkleTreeLeaf structure.
///
/// extra_data: The base64-encoded unsigned data pertaining to the
/// log entry. In the case of an X509ChainEntry, this is the
/// "certificate_chain". In the case of a PrecertChainEntry,
/// this is the whole "PrecertChainEntry".
///
/// Note that this message is not signed -- the retrieved data can be
/// verified by constructing the Merkle Tree Hash corresponding to a
/// retrieved STH. All leaves MUST be v1. However, a compliant v1
/// client MUST NOT construe an unrecognized MerkleLeafType or
/// LogEntryType value as an error. This means it may be unable to parse
/// some entries, but note that each client can inspect the entries it
/// does recognize as well as verify the integrity of the data by
/// treating unrecognized leaves as opaque input to the tree.
///
/// The "start" and "end" parameters SHOULD be within the range 0 <= x <
/// "tree_size" as returned by "get-sth" in Section 4.3.
///
/// Logs MAY honor requests where 0 <= "start" < "tree_size" and "end" >=
/// "tree_size" by returning a partial response covering only the valid
/// entries in the specified range. Note that the following restriction
/// may also apply:
///
/// Logs MAY restrict the number of entries that can be retrieved per
/// "get-entries" request. If a client requests more than the permitted
/// number of entries, the log SHALL return the maximum number of entries
/// permissible. These entries SHALL be sequential beginning with the
/// entry specified by "start".
/// ```
pub const GET_ENTRIES: Endpoint = (reqwest::Method::GET, "/ct/v1/get-entries");

View file

@ -4,6 +4,7 @@ use reqwest::Url;
use responses::{
AddChainRequest,
AddChainResponse,
GetEntriesResponse,
GetProofByHashResponse,
GetSthConsistencyResponse,
GetSthResponse
@ -205,4 +206,40 @@ impl CtApiClient {
.json()
.await
}
/// Fetches the CT log entries within the range `[start, end]` where both
/// parameters are 0-indexed. The response contains both the MerkleTreeLeaf
/// structure and full certificate chain of each entry. Logs may or may not
/// properly honor requests in which the start parameter is less than 0 or
/// the end parameter is greater than the current tree size, to try to
/// ensure these bounds are correct. In addition, there is no guarantee that
/// the resulting response will have the list of entries exactly the size
/// requested, as CT logs can enforce limits on how much data is returned at
/// once.
///
/// See: [`endpoints::GET_ENTRIES`]
///
/// ## Errors
///
/// This may error if either the request failed (due to lack of internet or
/// invalid domain, for example), or if the CT log gave a 4xx/5xx response.
/// The CT log may error the response if it doesn't allow invalid bounds and
/// the start and end parameters were specified incorrectly.
pub async fn get_log_entries(
&self,
start: u64,
end: u64
) -> reqwest::Result<GetEntriesResponse> {
self.inner_client
.request(
endpoints::GET_ENTRIES.0,
self.log_url.to_string() + endpoints::GET_ENTRIES.1
)
.query(&[("start", start), ("end", end)])
.send()
.await?
.error_for_status()?
.json()
.await
}
}

View file

@ -51,3 +51,18 @@ pub struct GetProofByHashResponse {
pub leaf_index: u64,
pub audit_path: Vec<String>
}
/// A response given when fetching CT log entries within a range
///
/// See: [`super::endpoints::GET_ENTRIES`]
#[derive(Debug, Deserialize)]
pub struct GetEntriesResponse {
pub entries: Vec<GetEntriesResponseEntry>
}
/// A specific entry in a [`GetEntriesResponse`]
#[derive(Debug, Deserialize)]
pub struct GetEntriesResponseEntry {
pub leaf_input: String,
pub extra_data: String
}