Skip to content

Commit 55dfca1

Browse files
fix: add custom server certificates
1 parent 8dfcc7d commit 55dfca1

File tree

6 files changed

+45
-47
lines changed

6 files changed

+45
-47
lines changed

examples/src/YC/Program.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ await Parser.Default.ParseArguments<CmdOptions>(args).WithParsedAsync(async cmd
1111
var saProvider = new ServiceAccountProvider(saFilePath: cmd.SaFilePath, loggerFactory: loggerFactory);
1212
await saProvider.Initialize();
1313

14-
var cert = YcCerts.GetDefaultServerCertificate();
15-
1614
var builder = new YdbConnectionStringBuilder
1715
{
1816
UseTls = true,
@@ -21,11 +19,12 @@ await Parser.Default.ParseArguments<CmdOptions>(args).WithParsedAsync(async cmd
2119
Database = cmd.Database,
2220
CredentialsProvider = saProvider,
2321
LoggerFactory = loggerFactory,
24-
CustomCertificate = cert
22+
ServerCertificates = YcCerts.GetYcServerCertificates()
2523
};
2624

2725
await using var ydbConnection = new YdbConnection(builder);
2826
await ydbConnection.OpenAsync();
2927

30-
Console.WriteLine(await new YdbCommand(ydbConnection) { CommandText = "SELECT 'Hello YDB!'u" }.ExecuteScalarAsync());
28+
Console.WriteLine(await new YdbCommand(ydbConnection) { CommandText = "SELECT 'Hello Dedicated YDB!'u" }
29+
.ExecuteScalarAsync());
3130
});

examples/src/YC/YC.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
1414
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
1515
<PackageReference Include="Ydb.Protos" Version="1.1.1" />
16+
<PackageReference Include="Ydb.Sdk.Yc.Auth" Version="0.1.0" />
1617
</ItemGroup>
1718
<ItemGroup>
1819
<ProjectReference Include="..\..\..\src\Ydb.Sdk\src\Ydb.Sdk.csproj" />
19-
<ProjectReference Include="..\..\..\..\ydb-dotnet-yc\src\Ydb.Sdk.Yc.Auth\src\Ydb.Sdk.Yc.Auth.csproj" />
2020
</ItemGroup>
2121
</Project>

src/Ydb.Sdk/src/Ado/YdbConnectionStringBuilder.cs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -137,22 +137,11 @@ public string? RootCertificate
137137

138138
private string? _rootCertificate;
139139

140-
public ILoggerFactory? LoggerFactory { get; set; }
140+
public ILoggerFactory? LoggerFactory { get; init; }
141141

142-
public ICredentialsProvider? CredentialsProvider { get; set; }
142+
public ICredentialsProvider? CredentialsProvider { get; init; }
143143

144-
public X509Certificate? CustomCertificate
145-
{
146-
get => _customCertificate;
147-
set
148-
{
149-
RootCertificate = null;
150-
151-
_customCertificate = value;
152-
}
153-
}
154-
155-
private X509Certificate? _customCertificate;
144+
public X509Certificate2Collection? ServerCertificates { get; init; }
156145

157146
private void SaveValue(string propertyName, object? value)
158147
{
@@ -196,14 +185,14 @@ internal Task<Driver> BuildDriver()
196185
{
197186
var credentialsProvider = CredentialsProvider ??
198187
(User != null ? new StaticCredentialsProvider(User, Password) : null);
199-
var cert = CustomCertificate ??
200-
(RootCertificate != null ? X509Certificate.CreateFromCertFile(RootCertificate) : null);
188+
var cert = RootCertificate != null ? X509Certificate.CreateFromCertFile(RootCertificate) : null;
201189

202190
return Driver.CreateInitialized(new DriverConfig(
203191
endpoint: Endpoint,
204192
database: Database,
205193
credentials: credentialsProvider,
206-
customServerCertificate: cert
194+
customServerCertificate: cert,
195+
customServerCertificates: ServerCertificates
207196
), LoggerFactory);
208197
}
209198

src/Ydb.Sdk/src/DriverConfig.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,31 @@ public class DriverConfig
88
public string Endpoint { get; }
99
public string Database { get; }
1010
public ICredentialsProvider Credentials { get; }
11-
public X509Certificate? CustomServerCertificate { get; }
12-
11+
12+
internal X509Certificate2Collection CustomServerCertificates { get; } = new();
1313
internal TimeSpan EndpointDiscoveryInterval = TimeSpan.FromMinutes(1);
1414
internal TimeSpan EndpointDiscoveryTimeout = TimeSpan.FromSeconds(10);
1515

1616
public DriverConfig(
1717
string endpoint,
1818
string database,
1919
ICredentialsProvider? credentials = null,
20-
X509Certificate? customServerCertificate = null)
20+
X509Certificate? customServerCertificate = null,
21+
X509Certificate2Collection? customServerCertificates = null)
2122
{
2223
Endpoint = FormatEndpoint(endpoint);
2324
Database = database;
2425
Credentials = credentials ?? new AnonymousProvider();
25-
CustomServerCertificate = customServerCertificate;
26+
27+
if (customServerCertificate != null)
28+
{
29+
CustomServerCertificates.Add(new X509Certificate2(customServerCertificate));
30+
}
31+
32+
if (customServerCertificates != null)
33+
{
34+
CustomServerCertificates.AddRange(customServerCertificates);
35+
}
2636
}
2737

2838
private static string FormatEndpoint(string endpoint)

src/Ydb.Sdk/src/Pool/ChannelPool.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Grpc.Core;
66
using Grpc.Net.Client;
77
using Microsoft.Extensions.Logging;
8-
using Org.BouncyCastle.Security;
98

109
namespace Ydb.Sdk.Pool;
1110

@@ -79,14 +78,14 @@ public interface IChannelFactory<out T> where T : ChannelBase, IDisposable
7978
internal class GrpcChannelFactory : IChannelFactory<GrpcChannel>
8079
{
8180
private readonly ILoggerFactory _loggerFactory;
82-
private readonly X509Certificate? _x509Certificate;
8381
private readonly ILogger<GrpcChannelFactory> _logger;
82+
private readonly X509Certificate2Collection _x509Certificate2Collection;
8483

8584
internal GrpcChannelFactory(ILoggerFactory loggerFactory, DriverConfig config)
8685
{
8786
_loggerFactory = loggerFactory;
88-
_x509Certificate = config.CustomServerCertificate;
8987
_logger = loggerFactory.CreateLogger<GrpcChannelFactory>();
88+
_x509Certificate2Collection = config.CustomServerCertificates;
9089
}
9190

9291
public GrpcChannel CreateChannel(string endpoint)
@@ -98,47 +97,48 @@ public GrpcChannel CreateChannel(string endpoint)
9897
LoggerFactory = _loggerFactory
9998
};
10099

101-
if (_x509Certificate == null)
100+
var httpHandler = new SocketsHttpHandler();
101+
102+
// https://github.com/grpc/grpc-dotnet/issues/2312#issuecomment-1790661801
103+
httpHandler.Properties["__GrpcLoadBalancingDisabled"] = true;
104+
105+
channelOptions.HttpHandler = httpHandler;
106+
channelOptions.DisposeHttpClient = true;
107+
108+
if (_x509Certificate2Collection.Count == 0)
102109
{
103110
return GrpcChannel.ForAddress(endpoint, channelOptions);
104111
}
105112

106-
var httpHandler = new SocketsHttpHandler();
107-
108-
var customCertificate = DotNetUtilities.FromX509Certificate(_x509Certificate);
109-
110-
httpHandler.SslOptions.RemoteCertificateValidationCallback =
111-
(_, certificate, _, sslPolicyErrors) =>
113+
httpHandler.SslOptions.RemoteCertificateValidationCallback +=
114+
(_, certificate, chain, sslPolicyErrors) =>
112115
{
113116
if (sslPolicyErrors == SslPolicyErrors.None)
114117
{
115118
return true;
116119
}
117120

118-
if (certificate is null)
121+
if (certificate is null || chain is null)
119122
{
120123
return false;
121124
}
122125

123126
try
124127
{
125-
var cert = DotNetUtilities.FromX509Certificate(certificate);
126-
cert.Verify(customCertificate.GetPublicKey());
128+
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
129+
chain.ChainPolicy.ExtraStore.AddRange(_x509Certificate2Collection);
130+
131+
return chain.Build(new X509Certificate2(certificate)) && chain.ChainElements.Any(chainElement =>
132+
_x509Certificate2Collection.Any(trustedCert =>
133+
chainElement.Certificate.Thumbprint == trustedCert.Thumbprint));
127134
}
128135
catch (Exception e)
129136
{
130137
_logger.LogError(e, "Failed to verify remote certificate!");
131138

132139
return false;
133140
}
134-
135-
return true;
136141
};
137-
// https://github.com/grpc/grpc-dotnet/issues/2312#issuecomment-1790661801
138-
httpHandler.Properties["__GrpcLoadBalancingDisabled"] = true;
139-
140-
channelOptions.HttpHandler = httpHandler;
141-
channelOptions.DisposeHttpClient = true;
142142

143143
return GrpcChannel.ForAddress(endpoint, channelOptions);
144144
}

src/Ydb.Sdk/src/Transport/AuthGrpcChannelDriver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ ILoggerFactory loggerFactory
1717
new DriverConfig(
1818
endpoint: driverConfig.Endpoint,
1919
database: driverConfig.Database,
20-
customServerCertificate: driverConfig.CustomServerCertificate
20+
customServerCertificates: driverConfig.CustomServerCertificates
2121
), loggerFactory, loggerFactory.CreateLogger<AuthGrpcChannelDriver>())
2222
{
2323
_channel = grpcChannelFactory.CreateChannel(Config.Endpoint);

0 commit comments

Comments
 (0)