Initial commit (code only without large binaries)
This commit is contained in:
200
EdgeCommon/pkg/serverconfigs/sslconfigs/ssl_cert_config.go
Normal file
200
EdgeCommon/pkg/serverconfigs/sslconfigs/ssl_cert_config.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package sslconfigs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SSLCertConfig SSL证书
|
||||
type SSLCertConfig struct {
|
||||
Id int64 `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Description string `yaml:"description" json:"description"` // 说明
|
||||
CertData []byte `yaml:"certData" json:"certData"` // 证书数据
|
||||
KeyData []byte `yaml:"keyData" json:"keyData"` // 密钥数据
|
||||
ServerName string `yaml:"serverName" json:"serverName"` // 证书使用的主机名,在请求TLS服务器时需要
|
||||
IsCA bool `yaml:"isCA" json:"isCA"` // 是否为CA证书
|
||||
IsACME bool `yaml:"isACME" json:"isACME"` // 是否通过ACME协议免费申请
|
||||
|
||||
// 以下是从证书中分析所得
|
||||
TimeBeginAt int64 `yaml:"timeBeginAt" json:"timeBeginAt"`
|
||||
TimeEndAt int64 `yaml:"timeEndAt" json:"timeEndAt"`
|
||||
DNSNames []string `yaml:"dnsNames" json:"dnsNames"`
|
||||
CommonNames []string `yaml:"commonNames" json:"commonNames"`
|
||||
|
||||
// OCSP
|
||||
OCSP []byte `yaml:"ocsp" json:"ocsp"`
|
||||
OCSPExpiresAt int64 `yaml:"ocspExpiresAt" json:"ocspExpiresAt"`
|
||||
OCSPError string `yaml:"ocspError" json:"ocspError"`
|
||||
|
||||
cert *tls.Certificate
|
||||
caCerts []*x509.Certificate
|
||||
timeBegin time.Time
|
||||
timeEnd time.Time
|
||||
}
|
||||
|
||||
// Init 校验
|
||||
func (this *SSLCertConfig) Init(ctx context.Context) error {
|
||||
// 如果没有指定数据, 则从ctx中读取数据
|
||||
if ctx != nil && len(this.CertData) < 128 {
|
||||
var dataMapOne = ctx.Value("DataMap")
|
||||
if dataMapOne != nil && !reflect.ValueOf(dataMapOne).IsNil() {
|
||||
dataMap, ok := dataMapOne.(*shared.DataMap)
|
||||
if !ok {
|
||||
return errors.New("SSLCertConfig.init(): invalid 'DataMap' in context")
|
||||
}
|
||||
if dataMap != nil { // 再次检查是否为nil
|
||||
this.KeyData = dataMap.Read(this.KeyData)
|
||||
this.CertData = dataMap.Read(this.CertData)
|
||||
this.OCSP = dataMap.Read(this.OCSP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var commonNames []string // 发行组织
|
||||
var dnsNames []string // 域名
|
||||
|
||||
this.caCerts = []*x509.Certificate{}
|
||||
|
||||
// 分析证书
|
||||
if this.IsCA { // CA证书
|
||||
var data = this.CertData
|
||||
|
||||
var index = -1
|
||||
this.cert = &tls.Certificate{
|
||||
Certificate: [][]byte{},
|
||||
}
|
||||
for {
|
||||
index++
|
||||
|
||||
block, rest := pem.Decode(data)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
this.cert.Certificate = append(this.cert.Certificate, block.Bytes)
|
||||
data = rest
|
||||
c, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c == nil {
|
||||
return errors.New("no available certificates in file")
|
||||
}
|
||||
this.caCerts = append(this.caCerts, c)
|
||||
|
||||
for _, dnsName := range c.DNSNames {
|
||||
if !lists.ContainsString(dnsNames, dnsName) {
|
||||
dnsNames = append(dnsNames, dnsName)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ipAddress := range c.IPAddresses {
|
||||
if ipAddress == nil {
|
||||
continue
|
||||
}
|
||||
var ipAddressString = ipAddress.String()
|
||||
if !lists.ContainsString(dnsNames, ipAddressString) {
|
||||
dnsNames = append(dnsNames, ipAddressString)
|
||||
}
|
||||
}
|
||||
|
||||
commonNames = append(commonNames, c.Issuer.CommonName)
|
||||
|
||||
if index == 0 {
|
||||
this.timeBegin = c.NotBefore
|
||||
this.timeEnd = c.NotAfter
|
||||
}
|
||||
|
||||
if len(rest) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else { // 证书+私钥
|
||||
cert, err := tls.X509KeyPair(this.CertData, this.KeyData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load certificate '%s' failed: %w", strconv.FormatInt(this.Id, 10), err)
|
||||
}
|
||||
|
||||
for index, data := range cert.Certificate {
|
||||
c, err := x509.ParseCertificate(data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if cert.Leaf == nil {
|
||||
cert.Leaf = c
|
||||
}
|
||||
|
||||
for _, dnsName := range c.DNSNames {
|
||||
if !lists.ContainsString(dnsNames, dnsName) {
|
||||
dnsNames = append(dnsNames, dnsName)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ipAddress := range c.IPAddresses {
|
||||
if ipAddress == nil {
|
||||
continue
|
||||
}
|
||||
var ipAddressString = ipAddress.String()
|
||||
if !lists.ContainsString(dnsNames, ipAddressString) {
|
||||
dnsNames = append(dnsNames, ipAddressString)
|
||||
}
|
||||
}
|
||||
|
||||
commonNames = append(commonNames, c.Issuer.CommonName)
|
||||
|
||||
if index == 0 {
|
||||
this.timeBegin = c.NotBefore
|
||||
this.timeEnd = c.NotAfter
|
||||
}
|
||||
}
|
||||
|
||||
this.cert = &cert
|
||||
}
|
||||
|
||||
// 赋值分析结果
|
||||
this.DNSNames = dnsNames
|
||||
this.CommonNames = commonNames
|
||||
this.TimeBeginAt = this.timeBegin.Unix()
|
||||
this.TimeEndAt = this.timeEnd.Unix()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MatchDomain 校验是否匹配某个域名
|
||||
func (this *SSLCertConfig) MatchDomain(domain string) bool {
|
||||
if len(this.DNSNames) == 0 {
|
||||
return false
|
||||
}
|
||||
return configutils.MatchDomains(this.DNSNames, domain)
|
||||
}
|
||||
|
||||
// CertObject 获取证书对象
|
||||
func (this *SSLCertConfig) CertObject() *tls.Certificate {
|
||||
return this.cert
|
||||
}
|
||||
|
||||
func (this *SSLCertConfig) CACerts() []*x509.Certificate {
|
||||
return this.caCerts
|
||||
}
|
||||
|
||||
// TimeBegin 开始时间
|
||||
func (this *SSLCertConfig) TimeBegin() time.Time {
|
||||
return this.timeBegin
|
||||
}
|
||||
|
||||
// TimeEnd 结束时间
|
||||
func (this *SSLCertConfig) TimeEnd() time.Time {
|
||||
return this.timeEnd
|
||||
}
|
||||
Reference in New Issue
Block a user