package certs import ( "crypto/x509" "os" "testing" ) func TestCertManagerCAAndCert(t *testing.T) { tmpDir, err := os.MkdirTemp("", "certs-test-*") if err != nil { t.Fatalf("failed creating temp dir: %v", err) } defer os.RemoveAll(tmpDir) cm, err := NewCertManager(tmpDir) if err != nil { t.Fatalf("NewCertManager failed: %v", err) } // 1. Create CA caInfo, err := cm.CreateCA(CreateCARequest{ Name: "root-ca", CommonName: "DebTik Test Root CA", Organization: "Test Org", Days: 365, }) if err != nil { t.Fatalf("CreateCA failed: %v", err) } if !caInfo.IsCA || caInfo.Name != "root-ca" { t.Fatalf("Unexpected CA info: %+v", caInfo) } // 2. Issue server cert signed by root-ca certInfo, err := cm.CreateCertificate(CreateCertRequest{ Name: "web-cert", CommonName: "router.lan", CAName: "root-ca", SANs: []string{"127.0.0.1", "192.168.1.1", "router.local"}, Days: 90, IsServer: true, }) if err != nil { t.Fatalf("CreateCertificate failed: %v", err) } if certInfo.IsCA || certInfo.Issuer != "root-ca" { t.Fatalf("Unexpected cert info: %+v", certInfo) } // 3. Verify TLS KeyPair loading tlsCert, err := cm.GetTLSCertificate("web-cert") if err != nil { t.Fatalf("GetTLSCertificate failed: %v", err) } if len(tlsCert.Certificate) < 2 { t.Fatalf("Expected cert chain of at least 2 certs (cert + CA), got %d", len(tlsCert.Certificate)) } // Verify x509 chain against root-ca caPEM, _, err := cm.ExportPEM("root-ca") if err != nil { t.Fatalf("ExportPEM CA failed: %v", err) } roots := x509.NewCertPool() if !roots.AppendCertsFromPEM([]byte(caPEM)) { t.Fatalf("Failed to append CA PEM to pool") } serverCert, err := x509.ParseCertificate(tlsCert.Certificate[0]) if err != nil { t.Fatalf("Parse server cert failed: %v", err) } opts := x509.VerifyOptions{ Roots: roots, DNSName: "router.lan", } if _, err := serverCert.Verify(opts); err != nil { t.Fatalf("Cert verification failed: %v", err) } // 4. Test Export PEM certPEM, keyPEM, err := cm.ExportPEM("web-cert") if err != nil { t.Fatalf("ExportPEM web-cert failed: %v", err) } if len(certPEM) == 0 || len(keyPEM) == 0 { t.Fatalf("ExportPEM returned empty") } // 5. Test Import importInfo, err := cm.ImportCertificate(ImportCertRequest{ Name: "imported-cert", CertPEM: certPEM, KeyPEM: keyPEM, Comment: "imported test", }) if err != nil { t.Fatalf("ImportCertificate failed: %v", err) } if importInfo.CommonName != "router.lan" { t.Fatalf("Imported cert common name mismatch: %s", importInfo.CommonName) } // 6. Test Delete if err := cm.DeleteCertificate("imported-cert"); err != nil { t.Fatalf("DeleteCertificate failed: %v", err) } if _, err := cm.GetCertificate("imported-cert"); err == nil { t.Fatalf("Expected error getting deleted certificate") } } func TestCertManagerPersistence(t *testing.T) { tmpDir, err := os.MkdirTemp("", "certs-persist-*") if err != nil { t.Fatalf("failed creating temp dir: %v", err) } defer os.RemoveAll(tmpDir) cm1, err := NewCertManager(tmpDir) if err != nil { t.Fatalf("NewCertManager failed: %v", err) } _, err = cm1.CreateCA(CreateCARequest{Name: "persisted-ca", CommonName: "Persisted CA"}) if err != nil { t.Fatalf("CreateCA failed: %v", err) } // New manager with same dir should reload metadata cm2, err := NewCertManager(tmpDir) if err != nil { t.Fatalf("Reload NewCertManager failed: %v", err) } c, err := cm2.GetCertificate("persisted-ca") if err != nil { t.Fatalf("Failed to retrieve persisted CA: %v", err) } if c.Name != "persisted-ca" || !c.IsCA { t.Fatalf("Persisted CA mismatch: %+v", c) } }