OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / acme / autocert / renewal_test.go
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.
4
5 package autocert
6
7 import (
8         "context"
9         "crypto/ecdsa"
10         "crypto/elliptic"
11         "crypto/rand"
12         "crypto/tls"
13         "crypto/x509"
14         "encoding/base64"
15         "fmt"
16         "net/http"
17         "net/http/httptest"
18         "testing"
19         "time"
20
21         "golang.org/x/crypto/acme"
22 )
23
24 func TestRenewalNext(t *testing.T) {
25         now := time.Now()
26         timeNow = func() time.Time { return now }
27         defer func() { timeNow = time.Now }()
28
29         man := &Manager{RenewBefore: 7 * 24 * time.Hour}
30         defer man.stopRenew()
31         tt := []struct {
32                 expiry   time.Time
33                 min, max time.Duration
34         }{
35                 {now.Add(90 * 24 * time.Hour), 83*24*time.Hour - renewJitter, 83 * 24 * time.Hour},
36                 {now.Add(time.Hour), 0, 1},
37                 {now, 0, 1},
38                 {now.Add(-time.Hour), 0, 1},
39         }
40
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)
46                 }
47         }
48 }
49
50 func TestRenewFromCache(t *testing.T) {
51         const domain = "example.org"
52
53         // ACME CA server stub
54         var ca *httptest.Server
55         ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
56                 w.Header().Set("Replay-Nonce", "nonce")
57                 if r.Method == "HEAD" {
58                         // a nonce request
59                         return
60                 }
61
62                 switch r.URL.Path {
63                 // discovery
64                 case "/":
65                         if err := discoTmpl.Execute(w, ca.URL); err != nil {
66                                 t.Fatalf("discoTmpl: %v", err)
67                         }
68                 // client key registration
69                 case "/new-reg":
70                         w.Write([]byte("{}"))
71                 // domain authorization
72                 case "/new-authz":
73                         w.Header().Set("Location", ca.URL+"/authz/1")
74                         w.WriteHeader(http.StatusCreated)
75                         w.Write([]byte(`{"status": "valid"}`))
76                 // cert request
77                 case "/new-cert":
78                         var req struct {
79                                 CSR string `json:"csr"`
80                         }
81                         decodePayload(&req, r.Body)
82                         b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
83                         csr, err := x509.ParseCertificateRequest(b)
84                         if err != nil {
85                                 t.Fatalf("new-cert: CSR: %v", err)
86                         }
87                         der, err := dummyCert(csr.PublicKey, domain)
88                         if err != nil {
89                                 t.Fatalf("new-cert: dummyCert: %v", err)
90                         }
91                         chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
92                         w.Header().Set("Link", chainUp)
93                         w.WriteHeader(http.StatusCreated)
94                         w.Write(der)
95                 // CA chain cert
96                 case "/ca-cert":
97                         der, err := dummyCert(nil, "ca")
98                         if err != nil {
99                                 t.Fatalf("ca-cert: dummyCert: %v", err)
100                         }
101                         w.Write(der)
102                 default:
103                         t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
104                 }
105         }))
106         defer ca.Close()
107
108         // use EC key to run faster on 386
109         key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
110         if err != nil {
111                 t.Fatal(err)
112         }
113         man := &Manager{
114                 Prompt:      AcceptTOS,
115                 Cache:       newMemCache(),
116                 RenewBefore: 24 * time.Hour,
117                 Client: &acme.Client{
118                         Key:          key,
119                         DirectoryURL: ca.URL,
120                 },
121         }
122         defer man.stopRenew()
123
124         // cache an almost expired cert
125         now := time.Now()
126         cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain)
127         if err != nil {
128                 t.Fatal(err)
129         }
130         tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
131         if err := man.cachePut(context.Background(), domain, tlscert); err != nil {
132                 t.Fatal(err)
133         }
134
135         // veriy the renewal happened
136         defer func() {
137                 testDidRenewLoop = func(next time.Duration, err error) {}
138         }()
139         done := make(chan struct{})
140         testDidRenewLoop = func(next time.Duration, err error) {
141                 defer close(done)
142                 if err != nil {
143                         t.Errorf("testDidRenewLoop: %v", err)
144                 }
145                 // Next should be about 90 days:
146                 // dummyCert creates 90days expiry + account for man.RenewBefore.
147                 // Previous expiration was within 1 min.
148                 future := 88 * 24 * time.Hour
149                 if next < future {
150                         t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
151                 }
152
153                 // ensure the new cert is cached
154                 after := time.Now().Add(future)
155                 tlscert, err := man.cacheGet(context.Background(), domain)
156                 if err != nil {
157                         t.Fatalf("man.cacheGet: %v", err)
158                 }
159                 if !tlscert.Leaf.NotAfter.After(after) {
160                         t.Errorf("cache leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
161                 }
162
163                 // verify the old cert is also replaced in memory
164                 man.stateMu.Lock()
165                 defer man.stateMu.Unlock()
166                 s := man.state[domain]
167                 if s == nil {
168                         t.Fatalf("m.state[%q] is nil", domain)
169                 }
170                 tlscert, err = s.tlscert()
171                 if err != nil {
172                         t.Fatalf("s.tlscert: %v", err)
173                 }
174                 if !tlscert.Leaf.NotAfter.After(after) {
175                         t.Errorf("state leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
176                 }
177         }
178
179         // trigger renew
180         hello := &tls.ClientHelloInfo{ServerName: domain}
181         if _, err := man.GetCertificate(hello); err != nil {
182                 t.Fatal(err)
183         }
184
185         // wait for renew loop
186         select {
187         case <-time.After(10 * time.Second):
188                 t.Fatal("renew took too long to occur")
189         case <-done:
190         }
191 }