package tlscert import ( "crypto/rand" "crypto/x509" "encoding/pem" "os" "path/filepath" "runtime" "strings" "testing" "time" ) func tlsTestClock() time.Time { return time.Date(2026, 8, 14, 0, 0, 0, 0, time.UTC) } func TestGenerateCSRActivateAndReload(t *testing.T) { root := filepath.Join(t.TempDir(), "library") activeCert := filepath.Join(t.TempDir(), "active.crt") activeKey := filepath.Join(filepath.Dir(activeCert), "active.key") repository, err := Open(Options{Root: root, ActiveCert: activeCert, ActiveKey: activeKey, Clock: tlsTestClock}) if err != nil { t.Fatal(err) } created, err := repository.Generate("rack-console", Subject{Country: "KR", Organization: "TERA", CommonName: "console.example.local", Email: "ops@example.local"}) if err != nil { t.Fatal(err) } if created.KeyBits != 2048 || created.CommonName != "console.example.local" || !created.PrivateKeyStored { t.Fatalf("generated metadata = %#v", created) } csrPEM, err := repository.CSR(created.CertificateID, Subject{CommonName: "console.example.local", Organization: "TERA"}) if err != nil { t.Fatal(err) } block, _ := pem.Decode(csrPEM) if block == nil { t.Fatal("CSR is not PEM encoded") } csr, err := x509.ParseCertificateRequest(block.Bytes) if err != nil || csr.CheckSignature() != nil || csr.Subject.CommonName != "console.example.local" { t.Fatalf("CSR parse/signature = %#v, %v", csr, err) } if _, err := repository.Activate(created.CertificateID); err != nil { t.Fatal(err) } if info, err := os.Stat(activeKey); err != nil || runtime.GOOS != "windows" && info.Mode().Perm() != 0o600 { t.Fatalf("active key mode = %v, %v", info, err) } reloaded, err := Open(Options{Root: root, ActiveCert: activeCert, ActiveKey: activeKey, Clock: tlsTestClock}) if err != nil { t.Fatal(err) } if metadata, err := reloaded.Metadata(created.CertificateID); err != nil || metadata.FingerprintSHA256 != created.FingerprintSHA256 { t.Fatalf("reloaded metadata = %#v, %v", metadata, err) } } func TestImportEncryptedPEMAndRejectMismatchedKey(t *testing.T) { source, err := Open(Options{Clock: tlsTestClock}) if err != nil { t.Fatal(err) } first, err := generateRecord("first", Subject{CommonName: "first.local"}, "generated", tlsTestClock()) if err != nil { t.Fatal(err) } second, err := generateRecord("second", Subject{CommonName: "second.local"}, "generated", tlsTestClock()) if err != nil { t.Fatal(err) } keyBlock, _ := pem.Decode(first.keyPEM) encrypted, err := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", keyBlock.Bytes, []byte("secret-passphrase"), x509.PEMCipherAES256) if err != nil { t.Fatal(err) } metadata, err := source.Import(ImportRequest{CertificateID: "encrypted", CertificatePEM: first.certPEM, PrivateKeyPEM: pem.EncodeToMemory(encrypted), Password: "secret-passphrase"}) if err != nil || metadata.CertificateID != "encrypted" { t.Fatalf("encrypted import = %#v, %v", metadata, err) } if _, err := source.Import(ImportRequest{CertificateID: "mismatch", CertificatePEM: first.certPEM, PrivateKeyPEM: second.keyPEM}); err == nil || !strings.Contains(err.Error(), "does not match") { t.Fatalf("mismatched import error = %v", err) } } func TestRepositoryBoundsNamesAndFactoryDeletion(t *testing.T) { repository, err := Open(Options{Clock: tlsTestClock}) if err != nil { t.Fatal(err) } if _, err := repository.Generate("../escape", Subject{CommonName: "bad.local"}); err == nil { t.Fatal("unsafe certificate id accepted") } if err := repository.Delete(FactoryCertificateID); err == nil { t.Fatal("factory certificate deletion accepted") } }