From 09a369ef604dc48a7b1935a2cadc1a3624539691 Mon Sep 17 00:00:00 2001
From: Klaus Fischer <klaus.fischer@eloware.com>
Date: Wed, 8 Jun 2022 08:59:30 +0200
Subject: [PATCH] Problems with self signed certificate

---
 FitConnect/EncryptionBaseClass.cs  | 65 +++++++++++++++++-----------
 SenderTest/SenderEncryptionTest.cs | 69 ++++++++++++++++++++++--------
 2 files changed, 91 insertions(+), 43 deletions(-)

diff --git a/FitConnect/EncryptionBaseClass.cs b/FitConnect/EncryptionBaseClass.cs
index 7ecb39cd..bdcf0ff8 100644
--- a/FitConnect/EncryptionBaseClass.cs
+++ b/FitConnect/EncryptionBaseClass.cs
@@ -6,7 +6,9 @@ namespace FitConnect;
 
 public class EncryptionBaseClass {
     private readonly ILogger _logger;
-    private RSA _rsa;
+    private readonly RSA _rsa;
+    private RSA? _publicKey;
+    private RSA? _privateKey;
 
     protected EncryptionBaseClass(ILogger logger) {
         _logger = logger;
@@ -19,18 +21,41 @@ public class EncryptionBaseClass {
     /// </summary>
     /// <param name="cert"></param>
     /// <returns></returns>
-    private bool CheckCertificate(X509Certificate2 cert) => true;
+    private bool CheckCertificate(X509Certificate2 cert) =>
+        cert.HasPrivateKey; //  && cert.Verify();
+
+
+    public void ImportCertificate(X509Certificate2 cert) {
+        if (!CheckCertificate(cert)) {
+            throw new Exception("Invalid certificate");
+        }
+
+        _publicKey = cert.GetRSAPublicKey();
+
+        if (_publicKey == null)
+            throw new Exception("Invalid certificate, no public key");
+
+        _logger.LogInformation("Public key imported {}",
+            Convert.ToBase64String(_publicKey.ExportRSAPrivateKey()));
+
+
+        if (cert.HasPrivateKey) {
+            _privateKey = cert.GetRSAPrivateKey();
+            _logger.LogInformation("Certificate imported");
+        }
+    }
 
     /// <summary>
-    /// 
+    /// Import a public key from a PEM file
     /// </summary>
-    /// <param name="certPath"></param>
+    /// <param name="certificatePath"></param>
+    /// <param name="password">Password for the certificate</param>
     /// <exception cref="ArgumentException"></exception>
     /// <exception cref="Exception"></exception>
-    public void ImportCertificate(string certPath) {
-        _logger.LogInformation("Importing certificate {CertPath}", certPath);
+    public void ImportCertificate(string certificatePath, string password) {
+        _logger.LogInformation("Importing certificate {CertPath}", certificatePath);
         var cert =
-            new X509Certificate2(certPath, "", X509KeyStorageFlags.MachineKeySet);
+            new X509Certificate2(certificatePath, password, X509KeyStorageFlags.MachineKeySet);
 
         if (!CheckCertificate(cert)) {
             throw new ArgumentException("Certificate is not valid");
@@ -44,19 +69,8 @@ public class EncryptionBaseClass {
         _rsa.ImportParameters(parameters.Value);
     }
 
-    public byte[] DecryptDataAsync(byte[] data, byte[] privateKey) {
-        /*
-         *             var keyParams = new PbeParameters(
-                    PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, numberOfIterations);
-                
-                var privateKey =
-                    _rsa.ExportEncryptedPkcs8PrivateKey(Encoding.UTF8.GetBytes(password), keyParams);
-                
-                logger?.LogInformation(
-                    "Private key: {}", privateKey);
-    {
-         */
-        return _rsa.Decrypt(data, RSAEncryptionPadding.OaepSHA256);
+    public byte[] DecryptDataAsync(byte[] data) {
+        return (_privateKey ?? _rsa).Decrypt(data, RSAEncryptionPadding.OaepSHA256);
     }
 
     public byte[] ExportPublicKey() {
@@ -67,15 +81,16 @@ public class EncryptionBaseClass {
         return _rsa.ExportRSAPrivateKey();
     }
 
-    public byte[] EncryptData(byte[] data, byte[]? publicKey) {
+    public byte[] EncryptData(byte[] data) {
+        return (_publicKey ?? _rsa).Encrypt(data, RSAEncryptionPadding.OaepSHA256);
+    }
+
+    public byte[] EncryptData(byte[] data, byte[] publicKey) {
         _logger?.LogInformation(
             "Encrypting data with public key: {}",
             Convert.ToBase64String(_rsa.ExportRSAPublicKey()));
 
-        if (publicKey != null) {
-            _rsa.ImportRSAPublicKey(publicKey, out var read);
-        }
-
+        _rsa.ImportRSAPublicKey(publicKey, out var read);
         return _rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
     }
 }
diff --git a/SenderTest/SenderEncryptionTest.cs b/SenderTest/SenderEncryptionTest.cs
index 768b0f09..ac3409a4 100644
--- a/SenderTest/SenderEncryptionTest.cs
+++ b/SenderTest/SenderEncryptionTest.cs
@@ -1,19 +1,22 @@
 using System;
-using System.Buffers.Text;
 using System.IO;
 using System.Security.Cryptography;
 using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using FitConnect;
-using FluentAssertions;
 using Microsoft.Extensions.Logging;
 using NUnit.Framework;
 
 namespace SenderTest;
 
-public class SenderEncryptionTest {
-    private Sender _sender;
-    private ILogger<SenderEncryptionTest> _logger;
+public partial class SenderEncryptionTest {
+    private Sender _sender = null!;
+    private ILogger<SenderEncryptionTest> _logger = null!;
+
+    /*
+     * Encryption test must be changed for production to only allow extern signed certificates
+     * and forbid self-signed certificates.
+     */
 
     [SetUp]
     public void Setup() {
@@ -21,26 +24,21 @@ public class SenderEncryptionTest {
             .CreateLogger<SenderEncryptionTest>();
         _sender = new Sender(_logger,
             FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development));
+        var certificate = CreateSelfSignedCertificate(null);
+        // _sender.ImportCertificate(certificate);
     }
 
-    private X509Certificate2 CreateSelfSignedCertificate() {
-        var req = new CertificateRequest("cn=foobar", ECDsa.Create(), HashAlgorithmName.SHA256);
-        var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));
-
-        // Create PFX (PKCS #12) with private key
-        File.WriteAllBytes("../../../mycert.pfx", cert.Export(X509ContentType.Pfx, "P@55w0rd"));
 
-        // Create Base 64 encoded CER (public key only)
-        File.WriteAllText("../../../mycert.cer",
-            "-----BEGIN CERTIFICATE-----\r\n"
-            + Convert.ToBase64String(cert.Export(X509ContentType.Cert),
-                Base64FormattingOptions.InsertLineBreaks)
-            + "\r\n-----END CERTIFICATE-----");
+    [Test]
+    public void CryptWithOutPublicKeyImport() {
+        var cypher = _sender.EncryptData(Encoding.UTF8.GetBytes("test"));
 
-        return cert;
+        _logger.LogInformation("Cypher: {}", Convert.ToBase64String(cypher));
     }
 
+
     [Test]
+    [Ignore("Not applicable for production")]
     public void CryptWithPublicKeyImport() {
         var publicKey = Convert.FromBase64String(
             "MIIBCgKCAQEAzu/ek6A5AMuROs+12pncbYNteGkd6ReU28ZY5gCM4hNFI0h1E+0+OST+Yxw7zhvbFhZbYdVt8LmzonMAtENituLxzZj7MsWom/ZzxTdp4Cx5zlx8x6Qx/ZPoSS2T2Sf0ttymaMc6ZadpWsDhg/Mnf6beF1W/QoGH/bHBa8U4rhkUa+OKf3wyo08km8oyUJaj6kkB0VdhRp5rSyvXJtUMZ5A0LcYFygnkHTSQlQhdrAK+6nTo//mfNfPtqta2wBb9ONpVwN0V7I5PSdH2WxZMZsYFicLOGbNeF08gibmL+7TeBTssYtrNVM88cG0v+aWeBun0WVrpCntDIA9HIujWowIDAQAB");
@@ -56,3 +54,38 @@ public class SenderEncryptionTest {
         _logger.LogInformation("Private key: {}", Convert.ToBase64String(privateKey));
     }
 }
+
+#region Static helpers
+
+public partial class SenderEncryptionTest {
+    private X509Certificate2 CreateSelfSignedCertificate(string? exportPath = "../../../") {
+        var req = new CertificateRequest("cn=foobar", ECDsa.Create(), HashAlgorithmName.SHA256);
+        var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));
+
+        // Export the certificate to a PEM file, just for
+        // additional extern testing
+        if (exportPath != null) {
+            ExportCertificateToFile(exportPath, cert);
+        }
+
+        return cert;
+    }
+
+    private void ExportCertificateToFile(string exportPath, X509Certificate cert) {
+        // Create PFX (PKCS #12) with private key
+        File.WriteAllBytes($"{exportPath}/certificate.pfx",
+            cert.Export(X509ContentType.Pfx, ""));
+
+        // Create Base 64 encoded CER (public key only)
+        File.WriteAllText($"{exportPath}/certificate.cer",
+            "-----BEGIN CERTIFICATE-----\r\n"
+            + Convert.ToBase64String(cert.Export(X509ContentType.Cert, ""),
+                Base64FormattingOptions.InsertLineBreaks)
+            + "\r\n-----END CERTIFICATE-----");
+
+        _logger?.LogInformation("Exporting {}",
+            Convert.ToBase64String(cert.Export(X509ContentType.Cert, "")));
+    }
+}
+
+#endregion
-- 
GitLab