Skip to content

Commit 4a7143b

Browse files
authored
CSHARP-1003 Fix support for Astra custom domains in linux environments (#602)
1 parent e4e7f06 commit 4a7143b

File tree

4 files changed

+67
-26
lines changed

4 files changed

+67
-26
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# ChangeLog - DataStax C# Driver
22

3+
## 3.19.5
4+
5+
2023-11-23
6+
7+
### Bug fixes
8+
9+
* [[CSHARP-1003](https://datastax-oss.atlassian.net/browse/CSHARP-1003)] Fix support for Astra custom domain names in linux environments
10+
311
## 3.19.4
412

513
2023-11-07

src/Cassandra/Cassandra.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
<Copyright>Copyright © by DataStax</Copyright>
55
<AssemblyTitle>DataStax C# Driver for Apache Cassandra</AssemblyTitle>
66
<AssemblyVersion>3.99.0.0</AssemblyVersion>
7-
<FileVersion>3.19.4.0</FileVersion>
8-
<VersionPrefix>3.19.4</VersionPrefix>
7+
<FileVersion>3.19.5.0</FileVersion>
8+
<VersionPrefix>3.19.5</VersionPrefix>
99
<Authors>DataStax</Authors>
1010
<TargetFrameworks Condition="'$(BuildCoreOnly)' != 'True'">net452;netstandard2.0</TargetFrameworks>
1111
<TargetFramework Condition="'$(BuildCoreOnly)' == 'True'">netstandard2.0</TargetFramework>

src/Cassandra/DataStax/Cloud/CustomCACertificateValidator.cs

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
using System.Net.Security;
2121
using System.Security.Cryptography;
2222
using System.Security.Cryptography.X509Certificates;
23-
using System.Text.RegularExpressions;
2423

2524
namespace Cassandra.DataStax.Cloud
2625
{
@@ -32,9 +31,52 @@ internal class CustomCaCertificateValidator : ICertificateValidator
3231
private const string SubjectAlternateNameOid = "2.5.29.17"; // Oid for the SAN extension
3332

3433
private static readonly Logger Logger = new Logger(typeof(CustomCaCertificateValidator));
34+
35+
private static readonly string SanPlatformId;
36+
private static readonly string SanSeparator;
37+
3538
private readonly X509Certificate2 _trustedRootCertificateAuthority;
3639
private readonly string _hostname;
3740

41+
static CustomCaCertificateValidator()
42+
{
43+
// use a well known example SAN extension to extract the platform identifier (since it is affected by platform and locale/culture)
44+
45+
const string wellKnownSanExtension = @"MBuCC2V4YW1wbGUuY29tggxmYWtlLXN1YmplY3Q=";
46+
const string firstWellKnownDomainName = "example.com";
47+
const string secondWellKnownDomainName = "fake-subject";
48+
49+
var formattedExtString = new X509Extension(SubjectAlternateNameOid, Convert.FromBase64String(wellKnownSanExtension), true).Format(false);
50+
51+
// Windows identifier is affected by locale/culture
52+
// Example well known SAN extension has the following format:
53+
// Windows: "DNS Name=example.com, DNS Name=fake-subject"
54+
// Linux: "DNS:example.com, DNS:fake-subject"
55+
//
56+
// Parse it as the following:
57+
// <platform-id><domain-name><separator><platform-id><domain-name>
58+
// e.g. for Windows with EN culture:
59+
// platform-id -> "DNS Name="
60+
// first-domain-name -> "example.com"
61+
// second-domain-name -> "fake-subject"
62+
// separator -> ", "
63+
64+
// "example.com"
65+
var firstDomainNameIndex = formattedExtString.IndexOf(firstWellKnownDomainName, StringComparison.Ordinal);
66+
67+
// "fake-subject"
68+
var secondDomainNameIndex = formattedExtString.IndexOf(secondWellKnownDomainName, StringComparison.Ordinal);
69+
70+
// "DNS Name="
71+
SanPlatformId = formattedExtString.Substring(0, firstDomainNameIndex);
72+
73+
// ", "
74+
var separatorIndex = firstDomainNameIndex + firstWellKnownDomainName.Length;
75+
var lengthUntilSeparator = firstDomainNameIndex + firstWellKnownDomainName.Length;
76+
var separatorLength = secondDomainNameIndex - SanPlatformId.Length - lengthUntilSeparator;
77+
SanSeparator = formattedExtString.Substring(separatorIndex, separatorLength);
78+
}
79+
3880
public CustomCaCertificateValidator(X509Certificate2 trustedRootCertificateAuthority, string hostname)
3981
{
4082
_trustedRootCertificateAuthority =
@@ -168,32 +210,23 @@ private bool ValidateName(string name)
168210
return false;
169211
}
170212

213+
/// <summary>
214+
/// Check the static constructor inline comments for an explanation about this
215+
/// </summary>
171216
private IEnumerable<string> GetSubjectAlternativeNames(X509Certificate2 cert)
172217
{
173-
var result = new List<string>();
174-
175-
var subjectAlternativeName = cert.Extensions.Cast<X509Extension>()
176-
.Where(n => n.Oid.Value == SubjectAlternateNameOid)
177-
.Select(n => new AsnEncodedData(n.Oid, n.RawData))
178-
.Select(n => n.Format(true))
179-
.FirstOrDefault();
218+
var sanStrings = cert.Extensions
219+
.Cast<X509Extension>()
220+
.Where(ext => ext.Oid.Value == SubjectAlternateNameOid)
221+
.Select(ext => new AsnEncodedData(ext.Oid, ext.RawData).Format(false)).ToList();
180222

181-
if (subjectAlternativeName != null)
182-
{
183-
var alternativeNames = subjectAlternativeName.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
223+
var splitSanStrings = sanStrings.SelectMany(s => s.Split(new[] { SanSeparator }, StringSplitOptions.RemoveEmptyEntries));
184224

185-
foreach (var alternativeName in alternativeNames)
186-
{
187-
var groups = Regex.Match(alternativeName, @"^(.*)=(.*)").Groups; // @"^DNS Name=(.*)").Groups;
188-
189-
if (groups.Count > 0 && !string.IsNullOrEmpty(groups[2].Value))
190-
{
191-
result.Add(groups[2].Value);
192-
}
193-
}
194-
}
225+
// remove the platform identifier (i.e. "DNS Name=") from the strings to get the domain names
226+
return splitSanStrings
227+
.Where(s => s.StartsWith(SanPlatformId) && s.Length > SanPlatformId.Length)
228+
.Select(s => s.Substring(SanPlatformId.Length));
195229

196-
return result;
197230
}
198231

199232
private void GetOrCreateCert2(ref X509Certificate2 cert2, X509Certificate cert)

src/Extensions/Cassandra.AppMetrics/Cassandra.AppMetrics.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
<Description>This package builds on the DataStax Enterprise C# driver and DataStax C# Driver for Apache Cassandra, adding a metrics provider implementation using App Metrics.</Description>
55
<Copyright>Copyright © by DataStax</Copyright>
66
<AssemblyVersion>3.99.0.0</AssemblyVersion>
7-
<FileVersion>3.19.4.0</FileVersion>
8-
<VersionPrefix>3.19.4</VersionPrefix>
7+
<FileVersion>3.19.5.0</FileVersion>
8+
<VersionPrefix>3.19.5</VersionPrefix>
99
<Authors>DataStax</Authors>
1010
<TargetFrameworks Condition="'$(BuildCoreOnly)' != 'True'">netstandard2.0;net461</TargetFrameworks>
1111
<TargetFrameworks Condition="'$(BuildCoreOnly)' == 'True'">netstandard2.0</TargetFrameworks>

0 commit comments

Comments
 (0)