implemented LE and ACME and fixed some bugs
This commit is contained in:
160
backend/cert_parser.go
Normal file
160
backend/cert_parser.go
Normal file
@@ -0,0 +1,160 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user