forked from buffrr/letsdane
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tls.go
93 lines (81 loc) · 2.81 KB
/
tls.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package sane
import (
"crypto/tls"
"errors"
"fmt"
"log"
"net"
"time"
"github.com/miekg/dns"
"github.com/randomlogin/sane/prove"
"github.com/randomlogin/sane/sync"
)
type tlsError struct {
err string
}
func (t *tlsError) Error() string {
return t.err
}
// newTLSConfig creates a new tls configuration capable of validating DANE.
func newTLSConfig(host string, rrs []*dns.TLSA, nameCheck bool, roots []sync.BlockInfo, externalServices []string) *tls.Config {
return &tls.Config{
InsecureSkipVerify: true, // lgtm[go/disabled-certificate-check]
VerifyConnection: verifyConnection(rrs, nameCheck, host, roots, externalServices),
ServerName: host,
MinVersion: tls.VersionTLS12,
// Supported TLS 1.2 cipher suites
// Crypto package does automatic cipher suite ordering
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
},
}
}
// verifyConnection returns a function that verifies the given tls connection state using the host and rrs
func verifyConnection(rrs []*dns.TLSA, nameCheck bool, host string, roots []sync.BlockInfo, externalServices []string) func(cs tls.ConnectionState) error {
return func(cs tls.ConnectionState) error {
// the host can be ignored per RFC 7671. Not Before, Not After are ignored as well.
// https://tools.ietf.org/html/rfc7671
cert := cs.PeerCertificates[0]
if nameCheck {
if err := cert.VerifyHostname(cs.ServerName); err != nil {
return &tlsError{err: fmt.Sprintf("tls: %v", err)}
}
}
// Verify the leaf certificate against the TLSA rrs
for _, t := range rrs {
if t.Usage != 3 {
continue
}
if err := t.Verify(cs.PeerCertificates[0]); err == nil {
if err := prove.VerifyCertificateExtensions(roots, *cert, t, externalServices); err != nil {
log.Print(err)
return err
}
return nil
}
}
return &tlsError{err: "tls: dane authentication failed"}
}
}
// terminateTLSHandshake terminates the tls handshake with an internal error alert
// this is slightly more descriptive to indicate a validation failure instead of promptly closing the connection
func terminateTLSHandshake(conn net.Conn) {
defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Second * 3))
c := &tls.Config{
// returning an error in GetCertificate will send an internal error alert
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return nil, errors.New("tls: no cert available for this name")
},
}
clientTLS := tls.Server(conn, c)
clientTLS.Handshake()
}