aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/acme/acme_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/acme/acme_test.go')
-rw-r--r--vendor/golang.org/x/crypto/acme/acme_test.go305
1 files changed, 133 insertions, 172 deletions
diff --git a/vendor/golang.org/x/crypto/acme/acme_test.go b/vendor/golang.org/x/crypto/acme/acme_test.go
index 89f2efa..ef1fe47 100644
--- a/vendor/golang.org/x/crypto/acme/acme_test.go
+++ b/vendor/golang.org/x/crypto/acme/acme_test.go
@@ -13,9 +13,9 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
+ "encoding/hex"
"encoding/json"
"fmt"
- "io/ioutil"
"math/big"
"net/http"
"net/http/httptest"
@@ -485,95 +485,98 @@ func TestGetAuthorization(t *testing.T) {
}
func TestWaitAuthorization(t *testing.T) {
- var count int
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- count++
- w.Header().Set("Retry-After", "0")
- if count > 1 {
- fmt.Fprintf(w, `{"status":"valid"}`)
- return
+ t.Run("wait loop", func(t *testing.T) {
+ var count int
+ authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
+ count++
+ w.Header().Set("Retry-After", "0")
+ if count > 1 {
+ fmt.Fprintf(w, `{"status":"valid"}`)
+ return
+ }
+ fmt.Fprintf(w, `{"status":"pending"}`)
+ })
+ if err != nil {
+ t.Fatalf("non-nil error: %v", err)
}
- fmt.Fprintf(w, `{"status":"pending"}`)
- }))
- defer ts.Close()
-
- type res struct {
- authz *Authorization
- err error
- }
- done := make(chan res)
- defer close(done)
- go func() {
- var client Client
- a, err := client.WaitAuthorization(context.Background(), ts.URL)
- done <- res{a, err}
- }()
-
- select {
- case <-time.After(5 * time.Second):
- t.Fatal("WaitAuthz took too long to return")
- case res := <-done:
- if res.err != nil {
- t.Fatalf("res.err = %v", res.err)
+ if authz == nil {
+ t.Fatal("authz is nil")
+ }
+ })
+ t.Run("invalid status", func(t *testing.T) {
+ _, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, `{"status":"invalid"}`)
+ })
+ if _, ok := err.(*AuthorizationError); !ok {
+ t.Errorf("err is %v (%T); want non-nil *AuthorizationError", err, err)
+ }
+ })
+ t.Run("non-retriable error", func(t *testing.T) {
+ const code = http.StatusBadRequest
+ _, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(code)
+ })
+ res, ok := err.(*Error)
+ if !ok {
+ t.Fatalf("err is %v (%T); want a non-nil *Error", err, err)
}
- if res.authz == nil {
- t.Fatal("res.authz is nil")
+ if res.StatusCode != code {
+ t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code)
}
+ })
+ for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} {
+ t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) {
+ var count int
+ authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
+ count++
+ w.Header().Set("Retry-After", "0")
+ if count > 1 {
+ fmt.Fprintf(w, `{"status":"valid"}`)
+ return
+ }
+ w.WriteHeader(code)
+ })
+ if err != nil {
+ t.Fatalf("non-nil error: %v", err)
+ }
+ if authz == nil {
+ t.Fatal("authz is nil")
+ }
+ })
}
-}
-
-func TestWaitAuthorizationInvalid(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, `{"status":"invalid"}`)
- }))
- defer ts.Close()
-
- res := make(chan error)
- defer close(res)
- go func() {
- var client Client
- _, err := client.WaitAuthorization(context.Background(), ts.URL)
- res <- err
- }()
-
- select {
- case <-time.After(3 * time.Second):
- t.Fatal("WaitAuthz took too long to return")
- case err := <-res:
+ t.Run("context cancel", func(t *testing.T) {
+ ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
+ defer cancel()
+ _, err := runWaitAuthorization(ctx, t, func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Retry-After", "60")
+ fmt.Fprintf(w, `{"status":"pending"}`)
+ })
if err == nil {
t.Error("err is nil")
}
- if _, ok := err.(*AuthorizationError); !ok {
- t.Errorf("err is %T; want *AuthorizationError", err)
- }
- }
+ })
}
-
-func TestWaitAuthorizationCancel(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Retry-After", "60")
- fmt.Fprintf(w, `{"status":"pending"}`)
- }))
+func runWaitAuthorization(ctx context.Context, t *testing.T, h http.HandlerFunc) (*Authorization, error) {
+ t.Helper()
+ ts := httptest.NewServer(h)
defer ts.Close()
-
- res := make(chan error)
- defer close(res)
+ type res struct {
+ authz *Authorization
+ err error
+ }
+ ch := make(chan res, 1)
go func() {
var client Client
- ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
- defer cancel()
- _, err := client.WaitAuthorization(ctx, ts.URL)
- res <- err
+ a, err := client.WaitAuthorization(ctx, ts.URL)
+ ch <- res{a, err}
}()
-
select {
- case <-time.After(time.Second):
- t.Fatal("WaitAuthz took too long to return")
- case err := <-res:
- if err == nil {
- t.Error("err is nil")
- }
+ case <-time.After(3 * time.Second):
+ t.Fatal("WaitAuthorization took too long to return")
+ case v := <-ch:
+ return v.authz, v.err
}
+ panic("runWaitAuthorization: out of select")
}
func TestRevokeAuthorization(t *testing.T) {
@@ -600,7 +603,7 @@ func TestRevokeAuthorization(t *testing.T) {
t.Errorf("req.Delete is false")
}
case "/2":
- w.WriteHeader(http.StatusInternalServerError)
+ w.WriteHeader(http.StatusBadRequest)
}
}))
defer ts.Close()
@@ -821,7 +824,7 @@ func TestFetchCertRetry(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if count < 1 {
w.Header().Set("Retry-After", "0")
- w.WriteHeader(http.StatusAccepted)
+ w.WriteHeader(http.StatusTooManyRequests)
count++
return
}
@@ -1068,44 +1071,6 @@ func TestNonce_postJWS(t *testing.T) {
}
}
-func TestRetryPostJWS(t *testing.T) {
- var count int
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- count++
- w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
- if r.Method == "HEAD" {
- // We expect the client to do 2 head requests to fetch
- // nonces, one to start and another after getting badNonce
- return
- }
-
- head, err := decodeJWSHead(r)
- if err != nil {
- t.Errorf("decodeJWSHead: %v", err)
- } else if head.Nonce == "" {
- t.Error("head.Nonce is empty")
- } else if head.Nonce == "nonce1" {
- // return a badNonce error to force the call to retry
- w.WriteHeader(http.StatusBadRequest)
- w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`))
- return
- }
- // Make client.Authorize happy; we're not testing its result.
- w.WriteHeader(http.StatusCreated)
- w.Write([]byte(`{"status":"valid"}`))
- }))
- defer ts.Close()
-
- client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
- // This call will fail with badNonce, causing a retry
- if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
- t.Errorf("client.Authorize 1: %v", err)
- }
- if count != 4 {
- t.Errorf("total requests count: %d; want 4", count)
- }
-}
-
func TestLinkHeader(t *testing.T) {
h := http.Header{"Link": {
`<https://example.com/acme/new-authz>;rel="next"`,
@@ -1129,37 +1094,6 @@ func TestLinkHeader(t *testing.T) {
}
}
-func TestErrorResponse(t *testing.T) {
- s := `{
- "status": 400,
- "type": "urn:acme:error:xxx",
- "detail": "text"
- }`
- res := &http.Response{
- StatusCode: 400,
- Status: "400 Bad Request",
- Body: ioutil.NopCloser(strings.NewReader(s)),
- Header: http.Header{"X-Foo": {"bar"}},
- }
- err := responseError(res)
- v, ok := err.(*Error)
- if !ok {
- t.Fatalf("err = %+v (%T); want *Error type", err, err)
- }
- if v.StatusCode != 400 {
- t.Errorf("v.StatusCode = %v; want 400", v.StatusCode)
- }
- if v.ProblemType != "urn:acme:error:xxx" {
- t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType)
- }
- if v.Detail != "text" {
- t.Errorf("v.Detail = %q; want text", v.Detail)
- }
- if !reflect.DeepEqual(v.Header, res.Header) {
- t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header)
- }
-}
-
func TestTLSSNI01ChallengeCert(t *testing.T) {
const (
token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
@@ -1227,6 +1161,58 @@ func TestTLSSNI02ChallengeCert(t *testing.T) {
}
}
+func TestTLSALPN01ChallengeCert(t *testing.T) {
+ const (
+ token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
+ keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA." + testKeyECThumbprint
+ // echo -n <token.testKeyECThumbprint> | shasum -a 256
+ h = "0420dbbd5eefe7b4d06eb9d1d9f5acb4c7cda27d320e4b30332f0b6cb441734ad7b0"
+ domain = "example.com"
+ )
+
+ extValue, err := hex.DecodeString(h)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ client := &Client{Key: testKeyEC}
+ tlscert, err := client.TLSALPN01ChallengeCert(token, domain)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if n := len(tlscert.Certificate); n != 1 {
+ t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
+ }
+ cert, err := x509.ParseCertificate(tlscert.Certificate[0])
+ if err != nil {
+ t.Fatal(err)
+ }
+ names := []string{domain}
+ if !reflect.DeepEqual(cert.DNSNames, names) {
+ t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
+ }
+ if cn := cert.Subject.CommonName; cn != domain {
+ t.Errorf("CommonName = %q; want %q", cn, domain)
+ }
+ acmeExts := []pkix.Extension{}
+ for _, ext := range cert.Extensions {
+ if idPeACMEIdentifierV1.Equal(ext.Id) {
+ acmeExts = append(acmeExts, ext)
+ }
+ }
+ if len(acmeExts) != 1 {
+ t.Errorf("acmeExts = %v; want exactly one", acmeExts)
+ }
+ if !acmeExts[0].Critical {
+ t.Errorf("acmeExt.Critical = %v; want true", acmeExts[0].Critical)
+ }
+ if bytes.Compare(acmeExts[0].Value, extValue) != 0 {
+ t.Errorf("acmeExt.Value = %v; want %v", acmeExts[0].Value, extValue)
+ }
+
+}
+
func TestTLSChallengeCertOpt(t *testing.T) {
key, err := rsa.GenerateKey(rand.Reader, 512)
if err != nil {
@@ -1325,28 +1311,3 @@ func TestDNS01ChallengeRecord(t *testing.T) {
t.Errorf("val = %q; want %q", val, value)
}
}
-
-func TestBackoff(t *testing.T) {
- tt := []struct{ min, max time.Duration }{
- {time.Second, 2 * time.Second},
- {2 * time.Second, 3 * time.Second},
- {4 * time.Second, 5 * time.Second},
- {8 * time.Second, 9 * time.Second},
- }
- for i, test := range tt {
- d := backoff(i, time.Minute)
- if d < test.min || test.max < d {
- t.Errorf("%d: d = %v; want between %v and %v", i, d, test.min, test.max)
- }
- }
-
- min, max := time.Second, 2*time.Second
- if d := backoff(-1, time.Minute); d < min || max < d {
- t.Errorf("d = %v; want between %v and %v", d, min, max)
- }
-
- bound := 10 * time.Second
- if d := backoff(100, bound); d != bound {
- t.Errorf("d = %v; want %v", d, bound)
- }
-}