@@ -14,14 +14,15 @@ import (
14
14
// certificate.
15
15
type RenewFunc func () (* tls.Certificate , error )
16
16
17
- // TLSRenewer renews automatically a tls certificate with a given function .
17
+ // TLSRenewer automatically renews a tls certificate using a RenewFunc .
18
18
type TLSRenewer struct {
19
19
sync.RWMutex
20
20
RenewCertificate RenewFunc
21
21
cert * tls.Certificate
22
22
timer * time.Timer
23
23
renewBefore time.Duration
24
24
renewJitter time.Duration
25
+ certNotAfter time.Time
25
26
}
26
27
27
28
type tlsRenewerOptions func (r * TLSRenewer ) error
@@ -43,7 +44,7 @@ func WithRenewJitter(j time.Duration) func(r *TLSRenewer) error {
43
44
}
44
45
45
46
// NewTLSRenewer creates a TLSRenewer for the given cert. It will use the given
46
- // function to get a new certificate when required.
47
+ // RenewFunc to get a new certificate when required.
47
48
func NewTLSRenewer (cert * tls.Certificate , fn RenewFunc , opts ... tlsRenewerOptions ) (* TLSRenewer , error ) {
48
49
r := & TLSRenewer {
49
50
RenewCertificate : fn ,
@@ -91,7 +92,10 @@ func (r *TLSRenewer) RunContext(ctx context.Context) {
91
92
92
93
// Stop prevents the renew timer from firing.
93
94
func (r * TLSRenewer ) Stop () bool {
94
- return r .timer .Stop ()
95
+ if r .timer != nil {
96
+ return r .timer .Stop ()
97
+ }
98
+ return true
95
99
}
96
100
97
101
// GetCertificate returns the current server certificate.
@@ -101,6 +105,15 @@ func (r *TLSRenewer) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Cert
101
105
return r .getCertificate (), nil
102
106
}
103
107
108
+ // GetCertificateForCA returns the current server certificate. It can only be
109
+ // used if the renew function creates the new certificate and do not uses a TLS
110
+ // request. It's intended to be use by the certificate authority server.
111
+ //
112
+ // This method is set in the tls.Config GetCertificate property.
113
+ func (r * TLSRenewer ) GetCertificateForCA (clientHello * tls.ClientHelloInfo ) (* tls.Certificate , error ) {
114
+ return r .getCertificateForCA (), nil
115
+ }
116
+
104
117
// GetClientCertificate returns the current client certificate.
105
118
//
106
119
// This method is set in the tls.Config GetClientCertificate property.
@@ -109,17 +122,41 @@ func (r *TLSRenewer) GetClientCertificate(*tls.CertificateRequestInfo) (*tls.Cer
109
122
}
110
123
111
124
// getCertificate returns the certificate using a read-only lock.
125
+ //
126
+ // Known issue: It cannot renew an expired certificate because the /renew
127
+ // endpoint requires a valid client certificate. The certificate can expire
128
+ // if the timer does not fire e.g. when the CA is run from a laptop that
129
+ // enters sleep mode.
112
130
func (r * TLSRenewer ) getCertificate () * tls.Certificate {
113
131
r .RLock ()
114
132
cert := r .cert
115
133
r .RUnlock ()
116
134
return cert
117
135
}
118
136
119
- // setCertificate updates the certificate using a read-write lock.
137
+ // getCertificateForCA returns the certificate using a read-only lock. It will
138
+ // automatically renew the certificate if it has expired.
139
+ func (r * TLSRenewer ) getCertificateForCA () * tls.Certificate {
140
+ r .RLock ()
141
+ // Force certificate renewal if the timer didn't run.
142
+ // This is an special case that can happen after a computer sleep.
143
+ if time .Now ().After (r .certNotAfter ) {
144
+ r .RUnlock ()
145
+ r .renewCertificate ()
146
+ r .RLock ()
147
+ }
148
+ cert := r .cert
149
+ r .RUnlock ()
150
+ return cert
151
+ }
152
+
153
+ // setCertificate updates the certificate using a read-write lock. It also
154
+ // updates certNotAfter with 1m of delta; this will force the renewal of the
155
+ // certificate if it is about to expire.
120
156
func (r * TLSRenewer ) setCertificate (cert * tls.Certificate ) {
121
157
r .Lock ()
122
158
r .cert = cert
159
+ r .certNotAfter = cert .Leaf .NotAfter .Add (- 1 * time .Minute )
123
160
r .Unlock ()
124
161
}
125
162
@@ -133,7 +170,9 @@ func (r *TLSRenewer) renewCertificate() {
133
170
r .setCertificate (cert )
134
171
next = r .nextRenewDuration (cert .Leaf .NotAfter )
135
172
}
136
- r .timer = time .AfterFunc (next , r .renewCertificate )
173
+ r .Lock ()
174
+ r .timer .Reset (next )
175
+ r .Unlock ()
137
176
}
138
177
139
178
func (r * TLSRenewer ) nextRenewDuration (notAfter time.Time ) time.Duration {
0 commit comments