summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/crypto/acme
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2018-04-16 05:37:14 -0700
committerJoram Wilander <jwawilander@gmail.com>2018-04-16 08:37:14 -0400
commit6e2cb00008cbf09e556b00f87603797fcaa47e09 (patch)
tree3c0eb55ff4226a3f024aad373140d1fb860a6404 /vendor/golang.org/x/crypto/acme
parentbf24f51c4e1cc6286885460672f7f449e8c6f5ef (diff)
downloadchat-6e2cb00008cbf09e556b00f87603797fcaa47e09.tar.gz
chat-6e2cb00008cbf09e556b00f87603797fcaa47e09.tar.bz2
chat-6e2cb00008cbf09e556b00f87603797fcaa47e09.zip
Depenancy upgrades and movign to dep. (#8630)
Diffstat (limited to 'vendor/golang.org/x/crypto/acme')
-rw-r--r--vendor/golang.org/x/crypto/acme/acme.go9
-rw-r--r--vendor/golang.org/x/crypto/acme/acme_test.go1352
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/autocert_test.go757
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/cache_test.go58
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/example_test.go36
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/renewal.go33
-rw-r--r--vendor/golang.org/x/crypto/acme/autocert/renewal_test.go191
-rw-r--r--vendor/golang.org/x/crypto/acme/jws_test.go319
-rw-r--r--vendor/golang.org/x/crypto/acme/types_test.go63
9 files changed, 33 insertions, 2785 deletions
diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go
index fa9c4b39e..1f4fb69ed 100644
--- a/vendor/golang.org/x/crypto/acme/acme.go
+++ b/vendor/golang.org/x/crypto/acme/acme.go
@@ -400,7 +400,7 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
// WaitAuthorization polls an authorization at the given URL
// until it is in one of the final states, StatusValid or StatusInvalid,
-// or the context is done.
+// the ACME CA responded with a 4xx error code, or the context is done.
//
// It returns a non-nil Authorization only if its Status is StatusValid.
// In all other cases WaitAuthorization returns an error.
@@ -412,6 +412,13 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
if err != nil {
return nil, err
}
+ if res.StatusCode >= 400 && res.StatusCode <= 499 {
+ // Non-retriable error. For instance, Let's Encrypt may return 404 Not Found
+ // when requesting an expired authorization.
+ defer res.Body.Close()
+ return nil, responseError(res)
+ }
+
retry := res.Header.Get("Retry-After")
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
res.Body.Close()
diff --git a/vendor/golang.org/x/crypto/acme/acme_test.go b/vendor/golang.org/x/crypto/acme/acme_test.go
deleted file mode 100644
index 89f2efaa5..000000000
--- a/vendor/golang.org/x/crypto/acme/acme_test.go
+++ /dev/null
@@ -1,1352 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package acme
-
-import (
- "bytes"
- "context"
- "crypto/rand"
- "crypto/rsa"
- "crypto/tls"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "math/big"
- "net/http"
- "net/http/httptest"
- "reflect"
- "sort"
- "strings"
- "testing"
- "time"
-)
-
-// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
-// interface.
-func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
- // Decode request
- var req struct{ Payload string }
- if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
- t.Fatal(err)
- }
- payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
- if err != nil {
- t.Fatal(err)
- }
- err = json.Unmarshal(payload, v)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-type jwsHead struct {
- Alg string
- Nonce string
- JWK map[string]string `json:"jwk"`
-}
-
-func decodeJWSHead(r *http.Request) (*jwsHead, error) {
- var req struct{ Protected string }
- if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
- return nil, err
- }
- b, err := base64.RawURLEncoding.DecodeString(req.Protected)
- if err != nil {
- return nil, err
- }
- var head jwsHead
- if err := json.Unmarshal(b, &head); err != nil {
- return nil, err
- }
- return &head, nil
-}
-
-func TestDiscover(t *testing.T) {
- const (
- reg = "https://example.com/acme/new-reg"
- authz = "https://example.com/acme/new-authz"
- cert = "https://example.com/acme/new-cert"
- revoke = "https://example.com/acme/revoke-cert"
- )
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintf(w, `{
- "new-reg": %q,
- "new-authz": %q,
- "new-cert": %q,
- "revoke-cert": %q
- }`, reg, authz, cert, revoke)
- }))
- defer ts.Close()
- c := Client{DirectoryURL: ts.URL}
- dir, err := c.Discover(context.Background())
- if err != nil {
- t.Fatal(err)
- }
- if dir.RegURL != reg {
- t.Errorf("dir.RegURL = %q; want %q", dir.RegURL, reg)
- }
- if dir.AuthzURL != authz {
- t.Errorf("dir.AuthzURL = %q; want %q", dir.AuthzURL, authz)
- }
- if dir.CertURL != cert {
- t.Errorf("dir.CertURL = %q; want %q", dir.CertURL, cert)
- }
- if dir.RevokeURL != revoke {
- t.Errorf("dir.RevokeURL = %q; want %q", dir.RevokeURL, revoke)
- }
-}
-
-func TestRegister(t *testing.T) {
- contacts := []string{"mailto:admin@example.com"}
-
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "test-nonce")
- return
- }
- if r.Method != "POST" {
- t.Errorf("r.Method = %q; want POST", r.Method)
- }
-
- var j struct {
- Resource string
- Contact []string
- Agreement string
- }
- decodeJWSRequest(t, &j, r)
-
- // Test request
- if j.Resource != "new-reg" {
- t.Errorf("j.Resource = %q; want new-reg", j.Resource)
- }
- if !reflect.DeepEqual(j.Contact, contacts) {
- t.Errorf("j.Contact = %v; want %v", j.Contact, contacts)
- }
-
- w.Header().Set("Location", "https://ca.tld/acme/reg/1")
- w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
- w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
- w.Header().Add("Link", `<https://ca.tld/acme/terms>;rel="terms-of-service"`)
- w.WriteHeader(http.StatusCreated)
- b, _ := json.Marshal(contacts)
- fmt.Fprintf(w, `{"contact": %s}`, b)
- }))
- defer ts.Close()
-
- prompt := func(url string) bool {
- const terms = "https://ca.tld/acme/terms"
- if url != terms {
- t.Errorf("prompt url = %q; want %q", url, terms)
- }
- return false
- }
-
- c := Client{Key: testKeyEC, dir: &Directory{RegURL: ts.URL}}
- a := &Account{Contact: contacts}
- var err error
- if a, err = c.Register(context.Background(), a, prompt); err != nil {
- t.Fatal(err)
- }
- if a.URI != "https://ca.tld/acme/reg/1" {
- t.Errorf("a.URI = %q; want https://ca.tld/acme/reg/1", a.URI)
- }
- if a.Authz != "https://ca.tld/acme/new-authz" {
- t.Errorf("a.Authz = %q; want https://ca.tld/acme/new-authz", a.Authz)
- }
- if a.CurrentTerms != "https://ca.tld/acme/terms" {
- t.Errorf("a.CurrentTerms = %q; want https://ca.tld/acme/terms", a.CurrentTerms)
- }
- if !reflect.DeepEqual(a.Contact, contacts) {
- t.Errorf("a.Contact = %v; want %v", a.Contact, contacts)
- }
-}
-
-func TestUpdateReg(t *testing.T) {
- const terms = "https://ca.tld/acme/terms"
- contacts := []string{"mailto:admin@example.com"}
-
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "test-nonce")
- return
- }
- if r.Method != "POST" {
- t.Errorf("r.Method = %q; want POST", r.Method)
- }
-
- var j struct {
- Resource string
- Contact []string
- Agreement string
- }
- decodeJWSRequest(t, &j, r)
-
- // Test request
- if j.Resource != "reg" {
- t.Errorf("j.Resource = %q; want reg", j.Resource)
- }
- if j.Agreement != terms {
- t.Errorf("j.Agreement = %q; want %q", j.Agreement, terms)
- }
- if !reflect.DeepEqual(j.Contact, contacts) {
- t.Errorf("j.Contact = %v; want %v", j.Contact, contacts)
- }
-
- w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
- w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
- w.Header().Add("Link", fmt.Sprintf(`<%s>;rel="terms-of-service"`, terms))
- w.WriteHeader(http.StatusOK)
- b, _ := json.Marshal(contacts)
- fmt.Fprintf(w, `{"contact":%s, "agreement":%q}`, b, terms)
- }))
- defer ts.Close()
-
- c := Client{Key: testKeyEC}
- a := &Account{URI: ts.URL, Contact: contacts, AgreedTerms: terms}
- var err error
- if a, err = c.UpdateReg(context.Background(), a); err != nil {
- t.Fatal(err)
- }
- if a.Authz != "https://ca.tld/acme/new-authz" {
- t.Errorf("a.Authz = %q; want https://ca.tld/acme/new-authz", a.Authz)
- }
- if a.AgreedTerms != terms {
- t.Errorf("a.AgreedTerms = %q; want %q", a.AgreedTerms, terms)
- }
- if a.CurrentTerms != terms {
- t.Errorf("a.CurrentTerms = %q; want %q", a.CurrentTerms, terms)
- }
- if a.URI != ts.URL {
- t.Errorf("a.URI = %q; want %q", a.URI, ts.URL)
- }
-}
-
-func TestGetReg(t *testing.T) {
- const terms = "https://ca.tld/acme/terms"
- const newTerms = "https://ca.tld/acme/new-terms"
- contacts := []string{"mailto:admin@example.com"}
-
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "test-nonce")
- return
- }
- if r.Method != "POST" {
- t.Errorf("r.Method = %q; want POST", r.Method)
- }
-
- var j struct {
- Resource string
- Contact []string
- Agreement string
- }
- decodeJWSRequest(t, &j, r)
-
- // Test request
- if j.Resource != "reg" {
- t.Errorf("j.Resource = %q; want reg", j.Resource)
- }
- if len(j.Contact) != 0 {
- t.Errorf("j.Contact = %v", j.Contact)
- }
- if j.Agreement != "" {
- t.Errorf("j.Agreement = %q", j.Agreement)
- }
-
- w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
- w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
- w.Header().Add("Link", fmt.Sprintf(`<%s>;rel="terms-of-service"`, newTerms))
- w.WriteHeader(http.StatusOK)
- b, _ := json.Marshal(contacts)
- fmt.Fprintf(w, `{"contact":%s, "agreement":%q}`, b, terms)
- }))
- defer ts.Close()
-
- c := Client{Key: testKeyEC}
- a, err := c.GetReg(context.Background(), ts.URL)
- if err != nil {
- t.Fatal(err)
- }
- if a.Authz != "https://ca.tld/acme/new-authz" {
- t.Errorf("a.AuthzURL = %q; want https://ca.tld/acme/new-authz", a.Authz)
- }
- if a.AgreedTerms != terms {
- t.Errorf("a.AgreedTerms = %q; want %q", a.AgreedTerms, terms)
- }
- if a.CurrentTerms != newTerms {
- t.Errorf("a.CurrentTerms = %q; want %q", a.CurrentTerms, newTerms)
- }
- if a.URI != ts.URL {
- t.Errorf("a.URI = %q; want %q", a.URI, ts.URL)
- }
-}
-
-func TestAuthorize(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "test-nonce")
- return
- }
- if r.Method != "POST" {
- t.Errorf("r.Method = %q; want POST", r.Method)
- }
-
- var j struct {
- Resource string
- Identifier struct {
- Type string
- Value string
- }
- }
- decodeJWSRequest(t, &j, r)
-
- // Test request
- if j.Resource != "new-authz" {
- t.Errorf("j.Resource = %q; want new-authz", j.Resource)
- }
- if j.Identifier.Type != "dns" {
- t.Errorf("j.Identifier.Type = %q; want dns", j.Identifier.Type)
- }
- if j.Identifier.Value != "example.com" {
- t.Errorf("j.Identifier.Value = %q; want example.com", j.Identifier.Value)
- }
-
- w.Header().Set("Location", "https://ca.tld/acme/auth/1")
- w.WriteHeader(http.StatusCreated)
- fmt.Fprintf(w, `{
- "identifier": {"type":"dns","value":"example.com"},
- "status":"pending",
- "challenges":[
- {
- "type":"http-01",
- "status":"pending",
- "uri":"https://ca.tld/acme/challenge/publickey/id1",
- "token":"token1"
- },
- {
- "type":"tls-sni-01",
- "status":"pending",
- "uri":"https://ca.tld/acme/challenge/publickey/id2",
- "token":"token2"
- }
- ],
- "combinations":[[0],[1]]}`)
- }))
- defer ts.Close()
-
- cl := Client{Key: testKeyEC, dir: &Directory{AuthzURL: ts.URL}}
- auth, err := cl.Authorize(context.Background(), "example.com")
- if err != nil {
- t.Fatal(err)
- }
-
- if auth.URI != "https://ca.tld/acme/auth/1" {
- t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI)
- }
- if auth.Status != "pending" {
- t.Errorf("Status = %q; want pending", auth.Status)
- }
- if auth.Identifier.Type != "dns" {
- t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
- }
- if auth.Identifier.Value != "example.com" {
- t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
- }
-
- if n := len(auth.Challenges); n != 2 {
- t.Fatalf("len(auth.Challenges) = %d; want 2", n)
- }
-
- c := auth.Challenges[0]
- if c.Type != "http-01" {
- t.Errorf("c.Type = %q; want http-01", c.Type)
- }
- if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
- t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
- }
- if c.Token != "token1" {
- t.Errorf("c.Token = %q; want token1", c.Token)
- }
-
- c = auth.Challenges[1]
- if c.Type != "tls-sni-01" {
- t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
- }
- if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
- t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
- }
- if c.Token != "token2" {
- t.Errorf("c.Token = %q; want token2", c.Token)
- }
-
- combs := [][]int{{0}, {1}}
- if !reflect.DeepEqual(auth.Combinations, combs) {
- t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
- }
-}
-
-func TestAuthorizeValid(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "nonce")
- return
- }
- w.WriteHeader(http.StatusCreated)
- w.Write([]byte(`{"status":"valid"}`))
- }))
- defer ts.Close()
- client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
- _, err := client.Authorize(context.Background(), "example.com")
- if err != nil {
- t.Errorf("err = %v", err)
- }
-}
-
-func TestGetAuthorization(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method != "GET" {
- t.Errorf("r.Method = %q; want GET", r.Method)
- }
-
- w.WriteHeader(http.StatusOK)
- fmt.Fprintf(w, `{
- "identifier": {"type":"dns","value":"example.com"},
- "status":"pending",
- "challenges":[
- {
- "type":"http-01",
- "status":"pending",
- "uri":"https://ca.tld/acme/challenge/publickey/id1",
- "token":"token1"
- },
- {
- "type":"tls-sni-01",
- "status":"pending",
- "uri":"https://ca.tld/acme/challenge/publickey/id2",
- "token":"token2"
- }
- ],
- "combinations":[[0],[1]]}`)
- }))
- defer ts.Close()
-
- cl := Client{Key: testKeyEC}
- auth, err := cl.GetAuthorization(context.Background(), ts.URL)
- if err != nil {
- t.Fatal(err)
- }
-
- if auth.Status != "pending" {
- t.Errorf("Status = %q; want pending", auth.Status)
- }
- if auth.Identifier.Type != "dns" {
- t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
- }
- if auth.Identifier.Value != "example.com" {
- t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
- }
-
- if n := len(auth.Challenges); n != 2 {
- t.Fatalf("len(set.Challenges) = %d; want 2", n)
- }
-
- c := auth.Challenges[0]
- if c.Type != "http-01" {
- t.Errorf("c.Type = %q; want http-01", c.Type)
- }
- if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
- t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
- }
- if c.Token != "token1" {
- t.Errorf("c.Token = %q; want token1", c.Token)
- }
-
- c = auth.Challenges[1]
- if c.Type != "tls-sni-01" {
- t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
- }
- if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
- t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
- }
- if c.Token != "token2" {
- t.Errorf("c.Token = %q; want token2", c.Token)
- }
-
- combs := [][]int{{0}, {1}}
- if !reflect.DeepEqual(auth.Combinations, combs) {
- t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
- }
-}
-
-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
- }
- 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 res.authz == nil {
- t.Fatal("res.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:
- 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"}`)
- }))
- defer ts.Close()
-
- res := make(chan error)
- defer close(res)
- go func() {
- var client Client
- ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
- defer cancel()
- _, err := client.WaitAuthorization(ctx, ts.URL)
- res <- 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")
- }
- }
-}
-
-func TestRevokeAuthorization(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "nonce")
- return
- }
- switch r.URL.Path {
- case "/1":
- var req struct {
- Resource string
- Status string
- Delete bool
- }
- decodeJWSRequest(t, &req, r)
- if req.Resource != "authz" {
- t.Errorf("req.Resource = %q; want authz", req.Resource)
- }
- if req.Status != "deactivated" {
- t.Errorf("req.Status = %q; want deactivated", req.Status)
- }
- if !req.Delete {
- t.Errorf("req.Delete is false")
- }
- case "/2":
- w.WriteHeader(http.StatusInternalServerError)
- }
- }))
- defer ts.Close()
- client := &Client{Key: testKey}
- ctx := context.Background()
- if err := client.RevokeAuthorization(ctx, ts.URL+"/1"); err != nil {
- t.Errorf("err = %v", err)
- }
- if client.RevokeAuthorization(ctx, ts.URL+"/2") == nil {
- t.Error("nil error")
- }
-}
-
-func TestPollChallenge(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method != "GET" {
- t.Errorf("r.Method = %q; want GET", r.Method)
- }
-
- w.WriteHeader(http.StatusOK)
- fmt.Fprintf(w, `{
- "type":"http-01",
- "status":"pending",
- "uri":"https://ca.tld/acme/challenge/publickey/id1",
- "token":"token1"}`)
- }))
- defer ts.Close()
-
- cl := Client{Key: testKeyEC}
- chall, err := cl.GetChallenge(context.Background(), ts.URL)
- if err != nil {
- t.Fatal(err)
- }
-
- if chall.Status != "pending" {
- t.Errorf("Status = %q; want pending", chall.Status)
- }
- if chall.Type != "http-01" {
- t.Errorf("c.Type = %q; want http-01", chall.Type)
- }
- if chall.URI != "https://ca.tld/acme/challenge/publickey/id1" {
- t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", chall.URI)
- }
- if chall.Token != "token1" {
- t.Errorf("c.Token = %q; want token1", chall.Token)
- }
-}
-
-func TestAcceptChallenge(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "test-nonce")
- return
- }
- if r.Method != "POST" {
- t.Errorf("r.Method = %q; want POST", r.Method)
- }
-
- var j struct {
- Resource string
- Type string
- Auth string `json:"keyAuthorization"`
- }
- decodeJWSRequest(t, &j, r)
-
- // Test request
- if j.Resource != "challenge" {
- t.Errorf(`resource = %q; want "challenge"`, j.Resource)
- }
- if j.Type != "http-01" {
- t.Errorf(`type = %q; want "http-01"`, j.Type)
- }
- keyAuth := "token1." + testKeyECThumbprint
- if j.Auth != keyAuth {
- t.Errorf(`keyAuthorization = %q; want %q`, j.Auth, keyAuth)
- }
-
- // Respond to request
- w.WriteHeader(http.StatusAccepted)
- fmt.Fprintf(w, `{
- "type":"http-01",
- "status":"pending",
- "uri":"https://ca.tld/acme/challenge/publickey/id1",
- "token":"token1",
- "keyAuthorization":%q
- }`, keyAuth)
- }))
- defer ts.Close()
-
- cl := Client{Key: testKeyEC}
- c, err := cl.Accept(context.Background(), &Challenge{
- URI: ts.URL,
- Token: "token1",
- Type: "http-01",
- })
- if err != nil {
- t.Fatal(err)
- }
-
- if c.Type != "http-01" {
- t.Errorf("c.Type = %q; want http-01", c.Type)
- }
- if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
- t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
- }
- if c.Token != "token1" {
- t.Errorf("c.Token = %q; want token1", c.Token)
- }
-}
-
-func TestNewCert(t *testing.T) {
- notBefore := time.Now()
- notAfter := notBefore.AddDate(0, 2, 0)
- timeNow = func() time.Time { return notBefore }
-
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "test-nonce")
- return
- }
- if r.Method != "POST" {
- t.Errorf("r.Method = %q; want POST", r.Method)
- }
-
- var j struct {
- Resource string `json:"resource"`
- CSR string `json:"csr"`
- NotBefore string `json:"notBefore,omitempty"`
- NotAfter string `json:"notAfter,omitempty"`
- }
- decodeJWSRequest(t, &j, r)
-
- // Test request
- if j.Resource != "new-cert" {
- t.Errorf(`resource = %q; want "new-cert"`, j.Resource)
- }
- if j.NotBefore != notBefore.Format(time.RFC3339) {
- t.Errorf(`notBefore = %q; wanted %q`, j.NotBefore, notBefore.Format(time.RFC3339))
- }
- if j.NotAfter != notAfter.Format(time.RFC3339) {
- t.Errorf(`notAfter = %q; wanted %q`, j.NotAfter, notAfter.Format(time.RFC3339))
- }
-
- // Respond to request
- template := x509.Certificate{
- SerialNumber: big.NewInt(int64(1)),
- Subject: pkix.Name{
- Organization: []string{"goacme"},
- },
- NotBefore: notBefore,
- NotAfter: notAfter,
-
- KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
- ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
- BasicConstraintsValid: true,
- }
-
- sampleCert, err := x509.CreateCertificate(rand.Reader, &template, &template, &testKeyEC.PublicKey, testKeyEC)
- if err != nil {
- t.Fatalf("Error creating certificate: %v", err)
- }
-
- w.Header().Set("Location", "https://ca.tld/acme/cert/1")
- w.WriteHeader(http.StatusCreated)
- w.Write(sampleCert)
- }))
- defer ts.Close()
-
- csr := x509.CertificateRequest{
- Version: 0,
- Subject: pkix.Name{
- CommonName: "example.com",
- Organization: []string{"goacme"},
- },
- }
- csrb, err := x509.CreateCertificateRequest(rand.Reader, &csr, testKeyEC)
- if err != nil {
- t.Fatal(err)
- }
-
- c := Client{Key: testKeyEC, dir: &Directory{CertURL: ts.URL}}
- cert, certURL, err := c.CreateCert(context.Background(), csrb, notAfter.Sub(notBefore), false)
- if err != nil {
- t.Fatal(err)
- }
- if cert == nil {
- t.Errorf("cert is nil")
- }
- if certURL != "https://ca.tld/acme/cert/1" {
- t.Errorf("certURL = %q; want https://ca.tld/acme/cert/1", certURL)
- }
-}
-
-func TestFetchCert(t *testing.T) {
- var count byte
- var ts *httptest.Server
- ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- count++
- if count < 3 {
- up := fmt.Sprintf("<%s>;rel=up", ts.URL)
- w.Header().Set("Link", up)
- }
- w.Write([]byte{count})
- }))
- defer ts.Close()
- res, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
- if err != nil {
- t.Fatalf("FetchCert: %v", err)
- }
- cert := [][]byte{{1}, {2}, {3}}
- if !reflect.DeepEqual(res, cert) {
- t.Errorf("res = %v; want %v", res, cert)
- }
-}
-
-func TestFetchCertRetry(t *testing.T) {
- var count int
- 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)
- count++
- return
- }
- w.Write([]byte{1})
- }))
- defer ts.Close()
- res, err := (&Client{}).FetchCert(context.Background(), ts.URL, false)
- if err != nil {
- t.Fatalf("FetchCert: %v", err)
- }
- cert := [][]byte{{1}}
- if !reflect.DeepEqual(res, cert) {
- t.Errorf("res = %v; want %v", res, cert)
- }
-}
-
-func TestFetchCertCancel(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Retry-After", "0")
- w.WriteHeader(http.StatusAccepted)
- }))
- defer ts.Close()
- ctx, cancel := context.WithCancel(context.Background())
- done := make(chan struct{})
- var err error
- go func() {
- _, err = (&Client{}).FetchCert(ctx, ts.URL, false)
- close(done)
- }()
- cancel()
- <-done
- if err != context.Canceled {
- t.Errorf("err = %v; want %v", err, context.Canceled)
- }
-}
-
-func TestFetchCertDepth(t *testing.T) {
- var count byte
- var ts *httptest.Server
- ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- count++
- if count > maxChainLen+1 {
- t.Errorf("count = %d; want at most %d", count, maxChainLen+1)
- w.WriteHeader(http.StatusInternalServerError)
- }
- w.Header().Set("Link", fmt.Sprintf("<%s>;rel=up", ts.URL))
- w.Write([]byte{count})
- }))
- defer ts.Close()
- _, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
- if err == nil {
- t.Errorf("err is nil")
- }
-}
-
-func TestFetchCertBreadth(t *testing.T) {
- var ts *httptest.Server
- ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- for i := 0; i < maxChainLen+1; i++ {
- w.Header().Add("Link", fmt.Sprintf("<%s>;rel=up", ts.URL))
- }
- w.Write([]byte{1})
- }))
- defer ts.Close()
- _, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
- if err == nil {
- t.Errorf("err is nil")
- }
-}
-
-func TestFetchCertSize(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- b := bytes.Repeat([]byte{1}, maxCertSize+1)
- w.Write(b)
- }))
- defer ts.Close()
- _, err := (&Client{}).FetchCert(context.Background(), ts.URL, false)
- if err == nil {
- t.Errorf("err is nil")
- }
-}
-
-func TestRevokeCert(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method == "HEAD" {
- w.Header().Set("Replay-Nonce", "nonce")
- return
- }
-
- var req struct {
- Resource string
- Certificate string
- Reason int
- }
- decodeJWSRequest(t, &req, r)
- if req.Resource != "revoke-cert" {
- t.Errorf("req.Resource = %q; want revoke-cert", req.Resource)
- }
- if req.Reason != 1 {
- t.Errorf("req.Reason = %d; want 1", req.Reason)
- }
- // echo -n cert | base64 | tr -d '=' | tr '/+' '_-'
- cert := "Y2VydA"
- if req.Certificate != cert {
- t.Errorf("req.Certificate = %q; want %q", req.Certificate, cert)
- }
- }))
- defer ts.Close()
- client := &Client{
- Key: testKeyEC,
- dir: &Directory{RevokeURL: ts.URL},
- }
- ctx := context.Background()
- if err := client.RevokeCert(ctx, nil, []byte("cert"), CRLReasonKeyCompromise); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestNonce_add(t *testing.T) {
- var c Client
- c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
- c.addNonce(http.Header{"Replay-Nonce": {}})
- c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
-
- nonces := map[string]struct{}{"nonce": {}}
- if !reflect.DeepEqual(c.nonces, nonces) {
- t.Errorf("c.nonces = %q; want %q", c.nonces, nonces)
- }
-}
-
-func TestNonce_addMax(t *testing.T) {
- c := &Client{nonces: make(map[string]struct{})}
- for i := 0; i < maxNonces; i++ {
- c.nonces[fmt.Sprintf("%d", i)] = struct{}{}
- }
- c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
- if n := len(c.nonces); n != maxNonces {
- t.Errorf("len(c.nonces) = %d; want %d", n, maxNonces)
- }
-}
-
-func TestNonce_fetch(t *testing.T) {
- tests := []struct {
- code int
- nonce string
- }{
- {http.StatusOK, "nonce1"},
- {http.StatusBadRequest, "nonce2"},
- {http.StatusOK, ""},
- }
- var i int
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method != "HEAD" {
- t.Errorf("%d: r.Method = %q; want HEAD", i, r.Method)
- }
- w.Header().Set("Replay-Nonce", tests[i].nonce)
- w.WriteHeader(tests[i].code)
- }))
- defer ts.Close()
- for ; i < len(tests); i++ {
- test := tests[i]
- c := &Client{}
- n, err := c.fetchNonce(context.Background(), ts.URL)
- if n != test.nonce {
- t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
- }
- switch {
- case err == nil && test.nonce == "":
- t.Errorf("%d: n=%q, err=%v; want non-nil error", i, n, err)
- case err != nil && test.nonce != "":
- t.Errorf("%d: n=%q, err=%v; want %q", i, n, err, test.nonce)
- }
- }
-}
-
-func TestNonce_fetchError(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusTooManyRequests)
- }))
- defer ts.Close()
- c := &Client{}
- _, err := c.fetchNonce(context.Background(), ts.URL)
- e, ok := err.(*Error)
- if !ok {
- t.Fatalf("err is %T; want *Error", err)
- }
- if e.StatusCode != http.StatusTooManyRequests {
- t.Errorf("e.StatusCode = %d; want %d", e.StatusCode, http.StatusTooManyRequests)
- }
-}
-
-func TestNonce_postJWS(t *testing.T) {
- var count int
- seen := make(map[string]bool)
- 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 do a HEAD request
- // but only to fetch the first nonce.
- return
- }
- // Make client.Authorize happy; we're not testing its result.
- defer func() {
- w.WriteHeader(http.StatusCreated)
- w.Write([]byte(`{"status":"valid"}`))
- }()
-
- head, err := decodeJWSHead(r)
- if err != nil {
- t.Errorf("decodeJWSHead: %v", err)
- return
- }
- if head.Nonce == "" {
- t.Error("head.Nonce is empty")
- return
- }
- if seen[head.Nonce] {
- t.Errorf("nonce is already used: %q", head.Nonce)
- }
- seen[head.Nonce] = true
- }))
- defer ts.Close()
-
- client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
- if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
- t.Errorf("client.Authorize 1: %v", err)
- }
- // The second call should not generate another extra HEAD request.
- if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
- t.Errorf("client.Authorize 2: %v", err)
- }
-
- if count != 3 {
- t.Errorf("total requests count: %d; want 3", count)
- }
- if n := len(client.nonces); n != 1 {
- t.Errorf("len(client.nonces) = %d; want 1", n)
- }
- for k := range seen {
- if _, exist := client.nonces[k]; exist {
- t.Errorf("used nonce %q in client.nonces", k)
- }
- }
-}
-
-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"`,
- `<https://example.com/acme/recover-reg>; rel=recover`,
- `<https://example.com/acme/terms>; foo=bar; rel="terms-of-service"`,
- `<dup>;rel="next"`,
- }}
- tests := []struct {
- rel string
- out []string
- }{
- {"next", []string{"https://example.com/acme/new-authz", "dup"}},
- {"recover", []string{"https://example.com/acme/recover-reg"}},
- {"terms-of-service", []string{"https://example.com/acme/terms"}},
- {"empty", nil},
- }
- for i, test := range tests {
- if v := linkHeader(h, test.rel); !reflect.DeepEqual(v, test.out) {
- t.Errorf("%d: linkHeader(%q): %v; want %v", i, test.rel, v, test.out)
- }
- }
-}
-
-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"
- // echo -n <token.testKeyECThumbprint> | shasum -a 256
- san = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.acme.invalid"
- )
-
- client := &Client{Key: testKeyEC}
- tlscert, name, err := client.TLSSNI01ChallengeCert(token)
- 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)
- }
- if len(cert.DNSNames) != 1 || cert.DNSNames[0] != san {
- t.Fatalf("cert.DNSNames = %v; want %q", cert.DNSNames, san)
- }
- if cert.DNSNames[0] != name {
- t.Errorf("cert.DNSNames[0] != name: %q vs %q", cert.DNSNames[0], name)
- }
- if cn := cert.Subject.CommonName; cn != san {
- t.Errorf("cert.Subject.CommonName = %q; want %q", cn, san)
- }
-}
-
-func TestTLSSNI02ChallengeCert(t *testing.T) {
- const (
- token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
- // echo -n evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA | shasum -a 256
- sanA = "7ea0aaa69214e71e02cebb18bb867736.09b730209baabf60e43d4999979ff139.token.acme.invalid"
- // echo -n <token.testKeyECThumbprint> | shasum -a 256
- sanB = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.ka.acme.invalid"
- )
-
- client := &Client{Key: testKeyEC}
- tlscert, name, err := client.TLSSNI02ChallengeCert(token)
- 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{sanA, sanB}
- if !reflect.DeepEqual(cert.DNSNames, names) {
- t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
- }
- sort.Strings(cert.DNSNames)
- i := sort.SearchStrings(cert.DNSNames, name)
- if i >= len(cert.DNSNames) || cert.DNSNames[i] != name {
- t.Errorf("%v doesn't have %q", cert.DNSNames, name)
- }
- if cn := cert.Subject.CommonName; cn != sanA {
- t.Errorf("CommonName = %q; want %q", cn, sanA)
- }
-}
-
-func TestTLSChallengeCertOpt(t *testing.T) {
- key, err := rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- t.Fatal(err)
- }
- tmpl := &x509.Certificate{
- SerialNumber: big.NewInt(2),
- Subject: pkix.Name{Organization: []string{"Test"}},
- DNSNames: []string{"should-be-overwritten"},
- }
- opts := []CertOption{WithKey(key), WithTemplate(tmpl)}
-
- client := &Client{Key: testKeyEC}
- cert1, _, err := client.TLSSNI01ChallengeCert("token", opts...)
- if err != nil {
- t.Fatal(err)
- }
- cert2, _, err := client.TLSSNI02ChallengeCert("token", opts...)
- if err != nil {
- t.Fatal(err)
- }
-
- for i, tlscert := range []tls.Certificate{cert1, cert2} {
- // verify generated cert private key
- tlskey, ok := tlscert.PrivateKey.(*rsa.PrivateKey)
- if !ok {
- t.Errorf("%d: tlscert.PrivateKey is %T; want *rsa.PrivateKey", i, tlscert.PrivateKey)
- continue
- }
- if tlskey.D.Cmp(key.D) != 0 {
- t.Errorf("%d: tlskey.D = %v; want %v", i, tlskey.D, key.D)
- }
- // verify generated cert public key
- x509Cert, err := x509.ParseCertificate(tlscert.Certificate[0])
- if err != nil {
- t.Errorf("%d: %v", i, err)
- continue
- }
- tlspub, ok := x509Cert.PublicKey.(*rsa.PublicKey)
- if !ok {
- t.Errorf("%d: x509Cert.PublicKey is %T; want *rsa.PublicKey", i, x509Cert.PublicKey)
- continue
- }
- if tlspub.N.Cmp(key.N) != 0 {
- t.Errorf("%d: tlspub.N = %v; want %v", i, tlspub.N, key.N)
- }
- // verify template option
- sn := big.NewInt(2)
- if x509Cert.SerialNumber.Cmp(sn) != 0 {
- t.Errorf("%d: SerialNumber = %v; want %v", i, x509Cert.SerialNumber, sn)
- }
- org := []string{"Test"}
- if !reflect.DeepEqual(x509Cert.Subject.Organization, org) {
- t.Errorf("%d: Subject.Organization = %+v; want %+v", i, x509Cert.Subject.Organization, org)
- }
- for _, v := range x509Cert.DNSNames {
- if !strings.HasSuffix(v, ".acme.invalid") {
- t.Errorf("%d: invalid DNSNames element: %q", i, v)
- }
- }
- }
-}
-
-func TestHTTP01Challenge(t *testing.T) {
- const (
- token = "xxx"
- // thumbprint is precomputed for testKeyEC in jws_test.go
- value = token + "." + testKeyECThumbprint
- urlpath = "/.well-known/acme-challenge/" + token
- )
- client := &Client{Key: testKeyEC}
- val, err := client.HTTP01ChallengeResponse(token)
- if err != nil {
- t.Fatal(err)
- }
- if val != value {
- t.Errorf("val = %q; want %q", val, value)
- }
- if path := client.HTTP01ChallengePath(token); path != urlpath {
- t.Errorf("path = %q; want %q", path, urlpath)
- }
-}
-
-func TestDNS01ChallengeRecord(t *testing.T) {
- // echo -n xxx.<testKeyECThumbprint> | \
- // openssl dgst -binary -sha256 | \
- // base64 | tr -d '=' | tr '/+' '_-'
- const value = "8DERMexQ5VcdJ_prpPiA0mVdp7imgbCgjsG4SqqNMIo"
-
- client := &Client{Key: testKeyEC}
- val, err := client.DNS01ChallengeRecord("xxx")
- if err != nil {
- t.Fatal(err)
- }
- if val != value {
- 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)
- }
-}
diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go b/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
deleted file mode 100644
index 2da1912e9..000000000
--- a/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
+++ /dev/null
@@ -1,757 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package autocert
-
-import (
- "context"
- "crypto"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/rsa"
- "crypto/tls"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "html/template"
- "io"
- "math/big"
- "net/http"
- "net/http/httptest"
- "reflect"
- "strings"
- "sync"
- "testing"
- "time"
-
- "golang.org/x/crypto/acme"
-)
-
-var discoTmpl = template.Must(template.New("disco").Parse(`{
- "new-reg": "{{.}}/new-reg",
- "new-authz": "{{.}}/new-authz",
- "new-cert": "{{.}}/new-cert"
-}`))
-
-var authzTmpl = template.Must(template.New("authz").Parse(`{
- "status": "pending",
- "challenges": [
- {
- "uri": "{{.}}/challenge/1",
- "type": "tls-sni-01",
- "token": "token-01"
- },
- {
- "uri": "{{.}}/challenge/2",
- "type": "tls-sni-02",
- "token": "token-02"
- },
- {
- "uri": "{{.}}/challenge/dns-01",
- "type": "dns-01",
- "token": "token-dns-01"
- },
- {
- "uri": "{{.}}/challenge/http-01",
- "type": "http-01",
- "token": "token-http-01"
- }
- ]
-}`))
-
-type memCache struct {
- mu sync.Mutex
- keyData map[string][]byte
-}
-
-func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) {
- m.mu.Lock()
- defer m.mu.Unlock()
-
- v, ok := m.keyData[key]
- if !ok {
- return nil, ErrCacheMiss
- }
- return v, nil
-}
-
-func (m *memCache) Put(ctx context.Context, key string, data []byte) error {
- m.mu.Lock()
- defer m.mu.Unlock()
-
- m.keyData[key] = data
- return nil
-}
-
-func (m *memCache) Delete(ctx context.Context, key string) error {
- m.mu.Lock()
- defer m.mu.Unlock()
-
- delete(m.keyData, key)
- return nil
-}
-
-func newMemCache() *memCache {
- return &memCache{
- keyData: make(map[string][]byte),
- }
-}
-
-func dummyCert(pub interface{}, san ...string) ([]byte, error) {
- return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
-}
-
-func dateDummyCert(pub interface{}, start, end time.Time, san ...string) ([]byte, error) {
- // use EC key to run faster on 386
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- return nil, err
- }
- t := &x509.Certificate{
- SerialNumber: big.NewInt(1),
- NotBefore: start,
- NotAfter: end,
- BasicConstraintsValid: true,
- KeyUsage: x509.KeyUsageKeyEncipherment,
- DNSNames: san,
- }
- if pub == nil {
- pub = &key.PublicKey
- }
- return x509.CreateCertificate(rand.Reader, t, t, pub, key)
-}
-
-func decodePayload(v interface{}, r io.Reader) error {
- var req struct{ Payload string }
- if err := json.NewDecoder(r).Decode(&req); err != nil {
- return err
- }
- payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
- if err != nil {
- return err
- }
- return json.Unmarshal(payload, v)
-}
-
-func TestGetCertificate(t *testing.T) {
- man := &Manager{Prompt: AcceptTOS}
- defer man.stopRenew()
- hello := &tls.ClientHelloInfo{ServerName: "example.org"}
- testGetCertificate(t, man, "example.org", hello)
-}
-
-func TestGetCertificate_trailingDot(t *testing.T) {
- man := &Manager{Prompt: AcceptTOS}
- defer man.stopRenew()
- hello := &tls.ClientHelloInfo{ServerName: "example.org."}
- testGetCertificate(t, man, "example.org", hello)
-}
-
-func TestGetCertificate_ForceRSA(t *testing.T) {
- man := &Manager{
- Prompt: AcceptTOS,
- Cache: newMemCache(),
- ForceRSA: true,
- }
- defer man.stopRenew()
- hello := &tls.ClientHelloInfo{ServerName: "example.org"}
- testGetCertificate(t, man, "example.org", hello)
-
- cert, err := man.cacheGet(context.Background(), "example.org")
- if err != nil {
- t.Fatalf("man.cacheGet: %v", err)
- }
- if _, ok := cert.PrivateKey.(*rsa.PrivateKey); !ok {
- t.Errorf("cert.PrivateKey is %T; want *rsa.PrivateKey", cert.PrivateKey)
- }
-}
-
-func TestGetCertificate_nilPrompt(t *testing.T) {
- man := &Manager{}
- defer man.stopRenew()
- url, finish := startACMEServerStub(t, man, "example.org")
- defer finish()
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- man.Client = &acme.Client{
- Key: key,
- DirectoryURL: url,
- }
- hello := &tls.ClientHelloInfo{ServerName: "example.org"}
- if _, err := man.GetCertificate(hello); err == nil {
- t.Error("got certificate for example.org; wanted error")
- }
-}
-
-func TestGetCertificate_expiredCache(t *testing.T) {
- // Make an expired cert and cache it.
- pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- tmpl := &x509.Certificate{
- SerialNumber: big.NewInt(1),
- Subject: pkix.Name{CommonName: "example.org"},
- NotAfter: time.Now(),
- }
- pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
- if err != nil {
- t.Fatal(err)
- }
- tlscert := &tls.Certificate{
- Certificate: [][]byte{pub},
- PrivateKey: pk,
- }
-
- man := &Manager{Prompt: AcceptTOS, Cache: newMemCache()}
- defer man.stopRenew()
- if err := man.cachePut(context.Background(), "example.org", tlscert); err != nil {
- t.Fatalf("man.cachePut: %v", err)
- }
-
- // The expired cached cert should trigger a new cert issuance
- // and return without an error.
- hello := &tls.ClientHelloInfo{ServerName: "example.org"}
- testGetCertificate(t, man, "example.org", hello)
-}
-
-func TestGetCertificate_failedAttempt(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusBadRequest)
- }))
- defer ts.Close()
-
- const example = "example.org"
- d := createCertRetryAfter
- f := testDidRemoveState
- defer func() {
- createCertRetryAfter = d
- testDidRemoveState = f
- }()
- createCertRetryAfter = 0
- done := make(chan struct{})
- testDidRemoveState = func(domain string) {
- if domain != example {
- t.Errorf("testDidRemoveState: domain = %q; want %q", domain, example)
- }
- close(done)
- }
-
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- man := &Manager{
- Prompt: AcceptTOS,
- Client: &acme.Client{
- Key: key,
- DirectoryURL: ts.URL,
- },
- }
- defer man.stopRenew()
- hello := &tls.ClientHelloInfo{ServerName: example}
- if _, err := man.GetCertificate(hello); err == nil {
- t.Error("GetCertificate: err is nil")
- }
- select {
- case <-time.After(5 * time.Second):
- t.Errorf("took too long to remove the %q state", example)
- case <-done:
- man.stateMu.Lock()
- defer man.stateMu.Unlock()
- if v, exist := man.state[example]; exist {
- t.Errorf("state exists for %q: %+v", example, v)
- }
- }
-}
-
-// startACMEServerStub runs an ACME server
-// The domain argument is the expected domain name of a certificate request.
-func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, finish func()) {
- // echo token-02 | shasum -a 256
- // then divide result in 2 parts separated by dot
- tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
- verifyTokenCert := func() {
- hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
- _, err := man.GetCertificate(hello)
- if err != nil {
- t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err)
- return
- }
- }
-
- // ACME CA server stub
- var ca *httptest.Server
- ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Replay-Nonce", "nonce")
- if r.Method == "HEAD" {
- // a nonce request
- return
- }
-
- switch r.URL.Path {
- // discovery
- case "/":
- if err := discoTmpl.Execute(w, ca.URL); err != nil {
- t.Errorf("discoTmpl: %v", err)
- }
- // client key registration
- case "/new-reg":
- w.Write([]byte("{}"))
- // domain authorization
- case "/new-authz":
- w.Header().Set("Location", ca.URL+"/authz/1")
- w.WriteHeader(http.StatusCreated)
- if err := authzTmpl.Execute(w, ca.URL); err != nil {
- t.Errorf("authzTmpl: %v", err)
- }
- // accept tls-sni-02 challenge
- case "/challenge/2":
- verifyTokenCert()
- w.Write([]byte("{}"))
- // authorization status
- case "/authz/1":
- w.Write([]byte(`{"status": "valid"}`))
- // cert request
- case "/new-cert":
- var req struct {
- CSR string `json:"csr"`
- }
- decodePayload(&req, r.Body)
- b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
- csr, err := x509.ParseCertificateRequest(b)
- if err != nil {
- t.Errorf("new-cert: CSR: %v", err)
- }
- if csr.Subject.CommonName != domain {
- t.Errorf("CommonName in CSR = %q; want %q", csr.Subject.CommonName, domain)
- }
- der, err := dummyCert(csr.PublicKey, domain)
- if err != nil {
- t.Errorf("new-cert: dummyCert: %v", err)
- }
- chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
- w.Header().Set("Link", chainUp)
- w.WriteHeader(http.StatusCreated)
- w.Write(der)
- // CA chain cert
- case "/ca-cert":
- der, err := dummyCert(nil, "ca")
- if err != nil {
- t.Errorf("ca-cert: dummyCert: %v", err)
- }
- w.Write(der)
- default:
- t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
- }
- }))
- finish = func() {
- ca.Close()
-
- // make sure token cert was removed
- cancel := make(chan struct{})
- done := make(chan struct{})
- go func() {
- defer close(done)
- tick := time.NewTicker(100 * time.Millisecond)
- defer tick.Stop()
- for {
- hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
- if _, err := man.GetCertificate(hello); err != nil {
- return
- }
- select {
- case <-tick.C:
- case <-cancel:
- return
- }
- }
- }()
- select {
- case <-done:
- case <-time.After(5 * time.Second):
- close(cancel)
- t.Error("token cert was not removed")
- <-done
- }
- }
- return ca.URL, finish
-}
-
-// tests man.GetCertificate flow using the provided hello argument.
-// The domain argument is the expected domain name of a certificate request.
-func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) {
- url, finish := startACMEServerStub(t, man, domain)
- defer finish()
-
- // use EC key to run faster on 386
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- man.Client = &acme.Client{
- Key: key,
- DirectoryURL: url,
- }
-
- // simulate tls.Config.GetCertificate
- var tlscert *tls.Certificate
- done := make(chan struct{})
- go func() {
- tlscert, err = man.GetCertificate(hello)
- close(done)
- }()
- select {
- case <-time.After(time.Minute):
- t.Fatal("man.GetCertificate took too long to return")
- case <-done:
- }
- if err != nil {
- t.Fatalf("man.GetCertificate: %v", err)
- }
-
- // verify the tlscert is the same we responded with from the CA stub
- if len(tlscert.Certificate) == 0 {
- t.Fatal("len(tlscert.Certificate) is 0")
- }
- cert, err := x509.ParseCertificate(tlscert.Certificate[0])
- if err != nil {
- t.Fatalf("x509.ParseCertificate: %v", err)
- }
- if len(cert.DNSNames) == 0 || cert.DNSNames[0] != domain {
- t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain)
- }
-
-}
-
-func TestVerifyHTTP01(t *testing.T) {
- var (
- http01 http.Handler
-
- authzCount int // num. of created authorizations
- didAcceptHTTP01 bool
- )
-
- verifyHTTPToken := func() {
- r := httptest.NewRequest("GET", "/.well-known/acme-challenge/token-http-01", nil)
- w := httptest.NewRecorder()
- http01.ServeHTTP(w, r)
- if w.Code != http.StatusOK {
- t.Errorf("http token: w.Code = %d; want %d", w.Code, http.StatusOK)
- }
- if v := string(w.Body.Bytes()); !strings.HasPrefix(v, "token-http-01.") {
- t.Errorf("http token value = %q; want 'token-http-01.' prefix", v)
- }
- }
-
- // ACME CA server stub, only the needed bits.
- // TODO: Merge this with startACMEServerStub, making it a configurable CA for testing.
- var ca *httptest.Server
- ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Replay-Nonce", "nonce")
- if r.Method == "HEAD" {
- // a nonce request
- return
- }
-
- switch r.URL.Path {
- // Discovery.
- case "/":
- if err := discoTmpl.Execute(w, ca.URL); err != nil {
- t.Errorf("discoTmpl: %v", err)
- }
- // Client key registration.
- case "/new-reg":
- w.Write([]byte("{}"))
- // New domain authorization.
- case "/new-authz":
- authzCount++
- w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount))
- w.WriteHeader(http.StatusCreated)
- if err := authzTmpl.Execute(w, ca.URL); err != nil {
- t.Errorf("authzTmpl: %v", err)
- }
- // Accept tls-sni-02.
- case "/challenge/2":
- w.Write([]byte("{}"))
- // Reject tls-sni-01.
- case "/challenge/1":
- http.Error(w, "won't accept tls-sni-01", http.StatusBadRequest)
- // Should not accept dns-01.
- case "/challenge/dns-01":
- t.Errorf("dns-01 challenge was accepted")
- http.Error(w, "won't accept dns-01", http.StatusBadRequest)
- // Accept http-01.
- case "/challenge/http-01":
- didAcceptHTTP01 = true
- verifyHTTPToken()
- w.Write([]byte("{}"))
- // Authorization statuses.
- // Make tls-sni-xxx invalid.
- case "/authz/1", "/authz/2":
- w.Write([]byte(`{"status": "invalid"}`))
- case "/authz/3", "/authz/4":
- w.Write([]byte(`{"status": "valid"}`))
- default:
- http.NotFound(w, r)
- t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
- }
- }))
- defer ca.Close()
-
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- m := &Manager{
- Client: &acme.Client{
- Key: key,
- DirectoryURL: ca.URL,
- },
- }
- http01 = m.HTTPHandler(nil)
- if err := m.verify(context.Background(), m.Client, "example.org"); err != nil {
- t.Errorf("m.verify: %v", err)
- }
- // Only tls-sni-01, tls-sni-02 and http-01 must be accepted
- // The dns-01 challenge is unsupported.
- if authzCount != 3 {
- t.Errorf("authzCount = %d; want 3", authzCount)
- }
- if !didAcceptHTTP01 {
- t.Error("did not accept http-01 challenge")
- }
-}
-
-func TestHTTPHandlerDefaultFallback(t *testing.T) {
- tt := []struct {
- method, url string
- wantCode int
- wantLocation string
- }{
- {"GET", "http://example.org", 302, "https://example.org/"},
- {"GET", "http://example.org/foo", 302, "https://example.org/foo"},
- {"GET", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"},
- {"GET", "http://example.org/?a=b", 302, "https://example.org/?a=b"},
- {"GET", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"},
- {"GET", "http://example.org:80/foo?a=b", 302, "https://example.org:443/foo?a=b"},
- {"GET", "http://example.org:80/foo%20bar", 302, "https://example.org:443/foo%20bar"},
- {"GET", "http://[2602:d1:xxxx::c60a]:1234", 302, "https://[2602:d1:xxxx::c60a]:443/"},
- {"GET", "http://[2602:d1:xxxx::c60a]", 302, "https://[2602:d1:xxxx::c60a]/"},
- {"GET", "http://[2602:d1:xxxx::c60a]/foo?a=b", 302, "https://[2602:d1:xxxx::c60a]/foo?a=b"},
- {"HEAD", "http://example.org", 302, "https://example.org/"},
- {"HEAD", "http://example.org/foo", 302, "https://example.org/foo"},
- {"HEAD", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"},
- {"HEAD", "http://example.org/?a=b", 302, "https://example.org/?a=b"},
- {"HEAD", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"},
- {"POST", "http://example.org", 400, ""},
- {"PUT", "http://example.org", 400, ""},
- {"GET", "http://example.org/.well-known/acme-challenge/x", 404, ""},
- }
- var m Manager
- h := m.HTTPHandler(nil)
- for i, test := range tt {
- r := httptest.NewRequest(test.method, test.url, nil)
- w := httptest.NewRecorder()
- h.ServeHTTP(w, r)
- if w.Code != test.wantCode {
- t.Errorf("%d: w.Code = %d; want %d", i, w.Code, test.wantCode)
- t.Errorf("%d: body: %s", i, w.Body.Bytes())
- }
- if v := w.Header().Get("Location"); v != test.wantLocation {
- t.Errorf("%d: Location = %q; want %q", i, v, test.wantLocation)
- }
- }
-}
-
-func TestAccountKeyCache(t *testing.T) {
- m := Manager{Cache: newMemCache()}
- ctx := context.Background()
- k1, err := m.accountKey(ctx)
- if err != nil {
- t.Fatal(err)
- }
- k2, err := m.accountKey(ctx)
- if err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(k1, k2) {
- t.Errorf("account keys don't match: k1 = %#v; k2 = %#v", k1, k2)
- }
-}
-
-func TestCache(t *testing.T) {
- privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- tmpl := &x509.Certificate{
- SerialNumber: big.NewInt(1),
- Subject: pkix.Name{CommonName: "example.org"},
- NotAfter: time.Now().Add(time.Hour),
- }
- pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey)
- if err != nil {
- t.Fatal(err)
- }
- tlscert := &tls.Certificate{
- Certificate: [][]byte{pub},
- PrivateKey: privKey,
- }
-
- man := &Manager{Cache: newMemCache()}
- defer man.stopRenew()
- ctx := context.Background()
- if err := man.cachePut(ctx, "example.org", tlscert); err != nil {
- t.Fatalf("man.cachePut: %v", err)
- }
- res, err := man.cacheGet(ctx, "example.org")
- if err != nil {
- t.Fatalf("man.cacheGet: %v", err)
- }
- if res == nil {
- t.Fatal("res is nil")
- }
-}
-
-func TestHostWhitelist(t *testing.T) {
- policy := HostWhitelist("example.com", "example.org", "*.example.net")
- tt := []struct {
- host string
- allow bool
- }{
- {"example.com", true},
- {"example.org", true},
- {"one.example.com", false},
- {"two.example.org", false},
- {"three.example.net", false},
- {"dummy", false},
- }
- for i, test := range tt {
- err := policy(nil, test.host)
- if err != nil && test.allow {
- t.Errorf("%d: policy(%q): %v; want nil", i, test.host, err)
- }
- if err == nil && !test.allow {
- t.Errorf("%d: policy(%q): nil; want an error", i, test.host)
- }
- }
-}
-
-func TestValidCert(t *testing.T) {
- key1, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- key2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- key3, err := rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- t.Fatal(err)
- }
- cert1, err := dummyCert(key1.Public(), "example.org")
- if err != nil {
- t.Fatal(err)
- }
- cert2, err := dummyCert(key2.Public(), "example.org")
- if err != nil {
- t.Fatal(err)
- }
- cert3, err := dummyCert(key3.Public(), "example.org")
- if err != nil {
- t.Fatal(err)
- }
- now := time.Now()
- early, err := dateDummyCert(key1.Public(), now.Add(time.Hour), now.Add(2*time.Hour), "example.org")
- if err != nil {
- t.Fatal(err)
- }
- expired, err := dateDummyCert(key1.Public(), now.Add(-2*time.Hour), now.Add(-time.Hour), "example.org")
- if err != nil {
- t.Fatal(err)
- }
-
- tt := []struct {
- domain string
- key crypto.Signer
- cert [][]byte
- ok bool
- }{
- {"example.org", key1, [][]byte{cert1}, true},
- {"example.org", key3, [][]byte{cert3}, true},
- {"example.org", key1, [][]byte{cert1, cert2, cert3}, true},
- {"example.org", key1, [][]byte{cert1, {1}}, false},
- {"example.org", key1, [][]byte{{1}}, false},
- {"example.org", key1, [][]byte{cert2}, false},
- {"example.org", key2, [][]byte{cert1}, false},
- {"example.org", key1, [][]byte{cert3}, false},
- {"example.org", key3, [][]byte{cert1}, false},
- {"example.net", key1, [][]byte{cert1}, false},
- {"example.org", key1, [][]byte{early}, false},
- {"example.org", key1, [][]byte{expired}, false},
- }
- for i, test := range tt {
- leaf, err := validCert(test.domain, test.cert, test.key)
- if err != nil && test.ok {
- t.Errorf("%d: err = %v", i, err)
- }
- if err == nil && !test.ok {
- t.Errorf("%d: err is nil", i)
- }
- if err == nil && test.ok && leaf == nil {
- t.Errorf("%d: leaf is nil", i)
- }
- }
-}
-
-type cacheGetFunc func(ctx context.Context, key string) ([]byte, error)
-
-func (f cacheGetFunc) Get(ctx context.Context, key string) ([]byte, error) {
- return f(ctx, key)
-}
-
-func (f cacheGetFunc) Put(ctx context.Context, key string, data []byte) error {
- return fmt.Errorf("unsupported Put of %q = %q", key, data)
-}
-
-func (f cacheGetFunc) Delete(ctx context.Context, key string) error {
- return fmt.Errorf("unsupported Delete of %q", key)
-}
-
-func TestManagerGetCertificateBogusSNI(t *testing.T) {
- m := Manager{
- Prompt: AcceptTOS,
- Cache: cacheGetFunc(func(ctx context.Context, key string) ([]byte, error) {
- return nil, fmt.Errorf("cache.Get of %s", key)
- }),
- }
- tests := []struct {
- name string
- wantErr string
- }{
- {"foo.com", "cache.Get of foo.com"},
- {"foo.com.", "cache.Get of foo.com"},
- {`a\b.com`, "acme/autocert: server name contains invalid character"},
- {`a/b.com`, "acme/autocert: server name contains invalid character"},
- {"", "acme/autocert: missing server name"},
- {"foo", "acme/autocert: server name component count invalid"},
- {".foo", "acme/autocert: server name component count invalid"},
- {"foo.", "acme/autocert: server name component count invalid"},
- {"fo.o", "cache.Get of fo.o"},
- }
- for _, tt := range tests {
- _, err := m.GetCertificate(&tls.ClientHelloInfo{ServerName: tt.name})
- got := fmt.Sprint(err)
- if got != tt.wantErr {
- t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr)
- }
- }
-}
diff --git a/vendor/golang.org/x/crypto/acme/autocert/cache_test.go b/vendor/golang.org/x/crypto/acme/autocert/cache_test.go
deleted file mode 100644
index 653b05bed..000000000
--- a/vendor/golang.org/x/crypto/acme/autocert/cache_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package autocert
-
-import (
- "context"
- "io/ioutil"
- "os"
- "path/filepath"
- "reflect"
- "testing"
-)
-
-// make sure DirCache satisfies Cache interface
-var _ Cache = DirCache("/")
-
-func TestDirCache(t *testing.T) {
- dir, err := ioutil.TempDir("", "autocert")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(dir)
- dir = filepath.Join(dir, "certs") // a nonexistent dir
- cache := DirCache(dir)
- ctx := context.Background()
-
- // test cache miss
- if _, err := cache.Get(ctx, "nonexistent"); err != ErrCacheMiss {
- t.Errorf("get: %v; want ErrCacheMiss", err)
- }
-
- // test put/get
- b1 := []byte{1}
- if err := cache.Put(ctx, "dummy", b1); err != nil {
- t.Fatalf("put: %v", err)
- }
- b2, err := cache.Get(ctx, "dummy")
- if err != nil {
- t.Fatalf("get: %v", err)
- }
- if !reflect.DeepEqual(b1, b2) {
- t.Errorf("b1 = %v; want %v", b1, b2)
- }
- name := filepath.Join(dir, "dummy")
- if _, err := os.Stat(name); err != nil {
- t.Error(err)
- }
-
- // test delete
- if err := cache.Delete(ctx, "dummy"); err != nil {
- t.Fatalf("delete: %v", err)
- }
- if _, err := cache.Get(ctx, "dummy"); err != ErrCacheMiss {
- t.Errorf("get: %v; want ErrCacheMiss", err)
- }
-}
diff --git a/vendor/golang.org/x/crypto/acme/autocert/example_test.go b/vendor/golang.org/x/crypto/acme/autocert/example_test.go
deleted file mode 100644
index 552a62549..000000000
--- a/vendor/golang.org/x/crypto/acme/autocert/example_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package autocert_test
-
-import (
- "crypto/tls"
- "fmt"
- "log"
- "net/http"
-
- "golang.org/x/crypto/acme/autocert"
-)
-
-func ExampleNewListener() {
- mux := http.NewServeMux()
- mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "Hello, TLS user! Your config: %+v", r.TLS)
- })
- log.Fatal(http.Serve(autocert.NewListener("example.com"), mux))
-}
-
-func ExampleManager() {
- m := &autocert.Manager{
- Cache: autocert.DirCache("secret-dir"),
- Prompt: autocert.AcceptTOS,
- HostPolicy: autocert.HostWhitelist("example.org"),
- }
- go http.ListenAndServe(":http", m.HTTPHandler(nil))
- s := &http.Server{
- Addr: ":https",
- TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
- }
- s.ListenAndServeTLS("", "")
-}
diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal.go b/vendor/golang.org/x/crypto/acme/autocert/renewal.go
index 6c5da2bc8..3fa4d61a2 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/renewal.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/renewal.go
@@ -71,12 +71,21 @@ func (dr *domainRenewal) renew() {
testDidRenewLoop(next, err)
}
+// updateState locks and replaces the relevant Manager.state item with the given
+// state. It additionally updates dr.key with the given state's key.
+func (dr *domainRenewal) updateState(state *certState) {
+ dr.m.stateMu.Lock()
+ defer dr.m.stateMu.Unlock()
+ dr.key = state.key
+ dr.m.state[dr.domain] = state
+}
+
// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
// Instead, it requests a new certificate independently and, upon success,
// replaces dr.m.state item with a new one and updates cache for the given domain.
//
-// It may return immediately if the expiration date of the currently cached cert
-// is far enough in the future.
+// It may lock and update the Manager.state if the expiration date of the currently
+// cached cert is far enough in the future.
//
// The returned value is a time interval after which the renewal should occur again.
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
@@ -85,7 +94,16 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
if tlscert, err := dr.m.cacheGet(ctx, dr.domain); err == nil {
next := dr.next(tlscert.Leaf.NotAfter)
if next > dr.m.renewBefore()+renewJitter {
- return next, nil
+ signer, ok := tlscert.PrivateKey.(crypto.Signer)
+ if ok {
+ state := &certState{
+ key: signer,
+ cert: tlscert.Certificate,
+ leaf: tlscert.Leaf,
+ }
+ dr.updateState(state)
+ return next, nil
+ }
}
}
@@ -102,11 +120,10 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
if err != nil {
return 0, err
}
- dr.m.cachePut(ctx, dr.domain, tlscert)
- dr.m.stateMu.Lock()
- defer dr.m.stateMu.Unlock()
- // m.state is guaranteed to be non-nil at this point
- dr.m.state[dr.domain] = state
+ if err := dr.m.cachePut(ctx, dr.domain, tlscert); err != nil {
+ return 0, err
+ }
+ dr.updateState(state)
return dr.next(leaf.NotAfter), nil
}
diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go b/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
deleted file mode 100644
index 11d40ff5d..000000000
--- a/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package autocert
-
-import (
- "context"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/tls"
- "crypto/x509"
- "encoding/base64"
- "fmt"
- "net/http"
- "net/http/httptest"
- "testing"
- "time"
-
- "golang.org/x/crypto/acme"
-)
-
-func TestRenewalNext(t *testing.T) {
- now := time.Now()
- timeNow = func() time.Time { return now }
- defer func() { timeNow = time.Now }()
-
- man := &Manager{RenewBefore: 7 * 24 * time.Hour}
- defer man.stopRenew()
- tt := []struct {
- expiry time.Time
- min, max time.Duration
- }{
- {now.Add(90 * 24 * time.Hour), 83*24*time.Hour - renewJitter, 83 * 24 * time.Hour},
- {now.Add(time.Hour), 0, 1},
- {now, 0, 1},
- {now.Add(-time.Hour), 0, 1},
- }
-
- dr := &domainRenewal{m: man}
- for i, test := range tt {
- next := dr.next(test.expiry)
- if next < test.min || test.max < next {
- t.Errorf("%d: next = %v; want between %v and %v", i, next, test.min, test.max)
- }
- }
-}
-
-func TestRenewFromCache(t *testing.T) {
- const domain = "example.org"
-
- // ACME CA server stub
- var ca *httptest.Server
- ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Replay-Nonce", "nonce")
- if r.Method == "HEAD" {
- // a nonce request
- return
- }
-
- switch r.URL.Path {
- // discovery
- case "/":
- if err := discoTmpl.Execute(w, ca.URL); err != nil {
- t.Fatalf("discoTmpl: %v", err)
- }
- // client key registration
- case "/new-reg":
- w.Write([]byte("{}"))
- // domain authorization
- case "/new-authz":
- w.Header().Set("Location", ca.URL+"/authz/1")
- w.WriteHeader(http.StatusCreated)
- w.Write([]byte(`{"status": "valid"}`))
- // cert request
- case "/new-cert":
- var req struct {
- CSR string `json:"csr"`
- }
- decodePayload(&req, r.Body)
- b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
- csr, err := x509.ParseCertificateRequest(b)
- if err != nil {
- t.Fatalf("new-cert: CSR: %v", err)
- }
- der, err := dummyCert(csr.PublicKey, domain)
- if err != nil {
- t.Fatalf("new-cert: dummyCert: %v", err)
- }
- chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
- w.Header().Set("Link", chainUp)
- w.WriteHeader(http.StatusCreated)
- w.Write(der)
- // CA chain cert
- case "/ca-cert":
- der, err := dummyCert(nil, "ca")
- if err != nil {
- t.Fatalf("ca-cert: dummyCert: %v", err)
- }
- w.Write(der)
- default:
- t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
- }
- }))
- defer ca.Close()
-
- // use EC key to run faster on 386
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- man := &Manager{
- Prompt: AcceptTOS,
- Cache: newMemCache(),
- RenewBefore: 24 * time.Hour,
- Client: &acme.Client{
- Key: key,
- DirectoryURL: ca.URL,
- },
- }
- defer man.stopRenew()
-
- // cache an almost expired cert
- now := time.Now()
- cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain)
- if err != nil {
- t.Fatal(err)
- }
- tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
- if err := man.cachePut(context.Background(), domain, tlscert); err != nil {
- t.Fatal(err)
- }
-
- // veriy the renewal happened
- defer func() {
- testDidRenewLoop = func(next time.Duration, err error) {}
- }()
- done := make(chan struct{})
- testDidRenewLoop = func(next time.Duration, err error) {
- defer close(done)
- if err != nil {
- t.Errorf("testDidRenewLoop: %v", err)
- }
- // Next should be about 90 days:
- // dummyCert creates 90days expiry + account for man.RenewBefore.
- // Previous expiration was within 1 min.
- future := 88 * 24 * time.Hour
- if next < future {
- t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
- }
-
- // ensure the new cert is cached
- after := time.Now().Add(future)
- tlscert, err := man.cacheGet(context.Background(), domain)
- if err != nil {
- t.Fatalf("man.cacheGet: %v", err)
- }
- if !tlscert.Leaf.NotAfter.After(after) {
- t.Errorf("cache leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
- }
-
- // verify the old cert is also replaced in memory
- man.stateMu.Lock()
- defer man.stateMu.Unlock()
- s := man.state[domain]
- if s == nil {
- t.Fatalf("m.state[%q] is nil", domain)
- }
- tlscert, err = s.tlscert()
- if err != nil {
- t.Fatalf("s.tlscert: %v", err)
- }
- if !tlscert.Leaf.NotAfter.After(after) {
- t.Errorf("state leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
- }
- }
-
- // trigger renew
- hello := &tls.ClientHelloInfo{ServerName: domain}
- if _, err := man.GetCertificate(hello); err != nil {
- t.Fatal(err)
- }
-
- // wait for renew loop
- select {
- case <-time.After(10 * time.Second):
- t.Fatal("renew took too long to occur")
- case <-done:
- }
-}
diff --git a/vendor/golang.org/x/crypto/acme/jws_test.go b/vendor/golang.org/x/crypto/acme/jws_test.go
deleted file mode 100644
index 0ff0fb5a3..000000000
--- a/vendor/golang.org/x/crypto/acme/jws_test.go
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package acme
-
-import (
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rsa"
- "crypto/x509"
- "encoding/base64"
- "encoding/json"
- "encoding/pem"
- "fmt"
- "math/big"
- "testing"
-)
-
-const (
- testKeyPEM = `
------BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
-WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
-Ab7+zawrfRaFONa1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosq
-EXeaIkVYBEhbhNu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZf
-oyFyek380mHgJAumQ/I2fjj98/97mk3ihOY4AgVdCDj1z/GCoZkG5Rq7nbCGyosy
-KWyDX00Zs+nNqVhoLeIvXC4nnWdJMZ6rogxyQQIDAQABAoIBACIEZTOI1Kao9nmV
-9IeIsuaR1Y61b9neOF/MLmIVIZu+AAJFCMB4Iw11FV6sFodwpEyeZhx2WkpWVN+H
-r19eGiLX3zsL0DOdqBJoSIHDWCCMxgnYJ6nvS0nRxX3qVrBp8R2g12Ub+gNPbmFm
-ecf/eeERIVxfifd9VsyRu34eDEvcmKFuLYbElFcPh62xE3x12UZvV/sN7gXbawpP
-G+w255vbE5MoaKdnnO83cTFlcHvhn24M/78qP7Te5OAeelr1R89kYxQLpuGe4fbS
-zc6E3ym5Td6urDetGGrSY1Eu10/8sMusX+KNWkm+RsBRbkyKq72ks/qKpOxOa+c6
-9gm+Y8ECgYEA/iNUyg1ubRdH11p82l8KHtFC1DPE0V1gSZsX29TpM5jS4qv46K+s
-8Ym1zmrORM8x+cynfPx1VQZQ34EYeCMIX212ryJ+zDATl4NE0I4muMvSiH9vx6Xc
-7FmhNnaYzPsBL5Tm9nmtQuP09YEn8poiOJFiDs/4olnD5ogA5O4THGkCgYEA5MIL
-qWYBUuqbEWLRtMruUtpASclrBqNNsJEsMGbeqBJmoMxdHeSZckbLOrqm7GlMyNRJ
-Ne/5uWRGSzaMYuGmwsPpERzqEvYFnSrpjW5YtXZ+JtxFXNVfm9Z1gLLgvGpOUCIU
-RbpoDckDe1vgUuk3y5+DjZihs+rqIJ45XzXTzBkCgYBWuf3segruJZy5rEKhTv+o
-JqeUvRn0jNYYKFpLBeyTVBrbie6GkbUGNIWbrK05pC+c3K9nosvzuRUOQQL1tJbd
-4gA3oiD9U4bMFNr+BRTHyZ7OQBcIXdz3t1qhuHVKtnngIAN1p25uPlbRFUNpshnt
-jgeVoHlsBhApcs5DUc+pyQKBgDzeHPg/+g4z+nrPznjKnktRY1W+0El93kgi+J0Q
-YiJacxBKEGTJ1MKBb8X6sDurcRDm22wMpGfd9I5Cv2v4GsUsF7HD/cx5xdih+G73
-c4clNj/k0Ff5Nm1izPUno4C+0IOl7br39IPmfpSuR6wH/h6iHQDqIeybjxyKvT1G
-N0rRAoGBAKGD+4ZI/E1MoJ5CXB8cDDMHagbE3cq/DtmYzE2v1DFpQYu5I4PCm5c7
-EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO
-9XWsXpbSTsRPj0sv1rB+UzBJ0PgjK4q2zOF0sNo7b1+6nlM3BWPx
------END RSA PRIVATE KEY-----
-`
-
- // This thumbprint is for the testKey defined above.
- testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
-
- // openssl ecparam -name secp256k1 -genkey -noout
- testKeyECPEM = `
------BEGIN EC PRIVATE KEY-----
-MHcCAQEEIK07hGLr0RwyUdYJ8wbIiBS55CjnkMD23DWr+ccnypWLoAoGCCqGSM49
-AwEHoUQDQgAE5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HThqIrvawF5
-QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
------END EC PRIVATE KEY-----
-`
- // openssl ecparam -name secp384r1 -genkey -noout
- testKeyEC384PEM = `
------BEGIN EC PRIVATE KEY-----
-MIGkAgEBBDAQ4lNtXRORWr1bgKR1CGysr9AJ9SyEk4jiVnlUWWUChmSNL+i9SLSD
-Oe/naPqXJ6CgBwYFK4EEACKhZANiAAQzKtj+Ms0vHoTX5dzv3/L5YMXOWuI5UKRj
-JigpahYCqXD2BA1j0E/2xt5vlPf+gm0PL+UHSQsCokGnIGuaHCsJAp3ry0gHQEke
-WYXapUUFdvaK1R2/2hn5O+eiQM8YzCg=
------END EC PRIVATE KEY-----
-`
- // openssl ecparam -name secp521r1 -genkey -noout
- testKeyEC512PEM = `
------BEGIN EC PRIVATE KEY-----
-MIHcAgEBBEIBSNZKFcWzXzB/aJClAb305ibalKgtDA7+70eEkdPt28/3LZMM935Z
-KqYHh/COcxuu3Kt8azRAUz3gyr4zZKhlKUSgBwYFK4EEACOhgYkDgYYABAHUNKbx
-7JwC7H6pa2sV0tERWhHhB3JmW+OP6SUgMWryvIKajlx73eS24dy4QPGrWO9/ABsD
-FqcRSkNVTXnIv6+0mAF25knqIBIg5Q8M9BnOu9GGAchcwt3O7RDHmqewnJJDrbjd
-GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
------END EC PRIVATE KEY-----
-`
- // 1. openssl ec -in key.pem -noout -text
- // 2. remove first byte, 04 (the header); the rest is X and Y
- // 3. convert each with: echo <val> | xxd -r -p | base64 -w 100 | tr -d '=' | tr '/+' '_-'
- testKeyECPubX = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
- testKeyECPubY = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
- testKeyEC384PubX = "MyrY_jLNLx6E1-Xc79_y-WDFzlriOVCkYyYoKWoWAqlw9gQNY9BP9sbeb5T3_oJt"
- testKeyEC384PubY = "Dy_lB0kLAqJBpyBrmhwrCQKd68tIB0BJHlmF2qVFBXb2itUdv9oZ-TvnokDPGMwo"
- testKeyEC512PubX = "AdQ0pvHsnALsfqlraxXS0RFaEeEHcmZb44_pJSAxavK8gpqOXHvd5Lbh3LhA8atY738AGwMWpxFKQ1VNeci_r7SY"
- testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax"
-
- // echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
- // openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-'
- testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
-)
-
-var (
- testKey *rsa.PrivateKey
- testKeyEC *ecdsa.PrivateKey
- testKeyEC384 *ecdsa.PrivateKey
- testKeyEC512 *ecdsa.PrivateKey
-)
-
-func init() {
- testKey = parseRSA(testKeyPEM, "testKeyPEM")
- testKeyEC = parseEC(testKeyECPEM, "testKeyECPEM")
- testKeyEC384 = parseEC(testKeyEC384PEM, "testKeyEC384PEM")
- testKeyEC512 = parseEC(testKeyEC512PEM, "testKeyEC512PEM")
-}
-
-func decodePEM(s, name string) []byte {
- d, _ := pem.Decode([]byte(s))
- if d == nil {
- panic("no block found in " + name)
- }
- return d.Bytes
-}
-
-func parseRSA(s, name string) *rsa.PrivateKey {
- b := decodePEM(s, name)
- k, err := x509.ParsePKCS1PrivateKey(b)
- if err != nil {
- panic(fmt.Sprintf("%s: %v", name, err))
- }
- return k
-}
-
-func parseEC(s, name string) *ecdsa.PrivateKey {
- b := decodePEM(s, name)
- k, err := x509.ParseECPrivateKey(b)
- if err != nil {
- panic(fmt.Sprintf("%s: %v", name, err))
- }
- return k
-}
-
-func TestJWSEncodeJSON(t *testing.T) {
- claims := struct{ Msg string }{"Hello JWS"}
- // JWS signed with testKey and "nonce" as the nonce value
- // JSON-serialized JWS fields are split for easier testing
- const (
- // {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"}
- protected = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
- "IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
- "SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
- "QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
- "VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
- "NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
- "QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
- "bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
- "ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
- "b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
- "UVEifSwibm9uY2UiOiJub25jZSJ9"
- // {"Msg":"Hello JWS"}
- payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
- signature = "eAGUikStX_UxyiFhxSLMyuyBcIB80GeBkFROCpap2sW3EmkU_ggF" +
- "knaQzxrTfItICSAXsCLIquZ5BbrSWA_4vdEYrwWtdUj7NqFKjHRa" +
- "zpLHcoR7r1rEHvkoP1xj49lS5fc3Wjjq8JUhffkhGbWZ8ZVkgPdC" +
- "4tMBWiQDoth-x8jELP_3LYOB_ScUXi2mETBawLgOT2K8rA0Vbbmx" +
- "hWNlOWuUf-8hL5YX4IOEwsS8JK_TrTq5Zc9My0zHJmaieqDV0UlP" +
- "k0onFjPFkGm7MrPSgd0MqRG-4vSAg2O4hDo7rKv4n8POjjXlNQvM" +
- "9IPLr8qZ7usYBKhEGwX3yq_eicAwBw"
- )
-
- b, err := jwsEncodeJSON(claims, testKey, "nonce")
- if err != nil {
- t.Fatal(err)
- }
- var jws struct{ Protected, Payload, Signature string }
- if err := json.Unmarshal(b, &jws); err != nil {
- t.Fatal(err)
- }
- if jws.Protected != protected {
- t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
- }
- if jws.Payload != payload {
- t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
- }
- if jws.Signature != signature {
- t.Errorf("signature:\n%s\nwant:\n%s", jws.Signature, signature)
- }
-}
-
-func TestJWSEncodeJSONEC(t *testing.T) {
- tt := []struct {
- key *ecdsa.PrivateKey
- x, y string
- alg, crv string
- }{
- {testKeyEC, testKeyECPubX, testKeyECPubY, "ES256", "P-256"},
- {testKeyEC384, testKeyEC384PubX, testKeyEC384PubY, "ES384", "P-384"},
- {testKeyEC512, testKeyEC512PubX, testKeyEC512PubY, "ES512", "P-521"},
- }
- for i, test := range tt {
- claims := struct{ Msg string }{"Hello JWS"}
- b, err := jwsEncodeJSON(claims, test.key, "nonce")
- if err != nil {
- t.Errorf("%d: %v", i, err)
- continue
- }
- var jws struct{ Protected, Payload, Signature string }
- if err := json.Unmarshal(b, &jws); err != nil {
- t.Errorf("%d: %v", i, err)
- continue
- }
-
- b, err = base64.RawURLEncoding.DecodeString(jws.Protected)
- if err != nil {
- t.Errorf("%d: jws.Protected: %v", i, err)
- }
- var head struct {
- Alg string
- Nonce string
- JWK struct {
- Crv string
- Kty string
- X string
- Y string
- } `json:"jwk"`
- }
- if err := json.Unmarshal(b, &head); err != nil {
- t.Errorf("%d: jws.Protected: %v", i, err)
- }
- if head.Alg != test.alg {
- t.Errorf("%d: head.Alg = %q; want %q", i, head.Alg, test.alg)
- }
- if head.Nonce != "nonce" {
- t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce)
- }
- if head.JWK.Crv != test.crv {
- t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv)
- }
- if head.JWK.Kty != "EC" {
- t.Errorf("%d: head.JWK.Kty = %q; want EC", i, head.JWK.Kty)
- }
- if head.JWK.X != test.x {
- t.Errorf("%d: head.JWK.X = %q; want %q", i, head.JWK.X, test.x)
- }
- if head.JWK.Y != test.y {
- t.Errorf("%d: head.JWK.Y = %q; want %q", i, head.JWK.Y, test.y)
- }
- }
-}
-
-func TestJWKThumbprintRSA(t *testing.T) {
- // Key example from RFC 7638
- const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" +
- "VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6" +
- "4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD" +
- "W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9" +
- "1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH" +
- "aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
- const base64E = "AQAB"
- const expected = "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"
-
- b, err := base64.RawURLEncoding.DecodeString(base64N)
- if err != nil {
- t.Fatalf("Error parsing example key N: %v", err)
- }
- n := new(big.Int).SetBytes(b)
-
- b, err = base64.RawURLEncoding.DecodeString(base64E)
- if err != nil {
- t.Fatalf("Error parsing example key E: %v", err)
- }
- e := new(big.Int).SetBytes(b)
-
- pub := &rsa.PublicKey{N: n, E: int(e.Uint64())}
- th, err := JWKThumbprint(pub)
- if err != nil {
- t.Error(err)
- }
- if th != expected {
- t.Errorf("thumbprint = %q; want %q", th, expected)
- }
-}
-
-func TestJWKThumbprintEC(t *testing.T) {
- // Key example from RFC 7520
- // expected was computed with
- // echo -n '{"crv":"P-521","kty":"EC","x":"<base64X>","y":"<base64Y>"}' | \
- // openssl dgst -binary -sha256 | \
- // base64 | \
- // tr -d '=' | tr '/+' '_-'
- const (
- base64X = "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkT" +
- "KqjqvjyekWF-7ytDyRXYgCF5cj0Kt"
- base64Y = "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUda" +
- "QkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
- expected = "dHri3SADZkrush5HU_50AoRhcKFryN-PI6jPBtPL55M"
- )
-
- b, err := base64.RawURLEncoding.DecodeString(base64X)
- if err != nil {
- t.Fatalf("Error parsing example key X: %v", err)
- }
- x := new(big.Int).SetBytes(b)
-
- b, err = base64.RawURLEncoding.DecodeString(base64Y)
- if err != nil {
- t.Fatalf("Error parsing example key Y: %v", err)
- }
- y := new(big.Int).SetBytes(b)
-
- pub := &ecdsa.PublicKey{Curve: elliptic.P521(), X: x, Y: y}
- th, err := JWKThumbprint(pub)
- if err != nil {
- t.Error(err)
- }
- if th != expected {
- t.Errorf("thumbprint = %q; want %q", th, expected)
- }
-}
-
-func TestJWKThumbprintErrUnsupportedKey(t *testing.T) {
- _, err := JWKThumbprint(struct{}{})
- if err != ErrUnsupportedKey {
- t.Errorf("err = %q; want %q", err, ErrUnsupportedKey)
- }
-}
diff --git a/vendor/golang.org/x/crypto/acme/types_test.go b/vendor/golang.org/x/crypto/acme/types_test.go
deleted file mode 100644
index a7553e6b7..000000000
--- a/vendor/golang.org/x/crypto/acme/types_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package acme
-
-import (
- "errors"
- "net/http"
- "testing"
- "time"
-)
-
-func TestRateLimit(t *testing.T) {
- now := time.Date(2017, 04, 27, 10, 0, 0, 0, time.UTC)
- f := timeNow
- defer func() { timeNow = f }()
- timeNow = func() time.Time { return now }
-
- h120, hTime := http.Header{}, http.Header{}
- h120.Set("Retry-After", "120")
- hTime.Set("Retry-After", "Tue Apr 27 11:00:00 2017")
-
- err1 := &Error{
- ProblemType: "urn:ietf:params:acme:error:nolimit",
- Header: h120,
- }
- err2 := &Error{
- ProblemType: "urn:ietf:params:acme:error:rateLimited",
- Header: h120,
- }
- err3 := &Error{
- ProblemType: "urn:ietf:params:acme:error:rateLimited",
- Header: nil,
- }
- err4 := &Error{
- ProblemType: "urn:ietf:params:acme:error:rateLimited",
- Header: hTime,
- }
-
- tt := []struct {
- err error
- res time.Duration
- ok bool
- }{
- {nil, 0, false},
- {errors.New("dummy"), 0, false},
- {err1, 0, false},
- {err2, 2 * time.Minute, true},
- {err3, 0, true},
- {err4, time.Hour, true},
- }
- for i, test := range tt {
- res, ok := RateLimit(test.err)
- if ok != test.ok {
- t.Errorf("%d: RateLimit(%+v): ok = %v; want %v", i, test.err, ok, test.ok)
- continue
- }
- if res != test.res {
- t.Errorf("%d: RateLimit(%+v) = %v; want %v", i, test.err, res, test.res)
- }
- }
-}