diff --git a/app/dns/nameserver.go b/app/dns/nameserver.go index 89f5b25e..b23cb186 100644 --- a/app/dns/nameserver.go +++ b/app/dns/nameserver.go @@ -45,11 +45,13 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis case strings.EqualFold(u.String(), "localhost"): return NewLocalNameServer(queryStrategy), nil case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode - return NewDoHNameServer(u, dispatcher, queryStrategy, false) + return NewDoHNameServer(u, queryStrategy, dispatcher, false), nil case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode - return NewDoHNameServer(u, dispatcher, queryStrategy, true) + return NewDoHNameServer(u, queryStrategy, dispatcher, true), nil case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode - return NewDoHLocalNameServer(u, queryStrategy), nil + return NewDoHNameServer(u, queryStrategy, nil, false), nil + case strings.EqualFold(u.Scheme, "h2c+local"): // DNS-over-HTTPS h2c Local mode + return NewDoHNameServer(u, queryStrategy, nil, true), nil case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode return NewQUICNameServer(u, queryStrategy) case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode diff --git a/app/dns/nameserver_doh.go b/app/dns/nameserver_doh.go index f602d80a..c74b9e53 100644 --- a/app/dns/nameserver_doh.go +++ b/app/dns/nameserver_doh.go @@ -8,10 +8,13 @@ import ( "io" "net/http" "net/url" + "strings" "sync" "time" + utls "github.com/refraction-networking/utls" "github.com/xtls/xray-core/common" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/net" @@ -31,7 +34,6 @@ import ( // which is compatible with traditional dns over udp(RFC1035), // thus most of the DOH implementation is copied from udpns.go type DoHNameServer struct { - dispatcher routing.Dispatcher sync.RWMutex ips map[string]*record pub *pubsub.Service @@ -42,108 +44,18 @@ type DoHNameServer struct { queryStrategy QueryStrategy } -// NewDoHNameServer creates DOH server object for remote resolving. -func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy, h2c bool) (*DoHNameServer, error) { +// NewDoHNameServer creates DOH/DOHL client object for remote/local resolving. +func NewDoHNameServer(url *url.URL, queryStrategy QueryStrategy, dispatcher routing.Dispatcher, h2c bool) *DoHNameServer { url.Scheme = "https" - errors.LogInfo(context.Background(), "DNS: created Remote DNS-over-HTTPS client for ", url.String(), ", with h2c ", h2c) - s := baseDOHNameServer(url, "DOH", queryStrategy) - - s.dispatcher = dispatcher - dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) { - dest, err := net.ParseDestination(network + ":" + addr) - if err != nil { - return nil, err - } - dnsCtx := toDnsContext(ctx, s.dohURL) - if h2c { - dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance - dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname()) - } - link, err := s.dispatcher.Dispatch(dnsCtx, dest) - select { - case <-ctx.Done(): - return nil, ctx.Err() - default: - - } - if err != nil { - return nil, err - } - - cc := common.ChainedClosable{} - if cw, ok := link.Writer.(common.Closable); ok { - cc = append(cc, cw) - } - if cr, ok := link.Reader.(common.Closable); ok { - cc = append(cc, cr) - } - return cnc.NewConnection( - cnc.ConnectionInputMulti(link.Writer), - cnc.ConnectionOutputMulti(link.Reader), - cnc.ConnectionOnClose(cc), - ), nil + mode := "DOH" + if dispatcher == nil { + mode = "DOHL" } - - s.httpClient = &http.Client{ - Timeout: time.Second * 180, - Transport: &http.Transport{ - MaxIdleConns: 30, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 30 * time.Second, - ForceAttemptHTTP2: true, - DialContext: dialContext, - }, - } - if h2c { - s.httpClient.Transport = &http2.Transport{ - IdleConnTimeout: 90 * time.Second, - DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { - return dialContext(ctx, network, addr) - }, - } - } - - return s, nil -} - -// NewDoHLocalNameServer creates DOH client object for local resolving -func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer { - url.Scheme = "https" - s := baseDOHNameServer(url, "DOHL", queryStrategy) - tr := &http.Transport{ - IdleConnTimeout: 90 * time.Second, - ForceAttemptHTTP2: true, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - dest, err := net.ParseDestination(network + ":" + addr) - if err != nil { - return nil, err - } - conn, err := internet.DialSystem(ctx, dest, nil) - log.Record(&log.AccessMessage{ - From: "DNS", - To: s.dohURL, - Status: log.AccessAccepted, - Detour: "local", - }) - if err != nil { - return nil, err - } - return conn, nil - }, - } - s.httpClient = &http.Client{ - Timeout: time.Second * 180, - Transport: tr, - } - errors.LogInfo(context.Background(), "DNS: created Local DNS-over-HTTPS client for ", url.String()) - return s -} - -func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer { + errors.LogInfo(context.Background(), "DNS: created ", mode, " client for ", url.String(), ", with h2c ", h2c) s := &DoHNameServer{ ips: make(map[string]*record), pub: pubsub.NewService(), - name: prefix + "//" + url.Host, + name: mode + "//" + url.Host, dohURL: url.String(), queryStrategy: queryStrategy, } @@ -151,6 +63,65 @@ func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) Interval: time.Minute, Execute: s.Cleanup, } + s.httpClient = &http.Client{ + Transport: &http2.Transport{ + IdleConnTimeout: net.ConnIdleTimeout, + ReadIdleTimeout: net.ChromeH2KeepAlivePeriod, + DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { + dest, err := net.ParseDestination(network + ":" + addr) + if err != nil { + return nil, err + } + var conn net.Conn + if dispatcher != nil { + dnsCtx := toDnsContext(ctx, s.dohURL) + if h2c { + dnsCtx = session.ContextWithMitmAlpn11(dnsCtx, false) // for insurance + dnsCtx = session.ContextWithMitmServerName(dnsCtx, url.Hostname()) + } + link, err := dispatcher.Dispatch(dnsCtx, dest) + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + if err != nil { + return nil, err + } + cc := common.ChainedClosable{} + if cw, ok := link.Writer.(common.Closable); ok { + cc = append(cc, cw) + } + if cr, ok := link.Reader.(common.Closable); ok { + cc = append(cc, cr) + } + conn = cnc.NewConnection( + cnc.ConnectionInputMulti(link.Writer), + cnc.ConnectionOutputMulti(link.Reader), + cnc.ConnectionOnClose(cc), + ) + } else { + log.Record(&log.AccessMessage{ + From: "DNS", + To: s.dohURL, + Status: log.AccessAccepted, + Detour: "local", + }) + conn, err = internet.DialSystem(ctx, dest, nil) + if err != nil { + return nil, err + } + } + if !h2c { + conn = utls.UClient(conn, &utls.Config{ServerName: url.Hostname()}, utls.HelloChrome_Auto) + if err := conn.(*utls.UConn).HandshakeContext(ctx); err != nil { + return nil, err + } + } + return conn, nil + }, + }, + } return s } @@ -310,6 +281,8 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte, req.Header.Add("Accept", "application/dns-message") req.Header.Add("Content-Type", "application/dns-message") + req.Header.Set("X-Padding", strings.Repeat("X", int(crypto.RandBetween(100, 1000)))) + hc := s.httpClient resp, err := hc.Do(req.WithContext(ctx)) diff --git a/app/dns/nameserver_doh_test.go b/app/dns/nameserver_doh_test.go index ae4f9cc7..3dfcb15c 100644 --- a/app/dns/nameserver_doh_test.go +++ b/app/dns/nameserver_doh_test.go @@ -17,7 +17,7 @@ func TestDOHNameServer(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP) + s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, @@ -34,7 +34,7 @@ func TestDOHNameServerWithCache(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP) + s := NewDoHNameServer(url, QueryStrategy_USE_IP, nil, false) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, @@ -62,7 +62,7 @@ func TestDOHNameServerWithIPv4Override(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4) + s := NewDoHNameServer(url, QueryStrategy_USE_IP4, nil, false) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, @@ -85,7 +85,7 @@ func TestDOHNameServerWithIPv6Override(t *testing.T) { url, err := url.Parse("https+local://1.1.1.1/dns-query") common.Must(err) - s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6) + s := NewDoHNameServer(url, QueryStrategy_USE_IP6, nil, false) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{ IPv4Enable: true, diff --git a/common/crypto/crypto.go b/common/crypto/crypto.go index 4ed70634..464b4fa7 100644 --- a/common/crypto/crypto.go +++ b/common/crypto/crypto.go @@ -1,2 +1,15 @@ // Package crypto provides common crypto libraries for Xray. package crypto // import "github.com/xtls/xray-core/common/crypto" + +import ( + "crypto/rand" + "math/big" +) + +func RandBetween(from int64, to int64) int64 { + if from == to { + return from + } + bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from)) + return from + bigInt.Int64() +} diff --git a/common/net/net.go b/common/net/net.go index ce321425..92431c42 100644 --- a/common/net/net.go +++ b/common/net/net.go @@ -1,2 +1,14 @@ // Package net is a drop-in replacement to Golang's net package, with some more functionalities. package net // import "github.com/xtls/xray-core/common/net" + +import "time" + +// defines the maximum time an idle TCP session can survive in the tunnel, so +// it should be consistent across HTTP versions and with other transports. +const ConnIdleTimeout = 300 * time.Second + +// consistent with quic-go +const QuicgoH3KeepAlivePeriod = 10 * time.Second + +// consistent with chrome +const ChromeH2KeepAlivePeriod = 45 * time.Second diff --git a/proxy/freedom/freedom.go b/proxy/freedom/freedom.go index 19bc15ab..324941ee 100644 --- a/proxy/freedom/freedom.go +++ b/proxy/freedom/freedom.go @@ -4,12 +4,12 @@ import ( "context" "crypto/rand" "io" - "math/big" "time" "github.com/pires/go-proxyproto" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" @@ -414,7 +414,7 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { noise = n.Packet } else { //Random noise - noise, err = GenerateRandomBytes(randBetween(int64(n.LengthMin), + noise, err = GenerateRandomBytes(crypto.RandBetween(int64(n.LengthMin), int64(n.LengthMax))) } if err != nil { @@ -423,7 +423,7 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)}) if n.DelayMin != 0 || n.DelayMax != 0 { - time.Sleep(time.Duration(randBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond) + time.Sleep(time.Duration(crypto.RandBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond) } } @@ -452,7 +452,7 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { buf := make([]byte, 1024) var hello []byte for from := 0; ; { - to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) + to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) if to > len(data) { to = len(data) } @@ -466,7 +466,7 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { hello = append(hello, buf[:5+l]...) } else { _, err := f.writer.Write(buf[:5+l]) - time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) + time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) if err != nil { return 0, err } @@ -493,13 +493,13 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { return f.writer.Write(b) } for from := 0; ; { - to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) + to := from + int(crypto.RandBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax))) if to > len(b) { to = len(b) } n, err := f.writer.Write(b[from:to]) from += n - time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) + time.Sleep(time.Duration(crypto.RandBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond) if err != nil { return from, err } @@ -509,14 +509,6 @@ func (f *FragmentWriter) Write(b []byte) (int, error) { } } -// stolen from github.com/xtls/xray-core/transport/internet/reality -func randBetween(left int64, right int64) int64 { - if left == right { - return left - } - bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left)) - return left + bigInt.Int64() -} func GenerateRandomBytes(n int64) ([]byte, error) { b := make([]byte, n) _, err := rand.Read(b) diff --git a/transport/internet/reality/reality.go b/transport/internet/reality/reality.go index 0efcd96e..a9352aaf 100644 --- a/transport/internet/reality/reality.go +++ b/transport/internet/reality/reality.go @@ -8,7 +8,6 @@ import ( "crypto/ecdh" "crypto/ed25519" "crypto/hmac" - "crypto/rand" "crypto/sha256" "crypto/sha512" gotls "crypto/tls" @@ -16,7 +15,6 @@ import ( "encoding/binary" "fmt" "io" - "math/big" "net/http" "reflect" "regexp" @@ -27,6 +25,7 @@ import ( utls "github.com/refraction-networking/utls" "github.com/xtls/reality" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/core" @@ -213,13 +212,13 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati } times := 1 if !first { - times = int(randBetween(config.SpiderY[4], config.SpiderY[5])) + times = int(crypto.RandBetween(config.SpiderY[4], config.SpiderY[5])) } for j := 0; j < times; j++ { if !first && j == 0 { req.Header.Set("Referer", firstURL) } - req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(randBetween(config.SpiderY[0], config.SpiderY[1])))}) + req.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", int(crypto.RandBetween(config.SpiderY[0], config.SpiderY[1])))}) if resp, err = client.Do(req); err != nil { break } @@ -243,18 +242,18 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati } maps.Unlock() if !first { - time.Sleep(time.Duration(randBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval + time.Sleep(time.Duration(crypto.RandBetween(config.SpiderY[6], config.SpiderY[7])) * time.Millisecond) // interval } } } get(true) - concurrency := int(randBetween(config.SpiderY[2], config.SpiderY[3])) + concurrency := int(crypto.RandBetween(config.SpiderY[2], config.SpiderY[3])) for i := 0; i < concurrency; i++ { go get(false) } // Do not close the connection }() - time.Sleep(time.Duration(randBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return + time.Sleep(time.Duration(crypto.RandBetween(config.SpiderY[8], config.SpiderY[9])) * time.Millisecond) // return return nil, errors.New("REALITY: processed invalid connection").AtWarning() } return uConn, nil @@ -271,7 +270,7 @@ var maps struct { } func getPathLocked(paths map[string]struct{}) string { - stopAt := int(randBetween(0, int64(len(paths)-1))) + stopAt := int(crypto.RandBetween(0, int64(len(paths)-1))) i := 0 for s := range paths { if i == stopAt { @@ -281,11 +280,3 @@ func getPathLocked(paths map[string]struct{}) string { } return "/" } - -func randBetween(left int64, right int64) int64 { - if left == right { - return left - } - bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left)) - return left + bigInt.Int64() -} diff --git a/transport/internet/splithttp/config.go b/transport/internet/splithttp/config.go index f160db31..21e81aa1 100644 --- a/transport/internet/splithttp/config.go +++ b/transport/internet/splithttp/config.go @@ -1,13 +1,12 @@ package splithttp import ( - "crypto/rand" - "math/big" "net/http" "net/url" "strings" "github.com/xtls/xray-core/common" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/transport/internet" ) @@ -184,9 +183,5 @@ func init() { } func (c RangeConfig) rand() int32 { - if c.From == c.To { - return c.From - } - bigInt, _ := rand.Int(rand.Reader, big.NewInt(int64(c.To-c.From))) - return c.From + int32(bigInt.Int64()) + return int32(crypto.RandBetween(int64(c.From), int64(c.To))) } diff --git a/transport/internet/splithttp/dialer.go b/transport/internet/splithttp/dialer.go index b97c39e9..f996a42e 100644 --- a/transport/internet/splithttp/dialer.go +++ b/transport/internet/splithttp/dialer.go @@ -30,16 +30,6 @@ import ( "golang.org/x/net/http2" ) -// defines the maximum time an idle TCP session can survive in the tunnel, so -// it should be consistent across HTTP versions and with other transports. -const connIdleTimeout = 300 * time.Second - -// consistent with quic-go -const quicgoH3KeepAlivePeriod = 10 * time.Second - -// consistent with chrome -const chromeH2KeepAlivePeriod = 45 * time.Second - type dialerConf struct { net.Destination *internet.MemoryStreamConfig @@ -154,13 +144,13 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea if httpVersion == "3" { if keepAlivePeriod == 0 { - keepAlivePeriod = quicgoH3KeepAlivePeriod + keepAlivePeriod = net.QuicgoH3KeepAlivePeriod } if keepAlivePeriod < 0 { keepAlivePeriod = 0 } quicConfig := &quic.Config{ - MaxIdleTimeout: connIdleTimeout, + MaxIdleTimeout: net.ConnIdleTimeout, // these two are defaults of quic-go/http3. the default of quic-go (no // http3) is different, so it is hardcoded here for clarity. @@ -168,7 +158,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea MaxIncomingStreams: -1, KeepAlivePeriod: keepAlivePeriod, } - transport = &http3.RoundTripper{ + transport = &http3.Transport{ QUICConfig: quicConfig, TLSClientConfig: gotlsConfig, Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { @@ -198,7 +188,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea return nil, err } default: - udpConn = &internet.FakePacketConn{c} + udpConn = &internet.FakePacketConn{Conn: c} udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String()) if err != nil { return nil, err @@ -210,7 +200,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea } } else if httpVersion == "2" { if keepAlivePeriod == 0 { - keepAlivePeriod = chromeH2KeepAlivePeriod + keepAlivePeriod = net.ChromeH2KeepAlivePeriod } if keepAlivePeriod < 0 { keepAlivePeriod = 0 @@ -219,7 +209,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea DialTLSContext: func(ctxInner context.Context, network string, addr string, cfg *gotls.Config) (net.Conn, error) { return dialContext(ctxInner) }, - IdleConnTimeout: connIdleTimeout, + IdleConnTimeout: net.ConnIdleTimeout, ReadIdleTimeout: keepAlivePeriod, } } else { @@ -230,7 +220,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea transport = &http.Transport{ DialTLSContext: httpDialContext, DialContext: httpDialContext, - IdleConnTimeout: connIdleTimeout, + IdleConnTimeout: net.ConnIdleTimeout, // chunked transfer download with KeepAlives is buggy with // http.Client and our custom dial context. DisableKeepAlives: true, diff --git a/transport/internet/tls/config.pb.go b/transport/internet/tls/config.pb.go index 43053c78..bc45dc4e 100644 --- a/transport/internet/tls/config.pb.go +++ b/transport/internet/tls/config.pb.go @@ -207,7 +207,7 @@ type Config struct { // @Critical PinnedPeerCertificateChainSha256 [][]byte `protobuf:"bytes,13,rep,name=pinned_peer_certificate_chain_sha256,json=pinnedPeerCertificateChainSha256,proto3" json:"pinned_peer_certificate_chain_sha256,omitempty"` // @Document Some certificate public key sha256 hashes. - // @Document After normal validation (required), if the verified cert's public key hash does not match any of these values, the connection will be aborted. + // @Document After normal validation (required), if one of certs in verified chain matches one of these values, the connection will be eventually accepted. // @Critical PinnedPeerCertificatePublicKeySha256 [][]byte `protobuf:"bytes,14,rep,name=pinned_peer_certificate_public_key_sha256,json=pinnedPeerCertificatePublicKeySha256,proto3" json:"pinned_peer_certificate_public_key_sha256,omitempty"` MasterKeyLog string `protobuf:"bytes,15,opt,name=master_key_log,json=masterKeyLog,proto3" json:"master_key_log,omitempty"` diff --git a/transport/internet/tls/config.proto b/transport/internet/tls/config.proto index c52d0be1..3fac25af 100644 --- a/transport/internet/tls/config.proto +++ b/transport/internet/tls/config.proto @@ -76,7 +76,7 @@ message Config { repeated bytes pinned_peer_certificate_chain_sha256 = 13; /* @Document Some certificate public key sha256 hashes. - @Document After normal validation (required), if the verified cert's public key hash does not match any of these values, the connection will be aborted. + @Document After normal validation (required), if one of certs in verified chain matches one of these values, the connection will be eventually accepted. @Critical */ repeated bytes pinned_peer_certificate_public_key_sha256 = 14;