1use std::{io::Cursor, path::Path, sync::Arc};
2
3use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
4use hyper_util::client::legacy::connect::HttpConnector;
5use rustls::{
6 client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
7 crypto::CryptoProvider,
8 pki_types::{CertificateDer, ServerName, UnixTime},
9 version::TLS13,
10 CertificateError, ClientConfig, DigitallySignedStruct, SignatureScheme,
11};
12use saluki_error::{generic_error, ErrorContext as _, GenericError};
13
14pub async fn build_datadog_agent_ipc_https_connector<P: AsRef<Path>>(
21 cert_path: P,
22) -> Result<HttpsConnector<HttpConnector>, GenericError> {
23 let tls_client_config = build_datadog_agent_ipc_tls_config(cert_path).await?;
24 let mut http_connector = HttpConnector::new();
25 http_connector.enforce_http(false);
26
27 Ok(HttpsConnectorBuilder::new()
28 .with_tls_config(tls_client_config)
29 .https_only()
30 .enable_http2()
31 .wrap_connector(http_connector))
32}
33
34#[derive(Debug)]
35struct DatadogAgentServerCertVerifier {
36 cert: CertificateDer<'static>,
37 provider: Arc<CryptoProvider>,
38}
39
40impl DatadogAgentServerCertVerifier {
41 fn from_certificate_and_provider(cert: CertificateDer<'static>, provider: Arc<CryptoProvider>) -> Self {
42 Self { cert, provider }
43 }
44}
45
46impl ServerCertVerifier for DatadogAgentServerCertVerifier {
47 fn verify_server_cert(
48 &self, end_entity: &CertificateDer<'_>, _intermediates: &[CertificateDer<'_>], _server_name: &ServerName<'_>,
49 _ocsp_response: &[u8], _now: UnixTime,
50 ) -> Result<ServerCertVerified, rustls::Error> {
51 if end_entity != &self.cert {
56 return Err(rustls::Error::InvalidCertificate(CertificateError::UnknownIssuer));
57 }
58
59 Ok(ServerCertVerified::assertion())
60 }
61
62 fn verify_tls12_signature(
63 &self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct,
64 ) -> Result<HandshakeSignatureValid, rustls::Error> {
65 rustls::crypto::verify_tls12_signature(message, cert, dss, &self.provider.signature_verification_algorithms)
66 }
67
68 fn verify_tls13_signature(
69 &self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct,
70 ) -> Result<HandshakeSignatureValid, rustls::Error> {
71 rustls::crypto::verify_tls13_signature(message, cert, dss, &self.provider.signature_verification_algorithms)
72 }
73
74 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
75 self.provider.signature_verification_algorithms.supported_schemes()
76 }
77}
78
79pub async fn build_datadog_agent_ipc_tls_config<P: AsRef<Path>>(cert_path: P) -> Result<ClientConfig, GenericError> {
80 let raw_cert_data = tokio::fs::read(cert_path.as_ref()).await.map_err(|e| {
82 generic_error!(
83 "Failed to read certificate file '{}' ({}).",
84 cert_path.as_ref().display(),
85 e.kind()
86 )
87 })?;
88
89 let mut cert_reader = Cursor::new(&raw_cert_data);
90 let parsed_cert = rustls_pemfile::certs(&mut cert_reader)
91 .next()
92 .ok_or_else(|| generic_error!("No certificate found in file."))?
93 .with_error_context(|| format!("Failed to parse certificate file '{}'.", cert_path.as_ref().display()))?;
94
95 let mut key_reader = Cursor::new(&raw_cert_data);
96 let parsed_key = rustls_pemfile::private_key(&mut key_reader)
97 .with_error_context(|| format!("Failed to parse private key file '{}'.", cert_path.as_ref().display()))?
98 .ok_or_else(|| generic_error!("No private key found in file."))?;
99
100 let crypto_provider = rustls::crypto::CryptoProvider::get_default()
103 .map(Arc::clone)
104 .ok_or_else(|| generic_error!("Default cryptography provider not yet installed."))?;
105 let agent_cert_verifier = Arc::new(DatadogAgentServerCertVerifier::from_certificate_and_provider(
106 parsed_cert.clone(),
107 crypto_provider,
108 ));
109
110 let tls_client_config = ClientConfig::builder_with_protocol_versions(&[&TLS13])
111 .dangerous()
112 .with_custom_certificate_verifier(agent_cert_verifier)
113 .with_client_auth_cert(vec![parsed_cert], parsed_key)
114 .with_error_context(|| {
115 format!(
116 "Failed to configure TLS client authentication with certificate/private key from '{}'.",
117 cert_path.as_ref().display()
118 )
119 })?;
120 Ok(tls_client_config)
121}