From 0aaf7608b1cf714ae512220e3313ca3530b75ab0 Mon Sep 17 00:00:00 2001 From: e1732a364fed <75717694+e1732a364fed@users.noreply.github.com> Date: Sun, 8 May 2022 09:11:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A4quic=E4=B9=9F=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=AF=81=E4=B9=A6=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 ++ README.md | 18 +++++++ advLayer/quic/client.go | 10 ++-- advLayer/quic/quic.go | 10 +++- examples/quic.client.toml | 4 ++ examples/quic.server.toml | 2 + examples/vlesss.client.toml | 2 +- examples/vlesss.server.toml | 12 +---- proxy/base.go | 69 +++++++-------------------- tlsLayer/cert.go | 1 + tlsLayer/client.go | 47 ++----------------- tlsLayer/const.go | 3 -- tlsLayer/server.go | 35 +------------- tlsLayer/tlsLayer.go | 94 +++++++++++++++++++++++++++++++++++++ 14 files changed, 158 insertions(+), 154 deletions(-) create mode 100644 tlsLayer/tlsLayer.go diff --git a/.gitignore b/.gitignore index 1d527e0..e75a5df 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,9 @@ BUILD_VERSION client.crt client.csr client.key +fakeclient.crt +fakeclient.csr +fakeclient.key +fakeca.key +fakeca.crt .vscode diff --git a/README.md b/README.md index 3da05b4..7150b0e 100644 --- a/README.md +++ b/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中被废弃了。 ### 交互模式 生成证书 diff --git a/advLayer/quic/client.go b/advLayer/quic/client.go index d38d4ce..67742a0 100644 --- a/advLayer/quic/client.go +++ b/advLayer/quic/client.go @@ -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, } } diff --git a/advLayer/quic/quic.go b/advLayer/quic/quic.go index fdb28bf..a6df390 100644 --- a/advLayer/quic/quic.go +++ b/advLayer/quic/quic.go @@ -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, diff --git a/examples/quic.client.toml b/examples/quic.client.toml index 845c88f..79b0586 100644 --- a/examples/quic.client.toml +++ b/examples/quic.client.toml @@ -27,6 +27,10 @@ advancedLayer = "quic" # tls = true +# 客户端证书,小白可无视。 +#cert = "client.crt" +#key = "client.key" + # early = true # 0-rtt # 我们可以选择性使用 “hysteria 阻塞控制” 方法, 但是协议依然为quic协议。具体请参考wiki等github页面上的 本作作者对hysteria的讨论 diff --git a/examples/quic.server.toml b/examples/quic.server.toml index 6bd9305..ef2a99b 100644 --- a/examples/quic.server.toml +++ b/examples/quic.server.toml @@ -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,则客户端和服务端都要指定,而且要相同 diff --git a/examples/vlesss.client.toml b/examples/vlesss.client.toml index 68c106b..3815e71 100644 --- a/examples/vlesss.client.toml +++ b/examples/vlesss.client.toml @@ -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" diff --git a/examples/vlesss.server.toml b/examples/vlesss.server.toml index 13d48b8..356c94f 100644 --- a/examples/vlesss.server.toml +++ b/examples/vlesss.server.toml @@ -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" diff --git a/proxy/base.go b/proxy/base.go index feb2a95..0b3e88b 100644 --- a/proxy/base.go +++ b/proxy/base.go @@ -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 { diff --git a/tlsLayer/cert.go b/tlsLayer/cert.go index f7326dd..ae3d7ae 100644 --- a/tlsLayer/cert.go +++ b/tlsLayer/cert.go @@ -154,6 +154,7 @@ func GetCertArrayFromFile(certFile, keyFile string) (certArray []tls.Certificate } certArray = GenerateRandomTLSCert() + err = nil } else { certArray = []tls.Certificate{cert} diff --git a/tlsLayer/client.go b/tlsLayer/client.go index 1059dd9..ae5c8d1 100644 --- a/tlsLayer/client.go +++ b/tlsLayer/client.go @@ -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) } diff --git a/tlsLayer/const.go b/tlsLayer/const.go index 63c2fee..62bf4bd 100644 --- a/tlsLayer/const.go +++ b/tlsLayer/const.go @@ -1,6 +1,3 @@ -/* -Package tlsLayer provides facilities for tls, including sniffing. -*/ package tlsLayer var etStrMap map[int]string diff --git a/tlsLayer/server.go b/tlsLayer/server.go index 8453541..680bbab 100644 --- a/tlsLayer/server.go +++ b/tlsLayer/server.go @@ -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 diff --git a/tlsLayer/tlsLayer.go b/tlsLayer/tlsLayer.go new file mode 100644 index 0000000..d022562 --- /dev/null +++ b/tlsLayer/tlsLayer.go @@ -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 +}