diff --git a/src/api/endpoints.rs b/src/api/endpoints.rs index 9eb55cc..1784c9b 100644 --- a/src/api/endpoints.rs +++ b/src/api/endpoints.rs @@ -44,3 +44,19 @@ type Endpoint<'a> = (reqwest::Method, &'a str); /// clients.) /// ``` pub const ADD_CHAIN_ENDPOINT: Endpoint = (reqwest::Method::POST, "/ct/v1/add-chain"); + +/// Reference: https://datatracker.ietf.org/doc/html/rfc6962#section-4.2 +/// ```txt +/// POST https:///ct/v1/add-pre-chain +/// +/// Inputs: +/// +/// chain: An array of base64-encoded Precertificates. The first +/// element is the end-entity certificate; the second chains to the +/// first and so on to the last, which is either the root +/// certificate or a certificate that chains to a known root +/// certificate. +/// +/// Outputs are the same as in Section 4.1. +/// ``` +pub const ADD_PRE_CHAIN_ENDPOINT: Endpoint = (reqwest::Method::POST, "/ct/v1/add-pre-chain"); diff --git a/src/api/mod.rs b/src/api/mod.rs index 08ce02e..4b401b7 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -17,7 +17,7 @@ impl CtApiClient { }) } - /// Adds a chain to the CT log. + /// Adds a standard x509 chain to the CT log. /// /// See: [`endpoints::ADD_CHAIN_ENDPOINT`] /// @@ -44,4 +44,37 @@ impl CtApiClient { .json() .await } + + /// Adds a precetificate chain to the CT log. This is largely the same as + /// [`CtApiClient::add_chain`], except is used specifically when the chain + /// starts with a precertificate rather than the final end-user certificate. + /// + /// See: [`endpoints::ADD_PRE_CHAIN_ENDPOINT`] + /// + /// ## 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. + /// Specifically, compliant CT logs will reject chains that do not verify + /// properly. For precertificates this will happen is the first entry is not + /// a precertificate, or if the precertificate is not directly signed by + /// a. The CA certificate signing the real certificate + /// b. A special-purpose Precertificate Signing Certificate which is + /// directly signed by the CA certificate signing the real certificate. + pub async fn add_pre_chain( + &self, + chain: Vec + ) -> reqwest::Result { + self.inner_client + .request( + endpoints::ADD_PRE_CHAIN_ENDPOINT.0, + self.log_url.to_string() + endpoints::ADD_PRE_CHAIN_ENDPOINT.1 + ) + .json(&AddChainRequest { chain }) + .send() + .await? + .error_for_status()? + .json() + .await + } } diff --git a/src/api/responses.rs b/src/api/responses.rs index a885c16..4f02a3e 100644 --- a/src/api/responses.rs +++ b/src/api/responses.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; /// A request payload for adding a chain to a CT log /// -/// See: [`super::endpoints::ADD_CHAIN_ENDPOINT`] +/// See: [`super::endpoints::ADD_CHAIN_ENDPOINT`] or [`super::endpoints::ADD_PRE_CHAIN_ENDPOINT`] #[derive(Debug, Serialize)] pub struct AddChainRequest { pub chain: Vec @@ -10,7 +10,7 @@ pub struct AddChainRequest { /// A response given when adding a chain to a CT log /// -/// See: [`super::endpoints::ADD_CHAIN_ENDPOINT`] +/// See: [`super::endpoints::ADD_CHAIN_ENDPOINT`] or [`super::endpoints::ADD_PRE_CHAIN_ENDPOINT`] #[derive(Debug, Deserialize)] pub struct AddChainResponse { pub sct_version: u8,