From e1cab4966f4e9a6b755a3cbed700484787df7b13 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 12 Mar 2021 15:49:39 +0100 Subject: [PATCH] Improve initialization of SCEP authority --- authority/authority.go | 8 +++++--- ca/ca.go | 31 +++++++++++++++---------------- cas/apiv1/registry.go | 2 +- scep/authority.go | 23 +++++------------------ scep/service.go | 35 +++++++++++++++++++++++++++++++---- 5 files changed, 57 insertions(+), 42 deletions(-) diff --git a/authority/authority.go b/authority/authority.go index a51b2162..74abda7b 100644 --- a/authority/authority.go +++ b/authority/authority.go @@ -234,10 +234,12 @@ func (a *Authority) init() error { } } - a.scepService = &scep.Service{ - Signer: options.Signer, - Decrypter: options.Decrypter, + a.scepService, err = scep.NewService(context.Background(), options) + if err != nil { + return err } + + // TODO: mimick the x509CAService GetCertificateAuthority here too? } // Read root certificates and store them in the certificates map. diff --git a/ca/ca.go b/ca/ca.go index c6af8a28..8cc7f405 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -151,12 +151,11 @@ func (ca *CA) Init(config *authority.Config) (*CA, error) { scepPrefix := "scep" scepAuthority, err := scep.New(auth, scep.AuthorityOptions{ - IntermediateCertificatePath: config.IntermediateCert, - Service: auth.GetSCEPService(), - Backdate: *config.AuthorityConfig.Backdate, - DB: auth.GetDatabase().(nosql.DB), - DNS: dns, - Prefix: scepPrefix, + Service: auth.GetSCEPService(), + Backdate: *config.AuthorityConfig.Backdate, + DB: auth.GetDatabase().(nosql.DB), + DNS: dns, + Prefix: scepPrefix, }) if err != nil { return nil, errors.Wrap(err, "error creating SCEP authority") @@ -358,13 +357,13 @@ func (ca *CA) getTLSConfig(auth *authority.Authority) (*tls.Config, error) { return tlsConfig, nil } -func dumpRoutes(mux chi.Routes) { - // helpful routine for logging all routes // - walkFunc := func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error { - fmt.Printf("%s %s\n", method, route) - return nil - } - if err := chi.Walk(mux, walkFunc); err != nil { - fmt.Printf("Logging err: %s\n", err.Error()) - } -} +// func dumpRoutes(mux chi.Routes) { +// // helpful routine for logging all routes // +// walkFunc := func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error { +// fmt.Printf("%s %s\n", method, route) +// return nil +// } +// if err := chi.Walk(mux, walkFunc); err != nil { +// fmt.Printf("Logging err: %s\n", err.Error()) +// } +// } diff --git a/cas/apiv1/registry.go b/cas/apiv1/registry.go index b74103b7..5876e9d7 100644 --- a/cas/apiv1/registry.go +++ b/cas/apiv1/registry.go @@ -18,7 +18,7 @@ func Register(t Type, fn CertificateAuthorityServiceNewFunc) { registry.Store(t.String(), fn) } -// LoadCertificateAuthorityServiceNewFunc returns the function initialize a KayManager. +// LoadCertificateAuthorityServiceNewFunc returns the function to initialize a KeyManager. func LoadCertificateAuthorityServiceNewFunc(t Type) (CertificateAuthorityServiceNewFunc, bool) { v, ok := registry.Load(t.String()) if !ok { diff --git a/scep/authority.go b/scep/authority.go index 69d83554..03bd6919 100644 --- a/scep/authority.go +++ b/scep/authority.go @@ -11,8 +11,6 @@ import ( "github.com/smallstep/certificates/authority/provisioner" database "github.com/smallstep/certificates/db" - "go.step.sm/crypto/pemutil" - "github.com/smallstep/nosql" microx509util "github.com/micromdm/scep/crypto/x509util" @@ -59,10 +57,8 @@ type Authority struct { // AuthorityOptions required to create a new SCEP Authority. type AuthorityOptions struct { - IntermediateCertificatePath string - + // Service provides the SCEP functions to Authority Service Service - // Backdate Backdate provisioner.Duration // DB is the database used by nosql. @@ -96,21 +92,12 @@ func New(signAuth SignAuthority, ops AuthorityOptions) (*Authority, error) { } } - // TODO: the below is a bit similar as what happens in the core Authority class, which - // creates the full x509 service. However, those aren't accessible directly, which is - // why I reimplemented this (for now). There might be an alternative that I haven't - // found yet. - certificateChain, err := pemutil.ReadCertificateBundle(ops.IntermediateCertificatePath) - if err != nil { - return nil, err - } - return &Authority{ backdate: ops.Backdate, db: ops.DB, prefix: ops.Prefix, dns: ops.DNS, - intermediateCertificate: certificateChain[0], + intermediateCertificate: ops.Service.certificateChain[0], service: ops.Service, signAuth: signAuth, }, nil @@ -208,7 +195,7 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err return err } - envelope, err := p7c.Decrypt(a.intermediateCertificate, a.service.Decrypter) + envelope, err := p7c.Decrypt(a.intermediateCertificate, a.service.decrypter) if err != nil { return err } @@ -351,7 +338,7 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m authCert := a.intermediateCertificate // sign the attributes - if err := signedData.AddSigner(authCert, a.service.Signer, config); err != nil { + if err := signedData.AddSigner(authCert, a.service.signer, config); err != nil { return nil, err } @@ -430,7 +417,7 @@ func (a *Authority) CreateFailureResponse(ctx context.Context, csr *x509.Certifi } // sign the attributes - if err := signedData.AddSigner(a.intermediateCertificate, a.service.Signer, config); err != nil { + if err := signedData.AddSigner(a.intermediateCertificate, a.service.signer, config); err != nil { return nil, err } diff --git a/scep/service.go b/scep/service.go index 1d743dd6..0b37716d 100644 --- a/scep/service.go +++ b/scep/service.go @@ -1,9 +1,36 @@ package scep -import "crypto" +import ( + "context" + "crypto" + "crypto/x509" + "strings" -// Service is a (temporary?) wrapper for signer/decrypters + "github.com/smallstep/certificates/cas/apiv1" +) + +// Service is a wrapper for crypto.Signer and crypto.Decrypter type Service struct { - Signer crypto.Signer - Decrypter crypto.Decrypter + certificateChain []*x509.Certificate + signer crypto.Signer + decrypter crypto.Decrypter +} + +func NewService(ctx context.Context, opts apiv1.Options) (*Service, error) { + + if err := opts.Validate(); err != nil { + return nil, err + } + + t := apiv1.Type(strings.ToLower(opts.Type)) + if t == apiv1.DefaultCAS { + t = apiv1.SoftCAS + } + + // TODO: should this become similar to the New CertificateAuthorityService as in x509CAService? + return &Service{ + chain: opts.CertificateChain, + signer: opts.Signer, + decrypter: opts.Decrypter, + }, nil }