acme: fetch fresh nonces from newNonce resource
Previously, nonce values were fetched from Directory URL. RFC8555 and some recent drafts provide specific URL to fetch new nonce values from. This CL makes the client always use new nonce URL when available and fall back to the previous behavior otherwise. Updates golang/go#21081 Change-Id: I6442004b01d46aa015c193ca4c80daa712b78790 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/191603 Run-TryBot: Alex Vaghin <ddos@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
+6
-2
@@ -750,12 +750,16 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
||||
}
|
||||
|
||||
// popNonce returns a nonce value previously stored with c.addNonce
|
||||
// or fetches a fresh one from a URL by issuing a HEAD request.
|
||||
// It first tries c.directoryURL() and then the provided url if the former fails.
|
||||
// or fetches a fresh one from c.dir.NonceURL.
|
||||
// If NonceURL is empty, it first tries c.directoryURL() and, failing that,
|
||||
// the provided url.
|
||||
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
|
||||
c.noncesMu.Lock()
|
||||
defer c.noncesMu.Unlock()
|
||||
if len(c.nonces) == 0 {
|
||||
if c.dir != nil && c.dir.NonceURL != "" {
|
||||
return c.fetchNonce(ctx, c.dir.NonceURL)
|
||||
}
|
||||
dirURL := c.directoryURL()
|
||||
v, err := c.fetchNonce(ctx, dirURL)
|
||||
if err != nil && url != dirURL {
|
||||
|
||||
@@ -84,3 +84,40 @@ func TestRFC_Discover(t *testing.T) {
|
||||
t.Error("dir.Meta.ExternalAccountRequired is false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRFC_popNonce(t *testing.T) {
|
||||
var count int
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// The Client uses only Directory.NonceURL when specified.
|
||||
// Expect no other URL paths.
|
||||
if r.URL.Path != "/new-nonce" {
|
||||
t.Errorf("r.URL.Path = %q; want /new-nonce", r.URL.Path)
|
||||
}
|
||||
if count > 0 {
|
||||
w.WriteHeader(http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
count++
|
||||
w.Header().Set("Replay-Nonce", "second")
|
||||
}))
|
||||
cl := &Client{
|
||||
DirectoryURL: ts.URL,
|
||||
dir: &Directory{NonceURL: ts.URL + "/new-nonce"},
|
||||
}
|
||||
cl.addNonce(http.Header{"Replay-Nonce": {"first"}})
|
||||
|
||||
for i, nonce := range []string{"first", "second"} {
|
||||
v, err := cl.popNonce(context.Background(), "")
|
||||
if err != nil {
|
||||
t.Errorf("%d: cl.popNonce: %v", i, err)
|
||||
}
|
||||
if v != nonce {
|
||||
t.Errorf("%d: cl.popNonce = %q; want %q", i, v, nonce)
|
||||
}
|
||||
}
|
||||
// No more nonces and server replies with an error past first nonce fetch.
|
||||
// Expected to fail.
|
||||
if _, err := cl.popNonce(context.Background(), ""); err == nil {
|
||||
t.Error("last cl.popNonce returned nil error")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user