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