Skip to content

Commit

Permalink
target/remote: Reimplement TLSA records discovery algorithm, add tests
Browse files Browse the repository at this point in the history
Now it covers all edge cases described by RFC 7672.
  • Loading branch information
foxcpp committed Nov 29, 2020
1 parent 777b9bd commit 804d62f
Show file tree
Hide file tree
Showing 8 changed files with 350 additions and 56 deletions.
65 changes: 65 additions & 0 deletions framework/dns/dnssec.go
Expand Up @@ -203,6 +203,71 @@ func (e ExtResolver) AuthLookupTXT(ctx context.Context, name string) (ad bool, r
return
}

// CheckCNAMEAD is a special function for use in DANE lookups. It attempts to determine final
// (canonical) name of the host and also reports whether the whole chain of CNAME's and final zone
// are "secure".
//
// If there are no A or AAAA records for host, rname = "" is returned.
func (e ExtResolver) CheckCNAMEAD(ctx context.Context, host string) (ad bool, rname string, err error) {
msg := new(dns.Msg)
msg.SetQuestion(dns.Fqdn(host), dns.TypeA)
msg.SetEdns0(4096, false)
msg.AuthenticatedData = true
resp, err := e.exchange(ctx, msg)
if err != nil {
return false, "", err
}

for _, r := range resp.Answer {
switch r := r.(type) {
case *dns.A:
rname = r.Hdr.Name
ad = resp.AuthenticatedData // Use AD flag from response we used to determine rname
}
}

if rname == "" {
// IPv6-only host? Try to find out rname using AAAA lookup.
msg := new(dns.Msg)
msg.SetQuestion(dns.Fqdn(host), dns.TypeA)
msg.SetEdns0(4096, false)
msg.AuthenticatedData = true
resp, err := e.exchange(ctx, msg)
if err == nil {
for _, r := range resp.Answer {
switch r := r.(type) {
case *dns.AAAA:
rname = r.Hdr.Name
ad = resp.AuthenticatedData
}
}
}
}

return ad, rname, nil
}

func (e ExtResolver) AuthLookupCNAME(ctx context.Context, host string) (ad bool, cname string, err error) {
msg := new(dns.Msg)
msg.SetQuestion(dns.Fqdn(host), dns.TypeCNAME)
msg.SetEdns0(4096, false)
msg.AuthenticatedData = true
resp, err := e.exchange(ctx, msg)
if err != nil {
return false, "", err
}

for _, r := range resp.Answer {
cnameR, ok := r.(*dns.CNAME)
if !ok {
continue
}
return resp.AuthenticatedData, cnameR.Target, nil
}

return resp.AuthenticatedData, "", nil
}

func (e ExtResolver) AuthLookupIPAddr(ctx context.Context, host string) (ad bool, addrs []net.IPAddr, err error) {
// First, query IPv6.
msg := new(dns.Msg)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -23,7 +23,7 @@ require (
github.com/foxcpp/go-imap-i18nlevel v0.0.0-20200208001533-d6ec88553005
github.com/foxcpp/go-imap-namespace v0.0.0-20200722130255-93092adf35f1
github.com/foxcpp/go-imap-sql v0.4.1-0.20200823124337-2f57903a7ed0
github.com/foxcpp/go-mockdns v0.0.0-20200531120619-ae750bbf9d73
github.com/foxcpp/go-mockdns v0.0.0-20201129203541-9b1391edef7e
github.com/foxcpp/go-mtasts v0.0.0-20191219193356-62bc3f1f74b8
github.com/go-sql-driver/mysql v1.5.0
github.com/google/uuid v1.1.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -131,6 +131,8 @@ github.com/foxcpp/go-mockdns v0.0.0-20191216195825-5eabd8dbfe1f h1:b/CFmrdqIGU6e
github.com/foxcpp/go-mockdns v0.0.0-20191216195825-5eabd8dbfe1f/go.mod h1:tPg4cp4nseejPd+UKxtCVQ2hUxNTZ7qQZJa7CLriIeo=
github.com/foxcpp/go-mockdns v0.0.0-20200531120619-ae750bbf9d73 h1:rZE8KRqNsxz1Jqd782wLMK4FgZ8BKMwPCQjIEpA1bUs=
github.com/foxcpp/go-mockdns v0.0.0-20200531120619-ae750bbf9d73/go.mod h1:tPg4cp4nseejPd+UKxtCVQ2hUxNTZ7qQZJa7CLriIeo=
github.com/foxcpp/go-mockdns v0.0.0-20201129203541-9b1391edef7e h1:zOfwjGk0A3wTpOLNreIEXonIinY+oqJ2R0/QeAbgYmc=
github.com/foxcpp/go-mockdns v0.0.0-20201129203541-9b1391edef7e/go.mod h1:tPg4cp4nseejPd+UKxtCVQ2hUxNTZ7qQZJa7CLriIeo=
github.com/foxcpp/go-mtasts v0.0.0-20191219193356-62bc3f1f74b8 h1:k8w0iy6GP9oeSZWUH3p2DqZHaXDKZGNs3NZGZMGfQHc=
github.com/foxcpp/go-mtasts v0.0.0-20191219193356-62bc3f1f74b8/go.mod h1:HO1YOCbBM8KjpgThMMFejHx6K/UsnEv2Oh9YGtBIlOU=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
Expand Down
6 changes: 6 additions & 0 deletions internal/target/remote/dane.go
Expand Up @@ -88,6 +88,12 @@ func verifyDANE(recs []dns.TLSA, connState tls.ConnectionState) (overridePKIX bo
}
}

// Authentication is not required if all records are unusable, see
// RFC 7672 Section 2.1.1.
if len(eeRecs) == 0 && len(taRecs) == 0 {
return false, nil
}

for _, rec := range eeRecs {
if rec.Verify(connState.PeerCertificates[0]) == nil {
// https://tools.ietf.org/html/rfc7672#section-3.1.1
Expand Down

0 comments on commit 804d62f

Please sign in to comment.