Files
goacme/main.go
2025-04-29 09:42:42 +02:00

177 lines
5.1 KiB
Go

package main
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strings"
"golang.org/x/crypto/acme"
"golang.org/x/crypto/acme/autocert"
)
// Diese Variablen halten die Pfade zum CA-Zertifikat und zum privaten Schlüssel
const (
CA_CERT_PATH = "/path/to/your/ca_cert.pem" // Pfad zu Ihrem CA-Zertifikat
CA_KEY_PATH = "/path/to/your/ca_key.pem" // Pfad zu Ihrem privaten CA-Schlüssel
)
var (
privateKey interface{}
caCert *x509.Certificate
)
func loadCACertificate() error {
// CA-Zertifikat laden
certPEM, err := os.ReadFile(CA_CERT_PATH)
if err != nil {
return fmt.Errorf("error reading CA cert: %v", err)
}
caCert, err = x509.ParseCertificate(certPEM)
if err != nil {
return fmt.Errorf("error parsing CA cert: %v", err)
}
// CA-Schlüssel laden (private key)
keyPEM, err := os.ReadFile(CA_KEY_PATH)
if err != nil {
return fmt.Errorf("error reading CA key: %v", err)
}
privateKey, err = parsePrivateKey(keyPEM)
if err != nil {
return fmt.Errorf("error parsing CA key: %v", err)
}
return nil
}
func loadEd25519PrivateKey(filePath string) (ed25519.PrivateKey, error) {
// Lese die Datei
keyData, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("failed to read private key file: %v", err)
}
// Stelle sicher, dass der Schlüssel als Seed vorliegt (32 Bytes)
if len(keyData) != ed25519.SeedSize {
return nil, fmt.Errorf("invalid seed size for ed25519 key: expected 32 bytes")
}
// Ed25519-Schlüssel aus dem Seed erstellen
privKey := ed25519.NewKeyFromSeed(keyData)
return privKey, nil
}
// Funktion zum Parsen des privaten Schlüssels (RSA, ECDSA, Ed25519)
func parsePrivateKey(keyPEM []byte) (interface{}, error) {
// Versuche RSA-Private-Key zu laden
if key, err := x509.ParsePKCS1PrivateKey(keyPEM); err == nil {
return key, nil
}
// Versuche ECDSA-Private-Key zu laden
if key, err := x509.ParseECPrivateKey(keyPEM); err == nil {
return key, nil
}
// Versuche Ed25519-Private-Key zu laden
if key, err := loadEd25519PrivateKey(string(keyPEM)); err == nil {
return key, nil
}
return nil, fmt.Errorf("unknown private key format")
}
// Funktion zur Zertifikatserstellung, die das CA-Zertifikat verwendet
func signCertificate(cert *x509.Certificate) ([]byte, error) {
// Sie können hier das CA-Zertifikat und den privaten Schlüssel verwenden,
// um das Zertifikat zu signieren. Zum Beispiel:
if rsaKey, ok := privateKey.(*rsa.PrivateKey); ok {
return x509.CreateCertificate(rand.Reader, cert, caCert, rsaKey.Public(), rsaKey)
} else if ecdsaKey, ok := privateKey.(*ecdsa.PrivateKey); ok {
return x509.CreateCertificate(rand.Reader, cert, caCert, ecdsaKey.Public(), ecdsaKey)
} else if ed25519Key, ok := privateKey.(ed25519.PrivateKey); ok {
return x509.CreateCertificate(rand.Reader, cert, caCert, ed25519Key.Public(), ed25519Key)
}
return nil, fmt.Errorf("unsupported private key type")
}
func handleACME(w http.ResponseWriter, r *http.Request) {
acmeHandler := autocert.NewManager()
acmeHandler.HostPolicy = autocert.HostWhitelist("example.com") // Passe die Domain an
// POST-Anforderung für new-order
if r.Method == http.MethodPost && strings.Contains(r.URL.Path, "/new-order") {
handleNewOrder(w, r)
return
}
acmeHandler.HTTPHandler(nil).ServeHTTP(w, r)
}
func handleNewOrder(w http.ResponseWriter, r *http.Request) {
// Sicherstellen, dass es eine JSON-Anfrage ist
if r.Header.Get("Content-Type") != "application/json" {
http.Error(w, "Content-Type must be application/json", http.StatusBadRequest)
return
}
var order acme.Order
// Anfrage decodieren
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&order); err != nil {
http.Error(w, fmt.Sprintf("Error decoding request: %v", err), http.StatusBadRequest)
return
}
// Validierung der Domain
if len(order.Identifiers) == 0 || !strings.HasSuffix(order.Identifiers[0].Value, ".stadt-hilden.de") {
http.Error(w, "Invalid domain", http.StatusUnauthorized)
return
}
// Antwort für den ACME-Client erstellen
orderURL := fmt.Sprintf("http://localhost:8080/acme/order/%d", 1234)
response := struct {
Status string `json:"status"`
Expires string `json:"expires"`
URL string `json:"url"`
}{
Status: "pending", // Bestellung ist noch ausstehend
Expires: "2025-01-01T00:00:00Z", // Beispielablaufdatum
URL: orderURL,
}
// JSON-Antwort zurückgeben
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, fmt.Sprintf("Error encoding response: %v", err), http.StatusInternalServerError)
return
}
}
func main() {
// CA-Zertifikat und privaten Schlüssel laden
if err := loadCACertificate(); err != nil {
log.Fatalf("Error loading CA certificate: %v", err)
}
// Ihr ACME-Server-Setup fortführen
http.HandleFunc("/acme", handleACME)
// Server starten
port := "8080"
fmt.Printf("Starting ACME server on :%s...\n", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}