add tlcp support via vendored-tongsuo feature (#121)

* add support for TLCP protocol via tongsuo

* g3keymess: add vendored-tongsuo feature

* update check scripts

* update to tokio-tongsuo 0.6.4 to get rid of default features
This commit is contained in:
Zhang Jingqiang 2023-08-28 13:04:56 +08:00 committed by GitHub
parent ae25182eba
commit 44b4ef2322
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 829 additions and 109 deletions

124
Cargo.lock generated
View file

@ -853,7 +853,7 @@ dependencies = [
"slog",
"thiserror",
"tokio",
"tokio-openssl",
"tokio-tongsuo",
]
[[package]]
@ -972,12 +972,12 @@ dependencies = [
"humanize-rs",
"idna",
"ip_network",
"openssl",
"rand",
"regex",
"rustls",
"rustls-pemfile",
"serde_json",
"tongsuo",
]
[[package]]
@ -1120,11 +1120,11 @@ dependencies = [
"g3-types",
"libc",
"log",
"openssl",
"openssl-sys",
"rmpv",
"rustls",
"tokio",
"tongsuo",
"tongsuo-sys",
]
[[package]]
@ -1153,7 +1153,6 @@ dependencies = [
"metrohash",
"num-traits",
"once_cell",
"openssl",
"percent-encoding",
"radix_trie",
"rand",
@ -1167,6 +1166,7 @@ dependencies = [
"slog",
"smallvec",
"thiserror",
"tongsuo",
"url",
"webpki-roots",
]
@ -1203,11 +1203,11 @@ dependencies = [
"humanize-rs",
"idna",
"ip_network",
"openssl",
"rand",
"regex",
"rustls",
"rustls-pemfile",
"tongsuo",
"url",
"yaml-rust",
]
@ -1242,7 +1242,6 @@ dependencies = [
"hex",
"http",
"indicatif",
"openssl",
"openssl-async-job",
"openssl-probe",
"quinn",
@ -1252,7 +1251,8 @@ dependencies = [
"rustls-pemfile",
"thiserror",
"tokio",
"tokio-openssl",
"tokio-tongsuo",
"tongsuo",
"trust-dns-client",
"trust-dns-proto",
"url",
@ -1274,11 +1274,11 @@ dependencies = [
"g3-yaml",
"log",
"memchr",
"openssl",
"openssl-probe",
"rmpv",
"rustc_version",
"tokio",
"tongsuo",
"yaml-rust",
]
@ -1312,7 +1312,6 @@ dependencies = [
"itoa",
"log",
"once_cell",
"openssl",
"openssl-async-job",
"openssl-probe",
"rustc_version",
@ -1320,6 +1319,7 @@ dependencies = [
"slog",
"thiserror",
"tokio",
"tongsuo",
"url",
"uuid",
"yaml-rust",
@ -1359,9 +1359,9 @@ dependencies = [
"clap_complete",
"g3-tls-cert",
"g3-types",
"openssl",
"openssl-probe",
"rustc_version",
"tongsuo",
]
[[package]]
@ -1418,7 +1418,6 @@ dependencies = [
"mlua",
"nix 0.27.0",
"once_cell",
"openssl",
"openssl-probe",
"percent-encoding",
"pin-project",
@ -1433,9 +1432,10 @@ dependencies = [
"slog",
"thiserror",
"tokio",
"tokio-openssl",
"tokio-rustls",
"tokio-tongsuo",
"tokio-util",
"tongsuo",
"url",
"uuid",
"yaml-rust",
@ -1522,7 +1522,6 @@ dependencies = [
"itoa",
"log",
"once_cell",
"openssl",
"openssl-probe",
"rand",
"rustc_version",
@ -1530,8 +1529,9 @@ dependencies = [
"slog",
"thiserror",
"tokio",
"tokio-openssl",
"tokio-rustls",
"tokio-tongsuo",
"tongsuo",
"uuid",
"yaml-rust",
]
@ -2162,21 +2162,6 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl"
version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
dependencies = [
"bitflags 2.4.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-async-job"
version = "0.1.0"
@ -2184,10 +2169,10 @@ dependencies = [
"anyhow",
"foreign-types",
"libc",
"openssl",
"openssl-sys",
"thiserror",
"tokio",
"tongsuo",
"tongsuo-sys",
]
[[package]]
@ -2216,19 +2201,6 @@ dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b"
dependencies = [
"cc",
"libc",
"openssl-src",
"pkg-config",
"vcpkg",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -3015,18 +2987,6 @@ dependencies = [
"syn 2.0.29",
]
[[package]]
name = "tokio-openssl"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a"
dependencies = [
"futures-util",
"openssl",
"openssl-sys",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.24.1"
@ -3048,6 +3008,18 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-tongsuo"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "351402c10b415b4a2cad8821bf1ecf28c8d603683b5724c4f23c154aa1f3ed5f"
dependencies = [
"futures-util",
"tokio",
"tongsuo",
"tongsuo-sys",
]
[[package]]
name = "tokio-util"
version = "0.7.8"
@ -3070,6 +3042,44 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4"
[[package]]
name = "tongsuo"
version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747f21ace9f4a49d36bf60cbf62d1db59f621817aa731f1624f4b30326d6a0ad"
dependencies = [
"bitflags 2.4.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"tongsuo-sys",
]
[[package]]
name = "tongsuo-src"
version = "840.0.2+8.4.0pre2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e0b51274068c147b89e1d2b1ca4e0e03adb4bb003952faab27b5b21fc1d138d"
dependencies = [
"cc",
]
[[package]]
name = "tongsuo-sys"
version = "0.9.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc04b6b1b96ab43294513c6a076cb3f20fde6a5d67a9bf7491fce53cb44d381"
dependencies = [
"cc",
"libc",
"openssl-src",
"pkg-config",
"tongsuo-src",
"vcpkg",
]
[[package]]
name = "tracing"
version = "0.1.37"

View file

@ -128,10 +128,10 @@ pin-project = "1.1"
#
rustls = "0.21.5"
tokio-rustls = "0.24"
tokio-openssl = "0.6"
openssl = "0.10.55"
tokio-openssl = { package = "tokio-tongsuo", version = "0.6.4", default-features = false }
openssl = { package = "tongsuo", version = "0.10.55", default-features = false }
openssl-sys = { package = "tongsuo-sys", version = "0.9" }
openssl-probe = "0.1"
openssl-sys = "0.9"
foreign-types = "0.3"
rustls-pemfile = "1.0"
rustls-native-certs = "0.6"

View file

@ -55,3 +55,4 @@ rustc_version.workspace = true
[features]
default = []
vendored-openssl = ["openssl/vendored", "dep:openssl-probe"]
vendored-tongsuo = ["openssl/tongsuo", "dep:openssl-probe", "g3-types/vendored-tongsuo"]

View file

@ -47,7 +47,7 @@ fn build_cli_args() -> Command {
}
fn main() -> anyhow::Result<()> {
#[cfg(feature = "vendored-openssl")]
#[cfg(any(feature = "vendored-openssl", feature = "vendored-tongsuo"))]
openssl_probe::init_ssl_cert_env_vars();
openssl::init();

View file

@ -50,7 +50,10 @@ const PROXY_TLS_ARG_PROTOCOL: &str = "proxy-tls-protocol";
const PROXY_TLS_ARG_CIPHERS: &str = "proxy-tls-ciphers";
const SESSION_CACHE_VALUES: [&str; 2] = ["off", "builtin"];
#[cfg(not(feature = "vendored-tongsuo"))]
const PROTOCOL_VALUES: [&str; 5] = ["ssl3.0", "tls1.0", "tls1.1", "tls1.2", "tls1.3"];
#[cfg(feature = "vendored-tongsuo")]
const PROTOCOL_VALUES: [&str; 6] = ["ssl3.0", "tls1.0", "tls1.1", "tls1.2", "tls1.3", "tlcp"];
pub(crate) trait AppendOpensslArgs {
fn append_openssl_args(self) -> Self;

View file

@ -33,3 +33,4 @@ rustc_version.workspace = true
[features]
default = []
vendored-openssl = ["openssl/vendored", "dep:openssl-probe"]
vendored-tongsuo = ["openssl/tongsuo", "dep:openssl-probe"]

View file

@ -25,7 +25,7 @@ use log::{debug, error, info};
use g3fcgen::opts::ProcArgs;
fn main() -> anyhow::Result<()> {
#[cfg(feature = "vendored-openssl")]
#[cfg(any(feature = "vendored-openssl", feature = "vendored-tongsuo"))]
openssl_probe::init_ssl_cert_env_vars();
openssl::init();

View file

@ -54,3 +54,4 @@ rustc_version.workspace = true
[features]
default = []
vendored-openssl = ["openssl/vendored", "dep:openssl-probe"]
vendored-tongsuo = ["openssl/tongsuo", "dep:openssl-probe"]

View file

@ -25,7 +25,7 @@ use log::{debug, error, info, warn};
use g3keymess::opts::ProcArgs;
fn main() -> anyhow::Result<()> {
#[cfg(feature = "vendored-openssl")]
#[cfg(any(feature = "vendored-openssl", feature = "vendored-tongsuo"))]
openssl_probe::init_ssl_cert_env_vars();
openssl::init();

View file

@ -21,3 +21,4 @@ rustc_version.workspace = true
[features]
default = []
vendored-openssl = ["openssl/vendored", "dep:openssl-probe"]
vendored-tongsuo = ["openssl/tongsuo", "dep:openssl-probe"]

View file

@ -77,7 +77,7 @@ const ARG_GROUP_TYPE: &str = "type";
const ARG_GROUP_ALGORITHM: &str = "algorithm";
fn main() -> anyhow::Result<()> {
#[cfg(feature = "vendored-openssl")]
#[cfg(any(feature = "vendored-openssl", feature = "vendored-tongsuo"))]
openssl_probe::init_ssl_cert_env_vars();
openssl::init();

View file

@ -97,3 +97,4 @@ lua54 = ["lua", "mlua/lua54"]
python = ["pyo3"]
c-ares = ["g3-resolver/c-ares"]
vendored-openssl = ["openssl/vendored", "dep:openssl-probe"]
vendored-tongsuo = ["openssl/tongsuo", "dep:openssl-probe"]

View file

@ -25,7 +25,7 @@ use log::{debug, error, info};
use g3proxy::opts::ProcArgs;
fn main() -> anyhow::Result<()> {
#[cfg(feature = "vendored-openssl")]
#[cfg(any(feature = "vendored-openssl", feature = "vendored-tongsuo"))]
openssl_probe::init_ssl_cert_env_vars();
openssl::init();

View file

@ -53,3 +53,4 @@ rustc_version.workspace = true
[features]
default = []
vendored-openssl = ["openssl/vendored", "dep:openssl-probe"]
vendored-tongsuo = ["openssl/tongsuo", "dep:openssl-probe", "g3-yaml/vendored-tongsuo", "g3-types/vendored-tongsuo"]

View file

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgh7HdqMuQ301ewJ9r
zYYk0xiKtszo53RuPt51JduKNPShRANCAARkOiNPfyCvFGlnEwA2rp9UE9wbrlbn
PNSuBdZGbC4JS8I+NI9JdC+hAFdzmq/PJ5TvCPQd/+vCf0YWq/8lUAVv
-----END PRIVATE KEY-----

View file

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB4DCCAYagAwIBAgIBATAKBggqgRzPVQGDdTBGMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEQMA4GA1UEAwwHcm9v
dCBjYTAeFw0yMzAxMzAwMzE1MTJaFw0zMzAxMjcwMzE1MTJaMEUxCzAJBgNVBAYT
AkFBMQswCQYDVQQIDAJCQjELMAkGA1UECgwCQ0MxCzAJBgNVBAsMAkREMQ8wDQYD
VQQDDAZzdWIgY2EwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAARkOiNPfyCvFGln
EwA2rp9UE9wbrlbnPNSuBdZGbC4JS8I+NI9JdC+hAFdzmq/PJ5TvCPQd/+vCf0YW
q/8lUAVvo2YwZDAdBgNVHQ4EFgQUPR1l+yVWk8vZuQ3zpqUXhx9BrJMwHwYDVR0j
BBgwFoAUnLgA0gvvsSIpG7fB/NOlJP0LSj4wEgYDVR0TAQH/BAgwBgEB/wIBADAO
BgNVHQ8BAf8EBAMCAYYwCgYIKoEcz1UBg3UDSAAwRQIgYobetL2OZ0jDKGp1VEVS
DzwQO3/h37fjoZ/MdMxos4oCIQDWRC+7991r3WEl95kr3BifeAPNOO93FDikDdIb
oVcEMQ==
-----END CERTIFICATE-----

View file

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQguneE5EONZmGDo5sq
Cm2QiOMi0uzVgxHyHF1FNoL/DWyhRANCAASSoOJmotVNJ+LYNNqrADfwDJNILbQh
R0wIiCTMZLCnfAJOC/4T82t6tXR0cUVXt8IsClgfCHGiDNZRhhz1hTY5
-----END PRIVATE KEY-----

View file

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB3jCCAYSgAwIBAgIBADAKBggqgRzPVQGDdTBGMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEQMA4GA1UEAwwHcm9v
dCBjYTAeFw0yMzAxMzAwMzE1MTJaFw0zMzAxMjcwMzE1MTJaMEYxCzAJBgNVBAYT
AkFBMQswCQYDVQQIDAJCQjELMAkGA1UECgwCQ0MxCzAJBgNVBAsMAkREMRAwDgYD
VQQDDAdyb290IGNhMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEkqDiZqLVTSfi
2DTaqwA38AyTSC20IUdMCIgkzGSwp3wCTgv+E/NrerV0dHFFV7fCLApYHwhxogzW
UYYc9YU2OaNjMGEwHQYDVR0OBBYEFJy4ANIL77EiKRu3wfzTpST9C0o+MB8GA1Ud
IwQYMBaAFJy4ANIL77EiKRu3wfzTpST9C0o+MA8GA1UdEwEB/wQFMAMBAf8wDgYD
VR0PAQH/BAQDAgGGMAoGCCqBHM9VAYN1A0gAMEUCIQDrC1vOKKS+nIGTwIJTqeU6
LiadD/XmCdfKl68P3EnxuAIgKk3HWkgDP0WRnzTeBMQ0vE/f62T5GXQnog/R7wDi
X2c=
-----END CERTIFICATE-----

View file

@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIB9TCCAZqgAwIBAgIBAzAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEPMA0GA1UEAwwGc3Vi
IGNhMB4XDTIzMDEzMDAzMTUxMloXDTMzMDEyNzAzMTUxMlowSTELMAkGA1UEBhMC
QUExCzAJBgNVBAgMAkJCMQswCQYDVQQKDAJDQzELMAkGA1UECwwCREQxEzARBgNV
BAMMCnNlcnZlciBlbmMwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAASLlDwDZnE1
08andQYmPaNXE0mfpuxB5oZ7ztN8Jj5Yi1/qxll5uW+tdWopaEQ4odbXWHtYCyWe
v991flfpUwhFo3cwdTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDODAbBgNVHREEFDAS
ghB0ZXN0LmV4YW1wbGUuY29tMB0GA1UdDgQWBBRWd13eKqJlzdm9qDyu/lXFbscQ
MjAfBgNVHSMEGDAWgBQ9HWX7JVaTy9m5DfOmpReHH0GskzAKBggqgRzPVQGDdQNJ
ADBGAiEA6OEOKGAR0DAqxpQeTRotWPDtsFzU0PKL9XhJQ9boPUMCIQCywipeNzlc
9yXg4lq7eTPcpOPjwDOCpf4BmARWJ1pZ/w==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB4DCCAYagAwIBAgIBATAKBggqgRzPVQGDdTBGMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEQMA4GA1UEAwwHcm9v
dCBjYTAeFw0yMzAxMzAwMzE1MTJaFw0zMzAxMjcwMzE1MTJaMEUxCzAJBgNVBAYT
AkFBMQswCQYDVQQIDAJCQjELMAkGA1UECgwCQ0MxCzAJBgNVBAsMAkREMQ8wDQYD
VQQDDAZzdWIgY2EwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAARkOiNPfyCvFGln
EwA2rp9UE9wbrlbnPNSuBdZGbC4JS8I+NI9JdC+hAFdzmq/PJ5TvCPQd/+vCf0YW
q/8lUAVvo2YwZDAdBgNVHQ4EFgQUPR1l+yVWk8vZuQ3zpqUXhx9BrJMwHwYDVR0j
BBgwFoAUnLgA0gvvsSIpG7fB/NOlJP0LSj4wEgYDVR0TAQH/BAgwBgEB/wIBADAO
BgNVHQ8BAf8EBAMCAYYwCgYIKoEcz1UBg3UDSAAwRQIgYobetL2OZ0jDKGp1VEVS
DzwQO3/h37fjoZ/MdMxos4oCIQDWRC+7991r3WEl95kr3BifeAPNOO93FDikDdIb
oVcEMQ==
-----END CERTIFICATE-----

View file

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg4wL356VqZnGqEU5Z
n8O6n993fHtBtgIG3jPjN52eV0uhRANCAASLlDwDZnE108andQYmPaNXE0mfpuxB
5oZ7ztN8Jj5Yi1/qxll5uW+tdWopaEQ4odbXWHtYCyWev991flfpUwhF
-----END PRIVATE KEY-----

View file

@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIB9TCCAZugAwIBAgIBAjAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEPMA0GA1UEAwwGc3Vi
IGNhMB4XDTIzMDEzMDAzMTUxMloXDTMzMDEyNzAzMTUxMlowSjELMAkGA1UEBhMC
QUExCzAJBgNVBAgMAkJCMQswCQYDVQQKDAJDQzELMAkGA1UECwwCREQxFDASBgNV
BAMMC3NlcnZlciBzaWduMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEpD3WWLMN
Isla//cCE4/1pG2EDfFHVMSOyvto6Tztmp2jHK1zhPAviBKNps9zzdhM6454ndKw
my2CRXw8BZn5naN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBsAwGwYDVR0RBBQw
EoIQdGVzdC5leGFtcGxlLmNvbTAdBgNVHQ4EFgQU2MdNhtPFlmIe6x7kTQGDgUfJ
dMowHwYDVR0jBBgwFoAUPR1l+yVWk8vZuQ3zpqUXhx9BrJMwCgYIKoEcz1UBg3UD
SAAwRQIhAK5AFAB8s0FoAtrbaNmOd9D1N17cyUvYtdd8YxJNFpVhAiBYexsuKNvE
7uOK4C7v1BcXXxR3549hrQs+LbiPQQT+DA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB4DCCAYagAwIBAgIBATAKBggqgRzPVQGDdTBGMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEQMA4GA1UEAwwHcm9v
dCBjYTAeFw0yMzAxMzAwMzE1MTJaFw0zMzAxMjcwMzE1MTJaMEUxCzAJBgNVBAYT
AkFBMQswCQYDVQQIDAJCQjELMAkGA1UECgwCQ0MxCzAJBgNVBAsMAkREMQ8wDQYD
VQQDDAZzdWIgY2EwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAARkOiNPfyCvFGln
EwA2rp9UE9wbrlbnPNSuBdZGbC4JS8I+NI9JdC+hAFdzmq/PJ5TvCPQd/+vCf0YW
q/8lUAVvo2YwZDAdBgNVHQ4EFgQUPR1l+yVWk8vZuQ3zpqUXhx9BrJMwHwYDVR0j
BBgwFoAUnLgA0gvvsSIpG7fB/NOlJP0LSj4wEgYDVR0TAQH/BAgwBgEB/wIBADAO
BgNVHQ8BAf8EBAMCAYYwCgYIKoEcz1UBg3UDSAAwRQIgYobetL2OZ0jDKGp1VEVS
DzwQO3/h37fjoZ/MdMxos4oCIQDWRC+7991r3WEl95kr3BifeAPNOO93FDikDdIb
oVcEMQ==
-----END CERTIFICATE-----

View file

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg5dHcykCfsMbZq31l
LYbm1GxsGQGy/6evQpZTp0Q3ucWhRANCAASkPdZYsw0iyVr/9wITj/WkbYQN8UdU
xI7K+2jpPO2anaMcrXOE8C+IEo2mz3PN2Ezrjnid0rCbLYJFfDwFmfmd
-----END PRIVATE KEY-----

View file

@ -29,12 +29,17 @@ use g3_types::net::{OpensslCertificatePair, TcpSockSpeedLimitConfig};
use g3_types::route::AlpnMatch;
use g3_yaml::{YamlDocPosition, YamlMapCallback};
#[cfg(feature = "vendored-tongsuo")]
use g3_types::net::OpensslTlcpCertificatePair;
use super::OpensslServiceConfig;
#[derive(Clone, Debug, Default, PartialEq)]
pub(crate) struct OpensslHostConfig {
name: String,
cert_pairs: Vec<OpensslCertificatePair>,
#[cfg(feature = "vendored-tongsuo")]
tlcp_cert_pairs: Vec<OpensslTlcpCertificatePair>,
client_auth: bool,
client_auth_certs: Vec<Vec<u8>>,
pub(crate) request_alive_max: Option<usize>,
@ -68,7 +73,11 @@ impl OpensslHostConfig {
Ok(())
}
pub(crate) fn build_ssl_context(&self) -> anyhow::Result<SslContext> {
pub(crate) fn build_ssl_context(&self) -> anyhow::Result<Option<SslContext>> {
if self.cert_pairs.is_empty() {
return Ok(None);
}
let mut ssl_builder = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls_server())
.map_err(|e| anyhow!("failed to build ssl context: {e}"))?;
@ -140,7 +149,94 @@ impl OpensslHostConfig {
let ssl_acceptor = ssl_builder.build();
Ok(ssl_acceptor.into_context())
Ok(Some(ssl_acceptor.into_context()))
}
#[cfg(feature = "vendored-tongsuo")]
pub(crate) fn build_tlcp_context(&self) -> anyhow::Result<Option<SslContext>> {
use openssl::x509::X509Name;
if self.tlcp_cert_pairs.is_empty() {
return Ok(None);
}
let mut ssl_builder = SslAcceptor::mozilla_intermediate_v5(SslMethod::ntls_server())
.map_err(|e| anyhow!("failed to build ssl context: {e}"))?;
ssl_builder.enable_ntls();
ssl_builder.set_cipher_list(
"ECDHE-SM2-WITH-SM4-SM3:ECC-SM2-WITH-SM4-SM3:\
ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3:ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:\
IBSDH-SM9-SM4-CBC-SM3:IBSDH-SM9-SM4-GCM-SM3:IBC-SM9-SM4-CBC-SM3:IBC-SM9-SM4-GCM-SM3:\
RSA-SM4-CBC-SM3:RSA-SM4-GCM-SM3:RSA-SM4-CBC-SHA256:RSA-SM4-GCM-SHA256",
)?;
ssl_builder.set_session_cache_mode(SslSessionCacheMode::SERVER); // TODO use external cache?
if self.client_auth {
ssl_builder.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT);
let mut store_builder = X509StoreBuilder::new()
.map_err(|e| anyhow!("failed to create ca cert store builder: {e}"))?;
if self.client_auth_certs.is_empty() {
store_builder
.set_default_paths()
.map_err(|e| anyhow!("failed to load default ca certs: {e}"))?;
} else {
for (i, cert) in self.client_auth_certs.iter().enumerate() {
let ca_cert = X509::from_der(cert.as_slice()).unwrap();
store_builder
.add_cert(ca_cert)
.map_err(|e| anyhow!("failed to add ca certificate #{i}: {e}"))?;
}
}
let store = store_builder.build();
let mut ca_stack =
Stack::new().map_err(|e| anyhow!("failed to get new ca name stack: {e}"))?;
for (i, obj) in store.objects().iter().enumerate() {
if let Some(cert) = obj.x509() {
let der = cert
.subject_name()
.to_der()
.map_err(|e| anyhow!("[#{i}] failed to convert subject name: {e}"))?;
let name = X509Name::from_der(&der)
.map_err(|e| anyhow!("[#{i}] failed to convert back subject name: {e}"))?;
ca_stack
.push(name)
.map_err(|e| anyhow!("[#{i}] failed to push to ca name stack: {e}"))?;
}
}
ssl_builder.set_client_ca_list(ca_stack);
ssl_builder
.set_verify_cert_store(store)
.map_err(|e| anyhow!("failed to set ca certs: {e}"))?;
} else {
ssl_builder.set_verify(SslVerifyMode::NONE);
}
for (i, pair) in self.tlcp_cert_pairs.iter().enumerate() {
pair.add_to_ssl_context(&mut ssl_builder)
.context(format!("failed to add tlcp cert pair #{i} to ssl context"))?;
}
if !self.services.is_empty() {
let mut buf = Vec::with_capacity(32);
self.services.protocols().iter().for_each(|p| {
if let Ok(len) = u8::try_from(p.len()) {
buf.push(len);
buf.extend_from_slice(p.as_bytes());
}
});
if !buf.is_empty() {
ssl_builder
.set_alpn_protos(buf.as_slice())
.map_err(|e| anyhow!("failed to set alpn protocols: {e}"))?;
}
}
Ok(Some(ssl_builder.build().into_context()))
}
}
@ -175,6 +271,28 @@ impl YamlMapCallback for OpensslHostConfig {
}
Ok(())
}
#[cfg(feature = "vendored-tongsuo")]
"tlcp_cert_pairs" => {
let lookup_dir = g3_daemon::config::get_lookup_dir(doc)?;
if let Yaml::Array(seq) = value {
for (i, v) in seq.iter().enumerate() {
let pair =
g3_yaml::value::as_openssl_tlcp_certificate_pair(v, Some(lookup_dir))
.context(format!(
"invalid openssl tlcp cert pair value for {key}#{i}"
))?;
self.tlcp_cert_pairs.push(pair);
}
} else {
let pair =
g3_yaml::value::as_openssl_tlcp_certificate_pair(value, Some(lookup_dir))
.context(format!(
"invalid openssl tlcp cert pair value for key {key}"
))?;
self.tlcp_cert_pairs.push(pair);
}
Ok(())
}
"enable_client_auth" => {
self.client_auth = g3_yaml::value::as_bool(value)
.context(format!("invalid value for key {key}"))?;
@ -224,9 +342,14 @@ impl YamlMapCallback for OpensslHostConfig {
if self.name.is_empty() {
return Err(anyhow!("no name set"));
}
#[cfg(not(feature = "vendored-tongsuo"))]
if self.cert_pairs.is_empty() {
return Err(anyhow!("no certificate set"));
}
#[cfg(feature = "vendored-tongsuo")]
if self.cert_pairs.is_empty() && self.tlcp_cert_pairs.is_empty() {
return Err(anyhow!("neither tls nor tlcp certificate set"));
}
if self.services.is_empty() {
return Err(anyhow!("no backend service set"));
}

View file

@ -25,7 +25,7 @@ use log::{debug, error, info};
use g3tiles::opts::ProcArgs;
fn main() -> anyhow::Result<()> {
#[cfg(feature = "vendored-openssl")]
#[cfg(any(feature = "vendored-openssl", feature = "vendored-tongsuo"))]
openssl_probe::init_ssl_cert_env_vars();
openssl::init();

View file

@ -65,7 +65,11 @@ pub(super) fn build_ssl_acceptor(
return Err(sni_err);
};
if let Err(e) = ssl.set_ssl_context(&host.ssl_context) {
let Some(ssl_context) = &host.ssl_context else {
return Err(sni_err);
};
if let Err(e) = ssl.set_ssl_context(ssl_context) {
debug!("failed to set ssl context for host: {e}"); // TODO print host name
Err(sni_err)
} else {
@ -99,9 +103,84 @@ pub(super) fn build_ssl_acceptor(
Ok(builder.build())
}
#[cfg(feature = "vendored-tongsuo")]
pub(super) fn build_tlcp_context(
hosts: Arc<HostMatch<Arc<OpensslHost>>>,
host_index: Index<Ssl, Arc<OpensslHost>>,
sema_index: Index<Ssl, Option<GaugeSemaphorePermit>>,
alert_unrecognized_name: bool,
) -> anyhow::Result<SslContext> {
let mut builder = SslAcceptor::mozilla_intermediate_v5(SslMethod::ntls_server())
.map_err(|e| anyhow!("failed to get ssl context builder: {e}"))?;
builder.enable_force_ntls();
builder.set_cipher_list(
"ECDHE-SM2-WITH-SM4-SM3:ECC-SM2-WITH-SM4-SM3:\
ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3:ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:\
IBSDH-SM9-SM4-CBC-SM3:IBSDH-SM9-SM4-GCM-SM3:IBC-SM9-SM4-CBC-SM3:IBC-SM9-SM4-GCM-SM3:\
RSA-SM4-CBC-SM3:RSA-SM4-GCM-SM3:RSA-SM4-CBC-SHA256:RSA-SM4-GCM-SHA256",
)?;
builder.set_servername_callback(move |ssl, alert| {
let sni_err = if alert_unrecognized_name {
*alert = SslAlert::UNRECOGNIZED_NAME;
SniError::ALERT_FATAL
} else {
SniError::NOACK
};
let set_host_context = |ssl: &mut SslRef, host: &Arc<OpensslHost>| {
if host.check_rate_limit().is_err() {
return Err(sni_err);
}
// we do not check request alive sema here
let Ok(sema) = host.acquire_request_semaphore() else {
return Err(sni_err);
};
let Some(ssl_context) = &host.tlcp_context else {
return Err(sni_err);
};
if let Err(e) = ssl.set_ssl_context(ssl_context) {
debug!("failed to set tlcp ssl context for host: {e}"); // TODO print host name
Err(sni_err)
} else {
ssl.set_ex_data(host_index, host.clone());
ssl.set_ex_data(sema_index, sema);
Ok(())
}
};
if let Some(sni) = ssl.servername(NameType::HOST_NAME) {
match Host::from_str(sni) {
Ok(name) => {
if let Some(host) = hosts.get(&name) {
return set_host_context(ssl, host);
}
}
Err(e) => {
debug!("invalid sni hostname: {e:?}");
return Err(sni_err);
}
}
}
if let Some(host) = hosts.get_default() {
set_host_context(ssl, host)
} else {
Err(sni_err)
}
});
Ok(builder.build().into_context())
}
pub(crate) struct OpensslHost {
pub(super) config: Arc<OpensslHostConfig>,
ssl_context: SslContext,
ssl_context: Option<SslContext>,
#[cfg(feature = "vendored-tongsuo")]
tlcp_context: Option<SslContext>,
req_alive_sem: Option<GaugeSemaphore>,
request_rate_limit: Option<Arc<RateLimiter<NotKeyed, InMemoryState, DefaultClock>>>,
pub(crate) services: AlpnMatch<Arc<OpensslService>>,
@ -118,6 +197,8 @@ impl TryFrom<&Arc<OpensslHostConfig>> for OpensslHost {
impl OpensslHost {
pub(super) fn build_new(config: Arc<OpensslHostConfig>) -> anyhow::Result<Self> {
let ssl_context = config.build_ssl_context()?;
#[cfg(feature = "vendored-tongsuo")]
let tlcp_context = config.build_tlcp_context()?;
let services = (&config.services).try_into()?;
@ -130,6 +211,8 @@ impl OpensslHost {
Ok(OpensslHost {
config,
ssl_context,
#[cfg(feature = "vendored-tongsuo")]
tlcp_context,
req_alive_sem,
request_rate_limit,
services,
@ -138,6 +221,8 @@ impl OpensslHost {
pub(super) fn new_for_reload(&self, config: Arc<OpensslHostConfig>) -> anyhow::Result<Self> {
let ssl_context = config.build_ssl_context()?;
#[cfg(feature = "vendored-tongsuo")]
let tlcp_context = config.build_tlcp_context()?;
let services = (&config.services).try_into()?;
@ -173,6 +258,8 @@ impl OpensslHost {
Ok(OpensslHost {
config,
ssl_context,
#[cfg(feature = "vendored-tongsuo")]
tlcp_context,
req_alive_sem,
request_rate_limit,
services,

View file

@ -51,6 +51,8 @@ pub(crate) struct OpensslProxyServer {
hosts: Arc<HostMatch<Arc<OpensslHost>>>,
host_index: Index<Ssl, Arc<OpensslHost>>,
ssl_accept_context: SslContext,
#[cfg(feature = "vendored-tongsuo")]
tlcp_accept_context: SslContext,
quit_policy: Arc<ServerQuitPolicy>,
reload_version: usize,
@ -80,6 +82,14 @@ impl OpensslProxyServer {
let _ = Ssl::new(&ssl_accept_context)
.map_err(|e| anyhow!("unable build ssl context for real connections: {e}"))?;
#[cfg(feature = "vendored-tongsuo")]
let tlcp_accept_context = super::host::build_tlcp_context(
hosts.clone(),
host_index,
sema_index,
config.alert_unrecognized_name,
)?;
let ingress_net_filter = config
.ingress_net_filter
.as_ref()
@ -100,6 +110,8 @@ impl OpensslProxyServer {
hosts,
host_index,
ssl_accept_context,
#[cfg(feature = "vendored-tongsuo")]
tlcp_accept_context,
quit_policy: Arc::new(ServerQuitPolicy::default()),
reload_version: version,
})
@ -174,12 +186,56 @@ impl OpensslProxyServer {
false
}
#[cfg(feature = "vendored-tongsuo")]
async fn build_ssl(&self, stream: &TcpStream) -> Result<Ssl, ()> {
let mut buf = [0u8; 3];
let ssl =
match tokio::time::timeout(self.config.accept_timeout, stream.peek(&mut buf)).await {
Ok(Ok(3)) => {
if buf[0] != 0x16 {
// invalid data, may be attack
self.listen_stats.add_dropped();
return Err(());
}
if buf[1] == 0x01 && buf[2] == 0x01 {
Ssl::new(&self.tlcp_accept_context)
} else {
Ssl::new(&self.ssl_accept_context)
}
}
Ok(Ok(_n)) => {
// no enough data, may be attack
self.listen_stats.add_dropped();
return Err(());
}
Ok(Err(_e)) => {
// connection closed, may be attack
self.listen_stats.add_dropped();
return Err(());
}
Err(_) => {
// timeout, may be attack
self.listen_stats.add_dropped();
return Err(());
}
};
match ssl {
Ok(v) => Ok(v),
Err(e) => {
warn!("failed to build ssl context when accepting connections: {e}");
self.listen_stats.add_dropped();
Err(())
}
}
}
async fn run_task(
&self,
stream: TcpStream,
cc_info: ClientConnectionInfo,
_run_ctx: ServerRunContext,
) {
#[cfg(not(feature = "vendored-tongsuo"))]
let ssl = match Ssl::new(&self.ssl_accept_context) {
Ok(v) => v,
Err(e) => {
@ -187,6 +243,10 @@ impl OpensslProxyServer {
return;
}
};
#[cfg(feature = "vendored-tongsuo")]
let Ok(ssl) = self.build_ssl(&stream).await else {
return;
};
let ctx = CommonTaskContext {
server_config: Arc::clone(&self.config),

View file

@ -30,4 +30,5 @@ http = ["g3-types/http"]
proxy = ["g3-types/proxy"]
rustls = ["g3-types/rustls", "dep:rustls", "dep:rustls-pemfile"]
openssl = ["g3-types/openssl", "dep:openssl"]
vendored-tongsuo = ["openssl", "g3-types/vendored-tongsuo"]
route = ["g3-types/route"]

View file

@ -54,6 +54,8 @@ pub use self::rustls::{
#[cfg(feature = "openssl")]
mod openssl;
#[cfg(feature = "vendored-tongsuo")]
pub use self::openssl::as_openssl_tlcp_certificate_pair;
#[cfg(feature = "openssl")]
pub use self::openssl::{
as_openssl_certificate_pair, as_openssl_certificates, as_openssl_private_key,

View file

@ -23,6 +23,9 @@ use serde_json::Value;
use g3_types::net::{OpensslCertificatePair, OpensslProtocol, OpensslTlsClientConfigBuilder};
#[cfg(feature = "vendored-tongsuo")]
use g3_types::net::OpensslTlcpCertificatePair;
fn as_certificates_from_single_element(value: &Value) -> anyhow::Result<Vec<X509>> {
if let Value::String(s) = value {
let certs = X509::stack_from_pem(s.as_bytes())
@ -93,6 +96,52 @@ pub fn as_openssl_certificate_pair(value: &Value) -> anyhow::Result<OpensslCerti
}
}
#[cfg(feature = "vendored-tongsuo")]
pub fn as_openssl_tlcp_certificate_pair(
value: &Value,
) -> anyhow::Result<OpensslTlcpCertificatePair> {
if let Value::Object(map) = value {
let mut pair = OpensslTlcpCertificatePair::default();
for (k, v) in map {
match crate::key::normalize(k).as_str() {
"sign_certificate" | "sign_cert" => {
let cert = as_openssl_certificates(v)
.context(format!("invalid certificates value for key {k}"))?;
pair.set_sign_certificates(cert)
.context("failed to set sign certificate")?;
}
"enc_certificate" | "enc_cert" => {
let cert = as_openssl_certificates(v)
.context(format!("invalid certificates value for key {k}"))?;
pair.set_enc_certificates(cert)
.context("failed to set enc certificate")?;
}
"sign_private_key" | "sign_key" => {
let key = as_openssl_private_key(v)
.context(format!("invalid private key value for key {k}"))?;
pair.set_sign_private_key(key)
.context("failed to set private key")?;
}
"enc_private_key" | "enc_key" => {
let key = as_openssl_private_key(v)
.context(format!("invalid private key value for key {k}"))?;
pair.set_enc_private_key(key)
.context("failed to set private key")?;
}
_ => return Err(anyhow!("invalid key {k}")),
}
}
pair.check()?;
Ok(pair)
} else {
Err(anyhow!(
"yaml value type for 'openssl tlcp cert pair' should be 'map'"
))
}
}
fn as_openssl_protocol(value: &Value) -> anyhow::Result<OpensslProtocol> {
if let Value::String(s) = value {
OpensslProtocol::from_str(s)
@ -173,6 +222,12 @@ fn set_openssl_tls_client_config_builder(
.context(format!("invalid cert pair value for key {k}"))?;
builder.set_cert_pair(pair);
}
#[cfg(feature = "vendored-tongsuo")]
"tlcp_cert_pair" => {
let pair = as_openssl_tlcp_certificate_pair(v)
.context(format!("invalid tlcp certificate pair value for key {k}"))?;
builder.set_tlcp_cert_pair(pair);
}
"ca_certificate" | "ca_cert" | "server_auth_certificate" | "server_auth_cert" => {
let certs = as_openssl_certificates(v)
.context(format!("invalid certificates value for key {k}"))?;

View file

@ -53,6 +53,7 @@ auth-crypt = ["dep:digest", "dep:md-5", "dep:sha-1", "dep:blake3", "dep:hex"]
resolve = ["dep:ahash", "dep:radix_trie"]
rustls = ["dep:rustls", "dep:webpki-roots", "dep:rustls-pemfile", "dep:rustls-native-certs"]
openssl = ["dep:openssl", "dep:ahash", "dep:lru"]
vendored-tongsuo = ["openssl", "openssl/tongsuo"]
acl-rule = ["resolve", "dep:ahash", "dep:ip_network", "dep:ip_network_table", "dep:once_cell", "dep:regex", "dep:radix_trie", "proxy"]
http = ["dep:http", "dep:bytes", "dep:base64"]
proxy = ["http", "openssl"]

View file

@ -23,6 +23,11 @@ pub use tls_client::{
mod cert_pair;
pub use cert_pair::OpensslCertificatePair;
#[cfg(feature = "vendored-tongsuo")]
mod tlcp_cert_pair;
#[cfg(feature = "vendored-tongsuo")]
pub use tlcp_cert_pair::OpensslTlcpCertificatePair;
mod protocol;
pub use protocol::OpensslProtocol;

View file

@ -25,6 +25,8 @@ pub enum OpensslProtocol {
Tls11,
Tls12,
Tls13,
#[cfg(feature = "vendored-tongsuo")]
Tlcp11,
}
impl FromStr for OpensslProtocol {
@ -37,6 +39,8 @@ impl FromStr for OpensslProtocol {
"tls11" | "tls1.1" | "tls1_1" => Ok(OpensslProtocol::Tls11),
"tls12" | "tls1.2" | "tls1_2" => Ok(OpensslProtocol::Tls12),
"tls13" | "tls1.3" | "tls1_3" => Ok(OpensslProtocol::Tls13),
#[cfg(feature = "vendored-tongsuo")]
"tlcp" | "tlcp1.1" | "tlcp1_1" => Ok(OpensslProtocol::Tlcp11),
_ => Err(anyhow!("")),
}
}

View file

@ -0,0 +1,132 @@
/*
* Copyright 2023 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 anyhow::anyhow;
use openssl::pkey::{PKey, Private};
use openssl::ssl::SslContextBuilder;
use openssl::x509::X509;
#[derive(Default, Clone, Debug, Eq, PartialEq)]
pub struct OpensslTlcpCertificatePair {
enc_leaf_cert: Vec<u8>,
sign_leaf_cert: Vec<u8>,
chain_certs: Vec<Vec<u8>>,
enc_key: Vec<u8>,
sign_key: Vec<u8>,
}
impl OpensslTlcpCertificatePair {
pub fn check(&self) -> anyhow::Result<()> {
if self.sign_leaf_cert.is_empty() {
return Err(anyhow!("no sign certificate set"));
}
if self.enc_leaf_cert.is_empty() {
return Err(anyhow!("no enc certificate set"));
}
if self.enc_key.is_empty() {
return Err(anyhow!("no enc private key set"));
}
if self.sign_key.is_empty() {
return Err(anyhow!("no sign private key set"));
}
Ok(())
}
pub fn set_sign_certificates(&mut self, certs: Vec<X509>) -> anyhow::Result<()> {
let mut certs_iter = certs.into_iter();
let leaf_cert = certs_iter
.next()
.ok_or_else(|| anyhow!("no sign certificate found"))?;
let leaf_cert_der = leaf_cert
.to_der()
.map_err(|e| anyhow!("failed to encode sign certificate: {e}"))?;
self.sign_leaf_cert = leaf_cert_der;
for (i, cert) in certs_iter.enumerate() {
let bytes = cert
.to_der()
.map_err(|e| anyhow!("failed to encode chain certificate #{i}: {e}"))?;
self.chain_certs.push(bytes);
}
Ok(())
}
pub fn set_enc_certificates(&mut self, certs: Vec<X509>) -> anyhow::Result<()> {
let mut certs_iter = certs.into_iter();
let leaf_cert = certs_iter
.next()
.ok_or_else(|| anyhow!("no enc certificate found"))?;
let leaf_cert_der = leaf_cert
.to_der()
.map_err(|e| anyhow!("failed to encode enc certificate: {e}"))?;
self.enc_leaf_cert = leaf_cert_der;
for (i, cert) in certs_iter.enumerate() {
let bytes = cert
.to_der()
.map_err(|e| anyhow!("failed to encode chain certificate #{i}: {e}"))?;
self.chain_certs.push(bytes);
}
Ok(())
}
pub fn set_sign_private_key(&mut self, key: PKey<Private>) -> anyhow::Result<()> {
let key_der = key
.private_key_to_der()
.map_err(|e| anyhow!("failed to encode private key: {e}"))?;
self.sign_key = key_der;
Ok(())
}
pub fn set_enc_private_key(&mut self, key: PKey<Private>) -> anyhow::Result<()> {
let key_der = key
.private_key_to_der()
.map_err(|e| anyhow!("failed to encode private key: {e}"))?;
self.enc_key = key_der;
Ok(())
}
pub fn add_to_ssl_context(&self, ssl_builder: &mut SslContextBuilder) -> anyhow::Result<()> {
let leaf_cert = X509::from_der(self.sign_leaf_cert.as_slice()).unwrap();
ssl_builder
.set_sign_certificate(&leaf_cert)
.map_err(|e| anyhow!("failed to set sign certificate: {e}"))?;
let leaf_cert = X509::from_der(self.enc_leaf_cert.as_slice()).unwrap();
ssl_builder
.set_enc_certificate(&leaf_cert)
.map_err(|e| anyhow!("failed to set sign certificate: {e}"))?;
for (i, cert) in self.chain_certs.iter().enumerate() {
let chain_cert = X509::from_der(cert.as_slice()).unwrap();
ssl_builder
.add_extra_chain_cert(chain_cert)
.map_err(|e| anyhow!("failed to add chain certificate #{i}: {e}"))?;
}
let key = PKey::private_key_from_der(self.sign_key.as_slice()).unwrap();
ssl_builder
.set_sign_private_key(&key)
.map_err(|e| anyhow!("failed to set sign private key: {e}"))?;
let key = PKey::private_key_from_der(self.enc_key.as_slice()).unwrap();
ssl_builder
.set_enc_private_key(&key)
.map_err(|e| anyhow!("failed to set private key: {e}"))?;
Ok(())
}
}

View file

@ -18,7 +18,7 @@ use std::time::Duration;
use anyhow::anyhow;
use openssl::ssl::{
Ssl, SslConnector, SslContext, SslContextBuilder, SslMethod, SslVerifyMode, SslVersion,
Ssl, SslConnector, SslConnectorBuilder, SslContext, SslMethod, SslVerifyMode, SslVersion,
};
use openssl::x509::store::X509StoreBuilder;
use openssl::x509::X509;
@ -29,6 +29,9 @@ use super::{
};
use crate::net::tls::AlpnProtocol;
#[cfg(feature = "vendored-tongsuo")]
use super::OpensslTlcpCertificatePair;
const MINIMAL_HANDSHAKE_TIMEOUT: Duration = Duration::from_millis(100);
const DEFAULT_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(10);
@ -63,6 +66,8 @@ pub struct OpensslTlsClientConfigBuilder {
ca_certs: Vec<Vec<u8>>,
no_default_ca_certs: bool,
client_cert_pair: Option<OpensslCertificatePair>,
#[cfg(feature = "vendored-tongsuo")]
client_tlcp_cert_pair: Option<OpensslTlcpCertificatePair>,
handshake_timeout: Duration,
session_cache: OpensslSessionCacheConfig,
}
@ -76,6 +81,8 @@ impl Default for OpensslTlsClientConfigBuilder {
ca_certs: Vec::new(),
no_default_ca_certs: false,
client_cert_pair: None,
#[cfg(feature = "vendored-tongsuo")]
client_tlcp_cert_pair: None,
handshake_timeout: DEFAULT_HANDSHAKE_TIMEOUT,
session_cache: OpensslSessionCacheConfig::default(),
}
@ -102,6 +109,11 @@ impl OpensslTlsClientConfigBuilder {
cert_pair.check()?;
}
#[cfg(feature = "vendored-tongsuo")]
if let Some(tlcp_cert_pair) = &self.client_tlcp_cert_pair {
tlcp_cert_pair.check()?;
}
if !self.ciphers.is_empty() && self.protocol.is_none() {
return Err(anyhow!(
"protocol should be set to a fixed version if you want to specify cipher list / ciphersuites"
@ -154,6 +166,14 @@ impl OpensslTlsClientConfigBuilder {
self.client_cert_pair.replace(pair)
}
#[cfg(feature = "vendored-tongsuo")]
pub fn set_tlcp_cert_pair(
&mut self,
pair: OpensslTlcpCertificatePair,
) -> Option<OpensslTlcpCertificatePair> {
self.client_tlcp_cert_pair.replace(pair)
}
#[inline]
pub fn set_no_session_cache(&mut self) {
self.session_cache.set_no_session_cache();
@ -174,28 +194,48 @@ impl OpensslTlsClientConfigBuilder {
self.session_cache.set_each_capacity(cap);
}
fn set_tls_version(
&self,
version: SslVersion,
ctx_builder: &mut SslContextBuilder,
) -> anyhow::Result<()> {
ctx_builder
.set_min_proto_version(Some(version))
.map_err(|e| anyhow!("failed to set min protocol version: {e}"))?;
ctx_builder
.set_max_proto_version(Some(version))
.map_err(|e| anyhow!("failed to set max protocol version: {e}"))?;
#[cfg(feature = "vendored-tongsuo")]
fn new_tlcp_builder(&self) -> anyhow::Result<SslConnectorBuilder> {
let mut ctx_builder = SslConnector::builder(SslMethod::ntls_client())
.map_err(|e| anyhow!("failed to create ssl context builder: {e}"))?;
ctx_builder.set_verify(SslVerifyMode::PEER);
ctx_builder.enable_ntls();
let mut use_dhe = false;
if let Some(cert_pair) = &self.client_tlcp_cert_pair {
cert_pair.add_to_ssl_context(&mut ctx_builder)?;
use_dhe = true;
}
if !self.ciphers.is_empty() {
let cipher_list = self.ciphers.join(":");
ctx_builder
.set_cipher_list(&cipher_list)
.map_err(|e| anyhow!("failed to set cipher list: {e}"))?;
} else if use_dhe {
ctx_builder
.set_cipher_list(
"ECDHE-SM2-SM4-GCM-SM3:ECC-SM2-SM4-GCM-SM3:ECDHE-SM2-SM4-CBC-SM3:ECC-SM2-SM4-CBC-SM3:\
RSA-SM4-GCM-SM3:RSA-SM4-GCM-SHA256:RSA-SM4-CBC-SM3:RSA-SM4-CBC-SHA256",
)
.map_err(|e| anyhow!("failed to set cipher list: {e}"))?;
} else {
ctx_builder
.set_cipher_list(
"ECC-SM2-SM4-GCM-SM3:ECC-SM2-SM4-CBC-SM3:\
RSA-SM4-GCM-SM3:RSA-SM4-GCM-SHA256:RSA-SM4-CBC-SM3:RSA-SM4-CBC-SHA256",
)
.map_err(|e| anyhow!("failed to set cipher list: {e}"))?;
}
Ok(())
Ok(ctx_builder)
}
fn set_tls13(&self, ctx_builder: &mut SslContextBuilder) -> anyhow::Result<()> {
fn new_tls13_builder(&self) -> anyhow::Result<SslConnectorBuilder> {
let mut ctx_builder = SslConnector::builder(SslMethod::tls_client())
.map_err(|e| anyhow!("failed to create ssl context builder: {e}"))?;
ctx_builder.set_verify(SslVerifyMode::PEER);
ctx_builder
.set_min_proto_version(Some(SslVersion::TLS1_3))
.map_err(|e| anyhow!("failed to set min protocol version: {e}"))?;
@ -209,37 +249,66 @@ impl OpensslTlsClientConfigBuilder {
.set_ciphersuites(&ciphersuites)
.map_err(|e| anyhow!("failed to set ciphersuites: {e}"))?;
}
Ok(())
if let Some(cert_pair) = &self.client_cert_pair {
cert_pair.add_to_ssl_context(&mut ctx_builder)?;
}
Ok(ctx_builder)
}
fn new_versioned_builder(&self, version: SslVersion) -> anyhow::Result<SslConnectorBuilder> {
let mut ctx_builder = SslConnector::builder(SslMethod::tls_client())
.map_err(|e| anyhow!("failed to create ssl context builder: {e}"))?;
ctx_builder.set_verify(SslVerifyMode::PEER);
ctx_builder
.set_min_proto_version(Some(version))
.map_err(|e| anyhow!("failed to set min protocol version: {e}"))?;
ctx_builder
.set_max_proto_version(Some(version))
.map_err(|e| anyhow!("failed to set max protocol version: {e}"))?;
if !self.ciphers.is_empty() {
let cipher_list = self.ciphers.join(":");
ctx_builder
.set_cipher_list(&cipher_list)
.map_err(|e| anyhow!("failed to set cipher list: {e}"))?;
}
if let Some(cert_pair) = &self.client_cert_pair {
cert_pair.add_to_ssl_context(&mut ctx_builder)?;
}
Ok(ctx_builder)
}
fn new_default_builder(&self) -> anyhow::Result<SslConnectorBuilder> {
let mut ctx_builder = SslConnector::builder(SslMethod::tls_client())
.map_err(|e| anyhow!("failed to create ssl context builder: {e}"))?;
ctx_builder.set_verify(SslVerifyMode::PEER);
if let Some(cert_pair) = &self.client_cert_pair {
cert_pair.add_to_ssl_context(&mut ctx_builder)?;
}
Ok(ctx_builder)
}
pub fn build_with_alpn_protocols(
&self,
alpn_protocols: Option<Vec<AlpnProtocol>>,
) -> anyhow::Result<OpensslTlsClientConfig> {
let mut ctx_builder = SslConnector::builder(SslMethod::tls_client())
.map_err(|e| anyhow!("failed to create ssl context builder: {e}"))?;
ctx_builder.set_verify(SslVerifyMode::PEER);
match self.protocol {
Some(OpensslProtocol::Ssl3) => {
self.set_tls_version(SslVersion::SSL3, &mut ctx_builder)?;
}
Some(OpensslProtocol::Tls1) => {
self.set_tls_version(SslVersion::TLS1, &mut ctx_builder)?;
}
Some(OpensslProtocol::Tls11) => {
self.set_tls_version(SslVersion::TLS1_1, &mut ctx_builder)?;
}
Some(OpensslProtocol::Tls12) => {
self.set_tls_version(SslVersion::TLS1_2, &mut ctx_builder)?;
}
Some(OpensslProtocol::Tls13) => self.set_tls13(&mut ctx_builder)?,
None => {}
}
if let Some(cert_pair) = &self.client_cert_pair {
cert_pair.add_to_ssl_context(&mut ctx_builder)?;
}
let mut ctx_builder = match self.protocol {
Some(OpensslProtocol::Ssl3) => self.new_versioned_builder(SslVersion::SSL3)?,
Some(OpensslProtocol::Tls1) => self.new_versioned_builder(SslVersion::TLS1)?,
Some(OpensslProtocol::Tls11) => self.new_versioned_builder(SslVersion::TLS1_1)?,
Some(OpensslProtocol::Tls12) => self.new_versioned_builder(SslVersion::TLS1_2)?,
Some(OpensslProtocol::Tls13) => self.new_tls13_builder()?,
#[cfg(feature = "vendored-tongsuo")]
Some(OpensslProtocol::Tlcp11) => self.new_tlcp_builder()?,
None => self.new_default_builder()?,
};
let mut store_builder = X509StoreBuilder::new()
.map_err(|e| anyhow!("failed to create ca cert store builder: {e}"))?;

View file

@ -41,6 +41,7 @@ statsd = ["g3-statsd"]
resolve = ["g3-types/resolve"]
rustls = ["g3-types/rustls", "dep:rustls", "dep:rustls-pemfile"]
openssl = ["g3-types/openssl", "dep:openssl"]
vendored-tongsuo = ["openssl", "g3-types/vendored-tongsuo"]
http = ["g3-types/http", "dep:http"]
proxy = ["g3-types/proxy"]
acl-rule = ["g3-types/acl-rule", "dep:ip_network", "dep:regex", "proxy"]

View file

@ -77,6 +77,8 @@ pub use self::rustls::{
#[cfg(feature = "openssl")]
mod openssl;
#[cfg(feature = "vendored-tongsuo")]
pub use self::openssl::as_openssl_tlcp_certificate_pair;
#[cfg(feature = "openssl")]
pub use self::openssl::{
as_openssl_certificate_pair, as_openssl_certificates, as_openssl_private_key,

View file

@ -28,6 +28,9 @@ use g3_types::net::{
OpensslTlsInterceptionClientConfigBuilder,
};
#[cfg(feature = "vendored-tongsuo")]
use g3_types::net::OpensslTlcpCertificatePair;
fn as_certificates_from_single_element(
value: &Yaml,
lookup_dir: Option<&Path>,
@ -136,6 +139,55 @@ pub fn as_openssl_certificate_pair(
}
}
#[cfg(feature = "vendored-tongsuo")]
pub fn as_openssl_tlcp_certificate_pair(
value: &Yaml,
lookup_dir: Option<&Path>,
) -> anyhow::Result<OpensslTlcpCertificatePair> {
if let Yaml::Hash(map) = value {
let mut pair = OpensslTlcpCertificatePair::default();
crate::foreach_kv(map, |k, v| match crate::key::normalize(k).as_str() {
"sign_certificate" | "sign_cert" => {
let cert = as_openssl_certificates(v, lookup_dir)
.context(format!("invalid certificates value for key {k}"))?;
pair.set_sign_certificates(cert)
.context("failed to set sign certificate")?;
Ok(())
}
"enc_certificate" | "enc_cert" => {
let cert = as_openssl_certificates(v, lookup_dir)
.context(format!("invalid certificates value for key {k}"))?;
pair.set_enc_certificates(cert)
.context("failed to set enc certificate")?;
Ok(())
}
"sign_private_key" | "sign_key" => {
let key = as_openssl_private_key(v, lookup_dir)
.context(format!("invalid private key value for key {k}"))?;
pair.set_sign_private_key(key)
.context("failed to set private key")?;
Ok(())
}
"enc_private_key" | "enc_key" => {
let key = as_openssl_private_key(v, lookup_dir)
.context(format!("invalid private key value for key {k}"))?;
pair.set_enc_private_key(key)
.context("failed to set private key")?;
Ok(())
}
_ => Err(anyhow!("invalid key {k}")),
})?;
pair.check()?;
Ok(pair)
} else {
Err(anyhow!(
"yaml value type for 'openssl tlcp cert pair' should be 'map'"
))
}
}
fn as_openssl_protocol(value: &Yaml) -> anyhow::Result<OpensslProtocol> {
if let Yaml::String(s) = value {
OpensslProtocol::from_str(s)
@ -222,6 +274,13 @@ fn set_openssl_tls_client_config_builder(
builder.set_cert_pair(pair);
Ok(())
}
#[cfg(feature = "vendored-tongsuo")]
"tlcp_cert_pair" => {
let pair = as_openssl_tlcp_certificate_pair(v, lookup_dir)
.context(format!("invalid tlcp certificate pair value for key {k}"))?;
builder.set_tlcp_cert_pair(pair);
Ok(())
}
"ca_certificate" | "ca_cert" | "server_auth_certificate" | "server_auth_cert" => {
let certs = as_openssl_certificates(v, lookup_dir)
.context(format!("invalid certificates value for key {k}"))?;

View file

@ -18,6 +18,8 @@ script_name = sys.argv[0]
FORKED_NAMES = {
"cadence-with-flush": "cadence",
"tongsuo": "openssl",
"tongsuo-sys": "openssl-sys",
}