Skip to content

Commit 02733a5

Browse files
committed
Add check for certificate validity
go test -v -run TestCerts
1 parent c7c1fbc commit 02733a5

File tree

1 file changed

+94
-1
lines changed

1 file changed

+94
-1
lines changed

certifi_test.go

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,104 @@
44

55
package gocertifi
66

7-
import "testing"
7+
import (
8+
"crypto/x509"
9+
"encoding/pem"
10+
"testing"
11+
"time"
12+
)
813

914
func TestGetCerts(t *testing.T) {
1015
certPool, err := CACerts()
1116
if certPool == nil || err != nil || len(certPool.Subjects()) == 0 {
1217
t.Errorf("Failed to return the certificates.")
1318
}
1419
}
20+
21+
func parsePEM(pemCerts []byte) (certs []*x509.Certificate, err error) {
22+
for len(pemCerts) > 0 {
23+
var block *pem.Block
24+
block, pemCerts = pem.Decode(pemCerts)
25+
if block == nil {
26+
break
27+
}
28+
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
29+
continue
30+
}
31+
32+
cert, err := x509.ParseCertificate(block.Bytes)
33+
if err != nil {
34+
return nil, err
35+
}
36+
certs = append(certs, cert)
37+
}
38+
return
39+
}
40+
41+
func checkRootCertsPEM(t *testing.T, pemCerts []byte, when time.Time) (ok bool) {
42+
now := time.Now()
43+
t.Logf("Checking certificate validity on %s...", when)
44+
certs, err := parsePEM(pemCerts)
45+
if err != nil {
46+
t.Error(err)
47+
return false
48+
}
49+
50+
roots := x509.NewCertPool()
51+
for _, cert := range certs {
52+
roots.AddCert(cert)
53+
}
54+
55+
var minExpires time.Time
56+
ok = true
57+
for _, cert := range certs {
58+
if !cert.IsCA {
59+
t.Errorf("\u274C %s: not a certificate authority", cert.Subject)
60+
}
61+
// This check of keyusage is based on my understanding of key usage purposes
62+
// https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.8.0.pdf
63+
// Section 1.4.2 has no usage restrictions
64+
if cert.KeyUsage&(x509.KeyUsage(-1)^(x509.KeyUsageCertSign|x509.KeyUsageCRLSign|x509.KeyUsageDigitalSignature)) != 0 {
65+
t.Logf("\u26A0 %s key usage %#x (see constants at https://golang.org/pkg/crypto/x509/#KeyUsage)", cert.Subject, cert.KeyUsage)
66+
} else if cert.KeyUsage&(x509.KeyUsageCertSign|x509.KeyUsageCRLSign) == 0 {
67+
// If the certificate authority is not allowed to sign certificates, why is it here?
68+
// https://cabforum.org/baseline-requirements-certificate-contents/#CA-Certificates
69+
t.Logf("\u26A0 %s key usage %#x (see constants at https://golang.org/pkg/crypto/x509/#KeyUsage)", cert.Subject, cert.KeyUsage)
70+
}
71+
if minExpires.IsZero() || cert.NotAfter.Before(minExpires) {
72+
minExpires = cert.NotAfter
73+
}
74+
// Check that the certificate is valid now
75+
if cert.NotBefore.After(now) {
76+
t.Errorf("\u274C %s: fails NotBefore check: %s", cert.Subject, cert.NotBefore)
77+
continue
78+
}
79+
if cert.NotAfter.Before(now) {
80+
t.Errorf("\u274C %s: fails NotAfter check: \033[31m%s\033[m", cert.Subject, cert.NotAfter)
81+
// ... and that it will still be valid later
82+
} else if cert.NotAfter.Before(when) {
83+
t.Logf("\u26A0 %s: fails NotAfter check: \033[31m%s\033[m", cert.Subject, cert.NotAfter)
84+
continue
85+
}
86+
_, err := cert.Verify(x509.VerifyOptions{
87+
Roots: roots,
88+
CurrentTime: when,
89+
})
90+
if err != nil {
91+
t.Errorf("\u274C %s: %s", cert.Subject, err)
92+
ok = false
93+
} else {
94+
t.Logf("\u2705 %s (expires: %s)", cert.Subject, cert.NotAfter)
95+
}
96+
}
97+
if ok {
98+
t.Log("Success.")
99+
t.Logf("MinExpire: %s", minExpires)
100+
}
101+
return
102+
}
103+
104+
func TestCerts(t *testing.T) {
105+
// Check that certificates will still be valid in 3 months
106+
checkRootCertsPEM(t, []byte(pemcerts), time.Now().AddDate(0, 3, 0))
107+
}

0 commit comments

Comments
 (0)