wire_e2e_identity/acme/
certificate.rs

1use rusty_jwt_tools::prelude::{JwsAlgorithm, Pem};
2use x509_cert::{Certificate, der::Decode as _};
3
4use crate::acme::{AcmeAccount, AcmeFinalize, AcmeJws, AcmeOrder, RustyAcme, RustyAcmeError, RustyAcmeResult};
5
6impl RustyAcme {
7    /// For fetching the generated certificate
8    /// see [RFC 8555 Section 7.4.2](https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4.2)
9    pub fn certificate_req(
10        finalize: &AcmeFinalize,
11        account: &AcmeAccount,
12        alg: JwsAlgorithm,
13        kp: &Pem,
14        previous_nonce: String,
15    ) -> RustyAcmeResult<AcmeJws> {
16        // Extract the account URL from previous response which created a new account
17        let acct_url = account.acct_url()?;
18
19        // No payload required for getting a certificate
20        let payload = None::<serde_json::Value>;
21        let req = AcmeJws::new(alg, previous_nonce, &finalize.certificate, Some(&acct_url), payload, kp)?;
22        Ok(req)
23    }
24
25    /// see [RFC 8555 Section 7.4.2](https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4.2)
26    pub fn certificate_response(response: String, order: AcmeOrder) -> RustyAcmeResult<Vec<Certificate>> {
27        order.verify()?;
28        let pems: Vec<pem::Pem> = pem::parse_many(response)?;
29
30        // Note that pem::parse_many() may return an empty vector in various cases, which is not an
31        // error when looked at in isolation. But here we must treat that as an error because the
32        // ACME server has to provide provide us with at least one certificate, if everything went
33        // well.
34        if pems.is_empty() {
35            return Err(RustyAcmeError::SmallstepImplementationError(
36                "the ACME server response contains no certificates",
37            ));
38        }
39
40        let mut certs = Vec::with_capacity(pems.len());
41        for pem in pems {
42            certs.push(Certificate::from_der(pem.contents())?);
43        }
44        Ok(certs)
45    }
46}