github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/transport/internet/tls/config.go (about)

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