|  | @@ -2,20 +2,62 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  package tls
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -import "crypto/x509"
 | 
	
		
			
				|  |  | +import (
 | 
	
		
			
				|  |  | +	"crypto/x509"
 | 
	
		
			
				|  |  | +	"sync"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (c *Config) getCertPool() *x509.CertPool {
 | 
	
		
			
				|  |  | -	pool, err := x509.SystemCertPool()
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		newError("failed to get system cert pool.").Base(err).WriteToLog()
 | 
	
		
			
				|  |  | +	"v2ray.com/core/common/compare"
 | 
	
		
			
				|  |  | +)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +type certPoolCache struct {
 | 
	
		
			
				|  |  | +	sync.Mutex
 | 
	
		
			
				|  |  | +	once       sync.Once
 | 
	
		
			
				|  |  | +	pool       *x509.CertPool
 | 
	
		
			
				|  |  | +	extraCerts [][]byte
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (c *certPoolCache) hasCert(cert []byte) bool {
 | 
	
		
			
				|  |  | +	for _, xCert := range c.extraCerts {
 | 
	
		
			
				|  |  | +		if compare.BytesEqual(xCert, cert) {
 | 
	
		
			
				|  |  | +			return true
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	return false
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (c *certPoolCache) get(extraCerts []*Certificate) *x509.CertPool {
 | 
	
		
			
				|  |  | +	c.once.Do(func() {
 | 
	
		
			
				|  |  | +		pool, err := x509.SystemCertPool()
 | 
	
		
			
				|  |  | +		if err != nil {
 | 
	
		
			
				|  |  | +			newError("failed to get system cert pool.").Base(err).WriteToLog()
 | 
	
		
			
				|  |  | +			return
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		c.pool = pool
 | 
	
		
			
				|  |  | +	})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if c.pool == nil {
 | 
	
		
			
				|  |  |  		return nil
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	if pool != nil {
 | 
	
		
			
				|  |  | -		for _, cert := range c.Certificate {
 | 
	
		
			
				|  |  | -			if cert.Usage == Certificate_AUTHORITY_VERIFY {
 | 
	
		
			
				|  |  | -				pool.AppendCertsFromPEM(cert.Certificate)
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if len(extraCerts) == 0 {
 | 
	
		
			
				|  |  | +		return c.pool
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	c.Lock()
 | 
	
		
			
				|  |  | +	defer c.Unlock()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for _, cert := range extraCerts {
 | 
	
		
			
				|  |  | +		if !c.hasCert(cert.Certificate) {
 | 
	
		
			
				|  |  | +			c.pool.AppendCertsFromPEM(cert.Certificate)
 | 
	
		
			
				|  |  | +			c.extraCerts = append(c.extraCerts, cert.Certificate)
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	return pool
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return c.pool
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +var combineCertPool certPoolCache
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (c *Config) getCertPool() *x509.CertPool {
 | 
	
		
			
				|  |  | +	return combineCertPool.get(c.Certificate)
 | 
	
		
			
				|  |  |  }
 |