104 lines
3.4 KiB
Go
104 lines
3.4 KiB
Go
package checker
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestCCADBEmbedded asserts the shipped CSV parses cleanly. If this
|
|
// fails the build produced a broken binary, so fail loudly.
|
|
func TestCCADBEmbedded(t *testing.T) {
|
|
idx, err := loadCCADB()
|
|
if err != nil {
|
|
t.Fatalf("load embedded CCADB: %v", err)
|
|
}
|
|
if len(idx.bySKI) < 100 {
|
|
t.Errorf("expected >=100 SKI entries, got %d", len(idx.bySKI))
|
|
}
|
|
if len(idx.byDN) < 100 {
|
|
t.Errorf("expected >=100 DN entries, got %d", len(idx.byDN))
|
|
}
|
|
}
|
|
|
|
// TestLookup_LetsEncryptR10 exercises the AKI path against a well-known,
|
|
// currently-active intermediate.
|
|
func TestLookup_LetsEncryptR10(t *testing.T) {
|
|
domains, ok := Lookup("BBBCC347A5E4BCA9C6C3A4720C108DA235E1C8E8", "")
|
|
if !ok {
|
|
t.Fatal("expected Let's Encrypt R10 AKI to resolve")
|
|
}
|
|
if !slices.Contains(domains, "letsencrypt.org") {
|
|
t.Errorf("expected letsencrypt.org in domains, got %v", domains)
|
|
}
|
|
}
|
|
|
|
// TestLookup_CaseInsensitiveAKI ensures callers don't need to pre-
|
|
// uppercase the AKI.
|
|
func TestLookup_CaseInsensitiveAKI(t *testing.T) {
|
|
upper, ok := Lookup("BBBCC347A5E4BCA9C6C3A4720C108DA235E1C8E8", "")
|
|
if !ok {
|
|
t.Skip("fixture row missing from embedded CCADB")
|
|
}
|
|
lower, ok := Lookup("bbbcc347a5e4bca9c6c3a4720c108da235e1c8e8", "")
|
|
if !ok {
|
|
t.Fatal("lowercase AKI should resolve too")
|
|
}
|
|
if strings.Join(upper, ",") != strings.Join(lower, ",") {
|
|
t.Errorf("upper %v != lower %v", upper, lower)
|
|
}
|
|
}
|
|
|
|
// TestLookup_DNFallback asserts the DN path works when AKI is empty.
|
|
// We use Go's pkix.Name.String-style comma DN and expect it to match
|
|
// CCADB's semicolon DN for the same subject.
|
|
func TestLookup_DNFallback(t *testing.T) {
|
|
// The ISRG Root X2 row uses SKI 7C4296AEDE4B483BFA92F89E8CCF6D8BA9723795
|
|
// and Subject "CN=ISRG Root X2; O=Internet Security Research Group; C=US".
|
|
// Go would render the same DN with commas, so normalizeDN should
|
|
// collapse both to the same key.
|
|
domains, ok := Lookup("", "CN=ISRG Root X2,O=Internet Security Research Group,C=US")
|
|
if !ok {
|
|
t.Fatal("expected ISRG Root X2 DN to resolve via byDN index")
|
|
}
|
|
if !slices.Contains(domains, "letsencrypt.org") {
|
|
t.Errorf("expected letsencrypt.org, got %v", domains)
|
|
}
|
|
}
|
|
|
|
// TestLookup_Unknown ensures false is returned cleanly.
|
|
func TestLookup_Unknown(t *testing.T) {
|
|
if _, ok := Lookup("0000000000000000000000000000000000000000", ""); ok {
|
|
t.Error("unknown AKI must not resolve")
|
|
}
|
|
if _, ok := Lookup("", "CN=This CA Does Not Exist"); ok {
|
|
t.Error("unknown DN must not resolve")
|
|
}
|
|
if _, ok := Lookup("", ""); ok {
|
|
t.Error("empty inputs must not resolve")
|
|
}
|
|
}
|
|
|
|
// TestNormalizeDN_SortsAndUppercases exercises the canonicalization
|
|
// used by the DN fallback. This is the part most likely to miscompare
|
|
// across CSV formatting variations.
|
|
func TestNormalizeDN_SortsAndUppercases(t *testing.T) {
|
|
a := normalizeDN("CN=Foo,O=Bar,C=US")
|
|
b := normalizeDN("c=US; cn=Foo; o=Bar")
|
|
if a != b {
|
|
t.Errorf("expected canonical equality:\n a=%q\n b=%q", a, b)
|
|
}
|
|
}
|
|
|
|
// TestSplitCAADomains handles the comma-separated cell format that
|
|
// DigiCert and similar CAs use.
|
|
func TestSplitCAADomains(t *testing.T) {
|
|
got := splitCAADomains("www.digicert.com, digicert.com, amazon.com")
|
|
want := []string{"www.digicert.com", "digicert.com", "amazon.com"}
|
|
if !slices.Equal(got, want) {
|
|
t.Errorf("splitCAADomains got %v want %v", got, want)
|
|
}
|
|
if splitCAADomains("") != nil {
|
|
t.Error("empty input should yield nil")
|
|
}
|
|
}
|