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") } }