1use std::{collections::HashMap, path::PathBuf};
2
3use josekit::{jwk::Jwk, jwt::JwtPayload};
4use serde_json::Value;
5use ssi::did::Service;
6use trustchain_core::utils::generate_key;
7use trustchain_ion::attestor::IONAttestor;
8
9use crate::{
10 attestation_encryption_utils::{
11 josekit_to_ssi_jwk, ssi_to_josekit_jwk, DecryptVerify, Entity, SignEncrypt,
12 },
13 attestation_utils::{
14 attestation_request_path, matching_endpoint, ContentCRChallenge, ContentCRInitiation,
15 ElementwiseSerializeDeserialize, IdentityCRChallenge, IdentityCRInitiation,
16 RequesterDetails,
17 },
18 attestation_utils::{CustomResponse, Nonce, TrustchainCRError},
19 ATTESTATION_FRAGMENT,
20};
21
22pub async fn initiate_identity_challenge(
28 org_name: &str,
29 op_name: &str,
30 services: &[Service],
31) -> Result<(IdentityCRInitiation, PathBuf), TrustchainCRError> {
32 let temp_s_key_ssi = generate_key();
34 let temp_p_key_ssi = temp_s_key_ssi.to_public();
35 let temp_s_key =
36 ssi_to_josekit_jwk(&temp_s_key_ssi).map_err(|_| TrustchainCRError::FailedToGenerateKey)?;
37 let temp_p_key =
38 ssi_to_josekit_jwk(&temp_p_key_ssi).map_err(|_| TrustchainCRError::FailedToGenerateKey)?;
39
40 let requester = RequesterDetails {
42 requester_org: org_name.to_owned(),
43 operator_name: op_name.to_owned(),
44 };
45 let mut identity_cr_initiation = IdentityCRInitiation {
46 temp_s_key: None,
47 temp_p_key: Some(temp_p_key.clone()),
48 requester_details: Some(requester.clone()),
49 };
50
51 let url_path = "/did/attestor/identity/initiate";
53 let endpoint = matching_endpoint(services, ATTESTATION_FRAGMENT)?;
54 let uri = format!("{}{}", endpoint, url_path);
55
56 let client = reqwest::Client::new();
58 let result = client
59 .post(uri)
60 .json(&identity_cr_initiation)
61 .send()
62 .await
63 .map_err(TrustchainCRError::Reqwest)?;
64
65 if result.status() != 200 {
66 return Err(TrustchainCRError::FailedToInitiateCR);
67 }
68 let path = attestation_request_path(&temp_s_key_ssi.to_public(), "requester")?;
70 std::fs::create_dir_all(&path).map_err(|_| TrustchainCRError::FailedAttestationRequest)?;
71
72 identity_cr_initiation.temp_s_key = Some(temp_s_key);
74
75 Ok((identity_cr_initiation, path))
76}
77
78pub async fn identity_response(
85 path: &PathBuf,
86 services: &[Service],
87 attestor_p_key: &Jwk,
88) -> Result<IdentityCRChallenge, TrustchainCRError> {
89 let mut identity_challenge = IdentityCRChallenge::new()
91 .elementwise_deserialize(path)?
92 .ok_or(TrustchainCRError::FailedToDeserialize)?;
93 let identity_initiation = IdentityCRInitiation::new()
95 .elementwise_deserialize(path)?
96 .ok_or(TrustchainCRError::FailedToDeserialize)?;
97 let temp_s_key = identity_initiation.temp_s_key()?;
98 let temp_s_key_ssi = josekit_to_ssi_jwk(temp_s_key)?;
99
100 let requester = Entity {};
102 let decrypted_verified_payload = requester.decrypt_and_verify(
103 identity_challenge
104 .identity_challenge_signature
105 .clone()
106 .ok_or(TrustchainCRError::FieldNotFound)?,
107 temp_s_key,
108 attestor_p_key,
109 )?;
110 let signed_encrypted_response = requester.sign_and_encrypt_claim(
112 &decrypted_verified_payload,
113 temp_s_key,
114 attestor_p_key,
115 )?;
116 let key_id = temp_s_key_ssi.to_public().thumbprint()?;
117 let endpoint = matching_endpoint(services, ATTESTATION_FRAGMENT)?;
119 let url_path = "/did/attestor/identity/respond";
120 let uri = format!("{}{}/{}", endpoint, url_path, key_id);
121 let client = reqwest::Client::new();
123 let result = client
124 .post(uri)
125 .json(&signed_encrypted_response)
126 .send()
127 .await
128 .map_err(TrustchainCRError::Reqwest)?;
129 if result.status() != 200 {
130 return Err(TrustchainCRError::FailedToRespond(result));
131 }
132 let nonce_str = decrypted_verified_payload
134 .claim("identity_nonce")
135 .ok_or(TrustchainCRError::ClaimNotFound)?
136 .as_str()
137 .ok_or(TrustchainCRError::FailedToConvertToStr(
138 decrypted_verified_payload
140 .claim("identity_nonce")
141 .unwrap()
142 .clone(),
143 ))?;
144 let nonce = Nonce::from(String::from(nonce_str));
145 identity_challenge.update_p_key = Some(attestor_p_key.clone());
147 identity_challenge.identity_nonce = Some(nonce);
148 identity_challenge.identity_response_signature = Some(signed_encrypted_response);
149
150 Ok(identity_challenge)
151}
152
153pub async fn initiate_content_challenge(
162 path: &PathBuf,
163 ddid: &str,
164 services: &[Service],
165 attestor_p_key: &Jwk,
166) -> Result<(ContentCRInitiation, ContentCRChallenge), TrustchainCRError> {
167 let identity_cr_initiation = IdentityCRInitiation::new()
169 .elementwise_deserialize(path)?
170 .ok_or(TrustchainCRError::FailedToDeserialize)?;
171 let temp_s_key_ssi = josekit_to_ssi_jwk(&identity_cr_initiation.temp_s_key().cloned()?)?;
172 let key_id = temp_s_key_ssi.to_public().thumbprint()?;
173
174 let content_cr_initiation = ContentCRInitiation {
175 requester_did: Some(ddid.to_owned()),
176 };
177 let endpoint = matching_endpoint(services, ATTESTATION_FRAGMENT)?;
179 let url_path = "/did/attestor/content/initiate";
180 let uri = format!("{}{}/{}", endpoint, url_path, key_id);
181 let client = reqwest::Client::new();
183 let result = client
184 .post(uri)
185 .json(&ddid)
186 .send()
187 .await
188 .map_err(TrustchainCRError::Reqwest)?;
189 if result.status() != 200 {
190 println!("Status code: {}", result.status());
191 return Err(TrustchainCRError::FailedToRespond(result));
192 }
193
194 let response_body: CustomResponse = result.json().await.map_err(TrustchainCRError::Reqwest)?;
195 let signed_encrypted_challenge = response_body
196 .data
197 .ok_or(TrustchainCRError::ResponseMustContainData)?;
198
199 let (nonces, response) = content_response(
201 path,
202 &signed_encrypted_challenge.to_string(),
203 services,
204 attestor_p_key.clone(),
205 ddid,
206 )
207 .await?;
208 let content_challenge = ContentCRChallenge {
209 content_nonce: Some(nonces),
210 content_challenge_signature: Some(signed_encrypted_challenge.to_string()),
211 content_response_signature: Some(response),
212 };
213 Ok((content_cr_initiation, content_challenge))
214}
215
216pub async fn content_response(
226 path: &PathBuf,
227 challenge: &str,
228 services: &[Service],
229 attestor_p_key: Jwk,
230 ddid: &str,
231) -> Result<(HashMap<String, Nonce>, String), TrustchainCRError> {
232 let identity_initiation = IdentityCRInitiation::new()
234 .elementwise_deserialize(path)?
235 .ok_or(TrustchainCRError::FailedToDeserialize)?;
236 let temp_s_key = identity_initiation.temp_s_key()?;
237 let temp_s_key_ssi = josekit_to_ssi_jwk(temp_s_key)?;
238 let key_id = temp_s_key_ssi.to_public().thumbprint()?;
240 let endpoint = matching_endpoint(services, ATTESTATION_FRAGMENT)?;
241 let url_path = "/did/attestor/content/respond";
242 let uri = format!("{}{}/{}", endpoint, url_path, key_id);
243
244 let requester = Entity {};
246 let decrypted_verified_payload =
247 requester.decrypt_and_verify(challenge.to_owned(), temp_s_key, &attestor_p_key)?;
248 let challenges_map: HashMap<String, String> = serde_json::from_value(
250 decrypted_verified_payload
251 .claim("challenges")
252 .ok_or(TrustchainCRError::ClaimNotFound)?
253 .clone(),
254 )?;
255
256 let ion_attestor = IONAttestor::new(ddid);
258 let signing_keys = ion_attestor.signing_keys()?;
259 let mut signing_keys_map: HashMap<String, Jwk> = HashMap::new();
261 for key in signing_keys {
262 let key_id = key.thumbprint()?;
263 let jwk = ssi_to_josekit_jwk(&key)?;
264 signing_keys_map.insert(key_id, jwk);
265 }
266
267 let mut decrypted_nonces: HashMap<String, Nonce> = HashMap::new();
278 for (key_id, nonce) in challenges_map.iter() {
279 let payload = requester.decrypt(
280 &Value::from(nonce.clone()),
281 signing_keys_map
282 .get(key_id)
283 .ok_or(TrustchainCRError::KeyNotFound)?,
284 )?;
285 decrypted_nonces.insert(
286 String::from(key_id),
287 Nonce::from(
288 payload
289 .claim("nonce")
290 .ok_or(TrustchainCRError::ClaimNotFound)?
291 .as_str()
292 .ok_or(TrustchainCRError::FailedToConvertToStr(
293 payload.claim("nonce").unwrap().clone(),
295 ))?
296 .to_string(),
297 ),
298 );
299 }
300
301 let value: serde_json::Value = serde_json::to_value(&decrypted_nonces)?;
303 let mut payload = JwtPayload::new();
304 payload.set_claim("nonces", Some(value))?;
305 let signed_encrypted_response =
306 requester.sign_and_encrypt_claim(&payload, temp_s_key, &attestor_p_key)?;
307 let client = reqwest::Client::new();
309 let result = client
310 .post(uri)
311 .json(&signed_encrypted_response)
312 .send()
313 .await
314 .map_err(TrustchainCRError::Reqwest)?;
315 if result.status() != 200 {
316 println!("Status code: {}", result.status());
317 return Err(TrustchainCRError::FailedToRespond(result));
318 }
319 Ok((decrypted_nonces, signed_encrypted_response))
320}