Skip to content

Commit c772d8e

Browse files
authored
force using AES for cert algo (#1345)
* force using 3des for cert algo * happy build * use aes * happy build
1 parent a3321e0 commit c772d8e

File tree

3 files changed

+159
-105
lines changed

3 files changed

+159
-105
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
using k8s.Exceptions;
2+
using Org.BouncyCastle.Asn1.Nist;
3+
using Org.BouncyCastle.Asn1.Pkcs;
4+
using Org.BouncyCastle.Crypto;
5+
using Org.BouncyCastle.OpenSsl;
6+
using Org.BouncyCastle.Pkcs;
7+
using Org.BouncyCastle.Security;
8+
using Org.BouncyCastle.X509;
9+
using System.IO;
10+
using System.Security.Cryptography.X509Certificates;
11+
12+
namespace k8s
13+
{
14+
internal static class CertUtils
15+
{
16+
/// <summary>
17+
/// Load pem encoded cert file
18+
/// </summary>
19+
/// <param name="file">Path to pem encoded cert file</param>
20+
/// <returns>List of x509 instances.</returns>
21+
public static X509Certificate2Collection LoadPemFileCert(string file)
22+
{
23+
var certCollection = new X509Certificate2Collection();
24+
using (var stream = FileSystem.Current.OpenRead(file))
25+
{
26+
var certs = new X509CertificateParser().ReadCertificates(stream);
27+
28+
// Convert BouncyCastle X509Certificates to the .NET cryptography implementation and add
29+
// it to the certificate collection
30+
//
31+
foreach (Org.BouncyCastle.X509.X509Certificate cert in certs)
32+
{
33+
// This null password is to change the constructor to fix this KB:
34+
// https://support.microsoft.com/en-us/topic/kb5025823-change-in-how-net-applications-import-x-509-certificates-bf81c936-af2b-446e-9f7a-016f4713b46b
35+
string nullPassword = null;
36+
certCollection.Add(new X509Certificate2(cert.GetEncoded(), nullPassword));
37+
}
38+
}
39+
40+
return certCollection;
41+
}
42+
43+
/// <summary>
44+
/// Generates pfx from client configuration
45+
/// </summary>
46+
/// <param name="config">Kubernetes Client Configuration</param>
47+
/// <returns>Generated Pfx Path</returns>
48+
public static X509Certificate2 GeneratePfx(KubernetesClientConfiguration config)
49+
{
50+
if (config == null)
51+
{
52+
throw new ArgumentNullException(nameof(config));
53+
}
54+
55+
byte[] keyData = null;
56+
byte[] certData = null;
57+
58+
if (!string.IsNullOrWhiteSpace(config.ClientCertificateKeyData))
59+
{
60+
keyData = Convert.FromBase64String(config.ClientCertificateKeyData);
61+
}
62+
63+
if (!string.IsNullOrWhiteSpace(config.ClientKeyFilePath))
64+
{
65+
keyData = File.ReadAllBytes(config.ClientKeyFilePath);
66+
}
67+
68+
if (keyData == null)
69+
{
70+
throw new KubeConfigException("keyData is empty");
71+
}
72+
73+
if (!string.IsNullOrWhiteSpace(config.ClientCertificateData))
74+
{
75+
certData = Convert.FromBase64String(config.ClientCertificateData);
76+
}
77+
78+
if (!string.IsNullOrWhiteSpace(config.ClientCertificateFilePath))
79+
{
80+
certData = File.ReadAllBytes(config.ClientCertificateFilePath);
81+
}
82+
83+
if (certData == null)
84+
{
85+
throw new KubeConfigException("certData is empty");
86+
}
87+
88+
var cert = new X509CertificateParser().ReadCertificate(new MemoryStream(certData));
89+
// key usage is a bit string, zero-th bit is 'digitalSignature'
90+
// See https://www.alvestrand.no/objectid/2.5.29.15.html for more details.
91+
if (cert != null && cert.GetKeyUsage() != null && !cert.GetKeyUsage()[0])
92+
{
93+
throw new Exception(
94+
"Client certificates must be marked for digital signing. " +
95+
"See https://github.com/kubernetes-client/csharp/issues/319");
96+
}
97+
98+
object obj;
99+
using (var reader = new StreamReader(new MemoryStream(keyData)))
100+
{
101+
obj = new PemReader(reader).ReadObject();
102+
if (obj is AsymmetricCipherKeyPair key)
103+
{
104+
var cipherKey = key;
105+
obj = cipherKey.Private;
106+
}
107+
}
108+
109+
var keyParams = (AsymmetricKeyParameter)obj;
110+
111+
var store = new Pkcs12StoreBuilder()
112+
.SetKeyAlgorithm(NistObjectIdentifiers.IdAes128Cbc, PkcsObjectIdentifiers.IdHmacWithSha1)
113+
.Build();
114+
store.SetKeyEntry("K8SKEY", new AsymmetricKeyEntry(keyParams), new[] { new X509CertificateEntry(cert) });
115+
116+
using var pkcs = new MemoryStream();
117+
118+
store.Save(pkcs, new char[0], new SecureRandom());
119+
120+
// This null password is to change the constructor to fix this KB:
121+
// https://support.microsoft.com/en-us/topic/kb5025823-change-in-how-net-applications-import-x-509-certificates-bf81c936-af2b-446e-9f7a-016f4713b46b
122+
string nullPassword = null;
123+
124+
if (config.ClientCertificateKeyStoreFlags.HasValue)
125+
{
126+
return new X509Certificate2(pkcs.ToArray(), nullPassword, config.ClientCertificateKeyStoreFlags.Value);
127+
}
128+
else
129+
{
130+
return new X509Certificate2(pkcs.ToArray(), nullPassword);
131+
}
132+
}
133+
134+
/// <summary>
135+
/// Retrieves Client Certificate PFX from configuration
136+
/// </summary>
137+
/// <param name="config">Kubernetes Client Configuration</param>
138+
/// <returns>Client certificate PFX</returns>
139+
public static X509Certificate2 GetClientCert(KubernetesClientConfiguration config)
140+
{
141+
if (config == null)
142+
{
143+
throw new ArgumentNullException(nameof(config));
144+
}
145+
146+
if ((!string.IsNullOrWhiteSpace(config.ClientCertificateData) ||
147+
!string.IsNullOrWhiteSpace(config.ClientCertificateFilePath)) &&
148+
(!string.IsNullOrWhiteSpace(config.ClientCertificateKeyData) ||
149+
!string.IsNullOrWhiteSpace(config.ClientKeyFilePath)))
150+
{
151+
return GeneratePfx(config);
152+
}
153+
154+
return null;
155+
}
156+
}
157+
}

src/KubernetesClient.Classic/KubernetesClient.Classic.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
10-
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.32.3" />
9+
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
10+
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.32.0" />
1111
<PackageReference Include="IdentityModel.OidcClient" Version="5.2.1" />
1212
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
1313
</ItemGroup>
@@ -18,7 +18,6 @@
1818
</ItemGroup>
1919

2020
<ItemGroup>
21-
<Compile Include="..\KubernetesClient\CertUtils.cs" />
2221
<Compile Include="..\KubernetesClient\FileSystem.cs" />
2322
<Compile Include="..\KubernetesClient\IKubernetes.cs" />
2423
<Compile Include="..\KubernetesClient\Kubernetes.ConfigInit.cs" />

src/KubernetesClient/CertUtils.cs

Lines changed: 0 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
using k8s.Exceptions;
2-
#if !NET5_0_OR_GREATER
3-
using Org.BouncyCastle.Crypto;
4-
using Org.BouncyCastle.OpenSsl;
5-
using Org.BouncyCastle.Pkcs;
6-
using Org.BouncyCastle.Security;
7-
using Org.BouncyCastle.X509;
8-
#else
92
using System.Runtime.InteropServices;
103
using System.Text;
11-
#endif
124
using System.IO;
135
using System.Security.Cryptography.X509Certificates;
146

@@ -26,22 +18,7 @@ public static X509Certificate2Collection LoadPemFileCert(string file)
2618
var certCollection = new X509Certificate2Collection();
2719
using (var stream = FileSystem.Current.OpenRead(file))
2820
{
29-
#if NET5_0_OR_GREATER
3021
certCollection.ImportFromPem(new StreamReader(stream).ReadToEnd());
31-
#else
32-
var certs = new X509CertificateParser().ReadCertificates(stream);
33-
34-
// Convert BouncyCastle X509Certificates to the .NET cryptography implementation and add
35-
// it to the certificate collection
36-
//
37-
foreach (Org.BouncyCastle.X509.X509Certificate cert in certs)
38-
{
39-
// This null password is to change the constructor to fix this KB:
40-
// https://support.microsoft.com/en-us/topic/kb5025823-change-in-how-net-applications-import-x-509-certificates-bf81c936-af2b-446e-9f7a-016f4713b46b
41-
string nullPassword = null;
42-
certCollection.Add(new X509Certificate2(cert.GetEncoded(), nullPassword));
43-
}
44-
#endif
4522
}
4623

4724
return certCollection;
@@ -59,7 +36,6 @@ public static X509Certificate2 GeneratePfx(KubernetesClientConfiguration config)
5936
throw new ArgumentNullException(nameof(config));
6037
}
6138

