/
cert.go
101 lines (83 loc) · 2.43 KB
/
cert.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
94
95
96
97
98
99
100
101
package main
import (
"crypto/x509"
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/Luzifer/go_helpers/v2/str"
log "github.com/sirupsen/logrus"
)
type probeResult uint
const (
certificateOK probeResult = iota
certificateNotFound
certificateExpiresSoon
certificateInvalid
generalFailure
)
func (p probeResult) String() string {
switch p {
case certificateOK:
return "Certificate OK"
case certificateExpiresSoon:
return fmt.Sprintf("Certificate expires within %s", cfg.ExpireWarning)
case certificateInvalid:
return "Certificate invalid / intermediate certificates not present"
case certificateNotFound:
return "Did not find a certificate valid for this domain"
default:
return "Something went wrong in the request"
}
}
func checkCertificate(probeURL *url.URL) (probeResult, *x509.Certificate) {
checkLogger := log.WithFields(log.Fields{"probe_url": probeURL})
req, _ := http.NewRequest("HEAD", probeURL.String(), nil)
req.Header.Set("User-Agent", fmt.Sprintf("Mozilla/5.0 (compatible; PromCertcheck/%s; +https://github.com/Luzifer/promcertcheck)", version))
resp, err := http.DefaultClient.Do(req)
switch {
case err == nil:
case strings.Contains(err.Error(), redirectFoundError.Error()):
checkLogger.WithError(err).Warn("A redirect was found")
default:
checkLogger.WithError(err).Error("HTTP request failed")
return generalFailure, nil
}
resp.Body.Close()
var (
intermediatePool = x509.NewCertPool()
verifyCert *x509.Certificate
)
hostPort := strings.Split(probeURL.Host, ":")
host := hostPort[0]
for _, cert := range resp.TLS.PeerCertificates {
wildHost := "*" + host[strings.Index(host, "."):]
if !str.StringInSlice(host, cert.DNSNames) && !str.StringInSlice(wildHost, cert.DNSNames) {
intermediatePool.AddCert(cert)
continue
}
verifyCert = cert
}
if verifyCert == nil {
checkLogger.Debug("Certificate not found")
return certificateNotFound, nil
}
verificationResult := false
if _, err := verifyCert.Verify(x509.VerifyOptions{
Intermediates: intermediatePool,
Roots: rootPool,
}); err == nil {
verificationResult = true
}
if !verificationResult {
checkLogger.Debug("Certificate invalid")
return certificateInvalid, verifyCert
}
if verifyCert.NotAfter.Sub(time.Now()) < cfg.ExpireWarning {
checkLogger.Debug("Certificate expires soon")
return certificateExpiresSoon, verifyCert
}
checkLogger.Debug("Certificate OK")
return certificateOK, verifyCert
}