diff --git a/response.go b/response.go index 8756f44..47c64be 100644 --- a/response.go +++ b/response.go @@ -121,6 +121,23 @@ func (r *Response) ToWhoisStyleResponse() *WhoisStyleResponse { w.add("Name Server", n.LDHName) } + // "DNSSEC" + if s := d.SecureDNS; s != nil { + switch { + case s.DelegationSigned != nil: + if *s.DelegationSigned { + w.add("DNSSEC", "signedDelegation") + } else { + w.add("DNSSEC", "unsigned") + } + case len(s.DS) > 0: + // Some servers omit delegationSigned but still publish DS records. + // keyData is deliberately ignored: it is child DNSKEY data and does + // not prove the parent has published DS records. + w.add("DNSSEC", "signedDelegation") + } + } + return w } diff --git a/response_test.go b/response_test.go new file mode 100644 index 0000000..b14c6a9 --- /dev/null +++ b/response_test.go @@ -0,0 +1,49 @@ +// OpenRDAP +// Copyright 2017 Tom Harwood +// MIT License, see the LICENSE file. + +package rdap + +import "testing" + +func TestWhoisStyleDNSSEC(t *testing.T) { + yes, no := true, false + + tests := []struct { + name string + secureDNS *SecureDNS + want []string + }{ + {"no secureDNS", nil, nil}, + {"signed", &SecureDNS{DelegationSigned: &yes}, []string{"signedDelegation"}}, + {"unsigned", &SecureDNS{DelegationSigned: &no}, []string{"unsigned"}}, + {"unsigned wins over DS", &SecureDNS{DelegationSigned: &no, DS: []DSData{{}}}, []string{"unsigned"}}, + {"DS without delegationSigned", &SecureDNS{DS: []DSData{{}}}, []string{"signedDelegation"}}, + {"keyData without delegationSigned", &SecureDNS{Keys: []KeyData{{}}}, nil}, + {"empty secureDNS", &SecureDNS{}, nil}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Response{Object: &Domain{ + LDHName: "example.com", + Nameservers: []Nameserver{{LDHName: "ns1.example.com"}}, + SecureDNS: tt.secureDNS, + }} + w := r.ToWhoisStyleResponse() + + got := w.Data["DNSSEC"] + if len(got) != len(tt.want) || (len(got) == 1 && got[0] != tt.want[0]) { + t.Fatalf("DNSSEC = %v, want %v", got, tt.want) + } + + // ICANN WHOIS ordering places DNSSEC directly after the name servers. + if tt.want != nil { + order := w.KeyDisplayOrder + if order[len(order)-1] != "DNSSEC" || order[len(order)-2] != "Name Server" { + t.Fatalf("KeyDisplayOrder = %v, want DNSSEC after Name Server", order) + } + } + }) + } +}