mirror of
https://github.com/TeaOSLab/EdgeCommon.git
synced 2026-01-09 14:15:48 +08:00
208 lines
4.5 KiB
Go
208 lines
4.5 KiB
Go
|
|
package sslconfigs
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"crypto/tls"
|
|||
|
|
"crypto/x509"
|
|||
|
|
"errors"
|
|||
|
|
"github.com/iwind/TeaGo/types"
|
|||
|
|
"io/ioutil"
|
|||
|
|
"net"
|
|||
|
|
"regexp"
|
|||
|
|
"strconv"
|
|||
|
|
"strings"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// TLS Version
|
|||
|
|
type TLSVersion = string
|
|||
|
|
|
|||
|
|
// Cipher Suites
|
|||
|
|
type TLSCipherSuite = string
|
|||
|
|
|
|||
|
|
// SSL配置
|
|||
|
|
type SSLConfig struct {
|
|||
|
|
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
|
|||
|
|
|
|||
|
|
Certs []*SSLCertConfig `yaml:"certs" json:"certs"`
|
|||
|
|
ClientAuthType SSLClientAuthType `yaml:"clientAuthType" json:"clientAuthType"` // 客户端认证类型
|
|||
|
|
ClientCACertIds []string `yaml:"clientCACertIds" json:"clientCACertIds"` // 客户端认证CA
|
|||
|
|
|
|||
|
|
Listen []string `yaml:"listen" json:"listen"` // 网络地址
|
|||
|
|
MinVersion TLSVersion `yaml:"minVersion" json:"minVersion"` // 支持的最小版本
|
|||
|
|
CipherSuites []TLSCipherSuite `yaml:"cipherSuites" json:"cipherSuites"` // 加密算法套件
|
|||
|
|
|
|||
|
|
HSTS *HSTSConfig `yaml:"hsts2" json:"hsts"` // HSTS配置,yaml之所以使用hsts2,是因为要和以前的版本分开
|
|||
|
|
HTTP2Disabled bool `yaml:"http2Disabled" json:"http2Disabled"` // 是否禁用HTTP2
|
|||
|
|
|
|||
|
|
nameMapping map[string]*tls.Certificate // dnsName => cert
|
|||
|
|
|
|||
|
|
minVersion uint16
|
|||
|
|
cipherSuites []uint16
|
|||
|
|
|
|||
|
|
clientCAPool *x509.CertPool
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取新对象
|
|||
|
|
func NewSSLConfig() *SSLConfig {
|
|||
|
|
return &SSLConfig{}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 校验配置
|
|||
|
|
func (this *SSLConfig) Init() error {
|
|||
|
|
if !this.IsOn {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if len(this.Certs) == 0 {
|
|||
|
|
return errors.New("no certificates in https config")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, cert := range this.Certs {
|
|||
|
|
err := cert.Init()
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if this.Listen == nil {
|
|||
|
|
this.Listen = []string{}
|
|||
|
|
} else {
|
|||
|
|
for index, addr := range this.Listen {
|
|||
|
|
_, _, err := net.SplitHostPort(addr)
|
|||
|
|
if err != nil {
|
|||
|
|
this.Listen[index] = strings.TrimSuffix(addr, ":") + ":443"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// min version
|
|||
|
|
this.convertMinVersion()
|
|||
|
|
|
|||
|
|
// cipher suite categories
|
|||
|
|
this.initCipherSuites()
|
|||
|
|
|
|||
|
|
// hsts
|
|||
|
|
if this.HSTS != nil {
|
|||
|
|
err := this.HSTS.Init()
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CA证书
|
|||
|
|
if len(this.ClientCACertIds) > 0 && this.ClientAuthType != SSLClientAuthTypeNoClientCert {
|
|||
|
|
this.clientCAPool = x509.NewCertPool()
|
|||
|
|
list := SharedSSLCertList()
|
|||
|
|
for _, certId := range this.ClientCACertIds {
|
|||
|
|
cert := list.FindCert(certId)
|
|||
|
|
if cert == nil {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
if !cert.IsOn {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
data, err := ioutil.ReadFile(cert.FullCertPath())
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
this.clientCAPool.AppendCertsFromPEM(data)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 取得最小版本
|
|||
|
|
func (this *SSLConfig) TLSMinVersion() uint16 {
|
|||
|
|
return this.minVersion
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 套件
|
|||
|
|
func (this *SSLConfig) TLSCipherSuites() []uint16 {
|
|||
|
|
return this.cipherSuites
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 校验是否匹配某个域名
|
|||
|
|
func (this *SSLConfig) MatchDomain(domain string) (cert *tls.Certificate, ok bool) {
|
|||
|
|
for _, cert := range this.Certs {
|
|||
|
|
if cert.MatchDomain(domain) {
|
|||
|
|
return cert.CertObject(), true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return nil, false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 取得第一个证书
|
|||
|
|
func (this *SSLConfig) FirstCert() *tls.Certificate {
|
|||
|
|
for _, cert := range this.Certs {
|
|||
|
|
return cert.CertObject()
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 是否包含某个证书或密钥路径
|
|||
|
|
func (this *SSLConfig) ContainsFile(file string) bool {
|
|||
|
|
for _, cert := range this.Certs {
|
|||
|
|
if cert.CertFile == file || cert.KeyFile == file {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 删除证书文件
|
|||
|
|
func (this *SSLConfig) DeleteFiles() error {
|
|||
|
|
var resultErr error = nil
|
|||
|
|
|
|||
|
|
for _, cert := range this.Certs {
|
|||
|
|
err := cert.DeleteFiles()
|
|||
|
|
if err != nil {
|
|||
|
|
resultErr = err
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return resultErr
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查找单个证书配置
|
|||
|
|
func (this *SSLConfig) FindCert(certId string) *SSLCertConfig {
|
|||
|
|
for _, cert := range this.Certs {
|
|||
|
|
if cert.Id == certId {
|
|||
|
|
return cert
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加证书
|
|||
|
|
func (this *SSLConfig) AddCert(cert *SSLCertConfig) {
|
|||
|
|
this.Certs = append(this.Certs, cert)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CA证书Pool,用于TLS对客户端进行认证
|
|||
|
|
func (this *SSLConfig) CAPool() *x509.CertPool {
|
|||
|
|
return this.clientCAPool
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 分解所有监听地址
|
|||
|
|
func (this *SSLConfig) ParseListenAddresses() []string {
|
|||
|
|
result := []string{}
|
|||
|
|
var reg = regexp.MustCompile(`\[\s*(\d+)\s*[,:-]\s*(\d+)\s*]$`)
|
|||
|
|
for _, addr := range this.Listen {
|
|||
|
|
match := reg.FindStringSubmatch(addr)
|
|||
|
|
if len(match) == 0 {
|
|||
|
|
result = append(result, addr)
|
|||
|
|
} else {
|
|||
|
|
min := types.Int(match[1])
|
|||
|
|
max := types.Int(match[2])
|
|||
|
|
if min > max {
|
|||
|
|
min, max = max, min
|
|||
|
|
}
|
|||
|
|
for i := min; i <= max; i++ {
|
|||
|
|
newAddr := reg.ReplaceAllString(addr, ":"+strconv.Itoa(i))
|
|||
|
|
result = append(result, newAddr)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return result
|
|||
|
|
}
|