diff --git a/FitConnect/Encryption/CertificateHelper.cs b/FitConnect/Encryption/CertificateHelper.cs index 2076ebe0761c6303ef65b057cbc3e4cf1aa4a200..ac4d8eaed8acac27024b010376d5374065154276 100644 --- a/FitConnect/Encryption/CertificateHelper.cs +++ b/FitConnect/Encryption/CertificateHelper.cs @@ -18,39 +18,22 @@ public class CertificateHelper { X509Certificate2[]? rootCertificate = null) => ValidateCertificate(new JsonWebKey(keyJson), logLevel, rootCertificate); - internal bool ValidateCertificate(JsonWebKey key, LogLevel logLevel = LogLevel.Error, - X509Certificate2[]? root = null) { - var certificates = key.X5c.Select(s => new X509Certificate2(Convert.FromBase64String(s))) - .ToList(); - - // root ??= new X509Certificate2(Convert.FromBase64String(key.X5t)); - - _logger?.LogTrace("Found {Count} certificate(s)", certificates.Count); - - var valid = certificates.Aggregate(true, - (result, cert) => result - && ValidateCertificate(cert, out _, - root, - logLevel) - && cert.Verify() - ); - return valid; - } - internal bool ValidateCertificate(X509Certificate2 certificate, out X509ChainStatus[] chainStatus, X509Certificate2[]? rootCertificate = null, LogLevel logLevel = LogLevel.Warning) { var certificateChain = new X509Chain(); + certificate.ExportToPem($"./temp/{Guid.NewGuid().ToString()}.pem"); + _logger?.LogDebug("Issuers: {Issuer}", certificate.Issuer); if (rootCertificate != null) { certificateChain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; - // certificateChain.ChainPolicy.ExtraStore.AddRange(rootCertificate); + certificateChain.ChainPolicy.ExtraStore.AddRange(rootCertificate); certificateChain.ChainPolicy.CustomTrustStore.AddRange(rootCertificate); - certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; - certificateChain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; - certificateChain.ChainPolicy.DisableCertificateDownloads = true; + certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.Online; + certificateChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; + certificateChain.ChainPolicy.DisableCertificateDownloads = false; certificateChain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; _logger?.LogDebug("Using custom root certificate"); } @@ -73,13 +56,41 @@ public class CertificateHelper { if (!result) _logger?.Log(logLevel, "Certificate status: {ObjStatusInformation}", statusAggregation); -#if DEBUG - if (certificate.Verify() != result) { - _logger?.LogError( - "Certificate verification failed. Verify does not match internal test {Result}", - result); - } -#endif + return result; } + + internal bool ValidateCertificate(JsonWebKey key, LogLevel logLevel = LogLevel.Error, + X509Certificate2[]? root = null) { + var certificates = key.X5c.Select(s => new X509Certificate2(Convert.FromBase64String(s))) + .ToList(); + + if (certificates.Count != 3) { + _logger?.Log(logLevel, "Found {Count} certificate(s) but should be 3", + certificates.Count); + return false; + } + // root ??= new X509Certificate2(Convert.FromBase64String(key.X5t)); + + + var valid = certificates.Aggregate(true, + (result, cert) => result + && ValidateCertificate(cert, out _, root, logLevel) + // && cert.Verify() + ); + return valid; + } +} + +public static class X509Certificate2Extensions { + public static void ExportToPem(this X509Certificate2 certificate, string fileName) { + StringBuilder builder = new StringBuilder(); + builder.AppendLine("-----BEGIN CERTIFICATE-----"); + builder.AppendLine( + Convert.ToBase64String(certificate.RawData, Base64FormattingOptions.InsertLineBreaks)); + builder.AppendLine("-----END CERTIFICATE-----"); + var content = builder.ToString(); + + File.WriteAllText(fileName, content); + } } diff --git a/IntegrationTests/CertificateValidation.cs b/IntegrationTests/CertificateValidation.cs index eefce9cd01b15868741024eea33fdfa6ef5a894b..31412c81323685347f00752fcfa526a3cd3b04fe 100644 --- a/IntegrationTests/CertificateValidation.cs +++ b/IntegrationTests/CertificateValidation.cs @@ -159,9 +159,10 @@ public class CertificateValidation { var shouldFail = !fileName.Contains("/valid"); var jwk = new JsonWebKey(File.ReadAllText(fileName)); var valid = _certificateHelper.ValidateCertificate(jwk, - shouldFail ? LogLevel.Debug : LogLevel.Critical, new[] { + shouldFail ? LogLevel.Warning : LogLevel.Critical, new[] { new X509Certificate2("./certificates/root.pem"), - new X509Certificate2("./certificates/ca.30244.der") + new X509Certificate2("./certificates/ca.30244.der"), + new X509Certificate2("./certificates/ca.21636.der") }); if (shouldFail) diff --git a/IntegrationTests/IntegrationTests.csproj b/IntegrationTests/IntegrationTests.csproj index ee4d7ef4f4ce3c7b9c2e7811f1d9e0e6c5f86162..9a0e7d937266d26ce24b76647b4ed0d0ccf1ad52 100644 --- a/IntegrationTests/IntegrationTests.csproj +++ b/IntegrationTests/IntegrationTests.csproj @@ -36,9 +36,6 @@ <None Update="certificates\www-amazon-de-zertifikatskette.pem"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> - <None Update="certificates\invalidEncJwkWithLessThan3Certificates.json"> - <CopyToOutputDirectory>Always</CopyToOutputDirectory> - </None> <None Update="certificates\validEncJW_KeyUse.json"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> @@ -57,6 +54,18 @@ <None Update="certificates\ca.30244.der"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> + <None Update="certificates\ca.30244.der"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + <None Update="temp\readme.md"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + <None Update="certificates\ca.21636.der"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + <None Update="certificates\invalidEncJwkWithLessThan3Certificates.json"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> </ItemGroup> </Project> diff --git a/IntegrationTests/temp/readme.md b/IntegrationTests/temp/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391