github.com/Jeffail/benthos/v3@v3.65.0/lib/util/tls/type.go (about)

     1  package tls
     2  
     3  import (
     4  	"crypto/tls"
     5  	"crypto/x509"
     6  	"errors"
     7  	"os"
     8  )
     9  
    10  //------------------------------------------------------------------------------
    11  
    12  // Documentation is a markdown description of how and why to use TLS settings.
    13  const Documentation = `### TLS
    14  
    15  Custom TLS settings can be used to override system defaults. This includes
    16  providing a collection of root certificate authorities, providing a list of
    17  client certificates to use for client verification and skipping certificate
    18  verification.
    19  
    20  Client certificates can either be added by file or by raw contents:
    21  
    22  ` + "``` yaml" + `
    23  enabled: true
    24  client_certs:
    25    - cert_file: ./example.pem
    26      key_file: ./example.key
    27    - cert: foo
    28      key: bar
    29  ` + "```" + ``
    30  
    31  //------------------------------------------------------------------------------
    32  
    33  // ClientCertConfig contains config fields for a client certificate.
    34  type ClientCertConfig struct {
    35  	CertFile string `json:"cert_file" yaml:"cert_file"`
    36  	KeyFile  string `json:"key_file" yaml:"key_file"`
    37  	Cert     string `json:"cert" yaml:"cert"`
    38  	Key      string `json:"key" yaml:"key"`
    39  }
    40  
    41  // Config contains configuration params for TLS.
    42  type Config struct {
    43  	Enabled             bool               `json:"enabled" yaml:"enabled"`
    44  	RootCAs             string             `json:"root_cas" yaml:"root_cas"`
    45  	RootCAsFile         string             `json:"root_cas_file" yaml:"root_cas_file"`
    46  	InsecureSkipVerify  bool               `json:"skip_cert_verify" yaml:"skip_cert_verify"`
    47  	ClientCertificates  []ClientCertConfig `json:"client_certs" yaml:"client_certs"`
    48  	EnableRenegotiation bool               `json:"enable_renegotiation" yaml:"enable_renegotiation"`
    49  }
    50  
    51  // NewConfig creates a new Config with default values.
    52  func NewConfig() Config {
    53  	return Config{
    54  		Enabled:             false,
    55  		RootCAs:             "",
    56  		RootCAsFile:         "",
    57  		InsecureSkipVerify:  false,
    58  		ClientCertificates:  []ClientCertConfig{},
    59  		EnableRenegotiation: false,
    60  	}
    61  }
    62  
    63  //------------------------------------------------------------------------------
    64  
    65  // Get returns a valid *tls.Config based on the configuration values of Config.
    66  // If none of the config fields are set then a nil config is returned.
    67  func (c *Config) Get() (*tls.Config, error) {
    68  	var tlsConf *tls.Config
    69  	initConf := func() {
    70  		if tlsConf != nil {
    71  			return
    72  		}
    73  		tlsConf = &tls.Config{
    74  			MinVersion: tls.VersionTLS12,
    75  		}
    76  	}
    77  
    78  	if len(c.RootCAs) > 0 && len(c.RootCAsFile) > 0 {
    79  		return nil, errors.New("only one field between root_cas and root_cas_file can be specified")
    80  	}
    81  
    82  	if len(c.RootCAsFile) > 0 {
    83  		caCert, err := os.ReadFile(c.RootCAsFile)
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  		initConf()
    88  		tlsConf.RootCAs = x509.NewCertPool()
    89  		tlsConf.RootCAs.AppendCertsFromPEM(caCert)
    90  	}
    91  
    92  	if len(c.RootCAs) > 0 {
    93  		initConf()
    94  		tlsConf.RootCAs = x509.NewCertPool()
    95  		tlsConf.RootCAs.AppendCertsFromPEM([]byte(c.RootCAs))
    96  	}
    97  
    98  	for _, conf := range c.ClientCertificates {
    99  		cert, err := conf.Load()
   100  		if err != nil {
   101  			return nil, err
   102  		}
   103  		initConf()
   104  		tlsConf.Certificates = append(tlsConf.Certificates, cert)
   105  	}
   106  
   107  	if c.EnableRenegotiation {
   108  		initConf()
   109  		tlsConf.Renegotiation = tls.RenegotiateFreelyAsClient
   110  	}
   111  
   112  	if c.InsecureSkipVerify {
   113  		initConf()
   114  		tlsConf.InsecureSkipVerify = true
   115  	}
   116  
   117  	return tlsConf, nil
   118  }
   119  
   120  // Load returns a TLS certificate, based on either file paths in the
   121  // config or the raw certs as strings.
   122  func (c *ClientCertConfig) Load() (tls.Certificate, error) {
   123  	if c.CertFile != "" || c.KeyFile != "" {
   124  		if c.CertFile == "" {
   125  			return tls.Certificate{}, errors.New("missing cert_file field in client certificate config")
   126  		}
   127  		if c.KeyFile == "" {
   128  			return tls.Certificate{}, errors.New("missing key_file field in client certificate config")
   129  		}
   130  		return tls.LoadX509KeyPair(c.CertFile, c.KeyFile)
   131  	}
   132  	if c.Cert == "" {
   133  		return tls.Certificate{}, errors.New("missing cert field in client certificate config")
   134  	}
   135  	if c.Key == "" {
   136  		return tls.Certificate{}, errors.New("missing key field in client certificate config")
   137  	}
   138  	return tls.X509KeyPair([]byte(c.Cert), []byte(c.Key))
   139  }
   140  
   141  //------------------------------------------------------------------------------