1// +build !confonly 2 3package tls 4 5import ( 6 "crypto/tls" 7 "crypto/x509" 8 "strings" 9 "sync" 10 "time" 11 12 "github.com/v2fly/v2ray-core/v4/common/net" 13 "github.com/v2fly/v2ray-core/v4/common/protocol/tls/cert" 14 "github.com/v2fly/v2ray-core/v4/transport/internet" 15) 16 17var ( 18 globalSessionCache = tls.NewLRUClientSessionCache(128) 19) 20 21const exp8357 = "experiment:8357" 22 23// ParseCertificate converts a cert.Certificate to Certificate. 24func 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 35func (c *Config) loadSelfCertPool() (*x509.CertPool, error) { 36 root := x509.NewCertPool() 37 for _, cert := range c.Certificate { 38 if !root.AppendCertsFromPEM(cert.Certificate) { 39 return nil, newError("failed to append cert").AtWarning() 40 } 41 } 42 return root, nil 43} 44 45// BuildCertificates builds a list of TLS certificates from proto definition. 46func (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 62func 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)) 71} 72 73func 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 87func (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 97func 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 } 124 } 125 126 c.Certificates = newCerts 127 access.Unlock() 128 } 129 130 var issuedCertificate *tls.Certificate 131 132 // Create a new certificate from existing CA if possible 133 for _, rawCert := range ca { 134 if rawCert.Usage == Certificate_AUTHORITY_ISSUE { 135 newCert, err := issueCertificate(rawCert, domain) 136 if err != nil { 137 newError("failed to issue new certificate for ", domain).Base(err).WriteToLog() 138 continue 139 } 140 141 access.Lock() 142 c.Certificates = append(c.Certificates, *newCert) 143 issuedCertificate = &c.Certificates[len(c.Certificates)-1] 144 access.Unlock() 145 break 146 } 147 } 148 149 if issuedCertificate == nil { 150 return nil, newError("failed to create a new certificate for ", domain) 151 } 152 153 access.Lock() 154 c.BuildNameToCertificate() 155 access.Unlock() 156 157 return issuedCertificate, nil 158 } 159} 160 161func (c *Config) IsExperiment8357() bool { 162 return strings.HasPrefix(c.ServerName, exp8357) 163} 164 165func (c *Config) parseServerName() string { 166 if c.IsExperiment8357() { 167 return c.ServerName[len(exp8357):] 168 } 169 170 return c.ServerName 171} 172 173// GetTLSConfig converts this Config into tls.Config. 174func (c *Config) GetTLSConfig(opts ...Option) *tls.Config { 175 root, err := c.getCertPool() 176 if err != nil { 177 newError("failed to load system root certificate").AtError().Base(err).WriteToLog() 178 } 179 180 if c == nil { 181 return &tls.Config{ 182 ClientSessionCache: globalSessionCache, 183 RootCAs: root, 184 InsecureSkipVerify: false, 185 NextProtos: nil, 186 SessionTicketsDisabled: true, 187 } 188 } 189 190 config := &tls.Config{ 191 ClientSessionCache: globalSessionCache, 192 RootCAs: root, 193 InsecureSkipVerify: c.AllowInsecure, 194 NextProtos: c.NextProtocol, 195 SessionTicketsDisabled: !c.EnableSessionResumption, 196 } 197 198 for _, opt := range opts { 199 opt(config) 200 } 201 202 config.Certificates = c.BuildCertificates() 203 config.BuildNameToCertificate() 204 205 caCerts := c.getCustomCA() 206 if len(caCerts) > 0 { 207 config.GetCertificate = getGetCertificateFunc(config, caCerts) 208 } 209 210 if sn := c.parseServerName(); len(sn) > 0 { 211 config.ServerName = sn 212 } 213 214 if len(config.NextProtos) == 0 { 215 config.NextProtos = []string{"h2", "http/1.1"} 216 } 217 218 return config 219} 220 221// Option for building TLS config. 222type Option func(*tls.Config) 223 224// WithDestination sets the server name in TLS config. 225func WithDestination(dest net.Destination) Option { 226 return func(config *tls.Config) { 227 if dest.Address.Family().IsDomain() && config.ServerName == "" { 228 config.ServerName = dest.Address.Domain() 229 } 230 } 231} 232 233// WithNextProto sets the ALPN values in TLS config. 234func WithNextProto(protocol ...string) Option { 235 return func(config *tls.Config) { 236 if len(config.NextProtos) == 0 { 237 config.NextProtos = protocol 238 } 239 } 240} 241 242// ConfigFromStreamSettings fetches Config from stream settings. Nil if not found. 243func ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config { 244 if settings == nil { 245 return nil 246 } 247 config, ok := settings.SecuritySettings.(*Config) 248 if !ok { 249 return nil 250 } 251 return config 252} 253