2015-09-04 13:36:49 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/x509"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2017-11-05 15:03:26 +00:00
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
2015-09-04 13:36:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
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", config.ExpireWarning)
|
|
|
|
case certificateInvalid:
|
|
|
|
return "Certificate invalid / intermediate certificates not present"
|
|
|
|
case certificateNotFound:
|
|
|
|
return "Did not find a certificate valid for this domain"
|
|
|
|
case generalFailure:
|
|
|
|
return "Something went wrong in the request"
|
|
|
|
}
|
|
|
|
|
|
|
|
return "" // This does not happen.
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkCertificate(probeURL *url.URL) (probeResult, *x509.Certificate) {
|
2017-11-05 15:03:26 +00:00
|
|
|
checkLogger := log.WithFields(log.Fields{"probe_url": probeURL})
|
|
|
|
|
2015-09-04 13:36:49 +00:00
|
|
|
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 err.(type) {
|
|
|
|
case nil, redirectFoundError:
|
|
|
|
default:
|
2017-11-05 15:03:26 +00:00
|
|
|
checkLogger.WithError(err).Error("HTTP request failed")
|
2015-09-04 13:36:49 +00:00
|
|
|
if !strings.Contains(err.Error(), "Found a redirect.") {
|
|
|
|
return generalFailure, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resp.Body.Close()
|
|
|
|
|
|
|
|
intermediatePool := x509.NewCertPool()
|
|
|
|
var verifyCert *x509.Certificate
|
|
|
|
|
2016-09-29 09:40:55 +00:00
|
|
|
hostPort := strings.Split(probeURL.Host, ":")
|
|
|
|
host := hostPort[0]
|
|
|
|
|
2015-09-04 13:36:49 +00:00
|
|
|
for _, cert := range resp.TLS.PeerCertificates {
|
2016-09-29 09:40:55 +00:00
|
|
|
wildHost := "*" + host[strings.Index(host, "."):]
|
|
|
|
if !inSlice(cert.DNSNames, host) && !inSlice(cert.DNSNames, wildHost) {
|
2015-09-04 13:36:49 +00:00
|
|
|
intermediatePool.AddCert(cert)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
verifyCert = cert
|
|
|
|
}
|
|
|
|
|
|
|
|
if verifyCert == nil {
|
2017-11-05 15:03:26 +00:00
|
|
|
checkLogger.Debug("Certificate not found")
|
2015-09-04 13:36:49 +00:00
|
|
|
return certificateNotFound, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
verificationResult := false
|
|
|
|
if _, err := verifyCert.Verify(x509.VerifyOptions{
|
|
|
|
Intermediates: intermediatePool,
|
|
|
|
}); err == nil {
|
|
|
|
verificationResult = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if !verificationResult {
|
2017-11-05 15:03:26 +00:00
|
|
|
checkLogger.Debug("Certificate invalid")
|
2015-09-04 13:36:49 +00:00
|
|
|
return certificateInvalid, verifyCert
|
|
|
|
}
|
|
|
|
|
2017-06-26 13:04:28 +00:00
|
|
|
if verifyCert.NotAfter.Sub(time.Now()) < config.ExpireWarning {
|
2017-11-05 15:03:26 +00:00
|
|
|
checkLogger.Debug("Certificate expires soon")
|
2015-09-04 13:36:49 +00:00
|
|
|
return certificateExpiresSoon, verifyCert
|
|
|
|
}
|
|
|
|
|
2017-11-05 15:03:26 +00:00
|
|
|
checkLogger.Debug("Certificate OK")
|
2015-09-04 13:36:49 +00:00
|
|
|
return certificateOK, verifyCert
|
|
|
|
}
|