using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Security; using System.Security.Cryptography.X509Certificates; using Autofac; using FitConnect; using FitConnect.Encryption; using FitConnect.Models; using FluentAssertions; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; using MockContainer; using Newtonsoft.Json; using NUnit.Framework; namespace IntegrationTests; [TestFixture] public class CertificateValidation { [SetUp] public void Setup() { var container = Container.Create(); _settings = container.Resolve<IFitConnectSettings>(); _logger = LoggerFactory.Create( builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Debug); }).CreateLogger("E2E Test"); _certificateHelper = new CertificateHelper(_logger); } private IFitConnectSettings _settings = null!; private ILogger _logger = null!; private CertificateHelper _certificateHelper = null!; [Test] [Ignore("No credentials for dev environment")] public void CheckCertificateInEnvironment_Dev() { var environment = FitConnectEnvironment.Develop; var sender = Client.GetSender(environment, _settings.SenderClientId, _settings.SenderClientSecret, _logger); var certificate = (sender as FitConnect.Sender)! .GetPublicKeyForDestinationAsync(_settings.DestinationId).Result; new CertificateHelper(_logger).ValidateCertificateJsonWebKeyAsync( JsonWebKey.Create(certificate), null, LogLevel.Trace).Wait(); } [Test] public void CheckCertificateInEnvironment_Testing() { var environment = FitConnectEnvironment.Testing; var sender = Client.GetSender(environment, _settings.SenderClientId, _settings.SenderClientSecret, _logger); var certificate = (sender as FitConnect.Sender)! .GetPublicKeyForDestinationAsync(_settings.DestinationId).Result; new CertificateHelper(_logger).ValidateCertificateJsonWebKeyAsync( JsonWebKey.Create(certificate), null, LogLevel.Trace); } [Test] [Ignore("No credentials for staging environment")] public void CheckCertificateInEnvironment_Staging() { var environment = FitConnectEnvironment.Staging; var sender = Client.GetSender(environment, _settings.SenderClientId, _settings.SenderClientSecret, _logger); Assert.Throws<AggregateException>(() => { sender.SendAsync(SubmissionBuilder.WithDestination(_settings.DestinationId) .WithServiceType("", _settings.LeikaKey) .WithJsonData(@"{""data"":""value""}") .WithAttachments(new Attachment("Test.pdf", "Simple Test PDF")) .Build()).Wait(); })!.InnerExceptions.Any(e => e.GetType() == typeof(SecurityException)).Should().BeTrue(); } [Test] [Ignore("No credentials for production environment")] public void CheckCertificateInEnvironment_Production() { var environment = FitConnectEnvironment.Production; var sender = Client.GetSender(environment, _settings.SenderClientId, _settings.SenderClientSecret, _logger); Assert.Throws<AggregateException>(() => { sender.SendAsync(SubmissionBuilder.WithDestination(_settings.DestinationId) .WithServiceType("", _settings.LeikaKey) .WithJsonData(@"{""data"":""value""}") .WithAttachments(new Attachment("Test.pdf", "Simple Test PDF")) .Build()).Wait(); })!.InnerExceptions.Any(e => e.GetType() == typeof(SecurityException)).Should().BeTrue(); } [Test] public void CheckPublicKeyEncryption() { _certificateHelper .ValidateCertificateJsonWebKeyAsync(new JsonWebKey(_settings.PublicKeyEncryption)) .Result .Should().BeFalse(); } [Test] public void CheckPublicKeySignature() { _certificateHelper .ValidateCertificateJsonWebKeyAsync( new JsonWebKey(_settings.PublicKeySignatureVerification)) .Result .Should().BeFalse(); } [Test] [Ignore("Certificate from server is invalid, x5c are mixed")] public void TestDvdvCertificate() { var destinationJson = new HttpClient() .GetStringAsync( "https://dvdv-microservice-fit-connect.governikus-asp.de/dvdv-fitconnect/v1/destinations/f05bdafc-3ee7-418f-ab30-3c9fe6e1c7d6") .Result; var destination = (dynamic)JsonConvert.DeserializeObject(destinationJson)!; var content = JsonConvert.SerializeObject(destination.publicKeys.keys[0])!; var jwk = new JsonWebKey(content); var result = _certificateHelper.ValidateCertificateJsonWebKeyAsync(jwk).Result; result.Should().BeTrue(); } [Test] [Ignore("Not implemented")] public void CheckPemFiles() { if (!Directory.Exists("./certificates") || !Directory.Exists("./certificates/roots")) { Assert.Inconclusive("No certificates found"); return; } var files = Directory.GetFiles("./certificates"); var success = 0; var failed = 0; var failedCerts = new List<string>(); foreach (var fileName in files.Where(f => !f.EndsWith("root.pem"))) { _logger.LogInformation( "\n\n-----------------------------------------\nChecking file: {FileName}", fileName); if (fileName.EndsWith(".pem")) { var certificate = X509Certificate2.CreateFromPem(File.ReadAllText(fileName)); var valid = _certificateHelper.ValidateCertificatePemAsync(certificate).Result; if (valid) { success++; } else { failed++; failedCerts.Add(fileName); } } if (fileName.EndsWith(".json")) { var shouldFail = !fileName.Contains("/valid"); var keySetImport = new JsonWebKeySet(File.ReadAllText(fileName)); var keySet = keySetImport.Keys.Count != 0 ? keySetImport.Keys.ToList() : new List<JsonWebKey> { new(File.ReadAllText(fileName)) }; foreach (var jwk in keySet) { var valid = _certificateHelper.ValidateCertificateJsonWebKeyAsync(jwk, Directory.GetFiles("./certificates/roots") .Select(file => new X509Certificate2(file)).ToArray(), shouldFail ? LogLevel.Warning : LogLevel.Critical ).Result; if (shouldFail) valid = !valid; if (valid) { success++; } else { failed++; failedCerts.Add(fileName); } } } } _logger.LogWarning("Failed certificates: {Certs}", failedCerts.Aggregate("\n", (a, b) => a + "\t - " + b + "\n")); _logger.LogInformation("Success: {Success}, Failed: {Failed}", success, failed); failed.Should().Be(0); } }