Add scep authority to context.

This commit is contained in:
Mariano Cano 2022-04-27 18:02:37 -07:00
parent 216d8f0efb
commit 688f9ceb56
2 changed files with 44 additions and 5 deletions

View file

@ -225,9 +225,10 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) {
} }
} }
var scepAuthority *scep.Authority
if ca.shouldServeSCEPEndpoints() { if ca.shouldServeSCEPEndpoints() {
scepPrefix := "scep" scepPrefix := "scep"
scepAuthority, err := scep.New(auth, scep.AuthorityOptions{ scepAuthority, err = scep.New(auth, scep.AuthorityOptions{
Service: auth.GetSCEPService(), Service: auth.GetSCEPService(),
DNS: dns, DNS: dns,
Prefix: scepPrefix, Prefix: scepPrefix,
@ -279,7 +280,7 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) {
} }
// Create context with all the necessary values. // 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 = server.New(cfg.Address, handler, tlsConfig)
ca.srv.BaseContext = func(net.Listener) context.Context { 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. // 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) ctx := authority.NewContext(context.Background(), a)
if authDB := a.GetDatabase(); authDB != nil { if authDB := a.GetDatabase(); authDB != nil {
ctx = db.NewContext(ctx, authDB) 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 { if adminDB := a.GetAdminDatabase(); adminDB != nil {
ctx = admin.NewContext(ctx, adminDB) ctx = admin.NewContext(ctx, adminDB)
} }
if scepAuthority != nil {
ctx = scep.NewContext(ctx, scepAuthority)
}
if acmeDB != nil { if acmeDB != nil {
ctx = acme.NewContext(ctx, acmeDB) ctx = acme.NewContext(ctx, acmeDB)
} }

View file

@ -27,6 +27,29 @@ type Authority struct {
signAuth SignAuthority 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. // AuthorityOptions required to create a new SCEP Authority.
type AuthorityOptions struct { type AuthorityOptions struct {
// Service provides the certificate chain, the signer and the decrypter to the Authority // Service provides the certificate chain, the signer and the decrypter to the Authority
@ -40,6 +63,20 @@ type AuthorityOptions struct {
Prefix string 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 // SignAuthority is the interface for a signing authority
type SignAuthority interface { type SignAuthority interface {
Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) 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 // DecryptPKIEnvelope decrypts an enveloped message
func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error { func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error {
p7c, err := pkcs7.Parse(msg.P7.Content) p7c, err := pkcs7.Parse(msg.P7.Content)
if err != nil { if err != nil {
return fmt.Errorf("error parsing pkcs7 content: %w", err) 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 // SignCSR creates an x509.Certificate based on a CSR template and Cert Authority credentials
// returns a new PKIMessage with CertRep data // returns a new PKIMessage with CertRep data
func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage) (*PKIMessage, error) { 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 // 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 // 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 // poll for the status. It seems to be similar as what can happen in ACME, so might want to model