forked from dkumor/acmewrapper
/
cert.go
executable file
·102 lines (93 loc) · 2.85 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
102
package acmewrapper
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"os"
"time"
"github.com/xenolf/lego/acme"
)
// writeCert takes an acme CertificateResource (as returned from the acme.RenewCertificate
// and the acme.ObtainCertificate functions), and writes the cert and key files from it.
// If the files already exist, it renames the old versions by adding .bak to them. This makes
// sure that a little accident doesn't cause too much damage.
func (w *AcmeWrapper) writeCert(certfile, keyfile string, crt acme.CertificateResource) (err error) {
//If user has provided custom file handling, skip backups
if w.Config.SaveFileCallback != nil {
if err := w.saveFile(certfile, crt.Certificate); err != nil {
return err
}
if err := w.saveFile(keyfile, crt.PrivateKey); err != nil {
return err
}
return nil
}
//If the files already exist, move them to backup
err = os.Rename(certfile, certfile+".bak")
if err != nil && !os.IsNotExist(err) {
return err
}
err = os.Rename(keyfile, keyfile+".bak")
if err != nil && !os.IsNotExist(err) {
return err
}
err = ioutil.WriteFile(certfile, crt.Certificate, 0600)
if err != nil {
os.Rename(certfile+".bak", certfile)
os.Rename(keyfile+".bak", keyfile)
return err
}
err = ioutil.WriteFile(keyfile, crt.PrivateKey, 0600)
if err != nil {
os.Remove(certfile)
os.Rename(certfile+".bak", certfile)
os.Rename(keyfile+".bak", keyfile)
return err
}
return nil
}
func tlsCert(crt acme.CertificateResource) (*tls.Certificate, error) {
cert, err := tls.X509KeyPair(crt.Certificate, crt.PrivateKey)
return &cert, err
}
// checks if a is a subset of b
func arraySubset(a []string, b []string) bool {
if len(a) > len(b) {
return false
}
for _, i := range a {
if !stringInSlice(i, b) {
return false
}
}
return true
}
// CertNeedsUpdate returns whether the current certificate either
// does not exist, or is <X days from expiration, where X is set up in config,
// or does not match the domains set up in configuration.
func (w *AcmeWrapper) CertNeedsUpdate() bool {
if w.cert == nil {
// The cert doesn't exist - it certainly needs update
return true
}
// w.cert.Leaf is not set, so we have to manually parse the certs
// and make sure that they don't expire soon.
// We also create a list of the domains in our certifiate, to make sure
// that the cert is for the correct ones!
domains := []string{}
for _, c := range w.cert.Certificate {
crt, err := x509.ParseCertificate(c)
if err != nil {
// If there's an error, we assume the cert is broken, and needs update
return true
}
timeLeft := crt.NotAfter.Sub(time.Now().UTC())
if timeLeft < w.Config.RenewTime {
return true
}
domains = append(domains, crt.DNSNames...)
}
// Now make sure that the domains in our config are entirely contained in the
// domains that this cert handles
return !arraySubset(w.Config.Domains, domains)
}