mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
令quic也支持客户端证书验证
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -20,4 +20,9 @@ BUILD_VERSION
|
||||
client.crt
|
||||
client.csr
|
||||
client.key
|
||||
fakeclient.crt
|
||||
fakeclient.csr
|
||||
fakeclient.key
|
||||
fakeca.key
|
||||
fakeca.crt
|
||||
.vscode
|
||||
|
||||
18
README.md
18
README.md
@@ -220,6 +220,24 @@ openssl req -new -x509 -days 7305 -key cert.key -out cert.pem
|
||||
|
||||
此命令会生成ecc证书,这个证书比rsa证书 速度更快, 有利于网速加速(加速tls握手)。
|
||||
|
||||
#### 使用客户端证书的 高玩情况:
|
||||
|
||||
小白请无视这一段。
|
||||
|
||||
```sh
|
||||
# 生成ca的命令:
|
||||
openssl ecparam -genkey -name prime256v1 -out ca.key
|
||||
openssl req -new -x509 -days 365 -sha256 -key ca.key -out ca.crt #会提示让你输入 CountryName 等信息。
|
||||
|
||||
# 用ca生成客户端key和crt
|
||||
openssl ecparam -genkey -name prime256v1 -out client.key
|
||||
openssl req -new -key client.key -out client.csr #会提示 让你输入 CountryName 等信息。
|
||||
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
|
||||
```
|
||||
|
||||
之后, ca.crt 用于CA (服务端要配置这个), client.key 和 client.crt 用于 客户端证书 (客户端要配置这个)
|
||||
|
||||
注意 上面的openssl 生成 crt 的两个命令 要使用 -sha256参数, 因为默认的sha1已经不安全, 在go1.18中被废弃了。
|
||||
|
||||
### 交互模式 生成证书
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ type Client struct {
|
||||
connMapMutex sync.RWMutex
|
||||
}
|
||||
|
||||
func NewClient(addr *netLayer.Addr, alpnList []string, host string, insecure bool, args arguments) *Client {
|
||||
func NewClient(addr *netLayer.Addr, tConf tls.Config, args arguments) *Client {
|
||||
|
||||
if args.hysteriaMaxByteCount <= 0 {
|
||||
args.hysteriaMaxByteCount = Default_hysteriaMaxByteCount
|
||||
@@ -40,12 +40,8 @@ func NewClient(addr *netLayer.Addr, alpnList []string, host string, insecure boo
|
||||
|
||||
return &Client{
|
||||
serverAddrStr: addr.String(),
|
||||
tlsConf: tls.Config{
|
||||
InsecureSkipVerify: insecure,
|
||||
ServerName: host,
|
||||
NextProtos: alpnList,
|
||||
},
|
||||
arguments: args,
|
||||
tlsConf: tConf,
|
||||
arguments: args,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ Imperfect Package
|
||||
package quic
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"reflect"
|
||||
"time"
|
||||
@@ -139,7 +140,14 @@ func (Creator) NewClientFromConf(conf *advLayer.Conf) (advLayer.Client, error) {
|
||||
useHysteria, hysteria_manual, maxbyteCount, _ = getExtra(conf.Extra)
|
||||
}
|
||||
|
||||
return NewClient(&conf.Addr, alpn, conf.Host, conf.TlsConf.InsecureSkipVerify, arguments{
|
||||
var tConf tls.Config
|
||||
if conf.TlsConf != nil {
|
||||
tConf = *conf.TlsConf
|
||||
|
||||
}
|
||||
tConf.NextProtos = alpn
|
||||
|
||||
return NewClient(&conf.Addr, tConf, arguments{
|
||||
early: conf.IsEarly,
|
||||
useHysteria: useHysteria,
|
||||
hysteria_manual: hysteria_manual,
|
||||
|
||||
@@ -27,6 +27,10 @@ advancedLayer = "quic"
|
||||
|
||||
# tls = true
|
||||
|
||||
# 客户端证书,小白可无视。
|
||||
#cert = "client.crt"
|
||||
#key = "client.key"
|
||||
|
||||
# early = true # 0-rtt
|
||||
|
||||
# 我们可以选择性使用 “hysteria 阻塞控制” 方法, 但是协议依然为quic协议。具体请参考wiki等github页面上的 本作作者对hysteria的讨论
|
||||
|
||||
@@ -13,6 +13,8 @@ cert = "cert.pem"
|
||||
key = "cert.key"
|
||||
advancedLayer = "quic"
|
||||
|
||||
#ca = "ca.crt" # 可选,用于客户端证书 的验证
|
||||
|
||||
# network = udp # 只要 advancedLayer 设成了quic,network 就会自动被配置为udp,所以不需手动指定udp
|
||||
|
||||
#alpn = ["asdfsadf"] #如果指定alpn,则客户端和服务端都要指定,而且要相同
|
||||
|
||||
@@ -73,7 +73,7 @@ utls = true #是否使用 utls 来应用 chrome指纹进行伪装
|
||||
|
||||
# 如果要使用 websocket/grpc ,则 客户端和服务端 都要配置 advancedLayer 和 path
|
||||
|
||||
# 下面cert和key用于 "客户端证书", 小白可以无视,高级玩家可以用, 详见 vlesss.server.toml
|
||||
# 下面cert和key用于 "客户端证书", 小白可以无视,高级玩家可以用. 证书的生成命令 详见 README.md
|
||||
#cert = "client.crt"
|
||||
#key = "client.key"
|
||||
|
||||
|
||||
@@ -16,18 +16,8 @@ key = "cert.key" # 如果 cert和key中 有一项没给出, 或者文件不
|
||||
|
||||
#xver = 1 # 可选, 高级用法, 小白不用管. 若为1或者2, 则监听 PROXY protocol, 用于nginx等回落到 verysimple. 实际上目前无论给出的是1还是2, 都会同时监听 v1和v2. 不过这只是目前代码的实现而已, 也许未来会改动, 所以你还是确定选用一个版本.
|
||||
|
||||
# ca = "ca.crt" # 用于验证客户端证书
|
||||
ca = "ca.crt" # 可选, 用于验证客户端证书
|
||||
|
||||
# 生成ca的命令:
|
||||
# openssl ecparam -genkey -name prime256v1 -out ca.key
|
||||
# openssl req -new -x509 -days 365 -sha256 -key ca.key -out ca.crt #会提示让你输入 CountryName 等信息。
|
||||
|
||||
# 用ca生成客户端key和crt
|
||||
# openssl ecparam -genkey -name prime256v1 -out client.key
|
||||
# openssl req -new -key client.key -out client.csr #会提示 让你输入 CountryName 等信息。
|
||||
# openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
|
||||
|
||||
# 之后 client.key 和 client.crt 就是我们要的 客户端证书。 注意 上面的openssl 生成 crt 的两个命令 要使用 -sha256参数, 因为默认的sha1已经不安全, 在go1.18中被废弃了。
|
||||
|
||||
[[dial]]
|
||||
protocol = "direct"
|
||||
|
||||
@@ -321,25 +321,17 @@ func (b *Base) InitAdvLayer() {
|
||||
var tConf *tls.Config
|
||||
if creator.IsSuper() {
|
||||
|
||||
tConf = &tls.Config{
|
||||
InsecureSkipVerify: dc.Insecure,
|
||||
NextProtos: dc.Alpn,
|
||||
ServerName: dc.Host,
|
||||
}
|
||||
var certConf *tlsLayer.CertConf
|
||||
|
||||
if dc.TLSCert != "" && dc.TLSKey != "" {
|
||||
certArray, err := tlsLayer.GetCertArrayFromFile(dc.TLSCert, dc.TLSKey)
|
||||
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load client cert file failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.Certificates = certArray
|
||||
|
||||
certConf = &tlsLayer.CertConf{
|
||||
CertFile: dc.TLSCert,
|
||||
KeyFile: dc.TLSKey,
|
||||
}
|
||||
}
|
||||
|
||||
tConf = tlsLayer.GetTlsConfig(dc.Insecure, dc.Alpn, dc.Host, certConf)
|
||||
|
||||
}
|
||||
|
||||
aConf := &advLayer.Conf{
|
||||
@@ -377,52 +369,23 @@ func (b *Base) InitAdvLayer() {
|
||||
Headers = lc.HttpHeader
|
||||
}
|
||||
|
||||
var certArray []tls.Certificate
|
||||
|
||||
if creator.IsSuper() {
|
||||
if lc.TLSCert != "" && lc.TLSKey != "" {
|
||||
certArray, err = tlsLayer.GetCertArrayFromFile(lc.TLSCert, lc.TLSKey)
|
||||
|
||||
if err != nil {
|
||||
|
||||
if ce := utils.CanLogErr("can't create tls cert"); ce != nil {
|
||||
ce.Write(zap.String("cert", lc.TLSCert), zap.String("key", lc.TLSKey), zap.Error(err))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
tConf := &tls.Config{
|
||||
InsecureSkipVerify: lc.Insecure,
|
||||
NextProtos: lc.Alpn,
|
||||
ServerName: lc.Host,
|
||||
Certificates: certArray,
|
||||
}
|
||||
|
||||
if lc.CA != "" {
|
||||
certPool, err := tlsLayer.LoadCA(lc.CA)
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load CA failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.ClientCAs = certPool
|
||||
tConf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
|
||||
advSer, err := creator.NewServerFromConf(&advLayer.Conf{
|
||||
aConf := &advLayer.Conf{
|
||||
Path: lc.Path,
|
||||
Host: lc.Host,
|
||||
IsEarly: lc.IsEarly,
|
||||
Xver: lc.Xver,
|
||||
Addr: ad,
|
||||
Headers: Headers,
|
||||
TlsConf: tConf,
|
||||
Extra: lc.Extra,
|
||||
})
|
||||
}
|
||||
|
||||
if creator.IsSuper() {
|
||||
aConf.TlsConf = tlsLayer.GetTlsConfig(lc.Insecure, lc.Alpn, lc.Host, &tlsLayer.CertConf{
|
||||
CertFile: lc.TLSCert, KeyFile: lc.TLSKey, CA: lc.CA,
|
||||
})
|
||||
}
|
||||
|
||||
advSer, err := creator.NewServerFromConf(aConf)
|
||||
if err != nil {
|
||||
|
||||
if ce := utils.CanLogErr("InitAdvLayer server failed "); ce != nil {
|
||||
|
||||
@@ -154,6 +154,7 @@ func GetCertArrayFromFile(certFile, keyFile string) (certArray []tls.Certificate
|
||||
}
|
||||
|
||||
certArray = GenerateRandomTLSCert()
|
||||
err = nil
|
||||
|
||||
} else {
|
||||
certArray = []tls.Certificate{cert}
|
||||
|
||||
@@ -29,56 +29,15 @@ func NewClient(host string, insecure bool, use_uTls bool, alpnList []string, cer
|
||||
c.alpnList = alpnList
|
||||
|
||||
if use_uTls {
|
||||
tConf := utls.Config{
|
||||
InsecureSkipVerify: insecure,
|
||||
ServerName: host,
|
||||
NextProtos: alpnList,
|
||||
}
|
||||
|
||||
if certConf != nil {
|
||||
certArray, err := GetCertArrayFromFile(certConf.CertFile, certConf.KeyFile)
|
||||
c.uTlsConfig = GetUTlsConfig(insecure, alpnList, host, certConf)
|
||||
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load client cert file failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
var array []utls.Certificate
|
||||
|
||||
for _, c := range certArray {
|
||||
|
||||
array = append(array, *(*utls.Certificate)(unsafe.Pointer(&c)))
|
||||
}
|
||||
|
||||
tConf.Certificates = array
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
c.uTlsConfig = tConf
|
||||
|
||||
if ce := utils.CanLogInfo("using utls and Chrome fingerprint for"); ce != nil {
|
||||
if ce := utils.CanLogInfo("using uTls and Chrome fingerprint for"); ce != nil {
|
||||
ce.Write(zap.String("host", host))
|
||||
}
|
||||
} else {
|
||||
tConf := &tls.Config{
|
||||
InsecureSkipVerify: insecure,
|
||||
ServerName: host,
|
||||
NextProtos: alpnList,
|
||||
}
|
||||
if certConf != nil {
|
||||
certArray, err := GetCertArrayFromFile(certConf.CertFile, certConf.KeyFile)
|
||||
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load client cert file failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.Certificates = certArray
|
||||
|
||||
}
|
||||
}
|
||||
c.tlsConfig = tConf
|
||||
c.tlsConfig = GetTlsConfig(insecure, alpnList, host, certConf)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/*
|
||||
Package tlsLayer provides facilities for tls, including sniffing.
|
||||
*/
|
||||
package tlsLayer
|
||||
|
||||
var etStrMap map[int]string
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
@@ -17,17 +16,6 @@ type Server struct {
|
||||
//如 certFile, keyFile 有一项没给出,则会自动生成随机证书
|
||||
func NewServer(host string, certConf *CertConf, isInsecure bool, alpnList []string) (*Server, error) {
|
||||
|
||||
var certArray []tls.Certificate
|
||||
var err error
|
||||
|
||||
if certConf != nil {
|
||||
certArray, err = GetCertArrayFromFile(certConf.CertFile, certConf.KeyFile)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
//发现服务端必须给出 http/1.1 等,否则不会协商出这个alpn,而我们为了回落,是需要协商出所有可能需要的 alpn的。
|
||||
|
||||
//而且我们如果不提供 h1 和 h2 的alpn的话,很容易被审查者察觉的。
|
||||
@@ -44,29 +32,8 @@ func NewServer(host string, certConf *CertConf, isInsecure bool, alpnList []stri
|
||||
}
|
||||
}
|
||||
|
||||
tConf := &tls.Config{
|
||||
InsecureSkipVerify: isInsecure,
|
||||
ServerName: host,
|
||||
Certificates: certArray,
|
||||
NextProtos: alpnList,
|
||||
}
|
||||
|
||||
if certConf != nil {
|
||||
if certConf.CA != "" {
|
||||
certPool, err := LoadCA(certConf.CA)
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load CA failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.ClientCAs = certPool
|
||||
tConf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
tlsConfig: tConf,
|
||||
tlsConfig: GetTlsConfig(isInsecure, alpnList, host, certConf),
|
||||
}
|
||||
|
||||
return s, nil
|
||||
|
||||
94
tlsLayer/tlsLayer.go
Normal file
94
tlsLayer/tlsLayer.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Package tlsLayer provides facilities for tls, including sniffing.
|
||||
*/
|
||||
package tlsLayer
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"unsafe"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
utls "github.com/refraction-networking/utls"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func GetTlsConfig(insecure bool, alpn []string, host string, certConf *CertConf) *tls.Config {
|
||||
var certArray []tls.Certificate
|
||||
var err error
|
||||
|
||||
if certConf != nil {
|
||||
certArray, err = GetCertArrayFromFile(certConf.CertFile, certConf.KeyFile)
|
||||
|
||||
if err != nil {
|
||||
|
||||
if ce := utils.CanLogErr("can't create tls cert"); ce != nil {
|
||||
ce.Write(zap.String("cert", certConf.CertFile), zap.String("key", certConf.KeyFile), zap.Error(err))
|
||||
}
|
||||
|
||||
certArray = nil
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tConf := &tls.Config{
|
||||
InsecureSkipVerify: insecure,
|
||||
NextProtos: alpn,
|
||||
ServerName: host,
|
||||
Certificates: certArray,
|
||||
}
|
||||
if certConf != nil && certConf.CA != "" {
|
||||
certPool, err := LoadCA(certConf.CA)
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load CA failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.ClientCAs = certPool
|
||||
tConf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
return tConf
|
||||
}
|
||||
|
||||
func GetUTlsConfig(insecure bool, alpn []string, host string, certConf *CertConf) utls.Config {
|
||||
var certArray []utls.Certificate
|
||||
|
||||
if certConf != nil {
|
||||
tlscertArray, err := GetCertArrayFromFile(certConf.CertFile, certConf.KeyFile)
|
||||
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load client cert file failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
certArray = nil
|
||||
} else {
|
||||
|
||||
for _, c := range tlscertArray {
|
||||
|
||||
certArray = append(certArray, *(*utls.Certificate)(unsafe.Pointer(&c)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tConf := utls.Config{
|
||||
InsecureSkipVerify: insecure,
|
||||
NextProtos: alpn,
|
||||
ServerName: host,
|
||||
Certificates: certArray,
|
||||
}
|
||||
if certConf != nil && certConf.CA != "" {
|
||||
certPool, err := LoadCA(certConf.CA)
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load CA failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.ClientCAs = certPool
|
||||
tConf.ClientAuth = utls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
return tConf
|
||||
}
|
||||
Reference in New Issue
Block a user