package checker import ( "encoding/base64" "encoding/hex" "strings" "testing" "github.com/miekg/dns" ) func TestOwnerHashHex(t *testing.T) { // RFC 7929 worked example: the SHA-256 of "hugh" truncated to 28 // bytes, hex-encoded. got := ownerHashHex("hugh") if len(got) != 56 { t.Fatalf("len = %d, want 56", len(got)) } if got != strings.ToLower(got) { t.Errorf("expected lowercase hex, got %q", got) } // Stable across calls. if ownerHashHex("hugh") != got { t.Error("ownerHashHex is not deterministic") } // Different inputs ⇒ different output. if ownerHashHex("alice") == got { t.Error("collisions across distinct inputs") } } func TestExtractOwnerPrefix(t *testing.T) { cases := []struct { owner, prefix, want string }{ {"abc123._openpgpkey.example.com.", "_openpgpkey", "abc123"}, {"ABC123._OPENPGPKEY.example.com", "_openpgpkey", "abc123"}, {"abc123._smimecert.example.com.", "_smimecert", "abc123"}, {"example.com.", "_openpgpkey", ""}, {"_openpgpkey.example.com.", "_openpgpkey", ""}, // no leading hash label {"", "_openpgpkey", ""}, } for _, c := range cases { got := extractOwnerPrefix(c.owner, c.prefix, "") if got != c.want { t.Errorf("extractOwnerPrefix(%q,%q) = %q, want %q", c.owner, c.prefix, got, c.want) } } } func TestFirstNonEmpty(t *testing.T) { if got := firstNonEmpty("", " ", "x", "y"); got != "x" { t.Errorf("got %q, want x", got) } if got := firstNonEmpty("", "", ""); got != "" { t.Errorf("got %q, want empty", got) } } func TestKindForServiceType(t *testing.T) { cases := map[string]string{ ServiceOpenPGP: KindOpenPGPKey, ServiceSMimeCert: KindSMIMEA, "abstract.Other": "", "": "", } for in, want := range cases { if got := kindForServiceType(in); got != want { t.Errorf("kindForServiceType(%q) = %q, want %q", in, got, want) } } } func TestComputeOwner(t *testing.T) { body := serviceBody{Username: "alice"} exp, rec := computeOwner(body, OpenPGPKeyPrefix, "example.com") wantPrefix := ownerHashHex("alice") + "._openpgpkey.example.com." if exp != wantPrefix { t.Errorf("expected = %q, want %q", exp, wantPrefix) } if rec != "" { t.Errorf("recorded = %q, want empty", rec) } // With a record carrying its own owner. body.OpenPGP = &dns.OPENPGPKEY{Hdr: dns.RR_Header{Name: "abc._openpgpkey.example.com."}} _, rec = computeOwner(body, OpenPGPKeyPrefix, "example.com") if rec != "abc._openpgpkey.example.com." { t.Errorf("recorded = %q", rec) } // Empty username yields empty expected owner. exp, _ = computeOwner(serviceBody{}, OpenPGPKeyPrefix, "example.com") if exp != "" { t.Errorf("expected = %q, want empty", exp) } } func TestAnyOpenPGPMatches(t *testing.T) { ref := &dns.OPENPGPKEY{PublicKey: "AAAA"} rrs := []dns.RR{ &dns.OPENPGPKEY{PublicKey: "BBBB"}, &dns.OPENPGPKEY{PublicKey: " AAAA "}, // trims whitespace } if !anyOpenPGPMatches(rrs, ref) { t.Error("expected match") } if anyOpenPGPMatches([]dns.RR{&dns.OPENPGPKEY{PublicKey: "ZZZZ"}}, ref) { t.Error("unexpected match") } // Non-OPENPGPKEY RRs are skipped silently. if anyOpenPGPMatches([]dns.RR{&dns.A{}}, ref) { t.Error("non-OPENPGPKEY RR matched") } } func TestAnySMIMEAMatches(t *testing.T) { ref := &dns.SMIMEA{Usage: 3, Selector: 0, MatchingType: 0, Certificate: "DEADBEEF"} rrs := []dns.RR{ &dns.SMIMEA{Usage: 3, Selector: 0, MatchingType: 0, Certificate: "deadbeef"}, } if !anySMIMEAMatches(rrs, ref) { t.Error("expected case-insensitive match") } rrs = []dns.RR{&dns.SMIMEA{Usage: 1, Selector: 0, MatchingType: 0, Certificate: "deadbeef"}} if anySMIMEAMatches(rrs, ref) { t.Error("usage mismatch should not match") } } func TestAnalyzeOpenPGP_NoRecord(t *testing.T) { got := analyzeOpenPGP(serviceBody{}) if got == nil || got.ParseError == "" { t.Fatalf("expected ParseError, got %+v", got) } } func TestAnalyzeOpenPGP_BadBase64(t *testing.T) { body := serviceBody{OpenPGP: &dns.OPENPGPKEY{PublicKey: "!!! not base64 !!!"}} got := analyzeOpenPGP(body) if !strings.Contains(got.ParseError, "invalid base64") { t.Errorf("ParseError = %q", got.ParseError) } } func TestAnalyzeOpenPGP_OversizePayload(t *testing.T) { // A base64 payload whose decoded size would exceed the cap. raw := make([]byte, maxKeyMaterialBytes+1024) body := serviceBody{OpenPGP: &dns.OPENPGPKEY{PublicKey: base64.StdEncoding.EncodeToString(raw)}} got := analyzeOpenPGP(body) if !strings.Contains(got.ParseError, "exceeds") { t.Errorf("expected size-limit ParseError, got %q", got.ParseError) } // And we never tried to actually parse it as a keyring. if got.EntityCount != 0 { t.Errorf("EntityCount = %d, want 0", got.EntityCount) } } func TestAnalyzeOpenPGP_GarbageBytes(t *testing.T) { // Valid base64, but not a valid OpenPGP packet stream. body := serviceBody{OpenPGP: &dns.OPENPGPKEY{PublicKey: base64.StdEncoding.EncodeToString([]byte("not a key"))}} got := analyzeOpenPGP(body) if got.ParseError == "" { t.Error("expected ParseError for garbage payload") } if got.RawSize == 0 { t.Error("RawSize should be set even on parse failure") } } func TestAnalyzeSMIMEA_NoRecord(t *testing.T) { got := analyzeSMIMEA(serviceBody{}) if got == nil || got.ParseError == "" { t.Fatalf("expected ParseError, got %+v", got) } } func TestAnalyzeSMIMEA_DigestOnly(t *testing.T) { body := serviceBody{SMIMEA: &dns.SMIMEA{Usage: 3, Selector: 0, MatchingType: 1, Certificate: "abcd"}} got := analyzeSMIMEA(body) if got.ParseError != "" { t.Errorf("digest-only should not error: %q", got.ParseError) } if got.Certificate != nil || got.PublicKey != nil { t.Error("digest-only should not populate Certificate/PublicKey") } if got.HashHex != "abcd" { t.Errorf("HashHex = %q", got.HashHex) } } func TestAnalyzeSMIMEA_BadHex(t *testing.T) { body := serviceBody{SMIMEA: &dns.SMIMEA{Usage: 3, Selector: 0, MatchingType: 0, Certificate: "ZZZZ"}} got := analyzeSMIMEA(body) if got.ParseError == "" { t.Error("expected ParseError for invalid hex") } } func TestAnalyzeSMIMEA_OversizePayload(t *testing.T) { huge := strings.Repeat("ab", maxKeyMaterialBytes+1024) body := serviceBody{SMIMEA: &dns.SMIMEA{Usage: 3, Selector: 0, MatchingType: 0, Certificate: huge}} got := analyzeSMIMEA(body) if !strings.Contains(got.ParseError, "exceeds") { t.Errorf("expected size-limit ParseError, got %q", got.ParseError) } } func TestAnalyzeSMIMEA_NotACertificate(t *testing.T) { body := serviceBody{SMIMEA: &dns.SMIMEA{ Usage: 3, Selector: 0, MatchingType: 0, Certificate: hex.EncodeToString([]byte("not a DER cert")), }} got := analyzeSMIMEA(body) if got.ParseError == "" { t.Error("expected ParseError for non-cert bytes") } }