Update PEM header type per hydrant spec (#42052)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #40910

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually
This commit is contained in:
Jordan Montgomery 2026-03-19 15:37:22 -04:00 committed by GitHub
parent 357d280c4a
commit 97433a5de6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 10 additions and 8 deletions

View file

@ -0,0 +1 @@
* Updated the Request Certificate API to return the proper PEM header for PKCS #7 certificates returned by EST CAs

View file

@ -16,7 +16,6 @@ import (
"github.com/fleetdm/fleet/v4/server/contexts/authz"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/ptr"
)
// This code largely adapted from fleet/website/api/controllers/get-est-device-certificate.js
@ -135,8 +134,10 @@ func (svc *Service) RequestCertificate(ctx context.Context, p fleet.RequestCerti
return nil, &fleet.BadRequestError{Message: fmt.Sprintf("EST certificate request failed: %s", err.Error())}
}
svc.logger.InfoContext(ctx, "Successfully retrieved a certificate from EST", "ca_id", ca.ID, "idp_username", idpUsername)
// Wrap the certificate in a PEM block for easier consumption by the client
return ptr.String("-----BEGIN CERTIFICATE-----\n" + string(certificate.Certificate) + "\n-----END CERTIFICATE-----\n"), nil
// Wrap the certificate in a PEM block for easier consumption by the client. TODO: If we ever
// support CAs other than Hydrant/EST in this API, this may need to be modified to be aware of
// their formats.
return new("-----BEGIN PKCS7-----\n" + string(certificate.Certificate) + "\n-----END PKCS7-----\n"), nil
}
func (svc *Service) introspectIDPToken(ctx context.Context, idpClientID, idpToken, idpOauthURL string) (*oauthIntrospectionResponse, error) {

View file

@ -191,7 +191,7 @@ func TestRequestCertificate(t *testing.T) {
})
require.NoError(t, err)
require.NotNil(t, cert)
require.Equal(t, "-----BEGIN CERTIFICATE-----\n"+hydrantSimpleEnrollResponse+"\n-----END CERTIFICATE-----\n", *cert)
require.Equal(t, "-----BEGIN PKCS7-----\n"+hydrantSimpleEnrollResponse+"\n-----END PKCS7-----\n", *cert)
})
t.Run("Request a certificate - Happy path, no IDP", func(t *testing.T) {
@ -203,7 +203,7 @@ func TestRequestCertificate(t *testing.T) {
})
require.NoError(t, err)
require.NotNil(t, cert)
require.Equal(t, "-----BEGIN CERTIFICATE-----\n"+hydrantSimpleEnrollResponse+"\n-----END CERTIFICATE-----\n", *cert)
require.Equal(t, "-----BEGIN PKCS7-----\n"+hydrantSimpleEnrollResponse+"\n-----END PKCS7-----\n", *cert)
})
t.Run("Request a certificate - Happy path, no IDP, http sig auth", func(t *testing.T) {
@ -223,7 +223,7 @@ func TestRequestCertificate(t *testing.T) {
})
require.NoError(t, err)
require.NotNil(t, cert)
require.Equal(t, "-----BEGIN CERTIFICATE-----\n"+hydrantSimpleEnrollResponse+"\n-----END CERTIFICATE-----\n", *cert)
require.Equal(t, "-----BEGIN PKCS7-----\n"+hydrantSimpleEnrollResponse+"\n-----END PKCS7-----\n", *cert)
})
t.Run("Request a certificate - Happy path, no IDP, UPN does not match IDP info(should pass)", func(t *testing.T) {
@ -235,7 +235,7 @@ func TestRequestCertificate(t *testing.T) {
})
require.NoError(t, err)
require.NotNil(t, cert)
require.Equal(t, "-----BEGIN CERTIFICATE-----\n"+hydrantSimpleEnrollResponse+"\n-----END CERTIFICATE-----\n", *cert)
require.Equal(t, "-----BEGIN PKCS7-----\n"+hydrantSimpleEnrollResponse+"\n-----END PKCS7-----\n", *cert)
})
t.Run("Request a certificate - CA returns error", func(t *testing.T) {
@ -310,7 +310,7 @@ func TestRequestCertificate(t *testing.T) {
})
require.NoError(t, err)
require.NotNil(t, cert)
require.Equal(t, "-----BEGIN CERTIFICATE-----\n"+hydrantSimpleEnrollResponse+"\n-----END CERTIFICATE-----\n", *cert)
require.Equal(t, "-----BEGIN PKCS7-----\n"+hydrantSimpleEnrollResponse+"\n-----END PKCS7-----\n", *cert)
})
t.Run("Request certificate - non-Hydrant and non-EST CA", func(t *testing.T) {