diff --git a/ca/ca.go b/ca/ca.go index 933db275..a8ecbb05 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -225,9 +225,10 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { } } + var scepAuthority *scep.Authority if ca.shouldServeSCEPEndpoints() { scepPrefix := "scep" - scepAuthority, err := scep.New(auth, scep.AuthorityOptions{ + scepAuthority, err = scep.New(auth, scep.AuthorityOptions{ Service: auth.GetSCEPService(), DNS: dns, Prefix: scepPrefix, @@ -279,7 +280,7 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { } // Create context with all the necessary values. - baseContext := buildContext(auth, acmeDB) + baseContext := buildContext(auth, scepAuthority, acmeDB) ca.srv = server.New(cfg.Address, handler, tlsConfig) ca.srv.BaseContext = func(net.Listener) context.Context { @@ -303,7 +304,7 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { } // buildContext builds the server base context. -func buildContext(a *authority.Authority, acmeDB acme.DB) context.Context { +func buildContext(a *authority.Authority, scepAuthority *scep.Authority, acmeDB acme.DB) context.Context { ctx := authority.NewContext(context.Background(), a) if authDB := a.GetDatabase(); authDB != nil { ctx = db.NewContext(ctx, authDB) @@ -311,6 +312,9 @@ func buildContext(a *authority.Authority, acmeDB acme.DB) context.Context { if adminDB := a.GetAdminDatabase(); adminDB != nil { ctx = admin.NewContext(ctx, adminDB) } + if scepAuthority != nil { + ctx = scep.NewContext(ctx, scepAuthority) + } if acmeDB != nil { ctx = acme.NewContext(ctx, acmeDB) } diff --git a/scep/authority.go b/scep/authority.go index 71f92152..946fa948 100644 --- a/scep/authority.go +++ b/scep/authority.go @@ -27,6 +27,29 @@ type Authority struct { signAuth SignAuthority } +type authorityKey struct{} + +// NewContext adds the given authority to the context. +func NewContext(ctx context.Context, a *Authority) context.Context { + return context.WithValue(ctx, authorityKey{}, a) +} + +// FromContext returns the current authority from the given context. +func FromContext(ctx context.Context) (a *Authority, ok bool) { + a, ok = ctx.Value(authorityKey{}).(*Authority) + return +} + +// MustFromContext returns the current authority from the given context. It will +// panic if the authority is not in the context. +func MustFromContext(ctx context.Context) *Authority { + if a, ok := FromContext(ctx); !ok { + panic("scep authority is not in the context") + } else { + return a + } +} + // AuthorityOptions required to create a new SCEP Authority. type AuthorityOptions struct { // Service provides the certificate chain, the signer and the decrypter to the Authority @@ -40,6 +63,20 @@ type AuthorityOptions struct { Prefix string } +type optionsKey struct{} + +func newOptionsContext(ctx context.Context, o *AuthorityOptions) context.Context { + return context.WithValue(ctx, optionsKey{}, o) +} + +func optionsFromContext(ctx context.Context) *AuthorityOptions { + o, ok := ctx.Value(optionsKey{}).(*AuthorityOptions) + if !ok { + panic("scep options are not in the context") + } + return o +} + // SignAuthority is the interface for a signing authority type SignAuthority interface { Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) @@ -163,7 +200,6 @@ func (a *Authority) GetCACertificates(ctx context.Context) ([]*x509.Certificate, // DecryptPKIEnvelope decrypts an enveloped message func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error { - p7c, err := pkcs7.Parse(msg.P7.Content) if err != nil { return fmt.Errorf("error parsing pkcs7 content: %w", err) @@ -210,7 +246,6 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err // SignCSR creates an x509.Certificate based on a CSR template and Cert Authority credentials // returns a new PKIMessage with CertRep data func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage) (*PKIMessage, error) { - // TODO: intermediate storage of the request? In SCEP it's possible to request a csr/certificate // to be signed, which can be performed asynchronously / out-of-band. In that case a client can // poll for the status. It seems to be similar as what can happen in ACME, so might want to model