aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Stapleton Cordasco <graffatcolmingov@gmail.com>2025-03-29 20:55:24 -0500
committerGopher Robot <gobot@golang.org>2025-04-17 11:16:57 -0700
commit3f311e442e372a8282abb4d82b6d59ac79a97f75 (patch)
treeb64b03df08d90025c1eb932d7acb3d6a028a2106
parent1f7c62cd66d3486a9cbcec5a4614c0414e9c8dab (diff)
downloadgo-x-crypto-3f311e442e372a8282abb4d82b6d59ac79a97f75.tar.xz
acme: return error from pre-authorization when unsupported
Check the directory's AuthzURL to see if the server supports pre-authorization. If it's empty, then the server is not advertising support and we can encounter other bugs. Better to return early and give a clear error to the caller. From https://www.rfc-editor.org/rfc/rfc8555#section-7.4.1 If a CA wishes to allow pre-authorization within ACME, it can offer a "new authorization" resource in its directory by adding the field "newAuthz" with a URL for the newAuthz resource. Fixes golang/go#40839 Change-Id: Id3e92e8e2ae3c57285183d37544dd59b4988b3be Reviewed-on: https://go-review.googlesource.com/c/crypto/+/661675 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
-rw-r--r--acme/acme.go4
-rw-r--r--acme/acme_test.go52
-rw-r--r--acme/types.go4
3 files changed, 60 insertions, 0 deletions
diff --git a/acme/acme.go b/acme/acme.go
index a43c62f..cfb1dfd 100644
--- a/acme/acme.go
+++ b/acme/acme.go
@@ -353,6 +353,10 @@ func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
+ if c.dir.AuthzURL == "" {
+ // Pre-Authorization is unsupported
+ return nil, errPreAuthorizationNotSupported
+ }
type authzID struct {
Type string `json:"type"`
diff --git a/acme/acme_test.go b/acme/acme_test.go
index a090670..d286888 100644
--- a/acme/acme_test.go
+++ b/acme/acme_test.go
@@ -15,6 +15,7 @@ import (
"encoding/base64"
"encoding/hex"
"encoding/json"
+ "errors"
"fmt"
"io"
"math/big"
@@ -254,6 +255,57 @@ func TestAuthorizeValid(t *testing.T) {
}
}
+func TestAuthorizeUnsupported(t *testing.T) {
+ const (
+ nonce = "https://example.com/acme/new-nonce"
+ reg = "https://example.com/acme/new-acct"
+ order = "https://example.com/acme/new-order"
+ revoke = "https://example.com/acme/revoke-cert"
+ keychange = "https://example.com/acme/key-change"
+ metaTerms = "https://example.com/acme/terms/2017-5-30"
+ metaWebsite = "https://www.example.com/"
+ metaCAA = "example.com"
+ )
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Replay-Nonce", "nonce")
+ if r.Method == http.MethodHead {
+ return
+ }
+ switch r.URL.Path {
+ case "/": // Directory
+ w.Header().Set("Content-Type", "application/json")
+ fmt.Fprintf(w, `{
+ "newNonce": %q,
+ "newAccount": %q,
+ "newOrder": %q,
+ "revokeCert": %q,
+ "keyChange": %q,
+ "meta": {
+ "termsOfService": %q,
+ "website": %q,
+ "caaIdentities": [%q],
+ "externalAccountRequired": true
+ }
+ }`, nonce, reg, order, revoke, keychange, metaTerms, metaWebsite, metaCAA)
+ w.WriteHeader(http.StatusOK)
+ case "/acme/new-authz":
+ w.WriteHeader(http.StatusBadRequest)
+ }
+ }))
+ defer ts.Close()
+ client := &Client{Key: testKey, DirectoryURL: ts.URL}
+ dir, err := client.Discover(context.Background())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if dir.AuthzURL != "" {
+ t.Fatalf("expected AuthzURL to be empty, got %q", dir.AuthzURL)
+ }
+ if _, err := client.Authorize(context.Background(), "example.com"); !errors.Is(err, errPreAuthorizationNotSupported) {
+ t.Errorf("expected err to indicate pre-authorization is unsupported, got %+v", err)
+ }
+}
+
func TestWaitAuthorization(t *testing.T) {
t.Run("wait loop", func(t *testing.T) {
var count int
diff --git a/acme/types.go b/acme/types.go
index 45492ad..640223c 100644
--- a/acme/types.go
+++ b/acme/types.go
@@ -56,6 +56,10 @@ var (
// ErrNoAccount indicates that the Client's key has not been registered with the CA.
ErrNoAccount = errors.New("acme: account does not exist")
+
+ // errPreAuthorizationNotSupported indicates that the server does not
+ // support pre-authorization of identifiers.
+ errPreAuthorizationNotSupported = errors.New("acme: pre-authorization is not supported")
)
// A Subproblem describes an ACME subproblem as reported in an Error.