161 lines
4.2 KiB
Go
161 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"database/sql"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ParseCertificateExtrakt Ablaufdatum und CA-Status aus einem PEM-Zertifikat
|
|
// Gibt zurück: expiresAt, isIntermediate, error
|
|
func ParseCertificate(certPEM string) (time.Time, bool, error) {
|
|
block, _ := pem.Decode([]byte(certPEM))
|
|
if block == nil {
|
|
return time.Time{}, false, fmt.Errorf("fehler beim Dekodieren des PEM-Blocks")
|
|
}
|
|
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
return time.Time{}, false, fmt.Errorf("fehler beim Parsen des Zertifikats: %v", err)
|
|
}
|
|
|
|
expiresAt := cert.NotAfter
|
|
// Ein Zertifikat ist Intermediate wenn IsCA=true ist
|
|
isIntermediate := cert.IsCA
|
|
|
|
return expiresAt, isIntermediate, nil
|
|
}
|
|
|
|
// SplitCertificateChain trennt eine PEM-Zertifikatskette in einzelne Zertifikate
|
|
// Gibt zurück: leafCert (PEM), intermediateCert (PEM), error
|
|
func SplitCertificateChain(certChainPEM string) (string, string, error) {
|
|
var leafCert string
|
|
var intermediateCert string
|
|
|
|
// Dekodiere alle PEM-Blöcke aus der Kette
|
|
var blocks []*pem.Block
|
|
rest := []byte(certChainPEM)
|
|
for {
|
|
block, remaining := pem.Decode(rest)
|
|
if block == nil {
|
|
break
|
|
}
|
|
if block.Type == "CERTIFICATE" {
|
|
blocks = append(blocks, block)
|
|
}
|
|
rest = remaining
|
|
}
|
|
|
|
if len(blocks) == 0 {
|
|
return "", "", fmt.Errorf("keine Zertifikate in der Kette gefunden")
|
|
}
|
|
|
|
// Parse jedes Zertifikat und trenne nach IsCA
|
|
for _, block := range blocks {
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
continue // Überspringe ungültige Zertifikate
|
|
}
|
|
|
|
// Encode zurück zu PEM
|
|
certPEM := string(pem.EncodeToMemory(block))
|
|
|
|
if cert.IsCA {
|
|
// Intermediate CA
|
|
if intermediateCert != "" {
|
|
// Wenn bereits ein Intermediate vorhanden ist, hänge es an (kann mehrere geben)
|
|
intermediateCert += "\n" + certPEM
|
|
} else {
|
|
intermediateCert = certPEM
|
|
}
|
|
} else {
|
|
// Leaf Certificate
|
|
if leafCert != "" {
|
|
// Wenn bereits ein Leaf vorhanden ist, verwende das erste (sollte nur eines geben)
|
|
continue
|
|
}
|
|
leafCert = certPEM
|
|
}
|
|
}
|
|
|
|
return leafCert, intermediateCert, nil
|
|
}
|
|
|
|
// GetCertificateIssuer extrahiert den Issuer-Namen aus einem PEM-Zertifikat
|
|
// Gibt zurück: issuerName (string), error
|
|
func GetCertificateIssuer(certPEM string) (string, error) {
|
|
block, _ := pem.Decode([]byte(certPEM))
|
|
if block == nil {
|
|
return "", fmt.Errorf("fehler beim Dekodieren des PEM-Blocks")
|
|
}
|
|
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
return "", fmt.Errorf("fehler beim Parsen des Zertifikats: %v", err)
|
|
}
|
|
|
|
return cert.Issuer.String(), nil
|
|
}
|
|
|
|
// GetProviderNameFromIssuer bestimmt den Provider-Namen basierend auf dem Issuer
|
|
func GetProviderNameFromIssuer(issuer string) string {
|
|
issuerLower := fmt.Sprintf("%v", issuer)
|
|
if strings.Contains(issuerLower, "Let's Encrypt") || strings.Contains(issuerLower, "letsencrypt") {
|
|
return "Let's Encrypt"
|
|
}
|
|
if strings.Contains(issuerLower, "DigiCert") {
|
|
return "DigiCert"
|
|
}
|
|
if strings.Contains(issuerLower, "GlobalSign") {
|
|
return "GlobalSign"
|
|
}
|
|
if strings.Contains(issuerLower, "Sectigo") {
|
|
return "Sectigo"
|
|
}
|
|
if strings.Contains(issuerLower, "GoDaddy") {
|
|
return "GoDaddy"
|
|
}
|
|
// Fallback: Gib den Issuer-Namen zurück
|
|
return issuer
|
|
}
|
|
|
|
// CheckExistingValidCertificate prüft ob bereits ein gültiges Zertifikat für einen FQDN existiert
|
|
// Gibt zurück: exists (bool), expiresAt (time.Time), error
|
|
func CheckExistingValidCertificate(fqdnID, spaceID string) (bool, time.Time, error) {
|
|
var certPEM string
|
|
var expiresAtStr sql.NullString
|
|
err := db.QueryRow(`
|
|
SELECT certificate_pem, expires_at
|
|
FROM certificates
|
|
WHERE fqdn_id = ? AND space_id = ? AND status = 'issued'
|
|
ORDER BY created_at DESC
|
|
LIMIT 1
|
|
`, fqdnID, spaceID).Scan(&certPEM, &expiresAtStr)
|
|
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return false, time.Time{}, nil
|
|
}
|
|
return false, time.Time{}, err
|
|
}
|
|
|
|
// Wenn expires_at bereits in DB vorhanden ist, verwende es
|
|
if expiresAtStr.Valid && expiresAtStr.String != "" {
|
|
expiresAt, err := time.Parse("2006-01-02 15:04:05", expiresAtStr.String)
|
|
if err == nil {
|
|
return true, expiresAt, nil
|
|
}
|
|
}
|
|
|
|
// Sonst parse das Zertifikat
|
|
expiresAt, _, err := ParseCertificate(certPEM)
|
|
if err != nil {
|
|
return true, time.Time{}, err
|
|
}
|
|
|
|
return true, expiresAt, nil
|
|
}
|