diff --git a/Cargo.lock b/Cargo.lock index bdac1e0d3..1738c7816 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1460,6 +1460,7 @@ dependencies = [ "memchr", "slog", "uuid", + "variant-ssl", ] [[package]] diff --git a/g3proxy/Cargo.toml b/g3proxy/Cargo.toml index 587aa6ee5..1c7328cd7 100644 --- a/g3proxy/Cargo.toml +++ b/g3proxy/Cargo.toml @@ -79,7 +79,7 @@ g3-msgpack.workspace = true g3-openssl.workspace = true g3-redis-client = { workspace = true, features = ["yaml"] } g3-resolver.workspace = true -g3-slog-types = { workspace = true, features = ["http"] } +g3-slog-types = { workspace = true, features = ["http", "openssl"] } g3-smtp-proto.workspace = true g3-socket.workspace = true g3-socks.workspace = true diff --git a/g3proxy/src/inspect/start_tls/mod.rs b/g3proxy/src/inspect/start_tls/mod.rs index 53debe1d1..fce7698c6 100644 --- a/g3proxy/src/inspect/start_tls/mod.rs +++ b/g3proxy/src/inspect/start_tls/mod.rs @@ -18,13 +18,14 @@ use std::sync::Arc; use anyhow::anyhow; use openssl::ssl::Ssl; +use openssl::x509::X509VerifyResult; use slog::slog_info; use tokio::io::{AsyncRead, AsyncWrite}; use g3_dpi::Protocol; use g3_io_ext::{AsyncStream, OnceBufReader}; use g3_openssl::{SslConnector, SslLazyAcceptor}; -use g3_slog_types::{LtUpstreamAddr, LtUuid}; +use g3_slog_types::{LtUpstreamAddr, LtUuid, LtX509VerifyResult}; use g3_types::net::{Host, TlsCertUsage, TlsServiceType, UpstreamAddr}; use g3_udpdump::ExportedPduDissectorHint; @@ -51,6 +52,7 @@ macro_rules! intercept_log { "depth" => $obj.ctx.inspection_depth, "upstream" => LtUpstreamAddr(&$obj.upstream), "protocol" => Protocol::from($obj.protocol).as_str(), + "tls_server_verify" => $obj.server_verify_result.map(LtX509VerifyResult), ) }; } @@ -93,6 +95,7 @@ pub(crate) struct StartTlsInterceptObject { upstream: UpstreamAddr, tls_interception: TlsInterceptionContext, protocol: StartTlsProtocol, + server_verify_result: Option, } impl StartTlsInterceptObject @@ -111,6 +114,7 @@ where upstream, tls_interception: tls, protocol, + server_verify_result: None, } } @@ -226,6 +230,7 @@ where let upstream_cert = ups_tls_stream.ssl().peer_certificate().ok_or_else(|| { TlsInterceptionError::NoFakeCertGenerated(anyhow!("failed to get upstream certificate")) })?; + self.server_verify_result = Some(ups_tls_stream.ssl().verify_result()); let cert_domain = sni_hostname .map(|v| v.to_string()) .unwrap_or_else(|| self.upstream.host().to_string()); diff --git a/g3proxy/src/inspect/tls/mod.rs b/g3proxy/src/inspect/tls/mod.rs index eb1bf5165..ffedbed39 100644 --- a/g3proxy/src/inspect/tls/mod.rs +++ b/g3proxy/src/inspect/tls/mod.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use anyhow::anyhow; +use openssl::x509::X509VerifyResult; use slog::slog_info; use tokio::io::{AsyncRead, AsyncWrite}; use tokio::runtime::Handle; @@ -24,7 +25,7 @@ use tokio::runtime::Handle; use g3_cert_agent::CertAgentHandle; use g3_dpi::Protocol; use g3_io_ext::{AsyncStream, FlexBufReader, OnceBufReader}; -use g3_slog_types::{LtUpstreamAddr, LtUuid}; +use g3_slog_types::{LtUpstreamAddr, LtUuid, LtX509VerifyResult}; use g3_types::net::{ AlpnProtocol, OpensslInterceptionClientConfig, OpensslInterceptionServerConfig, UpstreamAddr, }; @@ -114,16 +115,17 @@ pub(crate) struct TlsInterceptObject { ctx: StreamInspectContext, upstream: UpstreamAddr, tls_interception: TlsInterceptionContext, + server_verify_result: Option, } macro_rules! intercept_log { ($obj:tt, $($args:tt)+) => { slog_info!($obj.ctx.intercept_logger(), $($args)+; "intercept_type" => "TlsHandshake", - "tls_server_verify" => !$obj.tls_interception.client_config.insecure, "task_id" => LtUuid($obj.ctx.server_task_id()), "depth" => $obj.ctx.inspection_depth, "upstream" => LtUpstreamAddr(&$obj.upstream), + "tls_server_verify" => $obj.server_verify_result.map(LtX509VerifyResult), ) }; } @@ -139,6 +141,7 @@ impl TlsInterceptObject { ctx, upstream, tls_interception: tls, + server_verify_result: None, } } diff --git a/g3proxy/src/inspect/tls/modern.rs b/g3proxy/src/inspect/tls/modern.rs index adcb52e79..8f751d3f3 100644 --- a/g3proxy/src/inspect/tls/modern.rs +++ b/g3proxy/src/inspect/tls/modern.rs @@ -184,6 +184,7 @@ where })? } }; + self.server_verify_result = Some(ups_tls_stream.ssl().verify_result()); // set certificate and private key let clt_ssl = lazy_acceptor.ssl_mut(); diff --git a/g3proxy/src/inspect/tls/tlcp.rs b/g3proxy/src/inspect/tls/tlcp.rs index 850b04db5..e133cb2e1 100644 --- a/g3proxy/src/inspect/tls/tlcp.rs +++ b/g3proxy/src/inspect/tls/tlcp.rs @@ -198,6 +198,7 @@ where })? } }; + self.server_verify_result = Some(ups_tls_stream.ssl().verify_result()); let enc_pre_fetch_pair = enc_pre_fetch_handle.await.map_err(|e| { TlsInterceptionError::NoFakeCertGenerated(anyhow!( diff --git a/lib/g3-slog-types/Cargo.toml b/lib/g3-slog-types/Cargo.toml index 6bc1e6f7f..c5e7c1e90 100644 --- a/lib/g3-slog-types/Cargo.toml +++ b/lib/g3-slog-types/Cargo.toml @@ -13,7 +13,10 @@ uuid.workspace = true memchr = { workspace = true, optional = true } http = { workspace = true, optional = true } h2 = { workspace = true, optional = true } +openssl = { workspace = true, optional = true } g3-types.workspace = true [features] +default = [] http = ["dep:memchr", "dep:http", "dep:h2"] +openssl = ["dep:openssl"] diff --git a/lib/g3-slog-types/src/lib.rs b/lib/g3-slog-types/src/lib.rs index df07c75b5..76d991b38 100644 --- a/lib/g3-slog-types/src/lib.rs +++ b/lib/g3-slog-types/src/lib.rs @@ -30,3 +30,8 @@ pub use self::uuid::LtUuid; mod http; #[cfg(feature = "http")] pub use self::http::{LtH2StreamId, LtHttpHeaderValue, LtHttpMethod, LtHttpUri}; + +#[cfg(feature = "openssl")] +mod openssl; +#[cfg(feature = "openssl")] +pub use self::openssl::LtX509VerifyResult; diff --git a/lib/g3-slog-types/src/openssl.rs b/lib/g3-slog-types/src/openssl.rs new file mode 100644 index 000000000..d04abd8a2 --- /dev/null +++ b/lib/g3-slog-types/src/openssl.rs @@ -0,0 +1,31 @@ +/* + * Copyright 2024 ByteDance and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use openssl::x509::X509VerifyResult; +use slog::{Record, Serializer, Value}; + +pub struct LtX509VerifyResult(pub X509VerifyResult); + +impl Value for LtX509VerifyResult { + fn serialize( + &self, + _record: &Record, + key: slog::Key, + serializer: &mut dyn Serializer, + ) -> slog::Result { + serializer.emit_str(key, self.0.error_string()) + } +}