Fix ACME order identifier allow/deny check

This commit is contained in:
Herman Slatman 2022-03-08 14:17:59 +01:00
parent 7c541888ad
commit 3ec9a7310c
No known key found for this signature in database
GPG key ID: F4D8A44EA0A75A4F
3 changed files with 15 additions and 13 deletions

View file

@ -13,6 +13,7 @@ import (
"github.com/go-chi/chi" "github.com/go-chi/chi"
"github.com/smallstep/certificates/acme" "github.com/smallstep/certificates/acme"
"github.com/smallstep/certificates/api" "github.com/smallstep/certificates/api"
"github.com/smallstep/certificates/authority/provisioner"
"go.step.sm/crypto/randutil" "go.step.sm/crypto/randutil"
) )
@ -107,7 +108,8 @@ func (h *Handler) NewOrder(w http.ResponseWriter, r *http.Request) {
for _, identifier := range nor.Identifiers { for _, identifier := range nor.Identifiers {
// TODO: gather all errors, so that we can build subproblems; include the nor.Validate() error here too, like in example? // TODO: gather all errors, so that we can build subproblems; include the nor.Validate() error here too, like in example?
err = prov.AuthorizeOrderIdentifier(ctx, identifier.Value) orderIdentifier := provisioner.ACMEIdentifier{Type: provisioner.ACMEIdentifierType(identifier.Type), Value: identifier.Value}
err = prov.AuthorizeOrderIdentifier(ctx, orderIdentifier)
if err != nil { if err != nil {
api.WriteError(w, acme.WrapError(acme.ErrorRejectedIdentifierType, err, "not authorized")) api.WriteError(w, acme.WrapError(acme.ErrorRejectedIdentifierType, err, "not authorized"))
return return

View file

@ -30,7 +30,7 @@ var clock Clock
// Provisioner is an interface that implements a subset of the provisioner.Interface -- // Provisioner is an interface that implements a subset of the provisioner.Interface --
// only those methods required by the ACME api/authority. // only those methods required by the ACME api/authority.
type Provisioner interface { type Provisioner interface {
AuthorizeOrderIdentifier(ctx context.Context, identifier string) error AuthorizeOrderIdentifier(ctx context.Context, identifier provisioner.ACMEIdentifier) error
AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error) AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error)
AuthorizeRevoke(ctx context.Context, token string) error AuthorizeRevoke(ctx context.Context, token string) error
GetID() string GetID() string
@ -45,7 +45,7 @@ type MockProvisioner struct {
Merr error Merr error
MgetID func() string MgetID func() string
MgetName func() string MgetName func() string
MauthorizeOrderIdentifier func(ctx context.Context, identifier string) error MauthorizeOrderIdentifier func(ctx context.Context, identifier provisioner.ACMEIdentifier) error
MauthorizeSign func(ctx context.Context, ott string) ([]provisioner.SignOption, error) MauthorizeSign func(ctx context.Context, ott string) ([]provisioner.SignOption, error)
MauthorizeRevoke func(ctx context.Context, token string) error MauthorizeRevoke func(ctx context.Context, token string) error
MdefaultTLSCertDuration func() time.Duration MdefaultTLSCertDuration func() time.Duration
@ -61,7 +61,7 @@ func (m *MockProvisioner) GetName() string {
} }
// AuthorizeOrderIdentifiers mock // AuthorizeOrderIdentifiers mock
func (m *MockProvisioner) AuthorizeOrderIdentifier(ctx context.Context, identifier string) error { func (m *MockProvisioner) AuthorizeOrderIdentifier(ctx context.Context, identifier provisioner.ACMEIdentifier) error {
if m.MauthorizeOrderIdentifier != nil { if m.MauthorizeOrderIdentifier != nil {
return m.MauthorizeOrderIdentifier(ctx, identifier) return m.MauthorizeOrderIdentifier(ctx, identifier)
} }

View file

@ -90,8 +90,6 @@ func (p *ACME) Init(config Config) (err error) {
} }
// Initialize the x509 allow/deny policy engine // Initialize the x509 allow/deny policy engine
// TODO(hs): ensure no race conditions happen when reloading settings and requesting certs?
// TODO(hs): implement memoization strategy, so that reloading is not required when no changes were made to allow/deny?
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil { if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err return err
} }
@ -115,20 +113,22 @@ type ACMEIdentifier struct {
Value string Value string
} }
// AuthorizeOrderIdentifiers verifies the provisioner is authorized to issue a // AuthorizeOrderIdentifier verifies the provisioner is allowed to issue a
// certificate for the Identifiers provided in an Order. // certificate for an ACME Order Identifier.
func (p *ACME) AuthorizeOrderIdentifier(ctx context.Context, identifier string) error { func (p *ACME) AuthorizeOrderIdentifier(ctx context.Context, identifier ACMEIdentifier) error {
// identifier is allowed if no policy is configured
if p.x509Policy == nil { if p.x509Policy == nil {
return nil return nil
} }
// assuming only valid identifiers (IP or DNS) are provided // assuming only valid identifiers (IP or DNS) are provided
var err error var err error
if ip := net.ParseIP(identifier); ip != nil { switch identifier.Type {
_, err = p.x509Policy.IsIPAllowed(ip) case IP:
} else { _, err = p.x509Policy.IsIPAllowed(net.ParseIP(identifier.Value))
_, err = p.x509Policy.IsDNSAllowed(identifier) case DNS:
_, err = p.x509Policy.IsDNSAllowed(identifier.Value)
} }
return err return err