Skip to content

Commit 65d84f0

Browse files
committed
Update certificate validation to use custom trust store for .NET 5.0 and greater
1 parent 58d3bd5 commit 65d84f0

File tree

2 files changed

+64
-5
lines changed

2 files changed

+64
-5
lines changed

src/KubernetesClient/Kubernetes.ConfigInit.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,13 @@ public static bool CertificateValidationCallBack(
213213
{
214214
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
215215

216-
// Added our trusted certificates to the chain
217-
//
218-
chain.ChainPolicy.ExtraStore.AddRange(caCerts);
219-
220-
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
216+
#if NET5_0_OR_GREATER
217+
// Use custom trust store only, ignore system root CA
218+
chain.ChainPolicy.CustomTrustStore.AddRange(caCerts);
219+
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
220+
#else
221+
throw new NotSupportedException("Custom trust store is not supported on this platform.");
222+
#endif
221223
var isValid = chain.Build((X509Certificate2)certificate);
222224

223225
var isTrusted = false;

tests/KubernetesClient.Tests/CertificateValidationTests.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using System.Security.Cryptography;
13
using System.Net.Security;
24
using System.Security.Cryptography.X509Certificates;
35
using Xunit;
@@ -6,6 +8,61 @@ namespace k8s.Tests
68
{
79
public class CertificateValidationTests
810
{
11+
[Fact]
12+
public void ShouldRejectCertFromDifferentCA()
13+
{
14+
// Load our "trusted" Kubernetes CA
15+
var trustedCaCert = CertUtils.LoadPemFileCert("assets/ca.crt");
16+
17+
// Generate a completely different CA and server cert in memory
18+
var differentCA = CreateSelfSignedCA("CN=Different CA");
19+
var untrustedServerCert = CreateServerCert(differentCA, "CN=fake-server.com");
20+
21+
var chain = new X509Chain();
22+
23+
// Pre-populate the chain like SSL validation would do
24+
// This will likely succeed because we allow unknown CAs in the validation
25+
chain.Build(untrustedServerCert);
26+
27+
var errors = SslPolicyErrors.RemoteCertificateChainErrors;
28+
29+
var result = Kubernetes.CertificateValidationCallBack(this, trustedCaCert, untrustedServerCert, chain, errors);
30+
31+
// This SHOULD be false because the server cert wasn't signed by our trusted CA
32+
// But the current K8s validation logic might incorrectly return true
33+
Assert.False(result, "Should reject certificates not signed by trusted CA");
34+
35+
// Cleanup
36+
differentCA.Dispose();
37+
untrustedServerCert.Dispose();
38+
}
39+
40+
// Helper methods to create test certificates
41+
private static X509Certificate2 CreateSelfSignedCA(string subject)
42+
{
43+
using (var rsa = RSA.Create(2048))
44+
{
45+
var req = new CertificateRequest(subject, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
46+
req.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
47+
req.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign, true));
48+
49+
return req.CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow.AddDays(365));
50+
}
51+
}
52+
53+
private static X509Certificate2 CreateServerCert(X509Certificate2 issuerCA, string subject)
54+
{
55+
using (var rsa = RSA.Create(2048))
56+
{
57+
var req = new CertificateRequest(subject, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
58+
req.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
59+
req.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment, true));
60+
req.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, true));
61+
62+
return req.Create(issuerCA, DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow.AddDays(90), new byte[] { 1, 2, 3, 4 });
63+
}
64+
}
65+
966
[Fact]
1067
public void ValidCert()
1168
{

0 commit comments

Comments
 (0)