openvpn: Fix certificate verification compatibility
This commit is contained in:
@@ -38,6 +38,8 @@
|
||||
"crl_path": "",
|
||||
"remote_certificate_ku": [],
|
||||
"remote_certificate_eku": "",
|
||||
"remote_certificate_tls": "",
|
||||
"certificate_profile": "",
|
||||
"version_min": "1.2",
|
||||
"version_max": "",
|
||||
"cipher": "",
|
||||
@@ -251,15 +253,35 @@ Disabled by default.
|
||||
|
||||
Required server certificate key usage masks, written as hexadecimal values in OpenVPN `remote-cert-ku` format.
|
||||
|
||||
Multiple values are combined, and all requested usages must be present.
|
||||
The certificate must contain all bits from at least one configured mask.
|
||||
|
||||
Disabled by default.
|
||||
|
||||
### tls.remote_certificate_eku
|
||||
|
||||
Required server certificate extended key usage, one of `server` or `client`.
|
||||
Required server certificate extended key usage.
|
||||
|
||||
Disabled by default. The standard OpenVPN server certificate usage check still applies.
|
||||
OpenSSL names, object identifiers, and the aliases `server` and `client` are accepted.
|
||||
|
||||
When set, this field replaces the default `tls.remote_certificate_tls` check.
|
||||
|
||||
Conflict with an explicitly configured `tls.remote_certificate_tls`.
|
||||
|
||||
### tls.remote_certificate_tls
|
||||
|
||||
Peer certificate purpose check, one of `server`, `client`, or `none`.
|
||||
|
||||
`server` is used by default.
|
||||
|
||||
`none` disables the certificate purpose check.
|
||||
|
||||
Conflict with `tls.remote_certificate_eku`.
|
||||
|
||||
### tls.certificate_profile
|
||||
|
||||
Certificate profile, one of `insecure`, `legacy`, `preferred`, or `suiteb`.
|
||||
|
||||
`legacy` is used by default.
|
||||
|
||||
### tls.version_min
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
"crl_path": "",
|
||||
"remote_certificate_ku": [],
|
||||
"remote_certificate_eku": "",
|
||||
"remote_certificate_tls": "",
|
||||
"certificate_profile": "",
|
||||
"version_min": "1.2",
|
||||
"version_max": "",
|
||||
"cipher": "",
|
||||
@@ -251,15 +253,35 @@ OpenVPN 控制通道 TLS 配置。
|
||||
|
||||
服务器证书所需的 Key Usage mask,使用 OpenVPN `remote-cert-ku` 格式的十六进制值。
|
||||
|
||||
多个值会被组合,证书必须包含所有要求的用途。
|
||||
证书必须包含至少一个已配置 mask 中的所有 bit。
|
||||
|
||||
默认禁用。
|
||||
|
||||
### tls.remote_certificate_eku
|
||||
|
||||
服务器证书所需的 Extended Key Usage,可选值为 `server` 或 `client`。
|
||||
服务器证书所需的 Extended Key Usage。
|
||||
|
||||
默认禁用。标准 OpenVPN 服务器证书用途检查仍然生效。
|
||||
接受 OpenSSL 名称、Object Identifier 以及 `server` 和 `client` 别名。
|
||||
|
||||
设置后,该字段会替代默认的 `tls.remote_certificate_tls` 检查。
|
||||
|
||||
与显式配置的 `tls.remote_certificate_tls` 冲突。
|
||||
|
||||
### tls.remote_certificate_tls
|
||||
|
||||
对端证书用途检查,可选值为 `server`、`client` 或 `none`。
|
||||
|
||||
默认使用 `server`。
|
||||
|
||||
`none` 禁用证书用途检查。
|
||||
|
||||
与 `tls.remote_certificate_eku` 冲突。
|
||||
|
||||
### tls.certificate_profile
|
||||
|
||||
证书 profile,可选值为 `insecure`、`legacy`、`preferred` 或 `suiteb`。
|
||||
|
||||
默认使用 `legacy`。
|
||||
|
||||
### tls.version_min
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"client_certificate": [],
|
||||
"client_certificate_path": "",
|
||||
"verify_client_certificate": "require",
|
||||
"certificate_profile": "",
|
||||
"control_wrap": {
|
||||
"type": "tls_crypt",
|
||||
"key": [],
|
||||
@@ -214,6 +215,12 @@ If set to `none`, client certificates are not requested.
|
||||
|
||||
This field does not replace `users`; when `users` is set, username/password authentication is still required.
|
||||
|
||||
### tls.certificate_profile
|
||||
|
||||
Certificate profile, one of `insecure`, `legacy`, `preferred`, or `suiteb`.
|
||||
|
||||
`legacy` is used by default.
|
||||
|
||||
### tls.control_wrap
|
||||
|
||||
OpenVPN control channel wrapping.
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"client_certificate": [],
|
||||
"client_certificate_path": "",
|
||||
"verify_client_certificate": "require",
|
||||
"certificate_profile": "",
|
||||
"control_wrap": {
|
||||
"type": "tls_crypt",
|
||||
"key": [],
|
||||
@@ -214,6 +215,12 @@ OpenVPN 客户端证书策略,`require`、`optional` 或 `none` 之一。
|
||||
|
||||
该字段不替代 `users`;设置 `users` 后仍然要求用户名/密码认证。
|
||||
|
||||
### tls.certificate_profile
|
||||
|
||||
证书 profile,可选值为 `insecure`、`legacy`、`preferred` 或 `suiteb`。
|
||||
|
||||
默认使用 `legacy`。
|
||||
|
||||
### tls.control_wrap
|
||||
|
||||
OpenVPN 控制信道包装。
|
||||
|
||||
@@ -47,7 +47,7 @@ require (
|
||||
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3
|
||||
github.com/sagernet/sing-mux v0.3.5
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260720032640-bf28b6a6f10e
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260719094204-c57d60b5c5a4
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260720132803-a5e407d00242
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
@@ -105,8 +105,9 @@ require (
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/certificate-transparency-go v1.3.2 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
|
||||
@@ -92,12 +92,14 @@ github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
|
||||
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
||||
github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
|
||||
github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/certificate-transparency-go v1.3.2 h1:9ahSNZF2o7SYMaKaXhAumVEzXB2QaayzII9C8rv7v+A=
|
||||
github.com/google/certificate-transparency-go v1.3.2/go.mod h1:H5FpMUaGa5Ab2+KCYsxg6sELw3Flkl7pGZzWdBoYLXs=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
@@ -287,8 +289,8 @@ github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONf
|
||||
github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260720032640-bf28b6a6f10e h1:z0QFO/Bj3ikw4qDM7iwlEzSRdt/04Mh1s1pPeI/LRs0=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260720032640-bf28b6a6f10e/go.mod h1:EIzh5HtImfQJxPKXFwS9lyMnmMy4aCQCx7ntQ4u41Gs=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260719094204-c57d60b5c5a4 h1:3H1pOsE5IRzr2U+oUTabPrvryj7xg1CEmOnMMwsQSQA=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260719094204-c57d60b5c5a4/go.mod h1:CmTGnS5ijVSqFQV1dTq4WvFLUoz7bk9xasBPsX8NcYo=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260720132803-a5e407d00242 h1:0ZvKyBmBIlAuZ9G+zAWdGh6SrmXIXN7NWENHDrptxtI=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260720132803-a5e407d00242/go.mod h1:mK4GzZyUIhG751Mt1MSvSqLGYOR7DFJd8q5QfgFjE2Y=
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31 h1:FuiTs45PaA1/f2Kj6E2QlctFBrJUUFB8QAHnV5im9c8=
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31/go.mod h1:9k+dzGsWMttUGldBzq3dU792YHXzW6NgfbOGltnXq+0=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
||||
|
||||
@@ -94,6 +94,8 @@ type OpenVPNOutboundTLSOptions struct {
|
||||
CRLPath string `json:"crl_path,omitempty"`
|
||||
RemoteCertificateKU badoption.Listable[string] `json:"remote_certificate_ku,omitempty"`
|
||||
RemoteCertificateEKU string `json:"remote_certificate_eku,omitempty"`
|
||||
RemoteCertificateTLS string `json:"remote_certificate_tls,omitempty"`
|
||||
CertificateProfile string `json:"certificate_profile,omitempty"`
|
||||
VersionMin string `json:"version_min,omitempty"`
|
||||
VersionMax string `json:"version_max,omitempty"`
|
||||
Cipher string `json:"cipher,omitempty"`
|
||||
@@ -109,6 +111,7 @@ type OpenVPNInboundTLSOptions struct {
|
||||
ClientCertificate badoption.Listable[string] `json:"client_certificate,omitempty"`
|
||||
ClientCertificatePath string `json:"client_certificate_path,omitempty"`
|
||||
VerifyClientCertificate string `json:"verify_client_certificate,omitempty"`
|
||||
CertificateProfile string `json:"certificate_profile,omitempty"`
|
||||
ControlWrap *OpenVPNInboundControlWrapOptions `json:"control_wrap,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -237,6 +237,20 @@ func (c *ClientEndpoint) buildClientOptions(options option.OpenVPNClientEndpoint
|
||||
tunnelRoutes := common.Map(options.Routes, func(route netip.Prefix) ovpn.TunnelRoute {
|
||||
return ovpn.TunnelRoute{Prefix: route}
|
||||
})
|
||||
remoteCertificateTLS := options.TLS.RemoteCertificateTLS
|
||||
switch remoteCertificateTLS {
|
||||
case "", "server", "client", "none":
|
||||
default:
|
||||
return ovpn.ClientOptions{}, E.New("invalid `tls.remote_certificate_tls`: ", remoteCertificateTLS)
|
||||
}
|
||||
if options.TLS.RemoteCertificateEKU != "" && remoteCertificateTLS != "" {
|
||||
return ovpn.ClientOptions{}, E.New("`tls.remote_certificate_eku` is conflict with `tls.remote_certificate_tls`")
|
||||
}
|
||||
if remoteCertificateTLS == "" && options.TLS.RemoteCertificateEKU == "" {
|
||||
remoteCertificateTLS = "server"
|
||||
} else if remoteCertificateTLS == "none" {
|
||||
remoteCertificateTLS = ""
|
||||
}
|
||||
clientTLSOptions := ovpn.ClientTLSOptions{
|
||||
CertificateAuthority: certificateAuthority,
|
||||
Certificate: clientCertificate,
|
||||
@@ -249,9 +263,10 @@ func (c *ClientEndpoint) buildClientOptions(options option.OpenVPNClientEndpoint
|
||||
CRLVerify: options.TLS.CRLPath,
|
||||
RemoteCertificateKU: options.TLS.RemoteCertificateKU,
|
||||
RemoteCertificateEKU: options.TLS.RemoteCertificateEKU,
|
||||
RemoteCertificateTLS: "server",
|
||||
RemoteCertificateTLS: remoteCertificateTLS,
|
||||
VersionMin: options.TLS.VersionMin,
|
||||
VersionMax: options.TLS.VersionMax,
|
||||
CertificateProfile: options.TLS.CertificateProfile,
|
||||
Cipher: options.TLS.Cipher,
|
||||
Groups: options.TLS.Groups,
|
||||
}
|
||||
|
||||
@@ -336,6 +336,7 @@ func buildServerTLSOptions(options option.OpenVPNInboundTLSOptions) (ovpn.Server
|
||||
Certificate: certificate,
|
||||
Key: key,
|
||||
VerifyClientCertificate: options.VerifyClientCertificate,
|
||||
CertificateProfile: options.CertificateProfile,
|
||||
}
|
||||
keyDirection := -1
|
||||
controlWrap := options.ControlWrap
|
||||
|
||||
+8
-7
@@ -13,10 +13,10 @@ require (
|
||||
github.com/opencontainers/image-spec v1.1.0
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4
|
||||
github.com/sagernet/sing v0.8.12-0.20260717153536-4f1ed45a99a5
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260709034545-e23afe1172dc
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260719050255-7e7bd198288c
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260719094150-557ca930fccd
|
||||
github.com/spyzhov/ajson v0.9.4
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go.uber.org/goleak v1.3.0
|
||||
@@ -67,8 +67,9 @@ require (
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/godbus/dbus/v5 v5.2.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/certificate-transparency-go v1.3.2 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect
|
||||
@@ -153,10 +154,10 @@ require (
|
||||
github.com/sagernet/nftables v0.3.0-mod.4 // indirect
|
||||
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 // indirect
|
||||
github.com/sagernet/sing-mux v0.3.5 // indirect
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260718163953-a1c7815e4f04 // indirect
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260718163953-26ecbeb6352c // indirect
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260720032640-bf28b6a6f10e // indirect
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260720132803-a5e407d00242 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.2.1 // indirect
|
||||
github.com/sagernet/sing-snell v0.0.0-20260710094516-a4e97ee24beb // indirect
|
||||
github.com/sagernet/sing-snell v0.0.0-20260719094200-c43fbee0e839 // indirect
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb // indirect
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 // indirect
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 // indirect
|
||||
@@ -181,7 +182,7 @@ require (
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||
|
||||
+23
-20
@@ -102,12 +102,14 @@ github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
|
||||
github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/certificate-transparency-go v1.3.2 h1:9ahSNZF2o7SYMaKaXhAumVEzXB2QaayzII9C8rv7v+A=
|
||||
github.com/google/certificate-transparency-go v1.3.2/go.mod h1:H5FpMUaGa5Ab2+KCYsxg6sELw3Flkl7pGZzWdBoYLXs=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
@@ -117,8 +119,8 @@ github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdF
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
|
||||
@@ -304,22 +306,22 @@ github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 h1:3y6
|
||||
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg=
|
||||
github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONfhI=
|
||||
github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260718163953-a1c7815e4f04 h1:HIb3Tu19qqH5fD5xnyyHb6zJaETIsnXamb/hWTtxil8=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260718163953-a1c7815e4f04/go.mod h1:EIzh5HtImfQJxPKXFwS9lyMnmMy4aCQCx7ntQ4u41Gs=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260718163953-26ecbeb6352c h1:EhwLZF3IUyDj4uZ7vkUZAI7GymXCeOCwiseuOTsFjp8=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260718163953-26ecbeb6352c/go.mod h1:CmTGnS5ijVSqFQV1dTq4WvFLUoz7bk9xasBPsX8NcYo=
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260709034545-e23afe1172dc h1:zdc0fj4JdAdgAmQIoh7ZF+B/wPTEF2X75lYDqTmvlaw=
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260709034545-e23afe1172dc/go.mod h1:9k+dzGsWMttUGldBzq3dU792YHXzW6NgfbOGltnXq+0=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260720032640-bf28b6a6f10e h1:z0QFO/Bj3ikw4qDM7iwlEzSRdt/04Mh1s1pPeI/LRs0=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260720032640-bf28b6a6f10e/go.mod h1:EIzh5HtImfQJxPKXFwS9lyMnmMy4aCQCx7ntQ4u41Gs=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260720132803-a5e407d00242 h1:0ZvKyBmBIlAuZ9G+zAWdGh6SrmXIXN7NWENHDrptxtI=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260720132803-a5e407d00242/go.mod h1:mK4GzZyUIhG751Mt1MSvSqLGYOR7DFJd8q5QfgFjE2Y=
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31 h1:FuiTs45PaA1/f2Kj6E2QlctFBrJUUFB8QAHnV5im9c8=
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31/go.mod h1:9k+dzGsWMttUGldBzq3dU792YHXzW6NgfbOGltnXq+0=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1 h1:ZiHZdnEnP+YS73NMsxiZmIFCwNd0M4k7PkGCKNXhbaM=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-snell v0.0.0-20260710094516-a4e97ee24beb h1:VvU2/PZqP5tbKTDq0BxkhRO8ZnKI4UJzziakgBiP2Qg=
|
||||
github.com/sagernet/sing-snell v0.0.0-20260710094516-a4e97ee24beb/go.mod h1:PcwzX/Xvqky0EP3kGt8OCjYb3R1pydenPHNQZcPZmXY=
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260719050255-7e7bd198288c h1:jS5eWD9PyXhHY89DueRDgenfcrfpyPOuuZIoNfnBmOs=
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260719050255-7e7bd198288c/go.mod h1:F/gRq5VX1WN/OZtsvbN2JjXXuNl2ATJglHMSk1/iN9U=
|
||||
github.com/sagernet/sing-snell v0.0.0-20260719094200-c43fbee0e839 h1:YL0oCb55moImUGvjhhVEYODGMo5i9dAf+RpmMFPCq9w=
|
||||
github.com/sagernet/sing-snell v0.0.0-20260719094200-c43fbee0e839/go.mod h1:PcwzX/Xvqky0EP3kGt8OCjYb3R1pydenPHNQZcPZmXY=
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260719094150-557ca930fccd h1:tH79/IieRjLx5DiVu3NpXc1hir0xL6Avmmist0aFHks=
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260719094150-557ca930fccd/go.mod h1:F/gRq5VX1WN/OZtsvbN2JjXXuNl2ATJglHMSk1/iN9U=
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb h1:KEMbfexD4DvrQGYWwx6r+AwH9Veh8z6cnBZmtCS2G+0=
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb/go.mod h1:D4CnJX3MNAAANhbQUxfIRgBdnvlTEaV7h6ojedcs+pw=
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
|
||||
@@ -390,12 +392,12 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
@@ -406,8 +408,8 @@ go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2W
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -541,6 +543,7 @@ golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4 h1:Pw6WnI9W/LIdRxqK7T6XGugGbHIRl5Q7q3BssH6xk4s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||
|
||||
+25
-9
@@ -84,9 +84,11 @@ type openVPNDockerServerEnvironment struct {
|
||||
}
|
||||
|
||||
type openVPNSelfCase struct {
|
||||
name string
|
||||
protocol string
|
||||
tlsCrypt bool
|
||||
name string
|
||||
protocol string
|
||||
tlsCrypt bool
|
||||
omitServerKeyUsage bool
|
||||
remoteCertificateTLS string
|
||||
}
|
||||
|
||||
func TestOpenVPNSelfToSelf(t *testing.T) {
|
||||
@@ -104,6 +106,12 @@ func TestOpenVPNSelfToSelf(t *testing.T) {
|
||||
protocol: N.NetworkUDP,
|
||||
tlsCrypt: true,
|
||||
},
|
||||
{
|
||||
name: "missing_server_key_usage",
|
||||
protocol: N.NetworkUDP,
|
||||
omitServerKeyUsage: true,
|
||||
remoteCertificateTLS: "none",
|
||||
},
|
||||
}
|
||||
for i := range testCases {
|
||||
currentTestCase := testCases[i]
|
||||
@@ -131,6 +139,9 @@ func runOpenVPNSelfToSelf(t *testing.T, testCase openVPNSelfCase) {
|
||||
echoPort := reserveOpenVPNEchoPort(t)
|
||||
readinessPort := reserveOpenVPNEchoPort(t)
|
||||
certificates := createOpenVPNCertificateBundle(t)
|
||||
if testCase.omitServerKeyUsage {
|
||||
certificates = createOpenVPNCertificateBundleWithServerKeyUsage(t, 0)
|
||||
}
|
||||
serverOptions := option.OpenVPNServerEndpointOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.MustParseAddr("127.0.0.1"))),
|
||||
@@ -154,6 +165,7 @@ func runOpenVPNSelfToSelf(t *testing.T, testCase openVPNSelfCase) {
|
||||
serverOptions.UDPFiltering = option.UDPNATBehaviorAddressAndPortDependent
|
||||
serverOptions.UDPNATMax = 128
|
||||
clientOptions := newOpenVPNTLSClientOptions(testCase.protocol, openVPNPort, certificates.caPath, certificates.clientCertPath, certificates.clientKeyPath)
|
||||
clientOptions.TLS.RemoteCertificateTLS = testCase.remoteCertificateTLS
|
||||
clientOptions.UDPMapping = option.UDPNATBehaviorAddressDependent
|
||||
clientOptions.UDPFiltering = option.UDPNATBehaviorAddressAndPortDependent
|
||||
clientOptions.UDPNATMax = 128
|
||||
@@ -1663,6 +1675,10 @@ func readOpenVPNPacketWithTimeout(packetConn net.PacketConn, buffer []byte) (int
|
||||
}
|
||||
|
||||
func createOpenVPNCertificateBundle(t *testing.T) openVPNCertificateBundle {
|
||||
return createOpenVPNCertificateBundleWithServerKeyUsage(t, x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature)
|
||||
}
|
||||
|
||||
func createOpenVPNCertificateBundleWithServerKeyUsage(t *testing.T, serverKeyUsage x509.KeyUsage) openVPNCertificateBundle {
|
||||
t.Helper()
|
||||
tempDir := t.TempDir()
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, 3072)
|
||||
@@ -1694,8 +1710,8 @@ func createOpenVPNCertificateBundle(t *testing.T) openVPNCertificateBundle {
|
||||
require.NoError(t, err)
|
||||
caPath := filepath.Join(tempDir, "ca.crt")
|
||||
writePEMFile(t, caPath, "CERTIFICATE", caCertificate)
|
||||
serverCertPath, serverKeyPath := createOpenVPNLeafCertificate(t, tempDir, "server", x509.ExtKeyUsageServerAuth, caTemplate, caKey)
|
||||
clientCertPath, clientKeyPath := createOpenVPNLeafCertificate(t, tempDir, "client", x509.ExtKeyUsageClientAuth, caTemplate, caKey)
|
||||
serverCertPath, serverKeyPath := createOpenVPNLeafCertificate(t, tempDir, "server", serverKeyUsage, x509.ExtKeyUsageServerAuth, caTemplate, caKey)
|
||||
clientCertPath, clientKeyPath := createOpenVPNLeafCertificate(t, tempDir, "client", x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, x509.ExtKeyUsageClientAuth, caTemplate, caKey)
|
||||
return openVPNCertificateBundle{
|
||||
caPath: caPath,
|
||||
serverCertPath: serverCertPath,
|
||||
@@ -1705,7 +1721,7 @@ func createOpenVPNCertificateBundle(t *testing.T) openVPNCertificateBundle {
|
||||
}
|
||||
}
|
||||
|
||||
func createOpenVPNLeafCertificate(t *testing.T, tempDir string, commonName string, usage x509.ExtKeyUsage, caTemplate *x509.Certificate, caKey *rsa.PrivateKey) (string, string) {
|
||||
func createOpenVPNLeafCertificate(t *testing.T, tempDir string, commonName string, keyUsage x509.KeyUsage, extendedKeyUsage x509.ExtKeyUsage, caTemplate *x509.Certificate, caKey *rsa.PrivateKey) (string, string) {
|
||||
t.Helper()
|
||||
leafKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err)
|
||||
@@ -1717,12 +1733,12 @@ func createOpenVPNLeafCertificate(t *testing.T, tempDir string, commonName strin
|
||||
},
|
||||
NotBefore: time.Now().Add(-time.Minute),
|
||||
NotAfter: time.Now().AddDate(0, 1, 0),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
KeyUsage: keyUsage,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
usage,
|
||||
extendedKeyUsage,
|
||||
},
|
||||
}
|
||||
if usage == x509.ExtKeyUsageServerAuth {
|
||||
if extendedKeyUsage == x509.ExtKeyUsageServerAuth {
|
||||
leafTemplate.IPAddresses = append(leafTemplate.IPAddresses, net.ParseIP("127.0.0.1"))
|
||||
leafTemplate.DNSNames = append(leafTemplate.DNSNames, "localhost")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user