From 5847103c5b619da2e16158432c3a1071e411d0dd Mon Sep 17 00:00:00 2001
From: Klaus Fischer <klaus.fischer@eloware.com>
Date: Tue, 6 Sep 2022 13:41:02 +0200
Subject: [PATCH] Added AuthenticationTags

---
 E2ETest/StraightForwardTest.cs                |  2 +-
 FitConnect/Encryption/FitEncryption.cs        | 26 +++++++++----------
 .../Subscriber/ISubscriberWithSubmission.cs   | 12 ++++++++-
 FitConnect/Models/Attachment.cs               |  4 ++-
 FitConnect/Models/Submission.cs               |  3 +++
 FitConnect/Services/Models/ServiceTypeDto.cs  | 11 ++++++++
 FitConnect/Services/Models/v1/Api/Metadata.cs |  2 +-
 FitConnect/Subscriber.cs                      | 21 +++++++++++----
 8 files changed, 58 insertions(+), 23 deletions(-)

diff --git a/E2ETest/StraightForwardTest.cs b/E2ETest/StraightForwardTest.cs
index 0eb0df15..19a3000b 100644
--- a/E2ETest/StraightForwardTest.cs
+++ b/E2ETest/StraightForwardTest.cs
@@ -47,7 +47,7 @@ public class StraightForwardTest : EndToEndTestBase {
         status.ForEach(
             s => Logger.LogInformation("Status {When} {Event}", s.EventTime, s.EventType));
     }
-
+    
     [Test]
     [Order(40)]
     public void RequestSubmission() {
diff --git a/FitConnect/Encryption/FitEncryption.cs b/FitConnect/Encryption/FitEncryption.cs
index 620d281a..5fdbb0a4 100644
--- a/FitConnect/Encryption/FitEncryption.cs
+++ b/FitConnect/Encryption/FitEncryption.cs
@@ -97,29 +97,27 @@ public class FitEncryption {
         _logger?.LogInformation("Generating authentication tags");
         var attachmentDictionary = new Dictionary<string, string>();
         submission.Attachments.ForEach(a =>
-            attachmentDictionary.Add(a.Id, CalculateAuthenticationHash(a.Content)));
-
+            attachmentDictionary.Add(a.Id, a.AttachmentAuthentication));
+
+        if (submission.Data != null)
+            return new {
+                authenticationTags = new {
+                    data = submission.DataAuthentication,
+                    metadata = submission.MetaAuthentication,
+                    attachments = attachmentDictionary
+                }
+            };
         return new {
             authenticationTags = new {
-                data = CalculateAuthenticationHash(submission?.Data ?? ""),
-                metadata = CalculateAuthenticationHash(submission?.Metadata?.ToString() ?? ""),
+                metadata = submission.MetaAuthentication,
                 attachments = attachmentDictionary
             }
         };
     }
 
