Проблема в том, что КОРНЕВОЙ ЦС, который должен проверять сертификат с сервера, не может присутствовать в корневом хранилище доверенных сертификатов системы клиента. Он должен быть загружен во время выполнения.
Окончательная реализация реализована под Linux, но она также не работает в Windows.
Это работает, только если Я добавляю корневой центр сертификации в системный центр сертификации. В остальных случаях я всегда получаю исключение.
Корневой ЦС не имеет зависимостей от другого ЦС. Это отдельный сертификат.
Я использую .net core 6.
Класс UserManagemenClient создается автоматически.
Код: Выделить всё
public partial class UserManagementClient : System.ServiceModel.ClientBase, ConsoleApp7.UserManagementService.IUserManagement
Программа вызывает следующее исключение.
Код: Выделить всё
System.AggregateException: One or more errors occurred. (Could not establish trust relationship for the SSL/TLS secure channel with authority 'gui.net:8443'.)
---> System.ServiceModel.Security.SecurityNegotiationException: Could not establish trust relationship for the SSL/TLS secure channel with authority 'gui.net:8443'.
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
at System.Net.Security.SslStream.ProcessAuthenticationWithTelemetryAsync(Boolean isAsync, Boolean isApm, CancellationToken cancellationToken)
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)
at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
--- End of inner exception stack trace ---
at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.c__DisplayClass1_0.b__0(IAsyncResult asyncResult)
Код: Выделить всё
public void Test2(string url)
{
var httpBinding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
Name = "UserManagementServiceSoapBinding"
};
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
httpBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
if (uri.ToLower().Contains("https"))
httpBinding.Security.Mode = BasicHttpSecurityMode.Transport;
var endpointAddress = new EndpointAddress(uri);
var client = new UserManagementClient(httpBinding, endpointAddress);
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.ChainTrust;
client.ClientCredentials.ServiceCertificate.Authentication.CustomCertificateValidator = new CustomRootCertificateValidator(rootCaCertPath);
try
{
var result = client.checkOTPAsync("aaa", new[]
{
"", "", ""
}).Result;
}
catch (Exception e)
{
Console.WriteLine(e);
return;
}
Console.WriteLine("Worked");
}
}
public class CustomRootCertificateValidator : X509CertificateValidator
{
private X509Certificate2 _rootCertificate;
public CustomRootCertificateValidator(string rootCertificatePath)
{
_rootCertificate = new X509Certificate2(rootCertificatePath);
}
public override void Validate(X509Certificate2 certificate)
{
if (certificate == null)
{
throw new ArgumentNullException(nameof(certificate));
}
var chain = new X509Chain();
chain.ChainPolicy.ExtraStore.Add(_rootCertificate);
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
bool isValid = chain.Build(certificate);
if (!isValid || chain.ChainElements[^1].Certificate.Thumbprint != _rootCertificate.Thumbprint)
{
throw new SecurityTokenValidationException("La validazione del certificato è fallita. Il certificato radice non è attendibile.");
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/790 ... ertificati
Мобильная версия