Skip to content

Windows MDM client certificate is backdated by the renewal period, halving its lifetime and opening the renewal window at issuance #52601

Description

@getvictor

Fleet versions


💥 Actual behavior

Fleet backdates every Windows MDM client certificate by the full renewal period, so the certificate is issued already 180 days old and expires 185 days after enrollment instead of the 365 days Fleet advertises.

populateClientCert computes NotBefore by subtracting the renewal period from the current time, then adds a hardcoded 365 days to get NotAfter:

certRenewalPeriodInSecsInt, err := strconv.Atoi(syncml.PolicyCertRenewalPeriodInSecs)  // 15552000s = 180 days
notBeforeDuration := time.Now().Add(time.Duration(certRenewalPeriodInSecsInt) * -time.Second)  // now - 180d
yearDuration := 365 * 24 * time.Hour
NotBefore: notBeforeDuration,                    // now - 180d
NotAfter:  notBeforeDuration.Add(yearDuration),  // now + 185d

Three separate problems fall out of this.

The certificate lives half as long as advertised. Fleet tells Windows one thing and issues another.

The renewal window is already open when the certificate is installed. The certificate is renewal-eligible from the instant it is issued, 180 days before the device even enrolled. Windows then retries every RetryInterval = 4 days for the entire life of the enrollment. This is why the EnrollmentState = 3 symptom in #50611 shows up on freshly enrolled hosts rather than only on hosts approaching expiry.

RenewPeriod and the advertised renewal period disagree. GetPolicies advertises RenewalPeriodSeconds = 15552000 (180 days) while the provisioning doc sends RenewPeriod = 365 days. The backdating has to be fixed for the renewal window to land anywhere sensible.

🛠️ Expected behavior

Fleet should issue a certificate whose validity matches what it advertises, and whose renewal window opens near the end of that validity rather than at the start.

  1. Set NotBefore to the current time. If a clock-skew allowance is wanted, use minutes or a few hours, not the 180 day renewal period.
  2. Derive NotAfter from syncml.PolicyCertValidityPeriodInSecs (the same constant Fleet advertises in GetPolicies) instead of the hardcoded yearDuration, so the advertised policy and the issued certificate cannot drift apart.
  3. Make the provisioning doc's RenewPeriod agree with PolicyCertRenewalPeriodInSecs, so a 365 day certificate with a 180 day renewal period opens its renewal window at day 185 rather than at day 0.

This bug is independent of the ROBO question. #51468 set WstepROBOSupport = "false" to stop Windows from attempting a renewal Fleet cannot service, and #52492 tracks the fact that Windows attempts renewal anyway. Even with ROBO fully implemented, the certificate lifetime and the renewal window would still be wrong.

🧑‍💻 Steps to reproduce

These steps:

  • Have been confirmed to consistently lead to reproduction in multiple Fleet instances.
  • Describe the workflow that led to the error, but have not yet been reproduced in multiple Fleet instances.
  1. Turn on Windows MDM on a Fleet server and enroll a Windows 10 or 11 host.
  2. On the host, open certlm.msc and find the Fleet-issued client certificate in Personal > Certificates (issued by the Fleet WSTEP identity CA, with OU = Fleet). Alternatively run Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Issuer -like '*Fleet*' } | Select-Object Subject, NotBefore, NotAfter.
  3. Observe that NotBefore is roughly 180 days in the past, dated well before the host enrolled, and that NotAfter is roughly 185 days in the future rather than 365 days.
  4. Read the provisioning doc values Fleet sent by checking HKLM\SOFTWARE\Microsoft\Enrollments\<GUID> for the enrollment with ProviderID = Fleet, and confirm the WSTEP renew settings show a 365 day RenewPeriod against a certificate with 185 days of remaining life.
  5. Confirm that Windows treats the certificate as renewal-eligible immediately: the scheduled task "Schedule created by enrollment client for renewal of certificate warning" under \Microsoft\Windows\EnterpriseMgmt\<GUID> runs and attempts renewal within the first RetryInterval window rather than waiting until the certificate is near expiry.

🕯️ More info (optional)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    #g-power-to-pcPower to the PC working groupbugSomething isn't working as documented

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions