Add configuration option for specifying the minimum public key length

Instead of using the defaultPublicKeyValidator a new validator called
publicKeyMinimumLengthValidator has been implemented that uses a
configurable minimum length for public keys in CSRs.

It's also an option to alter the defaultPublicKeyValidator to also
take a parameter, but that would touch quite some lines of code. This
might be a viable option after merging SCEP support.
This commit is contained in:
Herman Slatman 2021-05-06 22:56:28 +02:00 committed by max furman
parent 4168449935
commit 2beea1aa89
2 changed files with 47 additions and 4 deletions

View file

@ -2,6 +2,7 @@ package provisioner
import ( import (
"context" "context"
"fmt"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -17,9 +18,11 @@ type SCEP struct {
ForceCN bool `json:"forceCN,omitempty"` ForceCN bool `json:"forceCN,omitempty"`
ChallengePassword string `json:"challenge,omitempty"` ChallengePassword string `json:"challenge,omitempty"`
Capabilities []string `json:"capabilities,omitempty"` Capabilities []string `json:"capabilities,omitempty"`
Options *Options `json:"options,omitempty"` // MinimumPublicKeyLength is the minimum length for public keys in CSRs
Claims *Claims `json:"claims,omitempty"` MinimumPublicKeyLength int `json:"minimumPublicKeyLength,omitempty"`
claimer *Claimer Options *Options `json:"options,omitempty"`
Claims *Claims `json:"claims,omitempty"`
claimer *Claimer
secretChallengePassword string secretChallengePassword string
} }
@ -79,6 +82,15 @@ func (s *SCEP) Init(config Config) (err error) {
s.secretChallengePassword = s.ChallengePassword s.secretChallengePassword = s.ChallengePassword
s.ChallengePassword = "*** redacted ***" s.ChallengePassword = "*** redacted ***"
// Default to 2048 bits minimum public key length (for CSRs) if not set
if s.MinimumPublicKeyLength == 0 {
s.MinimumPublicKeyLength = 2048
}
if s.MinimumPublicKeyLength%8 != 0 {
return fmt.Errorf("only minimum public keys exactly divisible by 8 are supported; %d is not exactly divisibly by 8", s.MinimumPublicKeyLength)
}
// TODO: add other, SCEP specific, options? // TODO: add other, SCEP specific, options?
return err return err
@ -94,7 +106,7 @@ func (s *SCEP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e
newForceCNOption(s.ForceCN), newForceCNOption(s.ForceCN),
profileDefaultDuration(s.claimer.DefaultTLSCertDuration()), profileDefaultDuration(s.claimer.DefaultTLSCertDuration()),
// validators // validators
defaultPublicKeyValidator{}, newPublicKeyMinimumLengthValidator(s.MinimumPublicKeyLength),
newValidityValidator(s.claimer.MinTLSCertDuration(), s.claimer.MaxTLSCertDuration()), newValidityValidator(s.claimer.MinTLSCertDuration(), s.claimer.MaxTLSCertDuration()),
}, nil }, nil
} }

View file

@ -8,6 +8,7 @@ import (
"crypto/x509/pkix" "crypto/x509/pkix"
"encoding/asn1" "encoding/asn1"
"encoding/json" "encoding/json"
"fmt"
"net" "net"
"net/url" "net/url"
"reflect" "reflect"
@ -117,6 +118,36 @@ func (v defaultPublicKeyValidator) Valid(req *x509.CertificateRequest) error {
return nil return nil
} }
// publicKeyMinimumLengthValidator validates the length (in bits) of the public key
// of a certificate request is at least a certain length
type publicKeyMinimumLengthValidator struct {
length int
}
// newPublicKeyMinimumLengthValidator creates a new publicKeyMinimumLengthValidator
// with the given length as its minimum value
// TODO: change the defaultPublicKeyValidator to have a configurable length instead?
func newPublicKeyMinimumLengthValidator(length int) publicKeyMinimumLengthValidator {
return publicKeyMinimumLengthValidator{
length: length,
}
}
// Valid checks that certificate request common name matches the one configured.
func (v publicKeyMinimumLengthValidator) Valid(req *x509.CertificateRequest) error {
switch k := req.PublicKey.(type) {
case *rsa.PublicKey:
minimumLengthInBytes := v.length / 8
if k.Size() < minimumLengthInBytes {
return fmt.Errorf("rsa key in CSR must be at least %d bits (%d bytes)", v.length, minimumLengthInBytes)
}
case *ecdsa.PublicKey, ed25519.PublicKey:
default:
return errors.Errorf("unrecognized public key of type '%T' in CSR", k)
}
return nil
}
// commonNameValidator validates the common name of a certificate request. // commonNameValidator validates the common name of a certificate request.
type commonNameValidator string type commonNameValidator string