1 Star 0 Fork 0

sqos/beats

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
tls.go 8.15 KB
一键复制 编辑 原始数据 按行查看 历史
Steffen Siering 提交于 2016-11-29 15:49 . Update go-ucfg (#3045)
package outputs
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"github.com/elastic/beats/libbeat/logp"
"github.com/elastic/beats/libbeat/outputs/transport"
"github.com/joeshaw/multierror"
)
var (
// ErrNotACertificate indicates a PEM file to be loaded not being a valid
// PEM file or certificate.
ErrNotACertificate = errors.New("file is not a certificate")
// ErrCertificateNoKey indicate a configuration error with missing key file
ErrCertificateNoKey = errors.New("key file not configured")
// ErrKeyNoCertificate indicate a configuration error with missing certificate file
ErrKeyNoCertificate = errors.New("certificate file not configured")
)
// TLSConfig defines config file options for TLS clients.
type TLSConfig struct {
Enabled *bool `config:"enabled"`
VerificationMode transport.TLSVerificationMode `config:"verification_mode"` // one of 'none', 'full'
Versions []transport.TLSVersion `config:"supported_protocols"`
CipherSuites []tlsCipherSuite `config:"cipher_suites"`
CAs []string `config:"certificate_authorities"`
Certificate CertificateConfig `config:",inline"`
CurveTypes []tlsCurveType `config:"curve_types"`
}
type CertificateConfig struct {
Certificate string `config:"certificate"`
Key string `config:"key"`
Passphrase string `config:"key_passphrase"`
}
type tlsCipherSuite uint16
type tlsCurveType tls.CurveID
var tlsCipherSuites = map[string]tlsCipherSuite{
"ECDHE-ECDSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
"ECDHE-ECDSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
"ECDHE-ECDSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
"ECDHE-ECDSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
"ECDHE-ECDSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),
"ECDHE-RSA-3DES-CBC3-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),
"ECDHE-RSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),
"ECDHE-RSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256),
"ECDHE-RSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),
"ECDHE-RSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),
"ECDHE-RSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA),
"RSA-3DES-CBC3-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA),
"RSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA),
"RSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_RSA_WITH_AES_128_GCM_SHA256),
"RSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_AES_256_CBC_SHA),
"RSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_RSA_WITH_AES_256_GCM_SHA384),
"RSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_RC4_128_SHA),
}
var tlsCurveTypes = map[string]tlsCurveType{
"P-256": tlsCurveType(tls.CurveP256),
"P-384": tlsCurveType(tls.CurveP384),
"P-521": tlsCurveType(tls.CurveP521),
}
func (c *TLSConfig) Validate() error {
hasCertificate := c.Certificate.Certificate != ""
hasKey := c.Certificate.Key != ""
switch {
case hasCertificate && !hasKey:
return ErrCertificateNoKey
case !hasCertificate && hasKey:
return ErrKeyNoCertificate
}
return nil
}
func (c *TLSConfig) IsEnabled() bool {
return c != nil && (c.Enabled == nil || *c.Enabled)
}
// LoadTLSConfig will load a certificate from config with all TLS based keys
// defined. If Certificate and CertificateKey are configured, client authentication
// will be configured. If no CAs are configured, the host CA will be used by go
// built-in TLS support.
func LoadTLSConfig(config *TLSConfig) (*transport.TLSConfig, error) {
if !config.IsEnabled() {
return nil, nil
}
fail := multierror.Errors{}
logFail := func(es ...error) {
for _, e := range es {
if e != nil {
fail = append(fail, e)
}
}
}
var cipherSuites []uint16
for _, suite := range config.CipherSuites {
cipherSuites = append(cipherSuites, uint16(suite))
}
var curves []tls.CurveID
for _, id := range config.CurveTypes {
curves = append(curves, tls.CurveID(id))
}
cert, err := loadCertificate(&config.Certificate)
logFail(err)
cas, errs := loadCertificateAuthorities(config.CAs)
logFail(errs...)
// fail, if any error occurred when loading certificate files
if err = fail.Err(); err != nil {
return nil, err
}
var certs []tls.Certificate
if cert != nil {
certs = []tls.Certificate{*cert}
}
// return config if no error occurred
return &transport.TLSConfig{
Versions: config.Versions,
Verification: config.VerificationMode,
Certificates: certs,
RootCAs: cas,
CipherSuites: cipherSuites,
CurvePreferences: curves,
}, nil
}
func loadCertificate(config *CertificateConfig) (*tls.Certificate, error) {
certificate := config.Certificate
key := config.Key
hasCertificate := certificate != ""
hasKey := key != ""
switch {
case hasCertificate && !hasKey:
return nil, ErrCertificateNoKey
case !hasCertificate && hasKey:
return nil, ErrKeyNoCertificate
case !hasCertificate && !hasKey:
return nil, nil
}
certPEM, err := readPEMFile(certificate, config.Passphrase)
if err != nil {
logp.Critical("Failed reading certificate file %v: %v", certificate, err)
return nil, fmt.Errorf("%v %v", err, certificate)
}
keyPEM, err := readPEMFile(key, config.Passphrase)
if err != nil {
logp.Critical("Failed reading key file %v: %v", key, err)
return nil, fmt.Errorf("%v %v", err, key)
}
cert, err := tls.X509KeyPair(certPEM, keyPEM)
if err != nil {
logp.Critical("Failed loading client certificate", err)
return nil, err
}
return &cert, nil
}
func readPEMFile(path, passphrase string) ([]byte, error) {
pass := []byte(passphrase)
var blocks []*pem.Block
content, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
for len(content) > 0 {
var block *pem.Block
block, content = pem.Decode(content)
if block == nil {
if len(blocks) == 0 {
return nil, errors.New("no pem file")
}
break
}
if x509.IsEncryptedPEMBlock(block) {
var buffer []byte
var err error
if len(pass) == 0 {
err = errors.New("No passphrase available")
} else {
// Note, decrypting pem might succeed even with wrong password, but
// only noise will be stored in buffer in this case.
buffer, err = x509.DecryptPEMBlock(block, pass)
}
if err != nil {
logp.Err("Dropping encrypted pem '%v' block read from %v. %v",
block.Type, path, err)
continue
}
// DEK-Info contains encryption info. Remove header to mark block as
// unencrypted.
delete(block.Headers, "DEK-Info")
block.Bytes = buffer
}
blocks = append(blocks, block)
}
if len(blocks) == 0 {
return nil, errors.New("no PEM blocks")
}
// re-encode available, decrypted blocks
buffer := bytes.NewBuffer(nil)
for _, block := range blocks {
err := pem.Encode(buffer, block)
if err != nil {
return nil, err
}
}
return buffer.Bytes(), nil
}
func loadCertificateAuthorities(CAs []string) (*x509.CertPool, []error) {
errors := []error{}
if len(CAs) == 0 {
return nil, nil
}
roots := x509.NewCertPool()
for _, path := range CAs {
pemData, err := ioutil.ReadFile(path)
if err != nil {
logp.Critical("Failed reading CA certificate: %v", err)
errors = append(errors, fmt.Errorf("%v reading %v", err, path))
continue
}
if ok := roots.AppendCertsFromPEM(pemData); !ok {
logp.Critical("Failed reading CA certificate: %v", err)
errors = append(errors, fmt.Errorf("%v adding %v", ErrNotACertificate, path))
continue
}
}
return roots, errors
}
func (cs *tlsCipherSuite) Unpack(s string) error {
suite, found := tlsCipherSuites[s]
if !found {
return fmt.Errorf("invalid tls cipher suite '%v'", s)
}
*cs = suite
return nil
}
func (ct *tlsCurveType) Unpack(s string) error {
t, found := tlsCurveTypes[s]
if !found {
return fmt.Errorf("invalid tls curve type '%v'", s)
}
*ct = t
return nil
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/sqos/beats.git
git@gitee.com:sqos/beats.git
sqos
beats
beats
v5.6.2

搜索帮助