Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(devtools-proxy-support): remove certificates without issuer from system CA list COMPASS-8252 #467

Merged
merged 2 commits into from
Sep 5, 2024

Conversation

addaleax
Copy link
Contributor

@addaleax addaleax commented Sep 5, 2024

We have discovered that system certificate stores may contain certificates that a) OpenSSL may choose over other roots for the same certificate chain and b) are not accompanied by their own root certificate, i.e. only present an immediate certificate.

While we will ideally solve this by using X509_V_FLAG_PARTIAL_CHAIN, Node.js does not expose that as a feature yet.

Description

Open Questions

Checklist

…system CA list COMPASS-8252

We have discovered that system certificate stores may contain certificates
that a) OpenSSL may choose over other roots for the same certificate chain
and b) are not accompanied by their own root certificate, i.e. only present
an immediate certificate.

While we will ideally solve this by using `X509_V_FLAG_PARTIAL_CHAIN`,
Node.js does not expose that as a feature yet.
@@ -58,12 +107,14 @@ export async function systemCA(
existingOptions: {
ca?: NodeJSCAOption;
tlsCAFile?: string | null | undefined;
} = {}
} = {},
allowCertificatesWithoutIssuer?: boolean // defaults to false
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want to also expose this in connect method options or is the idea that we'd allow to activate it with the env var?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we wanted to expose it the idea is that we'd forward it all the way to the user in the UI, right?

I am pretty hopeful that this won't be necessary, and it's a temporary solution anyway. So yeah, the environment variable would be the way to get back to the current (i.e. "broken" 1.44) behavior if somebody does end up needing that for some reason

Copy link
Contributor

Choose a reason for hiding this comment

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

Ohhhhh, wait, I totally misread the variable name and thought it's the other way around, okay yeah, not exposing it at all makes sense 😄

Copy link
Contributor

@lerouxb lerouxb left a comment

Choose a reason for hiding this comment

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

Nice! Really quick turnaround time 😄

Copy link

@nirinchev nirinchev left a comment

Choose a reason for hiding this comment

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

This change looks reasonable to me, though I only have superficial context via the HELP tickets and the slack comms, so worth getting another pair of eyes on it.

Comment on lines 75 to 79
`Unable to parse certificate: ${
err && typeof err === 'object' && 'message' in err
? String(err.message)
: String(err)
}`

Choose a reason for hiding this comment

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

No strong opinion here and mostly out of curiosity, can this be rewritten more concisely as: Unable to parse certificate: ${ err?.message || err }? I guess it will require replacing the type for err with any, but other than that are there downsides?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess it will require replacing the type for err with any, but other than that are there downsides?

Nah, you pretty much got it – it's not more than a general tendency to avoid any whenever we can 🙂

Comment on lines +86 to +87
const keep =
!parsed ||

Choose a reason for hiding this comment

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

This is somewhat counterintuitive to me - if we were unable to parse the certificate, do we want to keep it? I guess there's no harm in doing it, but do we feel it's useful to hold on to pems that are not valid x509 certificates?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think we should ever encounter a situation like this in the first place. But if we do, I think this is the "safer" path – if nothing else, it aligns more closely with the previous behavior (and the one we're aiming for in the long term, once this code is removed again). So I think just leaving a diagnostic message here is probably okay?

}
return { pem, parsed };
});
pemWithParsedCache.set(ca, caWithParsedCerts);

Choose a reason for hiding this comment

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

Likely inconsequential, but for my understanding, why are we storing the unfiltered certificates in the cache rather than the filtered ones? My expectation is that the result of the filter will always be the same, so we might as well cache that rather than do the filtering every time.

Copy link
Contributor Author

@addaleax addaleax Sep 5, 2024

Choose a reason for hiding this comment

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

Good idea! Done in 4b60c71

@addaleax addaleax merged commit 98f6f31 into main Sep 5, 2024
5 checks passed
@addaleax addaleax deleted the 8252-dev branch September 5, 2024 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants