datadog_agent_commons/ipc/
tls.rs1use std::{
4 path::Path,
5 sync::Arc,
6 time::{Duration, Instant},
7};
8
9use rustls::{
10 client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
11 crypto::CryptoProvider,
12 pki_types::{CertificateDer, ServerName, UnixTime},
13 version::TLS13,
14 CertificateError, ClientConfig, DigitallySignedStruct, ServerConfig, SignatureScheme,
15};
16use rustls_pki_types::{pem::PemObject as _, PrivateKeyDer};
17use saluki_error::{generic_error, ErrorContext as _, GenericError};
18
19const DEFAULT_CERT_READ_TIMEOUT: Duration = Duration::from_secs(20);
20const DEFAULT_CERT_READ_INTERVAL: Duration = Duration::from_millis(100);
21
22#[derive(Debug)]
23struct DatadogAgentServerCertVerifier {
24 cert: CertificateDer<'static>,
25 provider: Arc<CryptoProvider>,
26}
27
28impl DatadogAgentServerCertVerifier {
29 fn from_certificate_and_provider(cert: CertificateDer<'static>, provider: Arc<CryptoProvider>) -> Self {
30 Self { cert, provider }
31 }
32}
33
34impl ServerCertVerifier for DatadogAgentServerCertVerifier {
35 fn verify_server_cert(
36 &self, end_entity: &CertificateDer<'_>, _intermediates: &[CertificateDer<'_>], _server_name: &ServerName<'_>,
37 _ocsp_response: &[u8], _now: UnixTime,
38 ) -> Result<ServerCertVerified, rustls::Error> {
39 if end_entity != &self.cert {
44 return Err(rustls::Error::InvalidCertificate(CertificateError::UnknownIssuer));
45 }
46
47 Ok(ServerCertVerified::assertion())
48 }
49
50 fn verify_tls12_signature(
51 &self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct,
52 ) -> Result<HandshakeSignatureValid, rustls::Error> {
53 rustls::crypto::verify_tls12_signature(message, cert, dss, &self.provider.signature_verification_algorithms)
54 }
55
56 fn verify_tls13_signature(
57 &self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct,
58 ) -> Result<HandshakeSignatureValid, rustls::Error> {
59 rustls::crypto::verify_tls13_signature(message, cert, dss, &self.provider.signature_verification_algorithms)
60 }
61
62 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
63 self.provider.signature_verification_algorithms.supported_schemes()
64 }
65}
66
67pub async fn build_ipc_client_ipc_tls_config<P: AsRef<Path>>(cert_path: P) -> Result<ClientConfig, GenericError> {
77 let (parsed_cert, parsed_key) = read_and_parse_certificate_file(
79 cert_path.as_ref(),
80 DEFAULT_CERT_READ_TIMEOUT,
81 DEFAULT_CERT_READ_INTERVAL,
82 )
83 .await?;
84
85 let crypto_provider = rustls::crypto::CryptoProvider::get_default()
87 .map(Arc::clone)
88 .ok_or_else(|| generic_error!("Default cryptography provider not yet installed."))?;
89 let agent_cert_verifier = Arc::new(DatadogAgentServerCertVerifier::from_certificate_and_provider(
90 parsed_cert.clone(),
91 crypto_provider,
92 ));
93
94 ClientConfig::builder_with_protocol_versions(&[&TLS13])
95 .dangerous()
96 .with_custom_certificate_verifier(agent_cert_verifier)
97 .with_client_auth_cert(vec![parsed_cert], parsed_key)
98 .with_error_context(|| {
99 format!(
100 "Failed to build client TLS configuration from certificate file '{}'.",
101 cert_path.as_ref().display()
102 )
103 })
104}
105
106pub async fn build_ipc_server_tls_config<P: AsRef<Path>>(cert_path: P) -> Result<ServerConfig, GenericError> {
116 let (parsed_cert, parsed_key) = read_and_parse_certificate_file(
118 cert_path.as_ref(),
119 DEFAULT_CERT_READ_TIMEOUT,
120 DEFAULT_CERT_READ_INTERVAL,
121 )
122 .await?;
123
124 ServerConfig::builder()
125 .with_no_client_auth()
126 .with_single_cert(vec![parsed_cert], parsed_key)
127 .with_error_context(|| {
128 format!(
129 "Failed to build server TLS configuration from certificate file '{}'.",
130 cert_path.as_ref().display()
131 )
132 })
133}
134
135async fn read_and_parse_certificate_file(
145 cert_path: &Path, timeout: Duration, interval: Duration,
146) -> Result<(CertificateDer<'static>, PrivateKeyDer<'static>), GenericError> {
147 if timeout < interval {
148 return Err(generic_error!(
149 "Timeout is less than interval ({} < {}).",
150 timeout.as_secs(),
151 interval.as_secs()
152 ));
153 }
154
155 let start_time = Instant::now();
156 let mut last_error = String::new();
157 while start_time.elapsed() < timeout {
158 match tokio::fs::read(cert_path).await {
159 Ok(raw_cert_data) => {
160 let parsed_cert = CertificateDer::from_pem_slice(&raw_cert_data[..])
161 .with_error_context(|| format!("Failed to parse certificate file '{}'.", cert_path.display()))?
162 .into_owned();
163
164 let parsed_key = PrivateKeyDer::from_pem_slice(&raw_cert_data[..])
165 .with_error_context(|| format!("Failed to parse private key file '{}'.", cert_path.display()))?
166 .clone_key();
167
168 return Ok((parsed_cert, parsed_key));
169 }
170 Err(e) => {
171 last_error = e.to_string();
172 tokio::time::sleep(interval).await;
173 }
174 }
175 }
176
177 Err(generic_error!(
178 "Failed to read certificate file '{}' after {} seconds: {}",
179 cert_path.display(),
180 timeout.as_secs(),
181 last_error
182 ))
183}