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  }