Procházet zdrojové kódy

重构证书管理代码

将 `acme` 包中的证书管理和申请相关代码迁移到新的 `certssl` 包中,并删除了旧的 `acme` 包。这样可以更好地组织和维护代码结构。
SongZihuan před 3 měsíci
rodič
revize
0e016915ce

+ 2 - 1
.gitignore

@@ -12,4 +12,5 @@ testdata
 
 pkg
 
-http-demo
+http-demo
+.htaccess

+ 0 - 1
.htaccess

@@ -1 +0,0 @@
-# 请将伪静态规则或自定义Apache配置填写到此处

+ 0 - 197
src/acme/newcert.go

@@ -1,197 +0,0 @@
-package acme
-
-import (
-	"bytes"
-	"crypto"
-	"crypto/ecdsa"
-	"crypto/elliptic"
-	"crypto/rand"
-	"crypto/x509"
-	"encoding/gob"
-	"encoding/pem"
-	"fmt"
-	"github.com/go-acme/lego/v4/certcrypto"
-	"github.com/go-acme/lego/v4/certificate"
-	"github.com/go-acme/lego/v4/challenge/http01"
-	"github.com/go-acme/lego/v4/lego"
-	"github.com/go-acme/lego/v4/registration"
-	"net"
-	"os"
-	"path"
-	"time"
-)
-
-func saveAccount(dir string, email string, reg *registration.Resource) error {
-	filepath := path.Join(dir, fmt.Sprintf("%s.account", email))
-
-	var buff bytes.Buffer
-	enc := gob.NewEncoder(&buff)
-	err := enc.Encode(reg)
-	if err != nil {
-		return err
-	}
-
-	return os.WriteFile(filepath, buff.Bytes(), 0644)
-}
-
-func loadAccount(dir string, email string) (*registration.Resource, error) {
-	filepath := path.Join(dir, fmt.Sprintf("%s.account", email))
-	file, err := os.Open(filepath)
-	if err != nil {
-		return nil, err
-	}
-	defer func() {
-		_ = file.Close()
-	}()
-
-	var reg registration.Resource
-	dec := gob.NewDecoder(file)
-
-	err = dec.Decode(&reg)
-	if err != nil {
-		return nil, err
-	}
-
-	return &reg, nil
-}
-
-func newCert(dir string, email string, httpsAddress string, domain string) (crypto.PrivateKey, *certificate.Resource, error) {
-	privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	user := NewUser(email, privateKey)
-
-	config := lego.NewConfig(user)
-	config.Certificate.KeyType = certcrypto.RSA4096
-	config.Certificate.Timeout = 30 * 24 * time.Hour
-	client, err := lego.NewClient(config)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	iface, port, err := net.SplitHostPort(httpsAddress)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer(domain, port))
-	if err != nil {
-		return nil, nil, err
-	}
-
-	regOption := registration.RegisterOptions{
-		TermsOfServiceAgreed: true,
-	}
-
-	reg, err := loadAccount(path.Join(dir, "account"), email)
-	if err != nil {
-		// 尝试注册
-		reg, err = client.Registration.Register(regOption)
-		if err != nil {
-			return nil, nil, err
-		}
-
-		err = saveAccount(dir, email, reg)
-		if err != nil {
-			return nil, nil, err
-		}
-	}
-	user.setRegistration(reg)
-
-	if domain == "" {
-		domain = iface
-	}
-
-	request := certificate.ObtainRequest{
-		Domains: []string{domain},
-		Bundle:  true,
-	}
-
-	certificates, err := client.Certificate.Obtain(request)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	return privateKey, certificates, nil
-}
-
-func getCert(resource *certificate.Resource) (*x509.Certificate, error) {
-	block, _ := pem.Decode(resource.Certificate)
-	if block == nil || block.Type != "CERTIFICATE" {
-		return nil, fmt.Errorf("failed to decode PEM block containing certificate")
-	}
-
-	cert, err := x509.ParseCertificate(block.Bytes)
-	if err != nil {
-		return nil, fmt.Errorf("failed to parse certificate: %v", err)
-	}
-
-	return cert, nil
-}
-
-func writerWithDate(baseDir string, resource *certificate.Resource) error {
-	cert, err := getCert(resource)
-	if err != nil {
-		return err
-	}
-
-	domain := cert.Subject.CommonName
-	if domain == "" && len(cert.DNSNames) == 0 {
-		return fmt.Errorf("no domains in certificate")
-	}
-	domain = cert.DNSNames[0]
-
-	year := fmt.Sprintf("%d", cert.NotBefore.Year())
-	month := fmt.Sprintf("%d", cert.NotBefore.Month())
-	day := fmt.Sprintf("%d", cert.NotBefore.Day())
-
-	dir := path.Join(baseDir, domain, year, month, day)
-
-	err = os.WriteFile(path.Join(dir, FilePrivateKey), resource.PrivateKey, os.ModePerm)
-	if err != nil {
-		return err
-	}
-
-	err = os.WriteFile(path.Join(dir, FileCertificate), resource.Certificate, os.ModePerm)
-	if err != nil {
-		return err
-	}
-
-	err = os.WriteFile(path.Join(dir, FileIssuerCertificate), resource.IssuerCertificate, os.ModePerm)
-	if err != nil {
-		return err
-	}
-
-	err = os.WriteFile(path.Join(dir, FileCSR), resource.CSR, os.ModePerm)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func writer(dir string, resource *certificate.Resource) error {
-	err := os.WriteFile(path.Join(dir, FilePrivateKey), resource.PrivateKey, os.ModePerm)
-	if err != nil {
-		return err
-	}
-
-	err = os.WriteFile(path.Join(dir, FileCertificate), resource.Certificate, os.ModePerm)
-	if err != nil {
-		return err
-	}
-
-	err = os.WriteFile(path.Join(dir, FileIssuerCertificate), resource.IssuerCertificate, os.ModePerm)
-	if err != nil {
-		return err
-	}
-
-	err = os.WriteFile(path.Join(dir, FileCSR), resource.CSR, os.ModePerm)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}

+ 32 - 0
src/certssl/account/data.go

@@ -0,0 +1,32 @@
+package account
+
+import (
+	"github.com/go-acme/lego/v4/lego"
+	"github.com/go-acme/lego/v4/registration"
+	"time"
+)
+
+const DefaultAccountExp = 24 * time.Hour
+
+// Account 不得包含指针
+type Account struct {
+	Resource       registration.Resource // 避免使用指针
+	Email          string
+	RegisterTime   time.Time
+	ExpirationTime time.Time
+}
+
+func newAccount(email string, client *lego.Client) (Account, error) {
+	res, err := register(client)
+	if err != nil {
+		return Account{}, err
+	}
+
+	now := time.Now()
+	return Account{
+		Resource:       *res,
+		Email:          email,
+		RegisterTime:   now,
+		ExpirationTime: now.Add(DefaultAccountExp),
+	}, nil
+}

+ 37 - 0
src/certssl/account/load.go

@@ -0,0 +1,37 @@
+package account
+
+import (
+	"encoding/gob"
+	"fmt"
+	"os"
+	"path"
+	"time"
+)
+
+var ErrExpiredAccount = fmt.Errorf("account not found")
+
+func loadAccount(dir string, email string) (Account, error) {
+	filepath := path.Join(dir, fmt.Sprintf("%s.account", email))
+
+	file, err := os.Open(filepath)
+	if err != nil {
+		return Account{}, err
+	}
+	defer func() {
+		_ = file.Close()
+	}()
+
+	var account Account
+	dec := gob.NewDecoder(file)
+
+	err = dec.Decode(&account)
+	if err != nil {
+		return Account{}, err
+	}
+
+	if time.Now().After(account.ExpirationTime) {
+		return Account{}, ErrExpiredAccount
+	}
+
+	return account, nil
+}

+ 34 - 0
src/certssl/account/main.go

@@ -0,0 +1,34 @@
+package account
+
+import (
+	"errors"
+	"github.com/go-acme/lego/v4/lego"
+	"github.com/go-acme/lego/v4/registration"
+	"os"
+	"path"
+)
+
+func GetAccount(basedir string, email string, client *lego.Client) (*registration.Resource, error) {
+	dir := path.Join(basedir, "account")
+	err := os.MkdirAll(basedir, 0775)
+	if err != nil {
+		return nil, err
+	}
+
+	account, err := loadAccount(dir, email)
+	if err != nil && errors.Is(err, ErrExpiredAccount) {
+		account, err = newAccount(email, client)
+		if err != nil {
+			return nil, err
+		}
+
+		err = saveAccount(dir, account)
+		if err != nil {
+			return nil, err
+		}
+	} else if err != nil {
+		return nil, nil
+	}
+
+	return &account.Resource, nil
+}

+ 19 - 0
src/certssl/account/register.go

@@ -0,0 +1,19 @@
+package account
+
+import (
+	"github.com/go-acme/lego/v4/lego"
+	"github.com/go-acme/lego/v4/registration"
+)
+
+func register(client *lego.Client) (*registration.Resource, error) {
+	regOption := registration.RegisterOptions{
+		TermsOfServiceAgreed: true,
+	}
+
+	reg, err := client.Registration.Register(regOption)
+	if err != nil {
+		return nil, err
+	}
+
+	return reg, nil
+}

+ 26 - 0
src/certssl/account/save.go

@@ -0,0 +1,26 @@
+package account
+
+import (
+	"bytes"
+	"encoding/gob"
+	"fmt"
+	"os"
+	"path"
+)
+
+func saveAccount(dir string, account Account) error {
+	err := os.MkdirAll(dir, 0775)
+	if err != nil {
+		return err
+	}
+	filepath := path.Join(dir, fmt.Sprintf("%s.account", account.Email))
+
+	var buff bytes.Buffer
+	enc := gob.NewEncoder(&buff)
+	err = enc.Encode(account)
+	if err != nil {
+		return err
+	}
+
+	return os.WriteFile(filepath, buff.Bytes(), 0644)
+}

+ 74 - 0
src/certssl/applycert/main.go

@@ -0,0 +1,74 @@
+package applycert
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"github.com/SongZihuan/Http-Demo/src/certssl/account"
+	"github.com/go-acme/lego/v4/certcrypto"
+	"github.com/go-acme/lego/v4/certificate"
+	"github.com/go-acme/lego/v4/challenge/http01"
+	"github.com/go-acme/lego/v4/lego"
+	"net"
+	"time"
+)
+
+func ApplyCert(basedir string, email string, httpsAddress string, domain string) (crypto.PrivateKey, *certificate.Resource, error) {
+	privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	user := newUser(email, privateKey)
+
+	config := lego.NewConfig(user)
+	config.Certificate.KeyType = certcrypto.RSA4096
+	config.Certificate.Timeout = 30 * 24 * time.Hour
+	client, err := lego.NewClient(config)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	iface, port, err := net.SplitHostPort(httpsAddress)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer(domain, port))
+	if err != nil {
+		return nil, nil, err
+	}
+
+	reg, err := account.GetAccount(basedir, user.GetEmail(), client)
+	if err != nil {
+		return nil, nil, err
+	}
+	user.setRegistration(reg)
+
+	if domain == "" {
+		domain = iface
+	}
+
+	request := certificate.ObtainRequest{
+		Domains: []string{domain},
+		Bundle:  true,
+	}
+
+	resource, err := client.Certificate.Obtain(request)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	err = writerWithDate(basedir, resource)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	err = writer(basedir, resource)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return privateKey, resource, nil
+}

