1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
21 "golang.org/x/crypto/acme"
24 func TestRenewalNext(t *testing.T) {
27 RenewBefore: 7 * 24 * time.Hour,
28 nowFunc: func() time.Time { return now },
33 min, max time.Duration
35 {now.Add(90 * 24 * time.Hour), 83*24*time.Hour - renewJitter, 83 * 24 * time.Hour},
36 {now.Add(time.Hour), 0, 1},
38 {now.Add(-time.Hour), 0, 1},
41 dr := &domainRenewal{m: man}
42 for i, test := range tt {
43 next := dr.next(test.expiry)
44 if next < test.min || test.max < next {
45 t.Errorf("%d: next = %v; want between %v and %v", i, next, test.min, test.max)
50 func TestRenewFromCache(t *testing.T) {
51 // ACME CA server stub
52 var ca *httptest.Server
53 ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
54 w.Header().Set("Replay-Nonce", "nonce")
55 if r.Method == "HEAD" {
63 if err := discoTmpl.Execute(w, ca.URL); err != nil {
64 t.Fatalf("discoTmpl: %v", err)
66 // client key registration
69 // domain authorization
71 w.Header().Set("Location", ca.URL+"/authz/1")
72 w.WriteHeader(http.StatusCreated)
73 w.Write([]byte(`{"status": "valid"}`))
77 CSR string `json:"csr"`
79 decodePayload(&req, r.Body)
80 b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
81 csr, err := x509.ParseCertificateRequest(b)
83 t.Fatalf("new-cert: CSR: %v", err)
85 der, err := dummyCert(csr.PublicKey, exampleDomain)
87 t.Fatalf("new-cert: dummyCert: %v", err)
89 chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
90 w.Header().Set("Link", chainUp)
91 w.WriteHeader(http.StatusCreated)
95 der, err := dummyCert(nil, "ca")
97 t.Fatalf("ca-cert: dummyCert: %v", err)
101 t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
108 Cache: newMemCache(t),
109 RenewBefore: 24 * time.Hour,
110 Client: &acme.Client{
111 DirectoryURL: ca.URL,
114 defer man.stopRenew()
116 // cache an almost expired cert
117 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
122 cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain)
126 tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
127 if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil {
131 // veriy the renewal happened
133 testDidRenewLoop = func(next time.Duration, err error) {}
135 done := make(chan struct{})
136 testDidRenewLoop = func(next time.Duration, err error) {
139 t.Errorf("testDidRenewLoop: %v", err)
141 // Next should be about 90 days:
142 // dummyCert creates 90days expiry + account for man.RenewBefore.
143 // Previous expiration was within 1 min.
144 future := 88 * 24 * time.Hour
146 t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
149 // ensure the new cert is cached
150 after := time.Now().Add(future)
151 tlscert, err := man.cacheGet(context.Background(), exampleCertKey)
153 t.Fatalf("man.cacheGet: %v", err)
155 if !tlscert.Leaf.NotAfter.After(after) {
156 t.Errorf("cache leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
159 // verify the old cert is also replaced in memory
161 defer man.stateMu.Unlock()
162 s := man.state[exampleCertKey]
164 t.Fatalf("m.state[%q] is nil", exampleCertKey)
166 tlscert, err = s.tlscert()
168 t.Fatalf("s.tlscert: %v", err)
170 if !tlscert.Leaf.NotAfter.After(after) {
171 t.Errorf("state leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
176 hello := clientHelloInfo(exampleDomain, true)
177 if _, err := man.GetCertificate(hello); err != nil {
181 // wait for renew loop
183 case <-time.After(10 * time.Second):
184 t.Fatal("renew took too long to occur")
189 func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
192 Cache: newMemCache(t),
193 RenewBefore: 24 * time.Hour,
194 Client: &acme.Client{
195 DirectoryURL: "invalid",
198 defer man.stopRenew()
200 // cache a recently renewed cert with a different private key
201 newKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
206 newCert, err := dateDummyCert(newKey.Public(), now.Add(-2*time.Hour), now.Add(time.Hour*24*90), exampleDomain)
210 newLeaf, err := validCert(exampleCertKey, [][]byte{newCert}, newKey, now)
214 newTLSCert := &tls.Certificate{PrivateKey: newKey, Certificate: [][]byte{newCert}, Leaf: newLeaf}
215 if err := man.cachePut(context.Background(), exampleCertKey, newTLSCert); err != nil {
219 // set internal state to an almost expired cert
220 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
224 oldCert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain)
228 oldLeaf, err := validCert(exampleCertKey, [][]byte{oldCert}, key, now)
233 if man.state == nil {
234 man.state = make(map[certKey]*certState)
238 cert: [][]byte{oldCert},
241 man.state[exampleCertKey] = s
244 // veriy the renewal accepted the newer cached cert
246 testDidRenewLoop = func(next time.Duration, err error) {}
248 done := make(chan struct{})
249 testDidRenewLoop = func(next time.Duration, err error) {
252 t.Errorf("testDidRenewLoop: %v", err)
254 // Next should be about 90 days
255 // Previous expiration was within 1 min.
256 future := 88 * 24 * time.Hour
258 t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
261 // ensure the cached cert was not modified
262 tlscert, err := man.cacheGet(context.Background(), exampleCertKey)
264 t.Fatalf("man.cacheGet: %v", err)
266 if !tlscert.Leaf.NotAfter.Equal(newLeaf.NotAfter) {
267 t.Errorf("cache leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newLeaf.NotAfter)
270 // verify the old cert is also replaced in memory
272 defer man.stateMu.Unlock()
273 s := man.state[exampleCertKey]
275 t.Fatalf("m.state[%q] is nil", exampleCertKey)
277 stateKey := s.key.Public().(*ecdsa.PublicKey)
278 if stateKey.X.Cmp(newKey.X) != 0 || stateKey.Y.Cmp(newKey.Y) != 0 {
279 t.Fatalf("state key was not updated from cache x: %v y: %v; want x: %v y: %v", stateKey.X, stateKey.Y, newKey.X, newKey.Y)
281 tlscert, err = s.tlscert()
283 t.Fatalf("s.tlscert: %v", err)
285 if !tlscert.Leaf.NotAfter.Equal(newLeaf.NotAfter) {
286 t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newLeaf.NotAfter)
289 // verify the private key is replaced in the renewal state
290 r := man.renewal[exampleCertKey]
292 t.Fatalf("m.renewal[%q] is nil", exampleCertKey)
294 renewalKey := r.key.Public().(*ecdsa.PublicKey)
295 if renewalKey.X.Cmp(newKey.X) != 0 || renewalKey.Y.Cmp(newKey.Y) != 0 {
296 t.Fatalf("renewal private key was not updated from cache x: %v y: %v; want x: %v y: %v", renewalKey.X, renewalKey.Y, newKey.X, newKey.Y)
301 // assert the expiring cert is returned from state
302 hello := clientHelloInfo(exampleDomain, true)
303 tlscert, err := man.GetCertificate(hello)
307 if !oldLeaf.NotAfter.Equal(tlscert.Leaf.NotAfter) {
308 t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, oldLeaf.NotAfter)
312 go man.renew(exampleCertKey, s.key, s.leaf.NotAfter)
314 // wait for renew loop
316 case <-time.After(10 * time.Second):
317 t.Fatal("renew took too long to occur")
319 // assert the new cert is returned from state after renew
320 hello := clientHelloInfo(exampleDomain, true)
321 tlscert, err := man.GetCertificate(hello)
325 if !newTLSCert.Leaf.NotAfter.Equal(tlscert.Leaf.NotAfter) {
326 t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newTLSCert.Leaf.NotAfter)