Skip to content

Commit

Permalink
Support Diagnostic mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
shuque committed Jul 30, 2020
1 parent fe430b9 commit a2e20e9
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 36 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ https://pkg.go.dev/github.com/shuque/dane?tab=doc

### Description

dane v0.1.8
dane v0.1.9

Package dane provides a set of functions to perform DANE authentication
of a TLS server, with fall back to PKIX authentication if no DANE TLSA
Expand Down Expand Up @@ -71,6 +71,12 @@ is populated with additional diagnostic information, such as DANE and
PKIX authentication status, the verified certificate chains, and the
verification status of each DANE TLSA record processed.

If dane.Config.DiagMode is set to true, then DialTLSA() and DialStartTLSA()
will return a working TLS connection handle even if server authentication
fails (rather than an error), but will populate the dane.Config's DiagError
member with the appropriate error instead.


### Example code

The basic steps in summary form are:
Expand Down
11 changes: 6 additions & 5 deletions byname.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@ func ConnectByName(hostname string, port int) (*tls.Conn, *Config, error) {

resolver, err := GetResolver("")
if err != nil {
return nil, nil, fmt.Errorf("Error obtaining resolver address: %s", err.Error())
return nil, nil, fmt.Errorf("error obtaining resolver address: %s", err.Error())
}

tlsa, err := GetTLSA(resolver, hostname, port)
if err != nil {
return nil, nil, fmt.Errorf("GetTLSA: %s", err.Error())
return nil, nil, err
}

needSecure := (tlsa != nil)
iplist, err := GetAddresses(resolver, hostname, needSecure)
if err != nil {
return nil, nil, fmt.Errorf("GetAddresses: %s", err.Error())
return nil, nil, err
}

if len(iplist) == 0 {
return nil, nil, fmt.Errorf("No addresses found")
return nil, nil, fmt.Errorf("%s: no addresses found", hostname)
}

for _, ip := range iplist {
Expand All @@ -52,5 +52,6 @@ func ConnectByName(hostname string, port int) (*tls.Conn, *Config, error) {
return conn, config, err
}

return conn, nil, fmt.Errorf("Failed to connect to any server address")
return conn, nil, fmt.Errorf("failed to connect to any server address for %s",
hostname)
}
9 changes: 9 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
// Config contains a DANE configuration for a single Server.
//
type Config struct {
DiagMode bool // Diagnostic mode
DiagError error // Holds possible error in Diagnostic mode
Server *Server // Server structure (name, ip, port)
NoVerify bool // Don't verify server certificate
DaneEEname bool // Do name checks even for DANE-EE mode
Expand Down Expand Up @@ -78,3 +80,10 @@ func (c *Config) SetServiceName(servicename string) {
func (c *Config) NoPKIXfallback() {
c.PKIX = false
}

//
// SetDiagMode sets the Diagnostic mode.
//
func (c *Config) SetDiagMode(value bool) {
c.DiagMode = value
}
18 changes: 10 additions & 8 deletions dns.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dane

import (
"errors"
"fmt"
"net"

Expand Down Expand Up @@ -120,7 +121,7 @@ func sendQuery(query *Query, resolver *Resolver) (*dns.Msg, error) {
return nil, err
}
if response == nil {
return nil, fmt.Errorf("Error: null DNS response to query")
return nil, errors.New("null response to DNS query")
}
return response, err
}
Expand Down Expand Up @@ -162,13 +163,14 @@ func GetAddresses(resolver *Resolver, hostname string, secure bool) ([]net.IP, e
return nil, err
}
if !responseOK(response) {
return nil, fmt.Errorf("Address lookup rcode: %d", response.MsgHdr.Rcode)
return nil, fmt.Errorf("address lookup for %s failed, rcode %d",
hostname, response.MsgHdr.Rcode)
}
if response.MsgHdr.Rcode == dns.RcodeNameError {
return nil, fmt.Errorf("%s: Non-existent domain name", hostname)
return nil, fmt.Errorf("%s: non-existent domain name", hostname)
}
if secure && !response.MsgHdr.AuthenticatedData {
return nil, fmt.Errorf("Address response was not authenticated")
return nil, fmt.Errorf("%s address response was not authenticated", hostname)
}

for _, rr := range response.Answer {
Expand Down Expand Up @@ -232,22 +234,22 @@ func GetTLSA(resolver *Resolver, hostname string, port int) (*TLSAinfo, error) {
}

if !responseOK(response) {
return nil, fmt.Errorf("TLSA response rcode: %s",
return nil, fmt.Errorf("bad response code to TLSA query %s: %s", qname,
dns.RcodeToString[response.MsgHdr.Rcode])
}

if !response.MsgHdr.AuthenticatedData {
if resolver.Pkixfallback {
return nil, nil
}
return nil, fmt.Errorf("ERROR: TLSA response was unauthenticated")
return nil, fmt.Errorf("response unauthenticated: %s/TLSA", qname)
}

if response.MsgHdr.Rcode == dns.RcodeNameError {
if resolver.Pkixfallback {
return nil, nil
}
return nil, fmt.Errorf("ERROR: %s: Non-exist domain name", hostname)
return nil, fmt.Errorf("%s: non-existent domain name", hostname)
}

tlsa := Message2TSLAinfo(q.Name, response)
Expand All @@ -256,7 +258,7 @@ func GetTLSA(resolver *Resolver, hostname string, port int) (*TLSAinfo, error) {
if resolver.Pkixfallback {
return nil, nil
}
return nil, fmt.Errorf("ERROR: No TLSA records found")
return nil, fmt.Errorf("no TLSA records found: %s", qname)
}

return tlsa, err
Expand Down
14 changes: 6 additions & 8 deletions resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ import (
// DNS resolver defaults
//
var (
defaultDNSTimeout = 2
defaultDNSRetries = 3
defaultTCPTimeout = 3
defaultResolverPort = 53
defaultResolvConf = "/etc/resolv.conf"
timeoutTCP time.Duration = time.Second * 5
retries = 3
defaultBufsize uint16 = 1460
defaultDNSTimeout = 2
defaultDNSRetries = 3
defaultTCPTimeout = 3
defaultResolverPort = 53
defaultResolvConf = "/etc/resolv.conf"
defaultBufsize uint16 = 1460
)

//
Expand Down
6 changes: 3 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ type Server struct {
func NewServer(name string, ip interface{}, port int) *Server {
s := new(Server)
s.Name = name
switch ip.(type) {
switch ip := ip.(type) {
case net.IP:
s.Ipaddr = ip.(net.IP)
s.Ipaddr = ip
case string:
s.Ipaddr = net.ParseIP(ip.(string))
s.Ipaddr = net.ParseIP(ip)
}
s.Port = port
return s
Expand Down
2 changes: 1 addition & 1 deletion starttls.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,6 @@ func StartTLS(tlsconfig *tls.Config, daneconfig *Config) (*tls.Conn, error) {
case "xmpp-client", "xmpp-server":
return DoXMPP(tlsconfig, daneconfig)
default:
return nil, fmt.Errorf("Unknown STARTTLS application: %s", daneconfig.Appname)
return nil, fmt.Errorf("unknown STARTTLS application: %s", daneconfig.Appname)
}
}
25 changes: 22 additions & 3 deletions tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,41 @@ func verifyServer(rawCerts [][]byte,

if !(daneconfig.DANE && daneconfig.TLSA != nil) {
if !daneconfig.Okpkix {
if daneconfig.DiagMode {
daneconfig.DiagError = err
return nil
}
return err
}
return certs[0].VerifyHostname(tlsconfig.ServerName)
err = certs[0].VerifyHostname(tlsconfig.ServerName)
if daneconfig.DiagMode {
daneconfig.DiagError = err
return nil
}
return err
}

if !daneconfig.Okpkix {
daneconfig.VerifiedChains, err = verifyChain(certs, tlsconfig, false)
if err != nil {
return fmt.Errorf("DANE TLS error: cert chain: %s", err.Error())
daneconfig.DiagError = fmt.Errorf("DANE TLS error: cert chain: %s", err.Error())
if daneconfig.DiagMode {
return nil
} else {
return daneconfig.DiagError
}
}
}

// TODO: set Okdane inside AuthenticateAll and return no value?
daneconfig.Okdane = AuthenticateAll(daneconfig)
if !daneconfig.Okdane {
return fmt.Errorf("DANE TLS authentication failed")
daneconfig.DiagError = fmt.Errorf("DANE TLS authentication failed")
if daneconfig.DiagMode {
return nil
} else {
return daneconfig.DiagError
}
}

return nil
Expand Down
8 changes: 3 additions & 5 deletions tlsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ type TLSAinfo struct {
func (t *TLSAinfo) Copy() *TLSAinfo {
c := new(TLSAinfo)
c.Qname = t.Qname
for _, a := range t.Alias {
c.Alias = append(c.Alias, a)
}
c.Alias = append(c.Alias, t.Alias...)
for _, r := range t.Rdata {
tr := new(TLSArdata)
tr.Usage = r.Usage
Expand Down Expand Up @@ -129,7 +127,7 @@ func ComputeTLSA(selector, mtype uint8, cert *x509.Certificate) (string, error)
case 1:
preimage = cert.RawSubjectPublicKeyInfo
default:
return "", fmt.Errorf("Unknown TLSA selector: %d", selector)
return "", fmt.Errorf("unknown TLSA selector: %d", selector)
}

switch mtype {
Expand All @@ -142,7 +140,7 @@ func ComputeTLSA(selector, mtype uint8, cert *x509.Certificate) (string, error)
tmp512 = sha512.Sum512(preimage)
output = tmp512[:]
default:
return "", fmt.Errorf("Unknown TLSA matching type: %d", mtype)
return "", fmt.Errorf("unknown TLSA matching type: %d", mtype)
}
return hex.EncodeToString(output), nil
}
Expand Down
2 changes: 1 addition & 1 deletion utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
func addressString(ipaddress net.IP, port int) string {

addr := ipaddress.String()
if strings.Index(addr, ":") == -1 {
if !strings.Contains(addr, ":") {
return addr + ":" + strconv.Itoa(port)
}
return "[" + addr + "]" + ":" + strconv.Itoa(port)
Expand Down
8 changes: 7 additions & 1 deletion version.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,18 @@
// PKIX authentication status, the verified certificate chains, and the
// verification status of each DANE TLSA record processed.
//
// If dane.Config.DiagMode is set to true, then DialTLSA() and DialStartTLSA()
// will return a working TLS connection handle even if server authentication
// fails (rather than an error), but will populate the dane.Config's DiagError
// member with the appropriate error instead.
//

package dane

import "fmt"

// Version - current version number
var Version = VersionStruct{0, 1, 8}
var Version = VersionStruct{0, 1, 9}

// VersionStruct - version structure
type VersionStruct struct {
Expand Down

0 comments on commit a2e20e9

Please sign in to comment.