github.com/v2fly/v2ray-core/v4@v4.45.2/transport/internet/tls/config.go (about) 1 //go:build !confonly 2 // +build !confonly 3 4 package tls 5 6 import ( 7 "crypto/hmac" 8 "crypto/tls" 9 "crypto/x509" 10 "encoding/base64" 11 "strings" 12 "sync" 13 "time" 14 15 "github.com/v2fly/v2ray-core/v4/common/net" 16 "github.com/v2fly/v2ray-core/v4/common/protocol/tls/cert" 17 "github.com/v2fly/v2ray-core/v4/transport/internet" 18 ) 19 20 var globalSessionCache = tls.NewLRUClientSessionCache(128) 21 22 const exp8357 = "experiment:8357" 23 24 // ParseCertificate converts a cert.Certificate to Certificate. 25 func ParseCertificate(c *cert.Certificate) *Certificate { 26 if c != nil { 27 certPEM, keyPEM := c.ToPEM() 28 return &Certificate{ 29 Certificate: certPEM, 30 Key: keyPEM, 31 } 32 } 33 return nil 34 } 35 36 func (c *Config) loadSelfCertPool() (*x509.CertPool, error) { 37 root := x509.NewCertPool() 38 for _, cert := range c.Certificate { 39 /* Do not treat client certificate authority as a peer certificate authority. 40 This is designed to prevent a client certificate with a permissive key usage from being used to attacker server. 41 In next release, the certificate usage will be enforced strictly. 42 Only a certificate with AUTHORITY_VERIFY usage will be accepted. 43 */ 44 if cert.Usage == Certificate_AUTHORITY_VERIFY_CLIENT { 45 continue 46 } 47 if !root.AppendCertsFromPEM(cert.Certificate) { 48 return nil, newError("failed to append cert").AtWarning() 49 } 50 } 51 return root, nil 52 } 53 54 func (c *Config) loadSelfCertPoolClientCA() (*x509.CertPool, error) { 55 root := x509.NewCertPool() 56 for _, cert := range c.Certificate { 57 /* Do not treat client certificate authority as a peer certificate authority. 58 This is designed to prevent a client certificate with a permissive key usage from being used to attacker server. 59 In next release, the certificate usage will be enforced strictly. 60 Only a certificate with AUTHORITY_VERIFY usage will be accepted. 61 */ 62 if cert.Usage != Certificate_AUTHORITY_VERIFY_CLIENT { 63 continue 64 } 65 if !root.AppendCertsFromPEM(cert.Certificate) { 66 return nil, newError("failed to append cert").AtWarning() 67 } 68 } 69 return root, nil 70 } 71 72 // BuildCertificates builds a list of TLS certificates from proto definition. 73 func (c *Config) BuildCertificates() []tls.Certificate { 74 certs := make([]tls.Certificate, 0, len(c.Certificate)) 75 for _, entry := range c.Certificate { 76 if entry.Usage != Certificate_ENCIPHERMENT { 77 continue 78 } 79 keyPair, err := tls.X509KeyPair(entry.Certificate, entry.Key) 80 if err != nil { 81 newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog() 82 continue 83 } 84 certs = append(certs, keyPair) 85 } 86 return certs 87 } 88 89 func isCertificateExpired(c *tls.Certificate) bool { 90 if c.Leaf == nil && len(c.Certificate) > 0 { 91 if pc, err := x509.ParseCertificate(c.Certificate[0]); err == nil { 92 c.Leaf = pc 93 } 94 } 95 96 // If leaf is not there, the certificate is probably not used yet. We trust user to provide a valid certificate. 97 return c.Leaf != nil && c.Leaf.NotAfter.Before(time.Now().Add(time.Minute*2)) 98 } 99 100 func issueCertificate(rawCA *Certificate, domain string) (*tls.Certificate, error) { 101 parent, err := cert.ParseCertificate(rawCA.Certificate, rawCA.Key) 102 if err != nil { 103 return nil, newError("failed to parse raw certificate").Base(err) 104 } 105 newCert, err := cert.Generate(parent, cert.CommonName(domain), cert.DNSNames(domain)) 106 if err != nil { 107 return nil, newError("failed to generate new certificate for ", domain).Base(err) 108 } 109 newCertPEM, newKeyPEM := newCert.ToPEM() 110 cert, err := tls.X509KeyPair(newCertPEM, newKeyPEM) 111 return &cert, err 112 } 113 114 func (c *Config) getCustomCA() []*Certificate { 115 certs := make([]*Certificate, 0, len(c.Certificate)) 116 for _, certificate := range c.Certificate { 117 if certificate.Usage == Certificate_AUTHORITY_ISSUE { 118 certs = append(certs, certificate) 119 } 120 } 121 return certs 122 } 123 124 func getGetCertificateFunc(c *tls.Config, ca []*Certificate) func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { 125 var access sync.RWMutex 126 127 return func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { 128 domain := hello.ServerName 129 certExpired := false 130 131 access.RLock() 132 certificate, found := c.NameToCertificate[domain] 133 access.RUnlock() 134 135 if found { 136 if !isCertificateExpired(certificate) { 137 return certificate, nil 138 } 139 certExpired = true 140 } 141 142 if certExpired { 143 newCerts := make([]tls.Certificate, 0, len(c.Certificates)) 144 145 access.Lock() 146 for _, certificate := range c.Certificates { 147 cert := certificate 148 if !isCertificateExpired(&cert) { 149 newCerts = append(newCerts, cert) 150 } else if cert.Leaf != nil { 151 expTime := cert.Leaf.NotAfter.Format(time.RFC3339) 152 newError("old certificate for ", domain, " (expire on ", expTime, ") discard").AtInfo().WriteToLog() 153 } 154 } 155 156 c.Certificates = newCerts 157 access.Unlock() 158 } 159 160 var issuedCertificate *tls.Certificate 161 162 // Create a new certificate from existing CA if possible 163 for _, rawCert := range ca { 164 if rawCert.Usage == Certificate_AUTHORITY_ISSUE { 165 newCert, err := issueCertificate(rawCert, domain) 166 if err != nil { 167 newError("failed to issue new certificate for ", domain).Base(err).WriteToLog() 168 continue 169 } 170 parsed, err := x509.ParseCertificate(newCert.Certificate[0]) 171 if err == nil { 172 newCert.Leaf = parsed 173 expTime := parsed.NotAfter.Format(time.RFC3339) 174 newError("new certificate for ", domain, " (expire on ", expTime, ") issued").AtInfo().WriteToLog() 175 } else { 176 newError("failed to parse new certificate for ", domain).Base(err).WriteToLog() 177 } 178 179 access.Lock() 180 c.Certificates = append(c.Certificates, *newCert) 181 issuedCertificate = &c.Certificates[len(c.Certificates)-1] 182 access.Unlock() 183 break 184 } 185 } 186 187 if issuedCertificate == nil { 188 return nil, newError("failed to create a new certificate for ", domain) 189 } 190 191 access.Lock() 192 c.BuildNameToCertificate() 193 access.Unlock() 194 195 return issuedCertificate, nil 196 } 197 } 198 199 func (c *Config) IsExperiment8357() bool { 200 return strings.HasPrefix(c.ServerName, exp8357) 201 } 202 203 func (c *Config) parseServerName() string { 204 if c.IsExperiment8357() { 205 return c.ServerName[len(exp8357):] 206 } 207 208 return c.ServerName 209 } 210 211 func (c *Config) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 212 if c.PinnedPeerCertificateChainSha256 != nil { 213 hashValue := GenerateCertChainHash(rawCerts) 214 for _, v := range c.PinnedPeerCertificateChainSha256 { 215 if hmac.Equal(hashValue, v) { 216 return nil 217 } 218 } 219 return newError("peer cert is unrecognized: ", base64.StdEncoding.EncodeToString(hashValue)) 220 } 221 return nil 222 } 223 224 // GetTLSConfig converts this Config into tls.Config. 225 func (c *Config) GetTLSConfig(opts ...Option) *tls.Config { 226 root, err := c.getCertPool() 227 if err != nil { 228 newError("failed to load system root certificate").AtError().Base(err).WriteToLog() 229 } 230 231 clientRoot, err := c.loadSelfCertPoolClientCA() 232 if err != nil { 233 newError("failed to load client root certificate").AtError().Base(err).WriteToLog() 234 } 235 236 if c == nil { 237 return &tls.Config{ 238 ClientSessionCache: globalSessionCache, 239 RootCAs: root, 240 InsecureSkipVerify: false, 241 NextProtos: nil, 242 SessionTicketsDisabled: true, 243 } 244 } 245 config := &tls.Config{ 246 ClientSessionCache: globalSessionCache, 247 RootCAs: root, 248 InsecureSkipVerify: c.AllowInsecure, 249 NextProtos: c.NextProtocol, 250 SessionTicketsDisabled: !c.EnableSessionResumption, 251 VerifyPeerCertificate: c.verifyPeerCert, 252 ClientCAs: clientRoot, 253 } 254 255 for _, opt := range opts { 256 opt(config) 257 } 258 if c.VerifyClientCertificate { 259 config.ClientAuth = tls.RequireAndVerifyClientCert 260 } 261 config.Certificates = c.BuildCertificates() 262 config.BuildNameToCertificate() 263 264 caCerts := c.getCustomCA() 265 if len(caCerts) > 0 { 266 config.GetCertificate = getGetCertificateFunc(config, caCerts) 267 } 268 269 if sn := c.parseServerName(); len(sn) > 0 { 270 config.ServerName = sn 271 } 272 273 if len(config.NextProtos) == 0 { 274 config.NextProtos = []string{"h2", "http/1.1"} 275 } 276 277 return config 278 } 279 280 // Option for building TLS config. 281 type Option func(*tls.Config) 282 283 // WithDestination sets the server name in TLS config. 284 func WithDestination(dest net.Destination) Option { 285 return func(config *tls.Config) { 286 if dest.Address.Family().IsDomain() && config.ServerName == "" { 287 config.ServerName = dest.Address.Domain() 288 } 289 } 290 } 291 292 // WithNextProto sets the ALPN values in TLS config. 293 func WithNextProto(protocol ...string) Option { 294 return func(config *tls.Config) { 295 if len(config.NextProtos) == 0 { 296 config.NextProtos = protocol 297 } 298 } 299 } 300 301 // ConfigFromStreamSettings fetches Config from stream settings. Nil if not found. 302 func ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config { 303 if settings == nil { 304 return nil 305 } 306 config, ok := settings.SecuritySettings.(*Config) 307 if !ok { 308 return nil 309 } 310 return config 311 }