Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions cmd/osquery-perf/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,17 @@ type agent struct {
// cache of this host's per-host certificates (the certs unique to this host, excluding the shared certs every host
// reports). Note that this requires a mutex even though only used in a.processQuery, that's because both the runLoop
// and the live query goroutines may call DistributedWrite (which calls processQuery).
certificatesMutex sync.RWMutex
hostCertSpecs []simulatedCert
certificatesMutex sync.RWMutex
hostCertSpecs []simulatedCert
// scepCertSpecs holds the certs issued to this host during Windows MDM SCEP exchanges, keyed by the SCEP CSP
// unique ID so a re-issued cert replaces its predecessor. certificatesWindows reports them so the server
// observes the fleet-<profileUUID> renewal-ID marker and marks the SCEP profile verified. Guarded by
// certificatesMutex.
scepCertSpecs map[string]simulatedCert

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like a stylistic thing, but the pattern I have seen with other maps is to use make to initialize them in newAgent in

agent := &agent{
...
scepCertSpecs: make(map[string]simulatedCert)
}

// withholdSCEPCert marks ~5% of hosts that never report their issued SCEP certs, exercising the server's SCEP
// verification backstop (test-only failure).
withholdSCEPCert bool

commonSoftwareNameSuffix string

entraIDDeviceID string
Expand Down Expand Up @@ -727,6 +736,7 @@ func newAgent(
cachedLastOpenedAt: make(map[string]*time.Time),
commonSoftwareNameSuffix: commonSoftwareNameSuffix,
mdmProfileFailureProb: mdmProfileFailureProb,
withholdSCEPCert: rand.Intn(100) < 5, // ~5%: withhold issued SCEP certs to exercise the verification backstop (test-only)
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
Outdated

entraIDDeviceID: uuid.NewString(),
entraIDUserPrincipalName: fmt.Sprintf("fake-%s@example.com", randomString(5)),
Expand Down Expand Up @@ -1624,6 +1634,17 @@ func (a *agent) doWindowsMDMCheckIn(onDemand bool) (newPollInterval time.Duratio
continue
}
a.stats.IncrementMDMSCEPSuccess()
if res.Cert == nil {
continue
}
// Report the issued cert via the certificates detail query so the server observes the
// fleet-<profileUUID> renewal-ID marker and marks the SCEP profile verified. The withheld
// ~5% never report theirs, so the server's verification backstop fails those profiles.
if a.withholdSCEPCert {
log.Printf("[test-only] agent %d: withholding issued SCEP cert for CSP %s to exercise the SCEP verification backstop", a.agentIndex, res.UniqueID)
continue
}
a.storeSCEPCertSpec(res.UniqueID, res.Cert)
}
}()
} else {
Expand Down
51 changes: 50 additions & 1 deletion cmd/osquery-perf/certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package main

import (
"crypto/sha1" //nolint:gosec
"crypto/x509"
"encoding/hex"
"fmt"
"maps"
// osquery-perf shares one global math/rand RNG seeded from the --seed flag so load-test runs are reproducible
"math/rand" //nolint:depguard
"slices"
"strings"
"time"

Expand Down Expand Up @@ -151,12 +153,59 @@ func (a *agent) generateCertSpecs() []simulatedCert {
a.churnPerHostCertSpecs()
}

specs := make([]simulatedCert, 0, len(sharedCerts)+len(a.hostCertSpecs))
specs := make([]simulatedCert, 0, len(sharedCerts)+len(a.hostCertSpecs)+len(a.scepCertSpecs))
specs = append(specs, sharedCerts...)
specs = append(specs, a.hostCertSpecs...)
// Include the certs issued via Windows MDM SCEP exchanges (never churned; replaced only on re-issuance). Sorted
// by CSP unique ID so the report order is stable across refreshes.
for _, id := range slices.Sorted(maps.Keys(a.scepCertSpecs)) {
specs = append(specs, a.scepCertSpecs[id])
}
return specs
}

// storeSCEPCertSpec records a certificate issued during a Windows MDM SCEP exchange so certificatesWindows reports
// it, keyed by the SCEP CSP unique ID so a re-issued cert (profile resend or renewal) replaces its predecessor.
func (a *agent) storeSCEPCertSpec(uniqueID string, cert *x509.Certificate) {
a.certificatesMutex.Lock()
defer a.certificatesMutex.Unlock()
if a.scepCertSpecs == nil {
a.scepCertSpecs = make(map[string]simulatedCert)
}
a.scepCertSpecs[uniqueID] = scepIssuedCertSpec(cert)
}

// scepIssuedCertSpec converts a certificate issued during a Windows MDM SCEP exchange into a simulatedCert. The
// cert's subject carries the fleet-<profileUUID> renewal-ID marker (expanded from the profile's
// $FLEET_VAR_SCEP_RENEWAL_ID), which the server matches on ingestion to flip the SCEP profile to verified. Reported
// machine-scoped: osquery-perf drives SCEP CSPs on the device channel, so the cert lands in the LocalMachine store.
func scepIssuedCertSpec(cert *x509.Certificate) simulatedCert {
return simulatedCert{
commonName: cert.Subject.CommonName,
subjectCommonName: cert.Subject.CommonName,
subjectOrg: firstOrEmpty(cert.Subject.Organization),
subjectOrgUnit: strings.Join(cert.Subject.OrganizationalUnit, "+OU="),
Comment thread
getvictor marked this conversation as resolved.
subjectCountry: firstOrEmpty(cert.Subject.Country),
issuerCommonName: cert.Issuer.CommonName,
issuerOrg: firstOrEmpty(cert.Issuer.Organization),
issuerCountry: firstOrEmpty(cert.Issuer.Country),
keyAlgorithm: "rsaEncryption",
keyStrength: "2048",
keyUsage: "Key Encipherment, Digital Signature",
signingAlgorithm: cert.SignatureAlgorithm.String(),
serial: cert.SerialNumber.String(),
notValidAfterUnix: fmt.Sprint(cert.NotAfter.Unix()),
notValidBeforeUnix: fmt.Sprint(cert.NotBefore.Unix()),
}
}

func firstOrEmpty(vals []string) string {
if len(vals) == 0 {
return ""
}
return vals[0]
}

// newPerHostCertSpecs generates 0-10 certificates unique to this host
func (a *agent) newPerHostCertSpecs() []simulatedCert {
count := rand.Intn(11) // 0..10
Expand Down
Loading