-
Notifications
You must be signed in to change notification settings - Fork 55
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
Add client certificate chain support and SSL context generation #454
Conversation
can we create test versions of these with a shell script? |
@mtmk Updated generator script with the openssl generation of the chained certs and added test cases for a multi-PEM file input |
checks seems to be failing. having a look. edit: Tests were failing with edit2: on Linux with .NET 6 when using chain certs |
@jmcrumb could you sign your commits please? |
is this still true? |
No. Just revised the description. |
@jmcrumb, I updated the docs a little. if you can please check the last commit and let me know if you're happy with it then we can merge this PR I think. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mtmk Looks good to me!
src/NATS.Client.Core/NatsTlsOpts.cs
Outdated
@@ -62,7 +63,7 @@ public sealed record NatsTlsOpts | |||
/// <summary> | |||
/// Callback that loads Client Certificate | |||
/// </summary> | |||
public Func<ValueTask<X509Certificate2>>? LoadClientCert { get; init; } | |||
public Func<ValueTask<X509Certificate2Collection>>? LoadClientCerts { get; init; } |
There was a problem hiding this comment.
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 necessarily pluralize LoadClientCerts
- it is still just 1 cert plus intermediates. Plural to me indicates the list of Client Certs will be tried based off some property of the cert such as common name or thumbprint. Should expand the doc here to explain why it's X509Certificate2Collection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also - should this callback return a SslStreamCertificateContext instead of an X509Certificate2Collection
, since it appears that is the correct API for building a client certificate chain with intermediates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about X509ChainPolicy
it needs that as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SslClientAuthenticationOptions.CertificateChainPolicy applies to remote certificate validation, I think that could be implemented similar to NatsTlsOpts.CertificateRevocationCheckMode
and is not needed in this callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard for me to weigh in on this with my limited vision of customers beyond my organization (and what they need). The most extreme and simple would be to expose the hook for SslClientAuthenticationOptions
or for a Func<SslClientAuthenticationOptions,SslClientAuthenticationOptions>
which allows for customizable overrides of the default built in SslStreamConnection
. Between that and the current state just seems like different levels of tradeoff between flexibility and consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, trying the tests without CertificateChainPolicy
doesn't seem to make any difference. Also looks like it might mess up the OCPS (I might've remembered the acronym wrong) feature:
If not null, CertificateRevocationCheckMode and SslCertificateTrust are ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also - should this callback return a SslStreamCertificateContext instead of an X509Certificate2Collection, since it appears that is the correct API for building a client certificate chain with intermediates
the only problem is that ClientCertificateContext
option (which gets assigned) is not available in net6.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that API popped up in net8, there is a mega thread about it here: dotnet/runtime#26323
@mtmk can we merge this to a staging branch? I think I'd like to undo the breaking change, and split it to:
I have something staged but I can't push to this PR because it's on a fork |
# Conflicts: # src/NATS.Client.Core/NatsTlsOpts.cs
thanks @jmcrumb! we're staging now. we should be ready to merge to main then release very soon. |
Great to hear, thank you! |
* Add client certificate chain support and SSL context generation (#454) * Add client certificate chain support and SSL context generation * Update certificate generation with certificate chain * Cert fix for tests * Test fix for .net6.0 * Minor doc updates * CA cert optional fix * CA cert optional fix * removed CA option from client context * Rename and docs * rename * rename * merge fixes --------- Co-authored-by: Maxon Crumb <mcrumb@starbucks.com> Co-authored-by: Ziya Suzen <ziya@suzen.net> * add NatsTlsOpts.LoadClientCertContext Signed-off-by: Caleb Lloyd <caleb@synadia.com> * remove LocalCertificateSelectionCallback on net8.0 Signed-off-by: Caleb Lloyd <caleb@synadia.com> * introduce ConfigureClientAuthentication Signed-off-by: Caleb Lloyd <caleb@synadia.com> * pragma Signed-off-by: Caleb Lloyd <caleb@synadia.com> * make SslClientAuthenticationOptionsExtensions internal Signed-off-by: Caleb Lloyd <caleb@synadia.com> --------- Signed-off-by: Caleb Lloyd <caleb@synadia.com> Co-authored-by: Maxon Crumb <37674616+jmcrumb@users.noreply.github.com> Co-authored-by: Maxon Crumb <mcrumb@starbucks.com> Co-authored-by: Ziya Suzen <ziya@suzen.net>
* #451 Dispose fixes * #433 Update NATS.Client.Hosting package as NATS.Extensions.Microsoft.DependencyInjection * (staged) #454 Add client certificate chain support and SSL context generation * #463 add NatsTlsOpts.LoadClientCertContext * #459 Object store metadata fix * #455 Deserialize empty payloads * Release 2.2.0 [nats:update-docs]
Context
Current implementation of client certificate loading does not allow for use of chained client certificates, either from the base options of filepath or the
LoadClientCertificate
hook inNatsTlsOpts
. The current behavior results in the first certificate in the file to be read, and any subsequent certificates contained are ignored. For clients which use certificate chaining, this forces server allowlisting of lowest-level intermediate certificates or failure to connect.Resolution
Change the SDK to use certificate collections rather than individual certificates as well as expose a hook for custom loading of said collection. Some of the functionality of this fix, specifically use of
SslStreamCertificateContext
during construction ofSslClientAuthenticationOptions
, is only available in the latest stable .NET major version (.NET 8), so this feature will only have support that the .NET 8 build of the NATS SDK.Changes
NatsTlsOpts.LoadCertificate(X509Certificate2)
toNatsTlsOpts.LoadCertificates(X509Certificate2Collection)
SslStreamCertificateContext
andX509ChainPolicy
creation for use during SSL handshakeAdditional Notes
During the RCA for this issue another bug was identified.
When attempting to connect from a Windows 10 Enterprise (19045.4046) machine, SSL connection was failing when
NatsTlsOpts.InsecureSkipVerify = false
. The same code ran without error on dockerized Linux. I suspect this is because of windows certificate handling (the same logic prompted special handling here, and may need to be applied to SslStreamConnection.RcsCbCaCertChain.In addition, during the failure above, a null pointer exception would occur at SetupReaderWriterAsync since
_currentConnectUri
was never set due to a caught error during SSL connection and authentication.