mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
For #19016 This changes all the places where we previously assumed that certs were hardcoded when the Fleet server started to query the database instead. The plan is to loadtest afterwards, but as a first preemptive measure, this adds a caching layer on top the mysql datastore. # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Added/updated tests - [x] If database migrations are included, checked table schema to confirm autoupdate - For database migrations: - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects. - [x] Ensured the correct collation is explicitly set for character columns (`COLLATE utf8mb4_unicode_ci`). - [x] Manual QA for all new/changed functionality
92 lines
2.5 KiB
Go
92 lines
2.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rsa"
|
|
"errors"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/mdm/assets"
|
|
"github.com/fleetdm/fleet/v4/server/mdm/scep/scep"
|
|
scepserver "github.com/fleetdm/fleet/v4/server/mdm/scep/server"
|
|
|
|
"github.com/go-kit/log"
|
|
)
|
|
|
|
var _ scepserver.Service = (*service)(nil)
|
|
|
|
type service struct {
|
|
// The (chainable) CSR signing function. Intended to handle all
|
|
// SCEP request functionality such as CSR & challenge checking, CA
|
|
// issuance, RA proxying, etc.
|
|
signer scepserver.CSRSigner
|
|
|
|
/// info logging is implemented in the service middleware layer.
|
|
debugLogger log.Logger
|
|
|
|
ds fleet.MDMAssetRetriever
|
|
}
|
|
|
|
func (svc *service) GetCACaps(ctx context.Context) ([]byte, error) {
|
|
defaultCaps := []byte("Renewal\nSHA-1\nSHA-256\nAES\nDES3\nSCEPStandard\nPOSTPKIOperation")
|
|
return defaultCaps, nil
|
|
}
|
|
|
|
func (svc *service) GetCACert(ctx context.Context, _ string) ([]byte, int, error) {
|
|
cert, err := assets.CAKeyPair(ctx, svc.ds)
|
|
if err != nil {
|
|
return nil, 0, ctxerr.Wrap(ctx, err, "parsing SCEP certificate")
|
|
}
|
|
return cert.Leaf.Raw, 1, nil
|
|
}
|
|
|
|
func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, error) {
|
|
if len(data) == 0 {
|
|
return nil, &fleet.BadRequestError{Message: "missing data for PKIOperation"}
|
|
}
|
|
msg, err := scep.ParsePKIMessage(data, scep.WithLogger(svc.debugLogger))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cert, err := assets.CAKeyPair(ctx, svc.ds)
|
|
if err != nil {
|
|
return nil, ctxerr.Wrap(ctx, err, "parsing SCEP certificate")
|
|
}
|
|
|
|
pk, ok := cert.PrivateKey.(*rsa.PrivateKey)
|
|
if !ok {
|
|
return nil, errors.New("private key not in RSA format")
|
|
}
|
|
|
|
if err := msg.DecryptPKIEnvelope(cert.Leaf, pk); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
crt, err := svc.signer.SignCSR(msg.CSRReqMessage)
|
|
if err == nil && crt == nil {
|
|
err = errors.New("no signed certificate")
|
|
}
|
|
if err != nil {
|
|
svc.debugLogger.Log("msg", "failed to sign CSR", "err", err)
|
|
certRep, err := msg.Fail(cert.Leaf, pk, scep.BadRequest)
|
|
return certRep.Raw, err
|
|
}
|
|
|
|
certRep, err := msg.Success(cert.Leaf, pk, crt)
|
|
return certRep.Raw, err
|
|
}
|
|
|
|
func (svc *service) GetNextCACert(ctx context.Context) ([]byte, error) {
|
|
return nil, errors.New("not implemented")
|
|
}
|
|
|
|
// NewService creates a new scep service
|
|
func NewSCEPService(ds fleet.MDMAssetRetriever, signer scepserver.CSRSigner, logger log.Logger) scepserver.Service {
|
|
return &service{
|
|
signer: signer,
|
|
debugLogger: log.NewNopLogger(),
|
|
ds: ds,
|
|
}
|
|
}
|