fix certificate parser part 2 (#33152)

fixes: #31390 

# 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.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
This commit is contained in:
Magnus Jensen 2025-09-23 16:12:11 +03:00 committed by GitHub
parent da07fff9da
commit e311e26538
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 53 additions and 32 deletions

View file

@ -0,0 +1,2 @@
* Fixed certificate ingest parser to no longer break on multiple equal signs in certificate key pair values
* Fixed certificate ingest parser to allow for only multiple relative distinguished names separated by +

View file

@ -220,16 +220,22 @@ func ExtractDetailsFromOsqueryDistinguishedName(str string) (*HostCertificateNam
str = strings.ReplaceAll(str, `\/`, `<<SLASH>>`) // Replace with our own "safe" sequence
parts := strings.Split(str, "/")
if len(parts) == 1 {
// Try to split into parts based on +
parts = strings.Split(str, "+")
}
var details HostCertificateNameDetails
for _, part := range parts {
kv := strings.Split(part, "=")
if len(kv) != 2 {
key, value, found := strings.Cut(part, "=")
if !found {
return nil, fmt.Errorf("invalid distinguished name, wrong key value pair format: %s", str)
}
value := strings.ReplaceAll(strings.Trim(kv[1], " "), `<<SLASH>>`, `/`) // Replace our "safe" sequence with forward slash
value = strings.ReplaceAll(strings.Trim(value, " "), `<<SLASH>>`, `/`) // Replace our "safe" sequence with forward slash
switch strings.ToUpper(kv[0]) {
switch strings.ToUpper(key) {
case "C":
details.Country = strings.Trim(value, " ")
case "O":

View file

@ -7,17 +7,13 @@ import (
)
func TestExtractHostCertificateNameDetails(t *testing.T) {
expected := HostCertificateNameDetails{
Country: "US",
Organization: "Fleet Device Management Inc.",
OrganizationalUnit: "Fleet Device Management Inc.",
CommonName: "FleetDM",
}
expectedWithSlash := HostCertificateNameDetails{
Country: "US",
Organization: "Fleet Device Management Inc.",
OrganizationalUnit: "Fleet Device Management Inc.",
CommonName: "FleetDM/valid",
getExpectedHostCertificateDetails := func(commonName string) *HostCertificateNameDetails {
return &HostCertificateNameDetails{
Country: "US",
Organization: "Fleet Device Management Inc.",
OrganizationalUnit: "Fleet Device Management Inc.",
CommonName: commonName,
}
}
cases := []struct {
@ -29,12 +25,12 @@ func TestExtractHostCertificateNameDetails(t *testing.T) {
{
name: "valid",
input: "/C=US/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM",
expected: &expected,
expected: getExpectedHostCertificateDetails("FleetDM"),
},
{
name: "valid with different order",
input: "/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM/C=US",
expected: &expected,
expected: getExpectedHostCertificateDetails("FleetDM"),
},
{
name: "valid with missing key",
@ -49,17 +45,22 @@ func TestExtractHostCertificateNameDetails(t *testing.T) {
{
name: "valid with additional keyr",
input: "/C=US/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM/L=SomeCity",
expected: &expected,
expected: getExpectedHostCertificateDetails("FleetDM"),
},
{
name: "valid format with extra slash",
input: `/C=US/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM\/valid`,
expected: &expectedWithSlash,
expected: getExpectedHostCertificateDetails("FleetDM/valid"),
},
{
name: "valid with safe escape sequence",
input: `/C=US/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM<<SLASH>>valid`,
expected: &expectedWithSlash,
expected: getExpectedHostCertificateDetails("FleetDM/valid"),
},
{
name: "valid format with equal signs in value",
input: "/C=US/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM=Company",
expected: getExpectedHostCertificateDetails("FleetDM=Company"),
},
{
name: "invalid format with extra slash without escape",
@ -67,14 +68,11 @@ func TestExtractHostCertificateNameDetails(t *testing.T) {
err: true,
},
{
name: "invalid format with wrong separator",
name: "format with wrong separator", // this will now just be treated as part of C
input: "C=US,O=Fleet Device Management Inc.,OU=Fleet Device Management Inc.,CN=FleetDM",
err: true,
},
{
name: "invalid format with extra equal",
input: "/C=US=/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM",
err: true,
expected: &HostCertificateNameDetails{
Country: "US,O=Fleet Device Management Inc.,OU=Fleet Device Management Inc.,CN=FleetDM",
},
},
{
name: "invalid format with malformed key values",
@ -99,12 +97,12 @@ func TestExtractHostCertificateNameDetails(t *testing.T) {
{
name: "missing first slash",
input: "C=US/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM",
expected: &expected,
expected: getExpectedHostCertificateDetails("FleetDM"),
},
{
name: "trailing slash",
input: "/C=US/O=Fleet Device Management Inc./OU=Fleet Device Management Inc./CN=FleetDM/",
expected: &expected,
expected: getExpectedHostCertificateDetails("FleetDM"),
},
{
name: "simple common name",
@ -127,9 +125,24 @@ func TestExtractHostCertificateNameDetails(t *testing.T) {
},
},
{
name: "invalid separator",
input: "/C=US,O=Fleet Device Management Inc.,OU=Fleet Device Management Inc.,CN=FleetDM",
err: true,
name: "with plusses as separator",
input: "DN=something+CN=FleetDM+OU=Org",
expected: &HostCertificateNameDetails{
Country: "",
Organization: "",
OrganizationalUnit: "Org",
CommonName: "FleetDM",
},
},
{
name: "with plusses inside values and slash as separator",
input: "DN=something/CN=FleetDM+valid/OU=Org",
expected: &HostCertificateNameDetails{
Country: "",
Organization: "",
OrganizationalUnit: "Org",
CommonName: "FleetDM+valid",
},
},
}
for _, tc := range cases {