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 tls_client = if (server.starts_with("ccm.") || server.starts_with("em.")) && server.ends_with("fortanix.com") {
66 MbedSSLClient::new_with_sni(Arc::new(config), true, Some(format!("nodes.{}", server)))
67 } else {
68 MbedSSLClient::new(Arc::new(config), true)
69 };
70
71 let connector = HttpsConnector::new(tls_client);
72 let mut client = Client::try_new_with_connector(&format!("https://{}:{}", server, port), None, connector)
73 .map_err(|e| format!("CCM client construction failed: {:?}", e))?;
74 client.set_use_new_paths(true);
75 let response = client.get_runtime_application_config(expected_hash).map_err(|e| format!("Failed requesting workflow config response: {:?}", e))?;
76
77 Ok(response)
78}
79
80pub fn get_sdkms_dataset(
81 sdkms_url: String,
82 dataset_id: String,
83 app_id: Uuid,
84 cert: Arc<MbedtlsList<Certificate>>,
85 key: Arc<Pk>,
86 ca_cert_list: Option<Arc<MbedtlsList<Certificate>>>,
87 ca_crl: Option<Arc<Crl>>
88) -> Result<Blob, String> {
89
90 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
91
92 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
93 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
94
95 if let Some(ca_cert_list) = ca_cert_list {
96 config.set_ca_list(ca_cert_list, ca_crl);
97 config.set_authmode(AuthMode::Required);
98 } else {
99 config.set_authmode(AuthMode::Optional);
100 }
101
102 config.push_cert(cert, key).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
103
104 let ssl = MbedSSLClient::new(Arc::new(config), true);
105 let connector = HttpsConnector::new(ssl);
106 let client = Arc::new(hyper::Client::with_connector(Pool::with_connector(Default::default(), connector)));
107
108 let client = sdkms::SdkmsClient::builder()
109 .with_api_endpoint(&sdkms_url)
110 .with_hyper_client(client)
111 .build().map_err(|e| format!("SDKMS Build failed: {:?}", e))?
112 .authenticate_with_cert(Some(&convert_uuid(app_id))).map_err(|e| format!("SDKMS authenticate failed: {:?}", e))?;
113
114 let key_id = sdkms::api_model::SobjectDescriptor::Name(dataset_id);
115
116 let result = client.export_sobject(&key_id).map_err(|e| format!("Failed SDKMS export operation: {:?}", e))?;
117
118 result.value.ok_or("Missing value in exported object".to_string())
119}
120
121pub fn https_get(url: Url,
122 ca_cert_list: Option<Arc<MbedtlsList<Certificate>>>,
123 ca_crl: Option<Arc<Crl>>
124) -> Result<Vec<u8>, String> {
125 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
126
127 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
128 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
129
130 if let Some(ca_cert_list) = ca_cert_list {
131 config.set_ca_list(ca_cert_list, ca_crl);
132 config.set_authmode(AuthMode::Required);
133 } else {
134 config.set_authmode(AuthMode::Optional);
135 }
136
137 let ssl = MbedSSLClient::new(Arc::new(config), true);
138 let connector = HttpsConnector::new(ssl);
139 let client = hyper::Client::with_connector(Pool::with_connector(Default::default(), connector));
140 let mut response = client.get(url).send().map_err(|e| format!("Failed downloading, error: {:?}", e))?;
141
142 if response.status != hyper::status::StatusCode::Ok {
143 return Err(format!("Request failed, result: {:?}", response));
144 }
145
146 let mut body = vec![];
147 response.read_to_end(&mut body).map_err(|e| format!("Failed reading body, error: {:?}", e))?;
148
149 Ok(body)
150}
151
152pub fn https_put(url: Url,
153 body: Vec<u8>,
154 ca_cert_list: Option<Arc<MbedtlsList<Certificate>>>,
155 ca_crl: Option<Arc<Crl>>
156) -> Result<(), String> {
157 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
158
159 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
160 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
161
162 if let Some(ca_cert_list) = ca_cert_list {
163 config.set_ca_list(ca_cert_list, ca_crl);
164 config.set_authmode(AuthMode::Required);
165 } else {
166 config.set_authmode(AuthMode::Optional);
167 }
168
169 let ssl = MbedSSLClient::new(Arc::new(config), true);
170 let connector = HttpsConnector::new(ssl);
171 let client = hyper::Client::with_connector(Pool::with_connector(Default::default(), connector));
172 let result = client.put(url).body(body.as_slice()).send().map_err(|e| format!("Failed upload, error: {:?}", e))?;
173
174 if result.status != hyper::status::StatusCode::Ok {
175 return Err(format!("Request failed, result: {:?}", result));
176 }
177
178 Ok(())
179}
180
181const CONNECTION_IDLE_TIMEOUT_SECS: u64 = 30;
182
183pub fn get_hyper_connector_pool(ca_chain: Vec<Vec<u8>>) -> Result<Arc<hyper::Client>, String> {
184 get_mbedtls_hyper_connector_pool(ca_chain, None)
185}
186
187pub fn get_mbedtls_hyper_connector_pool(ca_chain: Vec<Vec<u8>>, client_pki: Option<(Arc<MbedtlsList<Certificate>>, Arc<Pk>)>) -> Result<Arc<hyper::Client>, String> {
188 let mut config = Config::new(Endpoint::Client, Transport::Stream, Preset::Default);
189
190 config.set_rng(Arc::new(mbedtls::rng::Rdrand));
191 config.set_min_version(Version::Tls1_2).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
192
193 if !ca_chain.is_empty() {
194 let mut list = MbedtlsList::<Certificate>::new();
195 for i in ca_chain {
196 list.push(Certificate::from_der(&i).map_err(|e| format!("Failed parsing ca cert, error: {:?}", e))?);
197 }
198
199 config.set_ca_list(Arc::new(list), None);
200 config.set_authmode(AuthMode::Required);
201 } else {
202 config.set_authmode(AuthMode::Optional);
203 }
204
205 if let Some((cert, key)) = client_pki {
206 config.push_cert(cert, key).map_err(|e| format!("TLS configuration failed: {:?}", e))?;
207 }
208
209 let ssl = MbedSSLClient::new(Arc::new(config), true);
210 let connector = HttpsConnector::new(ssl);
211
212 let mut pool = Pool::with_connector(Default::default(), connector);
213 pool.set_idle_timeout(Some(Duration::from_secs(CONNECTION_IDLE_TIMEOUT_SECS)));
214
215 Ok(Arc::new(hyper::Client::with_connector(pool)))
216}