core_crypto/transaction_context/e2e_identity/
init_certificates.rs1use super::{Error, Result};
2use crate::e2e_identity::E2eiDumpedPkiEnv;
3use crate::{
4 KeystoreError, MlsError, RecursiveError,
5 e2e_identity::{CrlRegistration, NewCrlDistributionPoints, restore_pki_env},
6 transaction_context::TransactionContext,
7};
8use core_crypto_keystore::{
9 connection::FetchFromDatabase,
10 entities::{E2eiAcmeCA, E2eiCrl, E2eiIntermediateCert},
11};
12use openmls_traits::OpenMlsCryptoProvider;
13use wire_e2e_identity::prelude::x509::{
14 extract_crl_uris, extract_expiration_from_crl,
15 revocation::{PkiEnvironment, PkiEnvironmentParams},
16};
17use x509_cert::der::Decode;
18
19impl TransactionContext {
20 pub async fn e2ei_is_pki_env_setup(&self) -> Result<bool> {
23 Ok(self
24 .mls_provider()
25 .await
26 .map_err(RecursiveError::transaction("getting mls provider"))?
27 .authentication_service()
28 .is_env_setup()
29 .await)
30 }
31
32 pub async fn e2ei_dump_pki_env(&self) -> Result<Option<E2eiDumpedPkiEnv>> {
34 if !self.e2ei_is_pki_env_setup().await? {
35 return Ok(None);
36 }
37 let mls_provider = self
38 .mls_provider()
39 .await
40 .map_err(RecursiveError::transaction("getting mls provider"))?;
41 let Some(pki_env) = &*mls_provider.authentication_service().borrow().await else {
42 return Ok(None);
43 };
44 E2eiDumpedPkiEnv::from_pki_env(pki_env)
45 .await
46 .map_err(RecursiveError::e2e_identity("dumping pki env"))
47 .map_err(Into::into)
48 }
49
50 pub async fn e2ei_register_acme_ca(&self, trust_anchor_pem: String) -> Result<()> {
58 {
59 if self
60 .mls_provider()
61 .await
62 .map_err(RecursiveError::transaction("getting mls provider"))?
63 .keystore()
64 .find_unique::<E2eiAcmeCA>()
65 .await
66 .is_ok()
67 {
68 return Err(Error::TrustAnchorAlreadyRegistered);
69 }
70 }
71
72 let pki_env = PkiEnvironment::init(PkiEnvironmentParams {
73 intermediates: Default::default(),
74 trust_roots: Default::default(),
75 crls: Default::default(),
76 time_of_interest: Default::default(),
77 })?;
78
79 let root_cert = PkiEnvironment::decode_pem_cert(trust_anchor_pem)?;
81
82 pki_env.validate_trust_anchor_cert(&root_cert)?;
84
85 let cert_der = PkiEnvironment::encode_cert_to_der(&root_cert)?;
87 let acme_ca = E2eiAcmeCA { content: cert_der };
88 self.mls_provider()
89 .await
90 .map_err(RecursiveError::transaction("getting mls provider"))?
91 .keystore()
92 .save(acme_ca)
93 .await
94 .map_err(KeystoreError::wrap("saving acme ca"))?;
95
96 self.init_pki_env().await?;
98
99 Ok(())
100 }
101
102 pub(crate) async fn init_pki_env(&self) -> Result<()> {
103 if let Some(pki_env) = restore_pki_env(
104 &self
105 .mls_provider()
106 .await
107 .map_err(RecursiveError::transaction("getting mls provider"))?
108 .keystore(),
109 )
110 .await
111 .map_err(RecursiveError::e2e_identity("restoring pki env"))?
112 {
113 let provider = self
114 .mls_provider()
115 .await
116 .map_err(RecursiveError::transaction("getting mls provider"))?;
117 provider
118 .authentication_service()
119 .update_env(pki_env)
120 .await
121 .map_err(MlsError::wrap("updating authentication service env"))?;
122 }
123
124 Ok(())
125 }
126
127 pub async fn e2ei_register_intermediate_ca_pem(&self, cert_pem: String) -> Result<NewCrlDistributionPoints> {
135 let inter_ca = PkiEnvironment::decode_pem_cert(cert_pem)?;
137 self.e2ei_register_intermediate_ca(inter_ca).await
138 }
139
140 pub(crate) async fn e2ei_register_intermediate_ca_der(&self, cert_der: &[u8]) -> Result<NewCrlDistributionPoints> {
141 let inter_ca = x509_cert::Certificate::from_der(cert_der)?;
142 self.e2ei_register_intermediate_ca(inter_ca).await
143 }
144
145 async fn e2ei_register_intermediate_ca(
146 &self,
147 inter_ca: x509_cert::Certificate,
148 ) -> Result<NewCrlDistributionPoints> {
149 let keystore = self
151 .keystore()
152 .await
153 .map_err(RecursiveError::transaction("getting keystore"))?;
154 let trust_anchor = keystore
155 .find_unique::<E2eiAcmeCA>()
156 .await
157 .map_err(KeystoreError::wrap("finding acme ca"))?;
158 let trust_anchor = x509_cert::Certificate::from_der(&trust_anchor.content)?;
159
160 if inter_ca == trust_anchor {
163 return Ok(None.into());
164 }
165
166 let intermediate_crl = extract_crl_uris(&inter_ca)?.map(|s| s.into_iter().collect());
167
168 let (ski, aki) = PkiEnvironment::extract_ski_aki_from_cert(&inter_ca)?;
169
170 let ski_aki_pair = format!("{ski}:{}", aki.unwrap_or_default());
171
172 {
174 let provider = self
175 .mls_provider()
176 .await
177 .map_err(RecursiveError::transaction("getting mls provider"))?;
178 let auth_service_arc = provider.authentication_service().borrow().await;
179 let Some(pki_env) = auth_service_arc.as_ref() else {
180 return Err(Error::PkiEnvironmentUnset);
181 };
182 pki_env.validate_cert_and_revocation(&inter_ca)?;
183 }
184
185 let cert_der = PkiEnvironment::encode_cert_to_der(&inter_ca)?;
187 let intermediate_ca = E2eiIntermediateCert {
188 content: cert_der,
189 ski_aki_pair,
190 };
191 keystore
192 .save(intermediate_ca)
193 .await
194 .map_err(KeystoreError::wrap("saving intermediate ca"))?;
195
196 self.init_pki_env().await?;
197
198 Ok(intermediate_crl.into())
199 }
200
201 pub async fn e2ei_register_crl(&self, crl_dp: String, crl_der: Vec<u8>) -> Result<CrlRegistration> {
213 let crl = {
215 let provider = self
216 .mls_provider()
217 .await
218 .map_err(RecursiveError::transaction("getting mls provider"))?;
219 let auth_service_arc = provider.authentication_service().borrow().await;
220 let Some(pki_env) = auth_service_arc.as_ref() else {
221 return Err(Error::PkiEnvironmentUnset);
222 };
223 pki_env.validate_crl_with_raw(&crl_der)?
224 };
225
226 let expiration = extract_expiration_from_crl(&crl);
227
228 let ks = self
229 .keystore()
230 .await
231 .map_err(RecursiveError::transaction("getting keystore"))?;
232
233 let dirty = ks
234 .find::<E2eiCrl>(crl_dp.as_bytes())
235 .await
236 .ok()
237 .flatten()
238 .map(|existing_crl| {
239 PkiEnvironment::decode_der_crl(existing_crl.content.clone())
240 .map(|old_crl| old_crl.tbs_cert_list.revoked_certificates != crl.tbs_cert_list.revoked_certificates)
241 })
242 .transpose()?
243 .unwrap_or_default();
244
245 let crl_data = E2eiCrl {
247 content: PkiEnvironment::encode_crl_to_der(&crl)?,
248 distribution_point: crl_dp,
249 };
250 ks.save(crl_data).await.map_err(KeystoreError::wrap("saving crl"))?;
251
252 self.init_pki_env().await?;
253
254 Ok(CrlRegistration { expiration, dirty })
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use wasm_bindgen_test::*;
261 use x509_cert::der::EncodePem;
262
263 use crate::test_utils::*;
264
265 use super::super::Error;
266
267 wasm_bindgen_test_configure!(run_in_browser);
268
269 #[apply(all_cred_cipher)]
270 #[wasm_bindgen_test]
271 async fn register_acme_ca_should_fail_when_already_set(case: TestCase) {
272 use x509_cert::der::pem::LineEnding;
273
274 if !case.is_x509() {
275 return;
276 }
277 run_test_with_client_ids(case.clone(), ["alice"], move |[alice_central]| {
278 Box::pin(async move {
279 let alice_test_chain = alice_central.x509_test_chain.as_ref().as_ref().unwrap();
280 let alice_ta = alice_test_chain
281 .trust_anchor
282 .certificate
283 .to_pem(LineEnding::CRLF)
284 .unwrap();
285
286 assert!(matches!(
287 alice_central.context.e2ei_register_acme_ca(alice_ta).await.unwrap_err(),
288 Error::TrustAnchorAlreadyRegistered
289 ));
290 })
291 })
292 .await;
293 }
294
295 #[apply(all_cred_cipher)]
296 #[wasm_bindgen_test]
297 async fn x509_restore_should_not_happen_if_basic(case: TestCase) {
298 if case.is_x509() {
299 return;
300 }
301 run_test_with_client_ids(case.clone(), ["alice"], move |[alice_ctx]| {
302 Box::pin(async move {
303 let SessionContext {
304 context,
305 x509_test_chain,
306 ..
307 } = alice_ctx;
308
309 assert!(x509_test_chain.is_none());
310 assert!(!context.e2ei_is_pki_env_setup().await.unwrap());
311
312 assert!(x509_test_chain.is_none());
315 })
317 })
318 .await;
319 }
320}