Files
goutils/certlib/certgen/config_test.go
Kyle Isom 5dbb46c3ee Add AIA fields (OCSPServer, IssuingCertificateURL) to certgen.Profile
The Profile struct now supports optional OCSPServer and
IssuingCertificateURL fields. When populated, these are set on the
x509.Certificate template as Authority Information Access extensions
before signing. Empty slices are omitted.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:49:28 -07:00

189 lines
4.6 KiB
Go

package certgen
import (
"slices"
"testing"
)
func TestIsFQDN(t *testing.T) {
tests := []struct {
input string
want bool
}{
{"example.com", true},
{"sub.example.com", true},
{"example.com.", true}, // trailing dot
{"localhost", false}, // no dot
{"", false},
{"foo bar.com", false}, // space
{"-bad.com", false}, // leading hyphen
{"bad-.com", false}, // trailing hyphen
{"a..b.com", false}, // empty label
}
for _, tt := range tests {
got := isFQDN(tt.input)
if got != tt.want {
t.Errorf("isFQDN(%q) = %v, want %v", tt.input, got, tt.want)
}
}
}
func TestRequestAddsFQDNAsDNSSAN(t *testing.T) {
creq := &CertificateRequest{
KeySpec: KeySpec{Algorithm: "ecdsa", Size: 256},
Subject: Subject{
CommonName: "example.com",
Organization: "Test Org",
},
Profile: Profile{
Expiry: "1h",
},
}
_, req, err := creq.Generate()
if err != nil {
t.Fatalf("Generate() error: %v", err)
}
if !slices.Contains(req.DNSNames, "example.com") {
t.Errorf("expected DNS SAN to contain %q, got %v", "example.com", req.DNSNames)
}
}
func TestRequestFQDNNotDuplicated(t *testing.T) {
creq := &CertificateRequest{
KeySpec: KeySpec{Algorithm: "ecdsa", Size: 256},
Subject: Subject{
CommonName: "example.com",
Organization: "Test Org",
DNSNames: []string{"example.com", "www.example.com"},
},
Profile: Profile{
Expiry: "1h",
},
}
_, req, err := creq.Generate()
if err != nil {
t.Fatalf("Generate() error: %v", err)
}
count := 0
for _, name := range req.DNSNames {
if name == "example.com" {
count++
}
}
if count != 1 {
t.Errorf("expected exactly 1 occurrence of %q in DNS SANs, got %d: %v", "example.com", count, req.DNSNames)
}
}
func TestProfileAIAFieldsInCertificate(t *testing.T) {
caKey := KeySpec{Algorithm: "ecdsa", Size: 256}
_, caPriv, err := caKey.Generate()
if err != nil {
t.Fatalf("generate CA key: %v", err)
}
caProfile := Profile{
IsCA: true,
PathLen: 1,
KeyUse: []string{"cert sign", "crl sign"},
Expiry: "8760h",
}
caReq := &CertificateRequest{
KeySpec: caKey,
Subject: Subject{CommonName: "Test CA", Organization: "Test"},
Profile: caProfile,
}
caCSR, err := caReq.Request(caPriv)
if err != nil {
t.Fatalf("generate CA CSR: %v", err)
}
caCert, err := caProfile.SelfSign(caCSR, caPriv)
if err != nil {
t.Fatalf("self-sign CA: %v", err)
}
leafProfile := Profile{
KeyUse: []string{"digital signature"},
ExtKeyUsages: []string{"server auth"},
Expiry: "24h",
OCSPServer: []string{"https://ocsp.example.com"},
IssuingCertificateURL: []string{"https://pki.example.com/ca.pem"},
}
leafReq := &CertificateRequest{
KeySpec: KeySpec{Algorithm: "ecdsa", Size: 256},
Subject: Subject{CommonName: "leaf.example.com", Organization: "Test"},
Profile: leafProfile,
}
_, leafCSR, err := leafReq.Generate()
if err != nil {
t.Fatalf("generate leaf CSR: %v", err)
}
leafCert, err := leafProfile.SignRequest(caCert, leafCSR, caPriv)
if err != nil {
t.Fatalf("sign leaf: %v", err)
}
if len(leafCert.OCSPServer) != 1 || leafCert.OCSPServer[0] != "https://ocsp.example.com" {
t.Errorf("OCSPServer = %v, want [https://ocsp.example.com]", leafCert.OCSPServer)
}
if len(leafCert.IssuingCertificateURL) != 1 || leafCert.IssuingCertificateURL[0] != "https://pki.example.com/ca.pem" {
t.Errorf("IssuingCertificateURL = %v, want [https://pki.example.com/ca.pem]", leafCert.IssuingCertificateURL)
}
}
func TestProfileWithoutAIAOmitsExtension(t *testing.T) {
profile := Profile{
KeyUse: []string{"digital signature"},
ExtKeyUsages: []string{"server auth"},
Expiry: "24h",
}
creq := &CertificateRequest{
KeySpec: KeySpec{Algorithm: "ecdsa", Size: 256},
Subject: Subject{CommonName: "noaia.example.com", Organization: "Test"},
Profile: profile,
}
cert, _, err := GenerateSelfSigned(creq)
if err != nil {
t.Fatalf("generate: %v", err)
}
if len(cert.OCSPServer) != 0 {
t.Errorf("OCSPServer = %v, want empty", cert.OCSPServer)
}
if len(cert.IssuingCertificateURL) != 0 {
t.Errorf("IssuingCertificateURL = %v, want empty", cert.IssuingCertificateURL)
}
}
func TestRequestNonFQDNCommonNameNotAdded(t *testing.T) {
creq := &CertificateRequest{
KeySpec: KeySpec{Algorithm: "ecdsa", Size: 256},
Subject: Subject{
CommonName: "localhost",
Organization: "Test Org",
},
Profile: Profile{
Expiry: "1h",
},
}
_, req, err := creq.Generate()
if err != nil {
t.Fatalf("Generate() error: %v", err)
}
if slices.Contains(req.DNSNames, "localhost") {
t.Errorf("expected DNS SANs to not contain %q, got %v", "localhost", req.DNSNames)
}
}