-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
ssl.go
91 lines (80 loc) · 2.45 KB
/
ssl.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
package paymail
import (
"context"
"crypto/tls"
"fmt"
"net"
"time"
)
// CheckSSL will do a basic check on the host to see if there is a valid SSL cert
//
// All paymail requests should be via HTTPS and have a valid certificate
func (c *Client) CheckSSL(host string) (valid bool, err error) {
// Lookup the host
var ips []net.IPAddr
if ips, err = c.resolver.LookupIPAddr(context.Background(), host); err != nil {
return
}
// Loop through all found ip addresses
if len(ips) > 0 {
for _, ip := range ips {
// Set the dialer
dialer := net.Dialer{
Timeout: c.options.sslTimeout,
Deadline: time.Now().Add(c.options.sslDeadline),
}
// Set the connection
connection, dialErr := tls.DialWithDialer(
&dialer,
DefaultProtocol,
fmt.Sprintf("[%s]:%d", ip.String(), DefaultPort),
&tls.Config{ //nolint:gosec // no need to check for unhandled errors
ServerName: host,
},
)
if dialErr != nil {
// catch missing ipv6 connectivity
// if the ip is ipv6 and the resulting error is "no route to host", the record is skipped
// otherwise the check will switch to critical
/*
if validate.IsValidIPv6(ip.String()) {
switch dialErr.(type) {
case *net.OpError:
// https://stackoverflow.com/questions/38764084/proper-way-to-handle-missing-ipv6-connectivity
if dialErr.(*net.OpError).Err.(*os.SyscallError).Err == syscall.EHOSTUNREACH {
// log.Printf("%-15s - ignoring unreachable IPv6 address", ip)
continue
}
}
}
*/
continue
}
// remember the checked certs based on their Signature
checkedCerts := make(map[string]struct{})
// loop to all certs we get
// there might be multiple chains, as there may be one or more CAs present on the current system,
// so we have multiple possible chains
for _, chain := range connection.ConnectionState().VerifiedChains {
for _, cert := range chain {
if _, checked := checkedCerts[string(cert.Signature)]; checked {
continue
}
checkedCerts[string(cert.Signature)] = struct{}{}
// Filter out CA certificates
if cert.IsCA {
// log.Printf("ignoring CA certificate on ip %s by %s", ip, cert.Subject.CommonName)
continue
}
// Fail if less than 1 day for expiration
// remainingValidity := cert.NotAfter.Sub(time.Now())
if time.Until(cert.NotAfter) > 24*time.Hour {
valid = true
}
}
}
_ = connection.Close()
}
}
return
}