1use std::sync::Arc;
7use std::io::Read;
8
9pub use em_client::models;
10
11use hyper::client::Pool;
12use hyper::net::HttpsConnector;
13use em_client::{Api, Client};
14use mbedtls::alloc::{List as MbedtlsList};
15use mbedtls::pk::Pk;
16use mbedtls::ssl::Config;
17use mbedtls::ssl::config::{Endpoint, Preset, Transport, AuthMode, Version};
18use mbedtls::x509::{Certificate, Crl};
19use mbedtls::hash::{Md, Type};
20use sdkms::api_model::Blob;
21use uuid::Uuid;
22use url::Url;
23use std::time::Duration;
24use uuid_sdkms::{Uuid as SdkmsUuid};
25
26use crate::mbedtls_hyper::MbedSSLClient;
27
28pub fn convert_uuid(api_uuid: Uuid) -> SdkmsUuid {
29 SdkmsUuid::from_bytes(*api_uuid.as_bytes())
30}
31
32pub fn compute_sha256(input: &[u8]) -> Result<[u8; 32], String> {
34 let mut digest = [0; 32];
35 Md::hash(Type::Sha256, input, &mut digest)
36 .map_err(|e| format!("Error in calculating digest: {:?}", e))?;
37
38 Ok(digest)
39}
40
41pub fn get_runtime_configuration(
42 server: &str,
43 port: u16,
44 cert: Arc<MbedtlsList<Certificate>>,
45 key: Arc<Pk>,
46 ca_cert_list: Option<Arc<MbedtlsList<Certificate>>>,
47 ca_crl: Option<Arc<Crl>>,
48 expected_hash: &[u8; 32]
49) -> Result<models::RuntimeAppConfig, String> {
50
51 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
52
53 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
54 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
55
56 if let Some(ca_cert_list) = ca_cert_list {
57 config.set_ca_list(ca_cert_list, ca_crl);
58 config.set_authmode(AuthMode::Required);
59 } else {
60 config.set_authmode(AuthMode::Optional);
61 }
62
63 config.push_cert(cert, key).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
64
65 let ssl = MbedSSLClient::new_with_sni(Arc::new(config), true, Some(format!("nodes.{}", server)));
66 let connector = HttpsConnector::new(ssl);
67 let client = Client::try_new_with_connector(&format!("https://{}:{}/v1/runtime/app_configs", server, port), None, connector).map_err(|e| format!("EM SaaS request failed: {:?}", e))?;
68 let response = client.get_runtime_application_config(expected_hash).map_err(|e| format!("Failed requesting workflow config response: {:?}", e))?;
69
70 Ok(response)
71}
72
73pub fn get_sdkms_dataset(
74 sdkms_url: String,
75 dataset_id: String,
76 app_id: Uuid,
77 cert: Arc<MbedtlsList<Certificate>>,
78 key: Arc<Pk>,
79 ca_cert_list: Option<Arc<MbedtlsList<Certificate>>>,
80 ca_crl: Option<Arc<Crl>>
81) -> Result<Blob, String> {
82
83 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
84
85 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
86 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
87
88 if let Some(ca_cert_list) = ca_cert_list {
89 config.set_ca_list(ca_cert_list, ca_crl);
90 config.set_authmode(AuthMode::Required);
91 } else {
92 config.set_authmode(AuthMode::Optional);
93 }
94
95 config.push_cert(cert, key).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
96
97 let ssl = MbedSSLClient::new(Arc::new(config), true);
98 let connector = HttpsConnector::new(ssl);
99 let client = Arc::new(hyper::Client::with_connector(Pool::with_connector(Default::default(), connector)));
100
101 let client = sdkms::SdkmsClient::builder()
102 .with_api_endpoint(&sdkms_url)
103 .with_hyper_client(client)
104 .build().map_err(|e| format!("SDKMS Build failed: {:?}", e))?
105 .authenticate_with_cert(Some(&convert_uuid(app_id))).map_err(|e| format!("SDKMS authenticate failed: {:?}", e))?;
106
107 let key_id = sdkms::api_model::SobjectDescriptor::Name(dataset_id);
108
109 let result = client.export_sobject(&key_id).map_err(|e| format!("Failed SDKMS export operation: {:?}", e))?;
110
111 result.value.ok_or("Missing value in exported object".to_string())
112}
113
114pub fn https_get(url: Url,
115 ca_cert_list: Option<Arc<MbedtlsList<Certificate>>>,
116 ca_crl: Option<Arc<Crl>>
117) -> Result<Vec<u8>, String> {
118 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
119
120 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
121 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
122
123 if let Some(ca_cert_list) = ca_cert_list {
124 config.set_ca_list(ca_cert_list, ca_crl);
125 config.set_authmode(AuthMode::Required);
126 } else {
127 config.set_authmode(AuthMode::Optional);
128 }
129
130 let ssl = MbedSSLClient::new(Arc::new(config), true);
131 let connector = HttpsConnector::new(ssl);
132 let client = hyper::Client::with_connector(Pool::with_connector(Default::default(), connector));
133 let mut response = client.get(url).send().map_err(|e| format!("Failed downloading, error: {:?}", e))?;
134
135 if response.status != hyper::status::StatusCode::Ok {
136 return Err(format!("Request failed, result: {:?}", response));
137 }
138
139 let mut body = vec![];
140 response.read_to_end(&mut body).map_err(|e| format!("Failed reading body, error: {:?}", e))?;
141
142 Ok(body)
143}
144
145pub fn https_put(url: Url,
146 body: Vec<u8>,
147 ca_cert_list: Option<Arc<MbedtlsList<Certificate>>>,
148 ca_crl: Option<Arc<Crl>>
149) -> Result<(), String> {
150 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
151
152 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
153 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
154
155 if let Some(ca_cert_list) = ca_cert_list {
156 config.set_ca_list(ca_cert_list, ca_crl);
157 config.set_authmode(AuthMode::Required);
158 } else {
159 config.set_authmode(AuthMode::Optional);
160 }
161
162 let ssl = MbedSSLClient::new(Arc::new(config), true);
163 let connector = HttpsConnector::new(ssl);
164 let client = hyper::Client::with_connector(Pool::with_connector(Default::default(), connector));
165 let result = client.put(url).body(body.as_slice()).send().map_err(|e| format!("Failed upload, error: {:?}", e))?;
166
167 if result.status != hyper::status::StatusCode::Ok {
168 return Err(format!("Request failed, result: {:?}", result));
169 }
170
171 Ok(())
172}
173
174const CONNECTION_IDLE_TIMEOUT_SECS: u64 = 30;
175
176pub fn get_hyper_connector_pool(ca_chain: Vec<Vec<u8>>) -> Result<Arc<hyper::Client>, String> {
177 get_mbedtls_hyper_connector_pool(ca_chain, None)
178}
179
180pub fn get_mbedtls_hyper_connector_pool(ca_chain: Vec<Vec<u8>>, client_pki: Option<(Arc<MbedtlsList<Certificate>>, Arc<Pk>)>) -> Result<Arc<hyper::Client>, String> {
181 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
182
183 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
184 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
185
186 if !ca_chain.is_empty() {
187 let mut list = MbedtlsList::<Certificate>::new();
188 for i in ca_chain {
189 list.push(Certificate::from_der(&i).map_err(|e| format!("Failed parsing ca cert, error: {:?}", e))?);
190 }
191
192 config.set_ca_list(Arc::new(list), None);
193 config.set_authmode(AuthMode::Required);
194 } else {
195 config.set_authmode(AuthMode::Optional);
196 }
197
198 if let Some((cert, key)) = client_pki {
199 config.push_cert(cert, key).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
200 }
201
202 let ssl = MbedSSLClient::new(Arc::new(config), true);
203 let connector = HttpsConnector::new(ssl);
204
205 let mut pool = Pool::with_connector(Default::default(), connector);
206 pool.set_idle_timeout(Some(Duration::from_secs(CONNECTION_IDLE_TIMEOUT_SECS)));
207
208 Ok(Arc::new(hyper::Client::with_connector(pool)))
209}