github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/transport/internet/xtls/config.go (about) 1 // +build !confonly 2 3 package xtls 4 5 import ( 6 "crypto/x509" 7 "sync" 8 "time" 9 10 xtls "github.com/xtls/go" 11 12 "v2ray.com/core/common/net" 13 "v2ray.com/core/common/protocol/tls/cert" 14 "v2ray.com/core/transport/internet" 15 ) 16 17 var ( 18 globalSessionCache = xtls.NewLRUClientSessionCache(128) 19 ) 20 21 // ParseCertificate converts a cert.Certificate to Certificate. 22 func ParseCertificate(c *cert.Certificate) *Certificate { 23 certPEM, keyPEM := c.ToPEM() 24 return &Certificate{ 25 Certificate: certPEM, 26 Key: keyPEM, 27 } 28 } 29 30 func (c *Config) loadSelfCertPool() (*x509.CertPool, error) { 31 root := x509.NewCertPool() 32 for _, cert := range c.Certificate { 33 if !root.AppendCertsFromPEM(cert.Certificate) { 34 return nil, newError("failed to append cert").AtWarning() 35 } 36 } 37 return root, nil 38 } 39 40 // BuildCertificates builds a list of TLS certificates from proto definition. 41 func (c *Config) BuildCertificates() []xtls.Certificate { 42 certs := make([]xtls.Certificate, 0, len(c.Certificate)) 43 for _, entry := range c.Certificate { 44 if entry.Usage != Certificate_ENCIPHERMENT { 45 continue 46 } 47 keyPair, err := xtls.X509KeyPair(entry.Certificate, entry.Key) 48 if err != nil { 49 newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog() 50 continue 51 } 52 certs = append(certs, keyPair) 53 } 54 return certs 55 } 56 57 func isCertificateExpired(c *xtls.Certificate) bool { 58 if c.Leaf == nil && len(c.Certificate) > 0 { 59 if pc, err := x509.ParseCertificate(c.Certificate[0]); err == nil { 60 c.Leaf = pc 61 } 62 } 63 64 // If leaf is not there, the certificate is probably not used yet. We trust user to provide a valid certificate. 65 return c.Leaf != nil && c.Leaf.NotAfter.Before(time.Now().Add(-time.Minute)) 66 } 67 68 func issueCertificate(rawCA *Certificate, domain string) (*xtls.Certificate, error) { 69 parent, err := cert.ParseCertificate(rawCA.Certificate, rawCA.Key) 70 if err != nil { 71 return nil, newError("failed to parse raw certificate").Base(err) 72 } 73 newCert, err := cert.Generate(parent, cert.CommonName(domain), cert.DNSNames(domain)) 74 if err != nil { 75 return nil, newError("failed to generate new certificate for ", domain).Base(err) 76 } 77 newCertPEM, newKeyPEM := newCert.ToPEM() 78 cert, err := xtls.X509KeyPair(newCertPEM, newKeyPEM) 79 return &cert, err 80 } 81 82 func (c *Config) getCustomCA() []*Certificate { 83 certs := make([]*Certificate, 0, len(c.Certificate)) 84 for _, certificate := range c.Certificate { 85 if certificate.Usage == Certificate_AUTHORITY_ISSUE { 86 certs = append(certs, certificate) 87 } 88 } 89 return certs 90 } 91 92 func getGetCertificateFunc(c *xtls.Config, ca []*Certificate) func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) { 93 var access sync.RWMutex 94 95 return func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) { 96 domain := hello.ServerName 97 certExpired := false 98 99 access.RLock() 100 certificate, found := c.NameToCertificate[domain] 101 access.RUnlock() 102 103 if found { 104 if !isCertificateExpired(certificate) { 105 return certificate, nil 106 } 107 certExpired = true 108 } 109 110 if certExpired { 111 newCerts := make([]xtls.Certificate, 0, len(c.Certificates)) 112 113 access.Lock() 114 for _, certificate := range c.Certificates { 115 if !isCertificateExpired(&certificate) { 116 newCerts = append(newCerts, certificate) 117 } 118 } 119 120 c.Certificates = newCerts 121 access.Unlock() 122 } 123 124 var issuedCertificate *xtls.Certificate 125 126 // Create a new certificate from existing CA if possible 127 for _, rawCert := range ca { 128 if rawCert.Usage == Certificate_AUTHORITY_ISSUE { 129 newCert, err := issueCertificate(rawCert, domain) 130 if err != nil { 131 newError("failed to issue new certificate for ", domain).Base(err).WriteToLog() 132 continue 133 } 134 135 access.Lock() 136 c.Certificates = append(c.Certificates, *newCert) 137 issuedCertificate = &c.Certificates[len(c.Certificates)-1] 138 access.Unlock() 139 break 140 } 141 } 142 143 if issuedCertificate == nil { 144 return nil, newError("failed to create a new certificate for ", domain) 145 } 146 147 access.Lock() 148 c.BuildNameToCertificate() 149 access.Unlock() 150 151 return issuedCertificate, nil 152 } 153 } 154 155 func (c *Config) parseServerName() string { 156 return c.ServerName 157 } 158 159 // GetXTLSConfig converts this Config into xtls.Config. 160 func (c *Config) GetXTLSConfig(opts ...Option) *xtls.Config { 161 root, err := c.getCertPool() 162 if err != nil { 163 newError("failed to load system root certificate").AtError().Base(err).WriteToLog() 164 } 165 166 config := &xtls.Config{ 167 ClientSessionCache: globalSessionCache, 168 RootCAs: root, 169 InsecureSkipVerify: c.AllowInsecure, 170 NextProtos: c.NextProtocol, 171 SessionTicketsDisabled: c.DisableSessionResumption, 172 } 173 if c == nil { 174 return config 175 } 176 177 for _, opt := range opts { 178 opt(config) 179 } 180 181 config.Certificates = c.BuildCertificates() 182 config.BuildNameToCertificate() 183 184 caCerts := c.getCustomCA() 185 if len(caCerts) > 0 { 186 config.GetCertificate = getGetCertificateFunc(config, caCerts) 187 } 188 189 if sn := c.parseServerName(); len(sn) > 0 { 190 config.ServerName = sn 191 } 192 193 if len(config.NextProtos) == 0 { 194 config.NextProtos = []string{"h2", "http/1.1"} 195 } 196 197 return config 198 } 199 200 // Option for building XTLS config. 201 type Option func(*xtls.Config) 202 203 // WithDestination sets the server name in XTLS config. 204 func WithDestination(dest net.Destination) Option { 205 return func(config *xtls.Config) { 206 if dest.Address.Family().IsDomain() && config.ServerName == "" { 207 config.ServerName = dest.Address.Domain() 208 } 209 } 210 } 211 212 // WithNextProto sets the ALPN values in XTLS config. 213 func WithNextProto(protocol ...string) Option { 214 return func(config *xtls.Config) { 215 if len(config.NextProtos) == 0 { 216 config.NextProtos = protocol 217 } 218 } 219 } 220 221 // ConfigFromStreamSettings fetches Config from stream settings. Nil if not found. 222 func ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config { 223 if settings == nil { 224 return nil 225 } 226 config, ok := settings.SecuritySettings.(*Config) 227 if !ok { 228 return nil 229 } 230 return config 231 }