kipuka_dogtag/cmc.rs
1//! Full CMC (Certificate Management over CMS) operations.
2//!
3//! Provides passthrough submission of CMC requests to Dogtag's CMC Full
4//! enrollment endpoint. This supports kipuka's `/fullcmc` EST endpoint
5//! (RFC 7030 S4.3) by proxying CMC messages directly to the CA.
6
7use tracing::debug;
8
9use crate::client::DogtagClient;
10use crate::{DogtagError, DogtagResult};
11
12/// CMC-specific client operations.
13///
14/// Thin wrapper indicating CMC-related functionality. The actual HTTP
15/// client is shared via [`DogtagClient`].
16pub struct CmcClient;
17
18impl DogtagClient {
19 /// Submit a Full CMC request to Dogtag.
20 ///
21 /// Sends `POST /ca/ee/ca/profileSubmitCMCFull` with the raw CMC
22 /// request bytes (DER-encoded CMS/PKCS#7). Returns the CMC response
23 /// bytes for direct relay to the EST client.
24 ///
25 /// This is a pure passthrough: kipuka's `/fullcmc` endpoint receives
26 /// a CMC request from the EST client and forwards it to Dogtag without
27 /// interpretation. The response is similarly relayed back.
28 ///
29 /// # Content Types
30 ///
31 /// - Request: `application/pkcs7-mime` (CMC request, DER)
32 /// - Response: `application/pkcs7-mime` (CMC response, DER)
33 pub async fn submit_cmc_request(&self, cmc_der: &[u8]) -> DogtagResult<Vec<u8>> {
34 debug!(
35 size = cmc_der.len(),
36 "Submitting Full CMC request to Dogtag"
37 );
38
39 let resp = self
40 .post_bytes(
41 "/ca/ee/ca/profileSubmitCMCFull",
42 cmc_der.to_vec(),
43 "application/pkcs7-mime",
44 )
45 .await?;
46
47 let status = resp.status();
48 if !status.is_success() {
49 let body = resp.text().await.unwrap_or_default();
50 return Err(DogtagError::ApiError {
51 status: status.as_u16(),
52 body,
53 });
54 }
55
56 resp.bytes()
57 .await
58 .map(|b| b.to_vec())
59 .map_err(|e| DogtagError::ParseError(format!("Failed to read CMC response: {e}")))
60 }
61}