-    private string CalculateAuthenticationHash(string data = "") {
-        return CalculateAuthenticationHash(Encoding.UTF8.GetBytes(data));
-    }
-
-    private string CalculateAuthenticationHash(byte[]? data = null) {
-        var result = MD5.Create().ComputeHash(data ?? Array.Empty<byte>());
-        return System.Convert.ToHexString(result);
-    }
-
 
     public string CreateAcceptSecurityEventToken(SubmissionForPickupDto submission,
-        dynamic payload = null) {
+        dynamic? payload = null) {
         if (submission?.Id == null || submission?.CaseId == null ||
             submission?.DestinationId == null) {
             throw new ArgumentException("SubmissionId, CaseId and DestinationId are required");
diff --git a/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs b/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs
index 6d82850a..c7cd242a 100644
--- a/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs
+++ b/FitConnect/Interfaces/Subscriber/ISubscriberWithSubmission.cs
@@ -1,9 +1,10 @@
 using FitConnect.Models;
 using FitConnect.Models.v1.Api;
+using FitConnect.Services.Models;
 
 namespace FitConnect.Interfaces.Subscriber;
 
-public interface ISubscriberWithSubmission {
+public interface ISubscriberWithSubmission : WithSubmission {
     public Submission? Submission { get; }
 
     /// <summary>
@@ -42,3 +43,12 @@ public interface ISubscriberWithSubmission {
     /// <param name="status">state the submission has to be set to</param>
     public void CompleteSubmission(FinishSubmissionStatus status);
 }
+
+public interface WithSubmission {
+    /// <summary>
+    /// Verifies the submission acceptance status
+    /// </summary>
+    /// <param name="acceptanceStatus"></param>
+    /// <returns></returns>
+    public bool VerifyStatus(AcceptanceStatus acceptanceStatus);
+}
diff --git a/FitConnect/Models/Attachment.cs b/FitConnect/Models/Attachment.cs
index 86ed85f3..5450e7f3 100644
--- a/FitConnect/Models/Attachment.cs
+++ b/FitConnect/Models/Attachment.cs
@@ -5,9 +5,10 @@ using FitConnect.Models.Api.Metadata;
 namespace FitConnect.Models;
 
 public class Attachment {
-    public Attachment(Api.Metadata.Attachment metadata, byte[] content) {
+    public Attachment(Api.Metadata.Attachment metadata, byte[] content, string attachmentAuthentication) {
         Filename = metadata.Filename;
         Content = content;
+        AttachmentAuthentication = attachmentAuthentication;
         MimeType = Path.GetExtension(metadata.Filename) switch {
             "pdf" => "application/pdf",
             "xml" => "application/xml",
@@ -43,6 +44,7 @@ public class Attachment {
     public string Id { get; } = Guid.NewGuid().ToString();
 
     public byte[]? Content { get; init; }
+    public string AttachmentAuthentication { get; }
 
     public string? Hash => CalculateHash();
 
diff --git a/FitConnect/Models/Submission.cs b/FitConnect/Models/Submission.cs
index a1d78af9..c3027214 100644
--- a/FitConnect/Models/Submission.cs
+++ b/FitConnect/Models/Submission.cs
@@ -1,3 +1,4 @@
+using System.Security.Cryptography.X509Certificates;
 using FitConnect.Services.Models;
 using FitConnect.Services.Models.v1.Submission;
 
@@ -23,6 +24,8 @@ public class Submission {
     public string? Data { get; set; }
     public string? EncryptedMetadata { get; set; }
     public string? EncryptedData { get; set; }
+    public string? MetaAuthentication => EncryptedMetadata?.Split('.').Last();
+    public string? DataAuthentication => EncryptedData?.Split('.').Last();
 
     public bool IsSubmissionReadyToAdd(out string? error) {
         var innerError = "";
diff --git a/FitConnect/Services/Models/ServiceTypeDto.cs b/FitConnect/Services/Models/ServiceTypeDto.cs
index c34a7521..4a2b55f2 100644
--- a/FitConnect/Services/Models/ServiceTypeDto.cs
+++ b/FitConnect/Services/Models/ServiceTypeDto.cs
@@ -12,3 +12,14 @@ public class ServiceTypeDto {
     [JsonProperty("identifier")]
     public string? Identifier { get; set; }
 }
+
+public class AcceptanceStatus {
+    [JsonProperty("metadata")]
+    public string Metadata { get; set; }
+
+    [JsonProperty("data")]
+    public string Data { get; set; }
+
+    [JsonProperty("attachments")]
+    public Dictionary<string, string> Attachments { get; set; }
+}
diff --git a/FitConnect/Services/Models/v1/Api/Metadata.cs b/FitConnect/Services/Models/v1/Api/Metadata.cs
index 3f851590..77fa7876 100644
--- a/FitConnect/Services/Models/v1/Api/Metadata.cs
+++ b/FitConnect/Services/Models/v1/Api/Metadata.cs
@@ -53,7 +53,7 @@ namespace FitConnect.Models.Api.Metadata
 
         [JsonProperty("replyChannel", NullValueHandling = NullValueHandling.Ignore)]
         public ReplyChannel ReplyChannel { get; set; }
-
+        
         public override string ToString() => JsonConvert.SerializeObject(this);
     }
 
diff --git a/FitConnect/Subscriber.cs b/FitConnect/Subscriber.cs
index 05819659..1635bc5b 100644
--- a/FitConnect/Subscriber.cs
+++ b/FitConnect/Subscriber.cs
@@ -8,6 +8,7 @@ using FitConnect.Encryption;
 using FitConnect.Interfaces.Subscriber;
 using FitConnect.Models;
 using FitConnect.Models.v1.Api;
+using FitConnect.Services.Models;
 using FitConnect.Services.Models.v1.Submission;
 using IdentityModel;
 using Microsoft.AspNetCore.Http;
@@ -25,9 +26,8 @@ namespace FitConnect;
 public class Subscriber : FitConnectClient,
     ISubscriber,
     ISubscriberWithSubmission {
-    
     public Submission? Submission { get; private set; }
-    
+
     public Subscriber(FitConnectEnvironment environment,
         string clientId, string clientSecret,
         string privateKeyDecryption,
@@ -95,7 +95,6 @@ public class Subscriber : FitConnectClient,
 
         submission.Metadata = JsonConvert.DeserializeObject<Metadata>(metaDataString);
 
-
         if (submission.EncryptedData != null) {
             var (dataString, _, dataHash) = Encryption.Decrypt(submission.EncryptedData);
             submission.Data = dataString;
@@ -113,7 +112,6 @@ public class Subscriber : FitConnectClient,
         return this;
     }
 
-    
 
     /// <summary>
     ///     Reading attachments for a submission.
@@ -130,7 +128,8 @@ public class Subscriber : FitConnectClient,
             var attachmentMeta =
                 Submission.Metadata.ContentStructure.Attachments.First(a => a.AttachmentId == id);
 
-            attachments.Add(new Attachment(attachmentMeta, content));
+            attachments.Add(new Attachment(attachmentMeta, content,
+                encryptedAttachment.Split('.').Last()));
         }
 
         Submission.Attachments = attachments;
@@ -154,6 +153,18 @@ public class Subscriber : FitConnectClient,
         CompleteSubmission(Submission!, status);
     }
 
+    public bool VerifyStatus(AcceptanceStatus acceptanceStatus) {
+        if (Submission == null)
+            throw new NullReferenceException("Submission is null");
+        var result = true;
+        result &= acceptanceStatus.Metadata == Submission.MetaAuthentication;
+        result &= acceptanceStatus.Data == Submission.DataAuthentication;
+        foreach (var attachment in Submission.Attachments) {
+            result &= acceptanceStatus.Attachments[attachment.Id] == attachment.AttachmentAuthentication;
+        }
+
+        return result;
+    }
 
 
     private void CompleteSubmission(Submission submission,
-- 
GitLab