Skip to main content

wire_e2e_identity/acquisition/
oidc_challenge.rs

1use obfuscate::Obfuscated;
2use rusty_jwt_tools::{jwk_thumbprint::JwkThumbprint, prelude::Pem};
3use x509_cert::Certificate;
4
5use super::{Result, X509CredentialAcquisition, states};
6use crate::{
7    acme::{RustyAcme, RustyAcmeError},
8    pki_env::hooks::{HttpHeader, HttpMethod},
9};
10
11impl X509CredentialAcquisition<states::DpopChallengeCompleted> {
12    /// Complete the OIDC challenge and get the certificate chain.
13    ///
14    /// Returns (signing keypair in PEM format, certificate chain).
15    /// The first certificate in the chain is the end-entity certificate,
16    /// i.e. the one certifying the public portion of the signing keypair.
17    pub async fn complete_oidc_challenge(self) -> Result<(Pem, Vec<Certificate>)> {
18        let hooks = self.pki_env.hooks();
19
20        // Complete the OIDC challenge.
21        let oidc_challenge_token = &self.data.oidc_challenge.token;
22        let thumbprint = JwkThumbprint::generate(&self.acme_jwk, self.config.hash_alg)?.kid;
23        let key_auth = format!("{oidc_challenge_token}.{thumbprint}");
24        let snapshot = serde_json::to_vec(&self)?;
25
26        let url = &self.data.oidc_challenge.url;
27        let target = self.data.oidc_challenge.target.to_string();
28        let id_token = hooks.authenticate(target, key_auth, url.to_string(), snapshot).await?;
29        log::debug!(
30            "acquisition({:?}): got the ID token from the OIDC server",
31            Obfuscated::from(&self.sign_kp),
32        );
33
34        let oidc_challenge_request = RustyAcme::oidc_chall_request(
35            id_token,
36            &self.data.oidc_challenge,
37            &self.data.acme_account,
38            self.config.sign_alg,
39            &self.acme_kp,
40            self.data.nonce.clone(),
41        )?;
42        let (nonce, response) = self.acme_request(url, &oidc_challenge_request).await?;
43        let _ = RustyAcme::new_chall_response(response)?;
44        log::info!(
45            "acquisition({:?}): OIDC challenge completed",
46            Obfuscated::from(&self.sign_kp),
47        );
48
49        // Finalize the order. This generates a CSR (Certificate Signing Request) and
50        // sends it to the ACME server.
51        let finalize_request = RustyAcme::finalize_req(
52            &self.data.order,
53            &self.data.acme_account,
54            self.config.sign_alg,
55            &self.acme_kp,
56            &self.sign_kp,
57            nonce,
58        )?;
59        let (nonce, response) = self.acme_request(&self.data.order.finalize, &finalize_request).await?;
60        let finalize = RustyAcme::finalize_response(response)?;
61        log::debug!(
62            "acquisition({:?}): ACME order finalized",
63            Obfuscated::from(&self.sign_kp),
64        );
65
66        // Get the certificate chain.
67        //
68        // See [RFC 8555 Section 7.4.2](https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4.2).
69        let certificate_request = RustyAcme::certificate_req(
70            &finalize,
71            &self.data.acme_account,
72            self.config.sign_alg,
73            &self.acme_kp,
74            nonce,
75        )?;
76        let headers = vec![HttpHeader {
77            name: "content-type".into(),
78            value: "application/jose+json".into(),
79        }];
80        let body = serde_json::to_string(&certificate_request)?.into();
81        let response = hooks
82            .http_request(HttpMethod::Post, finalize.certificate.to_string(), headers, body)
83            .await?;
84        let response = String::from_utf8(response.body).map_err(|e| RustyAcmeError::from(e.utf8_error()))?;
85        let certificates = RustyAcme::certificate_response(response, self.data.order)?;
86        log::debug!(
87            "acquisition({:?}): got the certificate",
88            Obfuscated::from(&self.sign_kp),
89        );
90
91        super::checks::verify_cert_chain(&self.config, &self.pki_env, &self.sign_kp, &certificates).await?;
92        log::info!(
93            "acquisition({:?}): certificate verified successfully",
94            Obfuscated::from(&self.sign_kp),
95        );
96
97        Ok((self.sign_kp, certificates))
98    }
99}