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