github.com/v2fly/v2ray-core/v4@v4.45.2/transport/internet/tls/config.go (about)

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