Implement acme RFC 8555, challenge retries

This commit is contained in:
Wesley Graham 2020-02-07 15:28:10 -08:00 committed by David Cowden
parent 6fdbd856f7
commit 40d7c42e33
3 changed files with 30 additions and 18 deletions

View File

@ -2,14 +2,13 @@ package api
import (
"fmt"
"net/http"
"github.com/go-chi/chi"
"github.com/pkg/errors"
"github.com/smallstep/certificates/acme"
"github.com/smallstep/certificates/api"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/cli/jose"
"net/http"
)
func link(url, typ string) string {
@ -181,13 +180,15 @@ func (h *Handler) GetChallenge(w http.ResponseWriter, r *http.Request) {
ch, err = h.Auth.ValidateChallenge(prov, acc.GetID(), chID, acc.GetKey())
if err != nil {
api.WriteError(w, err)
return
} else if ch.Status != acme.StatusValid && ch.Status != acme.StatusInvalid {
w.Header().Add("Retry-After", "60")
api.JSON(w, ch)
} else {
getLink := h.Auth.GetLink
w.Header().Add("Link", link(getLink(acme.AuthzLink, acme.URLSafeProvisionerName(prov), true, ch.GetAuthzID()), "up"))
w.Header().Set("Location", getLink(acme.ChallengeLink, acme.URLSafeProvisionerName(prov), true, ch.GetID()))
api.JSON(w, ch)
}
getLink := h.Auth.GetLink
w.Header().Add("Link", link(getLink(acme.AuthzLink, acme.URLSafeProvisionerName(prov), true, ch.GetAuthzID()), "up"))
w.Header().Set("Location", getLink(acme.ChallengeLink, acme.URLSafeProvisionerName(prov), true, ch.GetID()))
api.JSON(w, ch)
}
// GetCertificate ACME api for retrieving a Certificate.

View File

@ -338,9 +338,12 @@ func (hc *http01Challenge) validate(db nosql.DB, jwk *jose.JSONWebKey, vo valida
return nil, err
}
if keyAuth != expected {
if err = hc.storeError(db,
RejectedIdentifierErr(errors.Errorf("keyAuthorization does not match; "+
"expected %s, but got %s", expected, keyAuth))); err != nil {
rejectedErr := RejectedIdentifierErr(errors.Errorf("keyAuthorization does not match; "+
"expected %s, but got %s", expected, keyAuth))
upd := hc.clone()
upd.Error = rejectedErr.ToACME()
upd.Error.Subproblems = append(upd.Error.Subproblems, rejectedErr)
if err = upd.save(db, hc); err != nil {
return nil, err
}
return hc, nil
@ -559,9 +562,12 @@ func (dc *dns01Challenge) validate(db nosql.DB, jwk *jose.JSONWebKey, vo validat
txtRecords, err := vo.lookupTxt("_acme-challenge." + domain)
if err != nil {
if err = dc.storeError(db,
DNSErr(errors.Wrapf(err, "error looking up TXT "+
"records for domain %s", domain))); err != nil {
dnsErr := DNSErr(errors.Wrapf(err, "error looking up TXT "+
"records for domain %s", domain))
upd := dc.clone()
upd.Error = dnsErr.ToACME()
upd.Error.Subproblems = append(upd.Error.Subproblems, dnsErr)
if err = upd.save(db, dc); err != nil {
return nil, err
}
return dc, nil
@ -581,14 +587,16 @@ func (dc *dns01Challenge) validate(db nosql.DB, jwk *jose.JSONWebKey, vo validat
}
}
if !found {
if err = dc.storeError(db,
RejectedIdentifierErr(errors.Errorf("keyAuthorization "+
"does not match; expected %s, but got %s", expectedKeyAuth, txtRecords))); err != nil {
rejectedErr := RejectedIdentifierErr(errors.Errorf("keyAuthorization "+
"does not match; expected %s, but got %s", expectedKeyAuth, txtRecords))
upd := dc.clone()
upd.Error = rejectedErr.ToACME()
upd.Error.Subproblems = append(upd.Error.Subproblems, rejectedErr)
if err = upd.save(db, dc); err != nil {
return nil, err
}
return dc, nil
}
// Update and store the challenge.
upd := &dns01Challenge{dc.baseChallenge.clone()}
upd.Status = StatusValid

View File

@ -858,6 +858,7 @@ func TestHTTP01Validate(t *testing.T) {
"expected %s, but got foo", expKeyAuth))
baseClone := ch.clone()
baseClone.Error = expErr.ToACME()
baseClone.Error.Subproblems = append(baseClone.Error.Subproblems, expErr)
newCh := &http01Challenge{baseClone}
newb, err := json.Marshal(newCh)
assert.FatalError(t, err)
@ -1746,6 +1747,7 @@ func TestDNS01Validate(t *testing.T) {
"domain %s: force", ch.getValue()))
baseClone := ch.clone()
baseClone.Error = expErr.ToACME()
baseClone.Error.Subproblems = append(baseClone.Error.Subproblems, expErr)
newCh := &dns01Challenge{baseClone}
newb, err := json.Marshal(newCh)
assert.FatalError(t, err)
@ -1842,6 +1844,7 @@ func TestDNS01Validate(t *testing.T) {
"expected %s, but got %s", expKeyAuth, []string{"foo", "bar"}))
baseClone := ch.clone()
baseClone.Error = expErr.ToACME()
baseClone.Error.Subproblems = append(baseClone.Error.Subproblems, expErr)
newCh := &http01Challenge{baseClone}
newb, err := json.Marshal(newCh)
assert.FatalError(t, err)