diff --git a/backend/services/setup/ssl/ssl.go b/backend/services/setup/ssl/ssl.go index 870a11c9..82757412 100644 --- a/backend/services/setup/ssl/ssl.go +++ b/backend/services/setup/ssl/ssl.go @@ -295,6 +295,18 @@ func sslDomains(cfg *config.Config) []string { } return domains } + +func certificateMatchesConfiguredDomains(cert *x509.Certificate, cfg *config.Config) bool { + if cert == nil || cfg == nil { + return false + } + for _, domain := range sslDomains(cfg) { + if err := cert.VerifyHostname(domain); err != nil { + return false + } + } + return true +} func wildcardCertificateDomains(cfg *config.Config) []string { if cfg == nil { return nil @@ -509,13 +521,7 @@ func CheckSSLCrtInfo() (int, time.Time, bool, error) { return -1, time.Now(), true, errors.Wrap(err) } - nameMatchFail := true - for _, name := range cert.DNSNames { - if strings.Contains(name, "imap") { - nameMatchFail = false - break - } - } + nameMatchFail := !certificateMatchesConfiguredDomains(cert, cfg) // 检查过期时间 hours := cert.NotAfter.Sub(time.Now()).Hours() diff --git a/backend/services/setup/ssl/ssl_test.go b/backend/services/setup/ssl/ssl_test.go index 90bf342a..3d4b7225 100644 --- a/backend/services/setup/ssl/ssl_test.go +++ b/backend/services/setup/ssl/ssl_test.go @@ -1,9 +1,16 @@ package ssl import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" "fmt" - "git.pcux.cn/xuans/Smail/config" + "math/big" "testing" + "time" + + "git.pcux.cn/xuans/Smail/config" ) func TestCheckSSLCrtInfo(t *testing.T) { @@ -15,3 +22,49 @@ func TestCheckSSLCrtInfo(t *testing.T) { fmt.Println(got, got1, match, err) } + +func TestCertificateMatchesConfiguredDomainsUsesHostnameVerification(t *testing.T) { + cert := createCertificateForDomains(t, []string{"example.com", "*.example.com"}) + parsed, err := x509.ParseCertificate(cert) + if err != nil { + t.Fatal(err) + } + if !certificateMatchesConfiguredDomains(parsed, &config.Config{ + Domain: "example.com", + WebDomain: "web.example.com", + Domains: []string{"example.com"}, + }) { + t.Fatal("wildcard certificate did not match configured service domains") + } + if certificateMatchesConfiguredDomains(parsed, &config.Config{ + Domain: "example.com", + WebDomain: "web.other.example.com", + Domains: []string{"example.com"}, + }) { + t.Fatal("certificate unexpectedly matched a domain outside its wildcard") + } +} + +func createCertificateForDomains(t *testing.T, domains []string) []byte { + t.Helper() + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + now := time.Now() + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: domains[0]}, + DNSNames: domains, + NotBefore: now.Add(-time.Hour), + NotAfter: now.Add(24 * time.Hour), + BasicConstraintsValid: true, + IsCA: true, + KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature, + } + der, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key) + if err != nil { + t.Fatal(err) + } + return der +}