Skip to content

Commit

Permalink
Merge pull request #1553 from smallstep/herman/change-scep-authority-…
Browse files Browse the repository at this point in the history
…initialization

Change SCEP authority initialization
  • Loading branch information
hslatman authored Sep 25, 2023
2 parents 0a5ae39 + c0fbace commit f505acb
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 37 deletions.
80 changes: 43 additions & 37 deletions authority/authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type Authority struct {
x509Enforcers []provisioner.CertificateEnforcer

// SCEP CA
scepOptions *scep.Options
validateSCEP bool
scepAuthority *scep.Authority

// SSH CA
Expand Down Expand Up @@ -123,6 +125,7 @@ func New(cfg *config.Config, opts ...Option) (*Authority, error) {
var a = &Authority{
config: cfg,
certificates: new(sync.Map),
validateSCEP: true,
}

// Apply options.
Expand Down Expand Up @@ -671,54 +674,57 @@ func (a *Authority) init() error {
// update that.
switch {
case a.requiresSCEP() && a.GetSCEP() == nil:
var options scep.Options
options.Roots = a.rootX509Certs
options.Intermediates, err = pemutil.ReadCertificateBundle(a.config.IntermediateCert)
if err != nil {
return err
}
options.SignerCert = options.Intermediates[0]
if options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
SigningKey: a.config.IntermediateKey,
Password: a.password,
}); err != nil {
return err
}

// TODO(hs): instead of creating the decrypter here, pass the
// intermediate key + chain down to the SCEP authority,
// and only instantiate it when required there. Is that possible?
// Also with entering passwords?
// TODO(hs): if moving the logic, try improving the logic for the
// decrypter password too? Right now it needs to be entered multiple
// times; I've observed it to be three times maximum, every time
// the intermediate key is read.
_, isRSA := options.Signer.Public().(*rsa.PublicKey)
if km, ok := a.keyManager.(kmsapi.Decrypter); ok && isRSA {
if decrypter, err := km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{
DecryptionKey: a.config.IntermediateKey,
Password: a.password,
}); err == nil {
// only pass the decrypter down when it was successfully created,
// meaning it's an RSA key, and `CreateDecrypter` did not fail.
options.Decrypter = decrypter
options.DecrypterCert = options.Intermediates[0]
if a.scepOptions == nil {
options := &scep.Options{
Roots: a.rootX509Certs,
Intermediates: a.intermediateX509Certs,
SignerCert: a.intermediateX509Certs[0],
}
if options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
SigningKey: a.config.IntermediateKey,
Password: a.password,
}); err != nil {
return err
}
// TODO(hs): instead of creating the decrypter here, pass the
// intermediate key + chain down to the SCEP authority,
// and only instantiate it when required there. Is that possible?
// Also with entering passwords?
// TODO(hs): if moving the logic, try improving the logic for the
// decrypter password too? Right now it needs to be entered multiple
// times; I've observed it to be three times maximum, every time
// the intermediate key is read.
_, isRSA := options.Signer.Public().(*rsa.PublicKey)
if km, ok := a.keyManager.(kmsapi.Decrypter); ok && isRSA {
if decrypter, err := km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{
DecryptionKey: a.config.IntermediateKey,
Password: a.password,
}); err == nil {
// only pass the decrypter down when it was successfully created,
// meaning it's an RSA key, and `CreateDecrypter` did not fail.
options.Decrypter = decrypter
options.DecrypterCert = options.Intermediates[0]
}
}

a.scepOptions = options
}

// provide the current SCEP provisioner names, so that the provisioners
// can be validated when the CA is started.
options.SCEPProvisionerNames = a.getSCEPProvisionerNames()
a.scepOptions.SCEPProvisionerNames = a.getSCEPProvisionerNames()

// create a new SCEP authority
scepAuthority, err := scep.New(a, options)
scepAuthority, err := scep.New(a, *a.scepOptions)
if err != nil {
return err
}

// validate the SCEP authority
if err := scepAuthority.Validate(); err != nil {
a.initLogf("failed validating SCEP authority: %v", err)
if a.validateSCEP {
// validate the SCEP authority
if err := scepAuthority.Validate(); err != nil {
a.initLogf("failed validating SCEP authority: %v", err)
}
}

// set the SCEP authority
Expand Down
12 changes: 12 additions & 0 deletions authority/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/smallstep/certificates/cas"
casapi "github.com/smallstep/certificates/cas/apiv1"
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/scep"
)

// Option sets options to the Authority.
Expand Down Expand Up @@ -205,6 +206,17 @@ func WithX509SignerFunc(fn func() ([]*x509.Certificate, crypto.Signer, error)) O
}
}

// WithFullSCEPOptions defines the options used for SCEP support.
//
// This feature is EXPERIMENTAL and might change at any time.
func WithFullSCEPOptions(options *scep.Options) Option {
return func(a *Authority) error {
a.scepOptions = options
a.validateSCEP = false
return nil
}
}

// WithSSHUserSigner defines the signer used to sign SSH user certificates.
func WithSSHUserSigner(s crypto.Signer) Option {
return func(a *Authority) error {
Expand Down

0 comments on commit f505acb

Please sign in to comment.