wire_e2e_identity/acquisition/
serialization.rs1use std::sync::Arc;
2
3use jwt_simple::prelude::Jwk;
4use rusty_jwt_tools::prelude::{ClientId, Pem};
5use uuid::Uuid;
6
7use super::{Result, X509CredentialAcquisition, X509CredentialConfiguration, states};
8use crate::pki_env::PkiEnvironment;
9
10#[derive(serde::Serialize, serde::Deserialize)]
11#[serde(remote = "ClientId")]
12pub struct ClientIdDef {
13 pub user_id: Uuid,
15 pub device_id: u64,
17 pub domain: String,
19}
20
21#[derive(serde::Deserialize, serde::Serialize)]
22struct X509CredentialAcquisitionSerialisationHelper<T: std::fmt::Debug> {
23 config: X509CredentialConfiguration,
24 sign_kp: Pem,
25 acme_kp: Pem,
26 acme_jwk: Jwk,
27 data: T,
28}
29
30impl X509CredentialAcquisition<states::DpopChallengeCompleted> {
31 pub fn deserialize(pki_env: Arc<PkiEnvironment>, bytes: &[u8]) -> Result<Self> {
32 let helper: X509CredentialAcquisitionSerialisationHelper<states::DpopChallengeCompleted> =
33 serde_json::from_slice(bytes)?;
34
35 Ok(Self {
36 pki_env,
37 config: helper.config,
38 sign_kp: helper.sign_kp,
39 acme_kp: helper.acme_kp,
40 acme_jwk: helper.acme_jwk,
41 data: helper.data,
42 })
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use core_crypto_keystore::{ConnectionType, Database, DatabaseKey};
49 use rusty_jwt_tools::prelude::{HashAlgorithm, JwsAlgorithm};
50
51 use super::*;
52 use crate::{
53 acme::{AcmeAccount, AcmeChallenge, AcmeOrder},
54 pki_env::hooks::{HttpHeader, HttpMethod, HttpResponse, PkiEnvironmentHooks, PkiEnvironmentHooksError},
55 };
56
57 #[derive(Debug)]
58 struct UnusedPkiEnvironmentHooks;
59
60 #[async_trait::async_trait]
61 impl PkiEnvironmentHooks for UnusedPkiEnvironmentHooks {
62 async fn http_request(
63 &self,
64 _method: HttpMethod,
65 _url: String,
66 _headers: Vec<HttpHeader>,
67 _body: Vec<u8>,
68 ) -> std::result::Result<HttpResponse, PkiEnvironmentHooksError> {
69 unreachable!("serialization round-trip should not perform HTTP requests")
70 }
71
72 async fn authenticate(
73 &self,
74 _idp: String,
75 _key_auth: String,
76 _acme_aud: String,
77 _acquisition_snapshot: Vec<u8>,
78 ) -> std::result::Result<String, PkiEnvironmentHooksError> {
79 unreachable!("serialization round-trip should not authenticate")
80 }
81
82 async fn get_backend_nonce(&self) -> std::result::Result<String, PkiEnvironmentHooksError> {
83 unreachable!("serialization round-trip should not request backend nonces")
84 }
85
86 async fn fetch_backend_access_token(
87 &self,
88 _dpop: String,
89 ) -> std::result::Result<String, PkiEnvironmentHooksError> {
90 unreachable!("serialization round-trip should not fetch backend access tokens")
91 }
92 }
93
94 #[tokio::test]
95 async fn can_serialize_and_deserialize_dpop_challenge_completed_acquisition() {
96 let pki_env = Arc::new(
97 PkiEnvironment::new(
98 Arc::new(UnusedPkiEnvironmentHooks),
99 Database::open(ConnectionType::InMemory, &DatabaseKey::generate())
100 .await
101 .unwrap(),
102 )
103 .await
104 .unwrap(),
105 );
106 let client_id = ClientId::try_new(Uuid::new_v4().to_string(), 1, "wire.example").unwrap();
107 let config = X509CredentialConfiguration {
108 acme_directory_url: "acme.example".into(),
109 sign_alg: JwsAlgorithm::P256,
110 hash_alg: HashAlgorithm::SHA256,
111 display_name: "Alice".into(),
112 client_id,
113 handle: "alice".into(),
114 domain: "wire.example".into(),
115 team: Some("team".into()),
116 validity_period: std::time::Duration::from_secs(3600),
117 };
118 let initialized = X509CredentialAcquisition::try_new(pki_env.clone(), config).unwrap();
119 let acquisition = X509CredentialAcquisition::<states::DpopChallengeCompleted> {
120 pki_env: initialized.pki_env,
121 config: initialized.config,
122 sign_kp: initialized.sign_kp,
123 acme_kp: initialized.acme_kp,
124 acme_jwk: initialized.acme_jwk,
125 data: states::DpopChallengeCompleted {
126 nonce: "acme-nonce".into(),
127 acme_account: AcmeAccount::default(),
128 order: AcmeOrder::default(),
129 oidc_challenge: AcmeChallenge::new_user(),
130 },
131 };
132
133 let serialized = serde_json::to_vec(&acquisition).unwrap();
134 let deserialized =
135 X509CredentialAcquisition::<states::DpopChallengeCompleted>::deserialize(pki_env, &serialized).unwrap();
136
137 assert_eq!(
138 serde_json::to_value(&acquisition).unwrap(),
139 serde_json::to_value(&deserialized).unwrap()
140 );
141 }
142}