62-
#if NET5_0_OR_GREATER
6339
string keyData = null;
6440
string certData = null;
6541

@@ -114,84 +90,6 @@ public static X509Certificate2 GeneratePfx(KubernetesClientConfiguration config)
11490
}
11591

11692
return cert;
117-
#else
118-
119-
byte[] keyData = null;
120-
byte[] certData = null;
121-
122-
if (!string.IsNullOrWhiteSpace(config.ClientCertificateKeyData))
123-
{
124-
keyData = Convert.FromBase64String(config.ClientCertificateKeyData);
125-
}
126-
127-
if (!string.IsNullOrWhiteSpace(config.ClientKeyFilePath))
128-
{
129-
keyData = File.ReadAllBytes(config.ClientKeyFilePath);
130-
}
131-
132-
if (keyData == null)
133-
{
134-
throw new KubeConfigException("keyData is empty");
135-
}
136-
137-
if (!string.IsNullOrWhiteSpace(config.ClientCertificateData))
138-
{
139-
certData = Convert.FromBase64String(config.ClientCertificateData);
140-
}
141-
142-
if (!string.IsNullOrWhiteSpace(config.ClientCertificateFilePath))
143-
{
144-
certData = File.ReadAllBytes(config.ClientCertificateFilePath);
145-
}
146-
147-
if (certData == null)
148-
{
149-
throw new KubeConfigException("certData is empty");
150-
}
151-
152-
var cert = new X509CertificateParser().ReadCertificate(new MemoryStream(certData));
153-
// key usage is a bit string, zero-th bit is 'digitalSignature'
154-
// See https://www.alvestrand.no/objectid/2.5.29.15.html for more details.
155-
if (cert != null && cert.GetKeyUsage() != null && !cert.GetKeyUsage()[0])
156-
{
157-
throw new Exception(
158-
"Client certificates must be marked for digital signing. " +
159-
"See https://github.com/kubernetes-client/csharp/issues/319");
160-
}
161-
162-
object obj;
163-
using (var reader = new StreamReader(new MemoryStream(keyData)))
164-
{
165-
obj = new PemReader(reader).ReadObject();
166-
if (obj is AsymmetricCipherKeyPair key)
167-
{
168-
var cipherKey = key;
169-
obj = cipherKey.Private;
170-
}
171-
}
172-
173-
var keyParams = (AsymmetricKeyParameter)obj;
174-
175-
var store = new Pkcs12StoreBuilder().Build();
176-
store.SetKeyEntry("K8SKEY", new AsymmetricKeyEntry(keyParams), new[] { new X509CertificateEntry(cert) });
177-
178-
using var pkcs = new MemoryStream();
179-
180-
store.Save(pkcs, new char[0], new SecureRandom());
181-
182-
// This null password is to change the constructor to fix this KB:
183-
// https://support.microsoft.com/en-us/topic/kb5025823-change-in-how-net-applications-import-x-509-certificates-bf81c936-af2b-446e-9f7a-016f4713b46b
184-
string nullPassword = null;
185-
186-
if (config.ClientCertificateKeyStoreFlags.HasValue)
187-
{
188-
return new X509Certificate2(pkcs.ToArray(), nullPassword, config.ClientCertificateKeyStoreFlags.Value);
189-
}
190-
else
191-
{
192-
return new X509Certificate2(pkcs.ToArray(), nullPassword);
193-
}
194-
#endif
19593
}
19694

19795
/// <summary>

0 commit comments

Comments
 (0)