+ 8 - 7
src/acme/read.go → src/certssl/applycert/read.go

@@ -1,21 +1,22 @@
-package acme
+package applycert
 
 import (
 	"crypto"
 	"crypto/x509"
 	"encoding/pem"
 	"fmt"
+	"github.com/SongZihuan/Http-Demo/src/certssl/filename"
 	"os"
 	"path"
 )
 
 func ReadLocalCertificateAndPrivateKey(dir string) (crypto.PrivateKey, *x509.Certificate, error) {
-	cert, err := ReadCertificate(dir)
+	cert, err := readCertificate(dir)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	privateKey, err := ReadPrivateKey(dir)
+	privateKey, err := readPrivateKey(dir)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -23,9 +24,9 @@ func ReadLocalCertificateAndPrivateKey(dir string) (crypto.PrivateKey, *x509.Cer
 	return privateKey, cert, nil
 }
 
-func ReadCertificate(dir string) (*x509.Certificate, error) {
+func readCertificate(dir string) (*x509.Certificate, error) {
 	// 请替换为你的证书文件路径
-	certPath := path.Join(dir, FileCertificate)
+	certPath := path.Join(dir, filename.FileCertificate)
 
 	// 读取PEM编码的证书文件
 	pemData, err := os.ReadFile(certPath)
@@ -48,9 +49,9 @@ func ReadCertificate(dir string) (*x509.Certificate, error) {
 	return cert, nil
 }
 
-func ReadPrivateKey(dir string) (crypto.PrivateKey, error) {
+func readPrivateKey(dir string) (crypto.PrivateKey, error) {
 	// 请替换为你的RSA私钥文件路径
-	keyPath := path.Join(dir, FilePrivateKey)
+	keyPath := path.Join(dir, filename.FilePrivateKey)
 
 	// 读取PEM编码的私钥文件
 	pemData, err := os.ReadFile(keyPath)

+ 2 - 2
src/acme/user.go → src/certssl/applycert/user.go

@@ -1,4 +1,4 @@
-package acme
+package applycert
 
 import (
 	"crypto"
@@ -11,7 +11,7 @@ type CertUser struct {
 	key          crypto.PrivateKey
 }
 
-func NewUser(email string, key crypto.PrivateKey) *CertUser {
+func newUser(email string, key crypto.PrivateKey) *CertUser {
 	return &CertUser{
 		email: email,
 		key:   key,

+ 84 - 0
src/certssl/applycert/write.go

@@ -0,0 +1,84 @@
+package applycert
+
+import (
+	"fmt"
+	"github.com/SongZihuan/Http-Demo/src/certssl/filename"
+	"github.com/SongZihuan/Http-Demo/utils"
+	"github.com/go-acme/lego/v4/certificate"
+	"os"
+	"path"
+)
+
+func writerWithDate(baseDir string, resource *certificate.Resource) error {
+	cert, err := utils.ReadCertificate(resource.Certificate)
+	if err != nil {
+		return err
+	}
+
+	domain := cert.Subject.CommonName
+	if domain == "" && len(cert.DNSNames) == 0 {
+		return fmt.Errorf("no domains in certificate")
+	}
+	domain = cert.DNSNames[0]
+
+	year := fmt.Sprintf("%d", cert.NotBefore.Year())
+	month := fmt.Sprintf("%d", cert.NotBefore.Month())
+	day := fmt.Sprintf("%d", cert.NotBefore.Day())
+
+	dir := path.Join(baseDir, domain, year, month, day)
+	err = os.MkdirAll(dir, 0775)
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(path.Join(dir, filename.FilePrivateKey), resource.PrivateKey, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(path.Join(dir, filename.FileCertificate), resource.Certificate, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(path.Join(dir, filename.FileIssuerCertificate), resource.IssuerCertificate, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(path.Join(dir, filename.FileCSR), resource.CSR, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func writer(dir string, resource *certificate.Resource) error {
+	err := os.MkdirAll(dir, 0775)
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(path.Join(dir, filename.FilePrivateKey), resource.PrivateKey, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(path.Join(dir, filename.FileCertificate), resource.Certificate, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(path.Join(dir, filename.FileIssuerCertificate), resource.IssuerCertificate, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(path.Join(dir, filename.FileCSR), resource.CSR, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

+ 1 - 1
src/acme/filename.go → src/certssl/filename/filename.go

@@ -1,4 +1,4 @@
-package acme
+package filename
 
 const (
 	FilePrivateKey        = "private.key"

+ 10 - 59
src/acme/ctrl.go → src/certssl/main.go

@@ -1,14 +1,15 @@
-package acme
+package certssl
 
 import (
 	"crypto"
 	"crypto/x509"
 	"fmt"
+	"github.com/SongZihuan/Http-Demo/src/certssl/applycert"
 	"github.com/SongZihuan/Http-Demo/utils"
 	"time"
 )
 
-func GetCertificateAndPrivateKey(dir string, email string, httpsAddress string, domain string) (crypto.PrivateKey, *x509.Certificate, error) {
+func GetCertificateAndPrivateKey(basedir string, email string, httpsAddress string, domain string) (crypto.PrivateKey, *x509.Certificate, error) {
 	if email == "" {
 		email = "no-reply@example.com"
 	}
@@ -21,27 +22,17 @@ func GetCertificateAndPrivateKey(dir string, email string, httpsAddress string,
 		return nil, nil, fmt.Errorf("not a valid domain")
 	}
 
-	privateKey, cert, err := ReadLocalCertificateAndPrivateKey(dir)
-	if err == nil && checkCertWithDomain(cert, domain) && checkCertWithTime(cert, 5*24*time.Hour) {
+	privateKey, cert, err := applycert.ReadLocalCertificateAndPrivateKey(basedir)
+	if err == nil && utils.CheckCertWithDomain(cert, domain) && utils.CheckCertWithTime(cert, 5*24*time.Hour) {
 		return privateKey, cert, nil
 	}
 
-	privateKey, resource, err := newCert(dir, email, httpsAddress, domain)
+	privateKey, resource, err := applycert.ApplyCert(basedir, email, httpsAddress, domain)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	err = writerWithDate(dir, resource)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	err = writer(dir, resource)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	cert, err = getCert(resource)
+	cert, err = utils.ReadCertificate(resource.Certificate)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -95,59 +86,19 @@ func watchCertificateAndPrivateKey(dir string, email string, httpsAddress string
 		return nil, nil, fmt.Errorf("not a valid domain")
 	}
 
-	if checkCertWithDomain(oldCert, domain) && checkCertWithTime(oldCert, 5*24*time.Hour) {
+	if utils.CheckCertWithDomain(oldCert, domain) && utils.CheckCertWithTime(oldCert, 5*24*time.Hour) {
 		return nil, nil, nil
 	}
 
-	privateKey, resource, err := newCert(dir, email, httpsAddress, domain)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	err = writerWithDate(dir, resource)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	err = writer(dir, resource)
+	privateKey, resource, err := applycert.ApplyCert(dir, email, httpsAddress, domain)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	cert, err := getCert(resource)
+	cert, err := utils.ReadCertificate(resource.Certificate)
 	if err != nil {
 		return nil, nil, err
 	}
 
 	return privateKey, cert, nil
 }
-
-func checkCertWithDomain(cert *x509.Certificate, domain string) bool {
-	// 遍历主题备用名称查找匹配的域名
-	for _, name := range cert.DNSNames {
-		if name == domain {
-			return true // 找到了匹配的域名
-		}
-	}
-
-	// 检查通用名作为回退,虽然现代实践倾向于使用SAN
-	if cert.Subject.CommonName != "" && cert.Subject.CommonName == domain {
-		return true // 通用名匹配
-	}
-
-	// 如果没有找到匹配,则返回错误
-	return false
-}
-
-func checkCertWithTime(cert *x509.Certificate, gracePeriod time.Duration) bool {
-	now := time.Now()
-	nowWithGracePeriod := now.Add(gracePeriod)
-
-	if now.Before(cert.NotBefore) {
-		return false
-	} else if nowWithGracePeriod.After(cert.NotBefore) {
-		return false
-	}
-
-	return false
-}

+ 4 - 4
src/httpsslserver/server.go

@@ -7,7 +7,7 @@ import (
 	"crypto/x509"
 	"errors"
 	"fmt"
-	"github.com/SongZihuan/Http-Demo/src/acme"
+	"github.com/SongZihuan/Http-Demo/src/certssl"
 	"github.com/SongZihuan/Http-Demo/src/engine"
 	"github.com/SongZihuan/Http-Demo/src/flagparser"
 	"net/http"
@@ -33,7 +33,7 @@ func InitHttpSSLServer() (err error) {
 	HttpSSLEmail = flagparser.HttpsEmail
 	HttpSSLCertDir = flagparser.HttpsCertDir
 
-	PrivateKey, Certificate, err = acme.GetCertificateAndPrivateKey(HttpSSLCertDir, HttpSSLEmail, HttpSSLAddress, HttpSSLDomain)
+	PrivateKey, Certificate, err = certssl.GetCertificateAndPrivateKey(HttpSSLCertDir, HttpSSLEmail, HttpSSLAddress, HttpSSLDomain)
 	if err != nil {
 		return err
 	}
@@ -87,10 +87,10 @@ ListenCycle:
 }
 
 func WatchCert(stopchan chan bool) {
-	newchan := make(chan acme.NewCert)
+	newchan := make(chan certssl.NewCert)
 
 	go func() {
-		err := acme.WatchCertificateAndPrivateKey(HttpSSLCertDir, HttpSSLEmail, HttpSSLAddress, HttpSSLDomain, PrivateKey, Certificate, stopchan, newchan)
+		err := certssl.WatchCertificateAndPrivateKey(HttpSSLCertDir, HttpSSLEmail, HttpSSLAddress, HttpSSLDomain, PrivateKey, Certificate, stopchan, newchan)
 		if err != nil {
 			fmt.Printf("watch cert error: %s", err.Error())
 		}

+ 52 - 0
utils/x509.go

@@ -0,0 +1,52 @@
+package utils
+
+import (
+	"crypto/x509"
+	"encoding/pem"
+	"fmt"
+	"time"
+)
+
+func ReadCertificate(data []byte) (*x509.Certificate, error) {
+	block, _ := pem.Decode(data)
+	if block == nil || block.Type != "CERTIFICATE" {
+		return nil, fmt.Errorf("failed to decode PEM block containing certificate")
+	}
+
+	cert, err := x509.ParseCertificate(block.Bytes)
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse certificate: %v", err)
+	}
+
+	return cert, nil
+}
+
+func CheckCertWithDomain(cert *x509.Certificate, domain string) bool {
+	// 遍历主题备用名称查找匹配的域名
+	for _, name := range cert.DNSNames {
+		if name == domain {
+			return true // 找到了匹配的域名
+		}
+	}
+
+	// 检查通用名作为回退,虽然现代实践倾向于使用SAN
+	if cert.Subject.CommonName != "" && cert.Subject.CommonName == domain {
+		return true // 通用名匹配
+	}
+
+	// 如果没有找到匹配,则返回错误
+	return false
+}
+
+func CheckCertWithTime(cert *x509.Certificate, gracePeriod time.Duration) bool {
+	now := time.Now()
+	nowWithGracePeriod := now.Add(gracePeriod)
+
+	if now.Before(cert.NotBefore) {
+		return false
+	} else if nowWithGracePeriod.After(cert.NotBefore) {
+		return false
+	}
+
+	return false
+}