4
4
"crypto/tls"
5
5
"crypto/x509"
6
6
"errors"
7
+ "fmt"
7
8
"io/ioutil"
8
9
"net"
9
10
"net/http"
@@ -18,40 +19,17 @@ import (
18
19
// of the server), an error with a warning (e.g. mismatch between the hostname and the CN or DNS alias
19
20
// in the certificate) and an error in case of failure.
20
21
func RetrieveCertsFromAddr (addr string , timeOut time.Duration ) ([]* x509.Certificate , error , error ) {
21
- conn , err := net .DialTimeout ("tcp" , addr , timeOut )
22
- if err != nil {
23
- return nil , nil , err
24
- }
25
-
26
- var warning error
27
- rx := regexp .MustCompile (":\\ d+$" )
28
- tlsConn := tls .Client (conn , & tls.Config {ServerName : rx .ReplaceAllString (addr , "" )})
29
- err = tlsConn .SetDeadline (time .Now ().Add (timeOut ))
30
- if err != nil {
31
- return nil , nil , err
32
- }
33
- err = tlsConn .Handshake ()
34
- if err != nil {
35
- tlsConn = tls .Client (conn , & tls.Config {InsecureSkipVerify : true })
36
- err2 := tlsConn .SetDeadline (time .Now ().Add (timeOut ))
37
- if err2 != nil {
38
- return nil , nil , err2
39
- }
40
- err2 = tlsConn .Handshake ()
41
- if err2 != nil {
42
- return nil , nil , err2
22
+ var certs []* x509.Certificate
23
+ var err , warn error
24
+ certs , warn = connectAndRetrieve (addr , timeOut , false )
25
+ if warn != nil {
26
+ certs , err = connectAndRetrieve (addr , timeOut , true )
27
+ if err != nil {
28
+ warn = nil
43
29
}
44
- warning = err
45
- }
46
- defer tlsConn .Close ()
47
- defer conn .Close ()
48
-
49
- if len (tlsConn .ConnectionState ().PeerCertificates ) == 0 {
50
- err := errors .New ("no certificates found" )
51
- return nil , warning , err
52
30
}
53
31
54
- return tlsConn . ConnectionState (). PeerCertificates , warning , nil
32
+ return certs , warn , err
55
33
}
56
34
57
35
// RetrieveChainFromIssuerURLs retrieves the chain for a certificate by following the
@@ -67,6 +45,30 @@ func RetrieveChainFromIssuerURLs(cert *x509.Certificate, timeOut time.Duration)
67
45
return chain , lastErr
68
46
}
69
47
48
+ // connectAndRetrieve does the actual TLS calls
49
+ func connectAndRetrieve (addr string , timeOut time.Duration , skipVerify bool ) ([]* x509.Certificate , error ) {
50
+ serverName := regexp .MustCompile (":\\ d+$" ).ReplaceAllString (addr , "" )
51
+ var tlsConfig tls.Config
52
+ if skipVerify {
53
+ tlsConfig .InsecureSkipVerify = true
54
+ } else {
55
+ tlsConfig .ServerName = serverName
56
+ }
57
+
58
+ dialer := & net.Dialer {Timeout : timeOut }
59
+ conn , err := tls .DialWithDialer (dialer , "tcp" , addr , & tlsConfig )
60
+ if err != nil {
61
+ return nil , fmt .Errorf ("[%s] %s" , serverName , err )
62
+ }
63
+ defer conn .Close ()
64
+
65
+ if len (conn .ConnectionState ().PeerCertificates ) == 0 {
66
+ return nil , errors .New ("no certificates found" )
67
+ }
68
+
69
+ return conn .ConnectionState ().PeerCertificates , nil
70
+ }
71
+
70
72
// recursiveHopCerts follows the URL links recursively
71
73
func recursiveHopCerts (
72
74
cert * x509.Certificate , chain * []* x509.Certificate , lastErr * error , timeOut time.Duration ) * x509.Certificate {
@@ -102,3 +104,4 @@ func recursiveHopCerts(
102
104
103
105
return nil
104
106
}
107
+
0 commit comments