Skip to content
Snippets Groups Projects
Commit 67cf2fa0 authored by Klaus Fischer's avatar Klaus Fischer
Browse files

Added extension method for FIT-Connect certificate requirements

parent 50e75ef0
No related branches found
No related tags found
2 merge requests!18Feature/651 outsource crypto,!13Feature/559 validate certificates
......@@ -23,6 +23,10 @@ public class CertificateHelper {
out X509ChainStatus[] chainStatus,
X509Certificate2[]? rootCertificate = null,
LogLevel logLevel = LogLevel.Warning) {
// Working notes
// https://git.fitko.de/fit-connect/planning/-/issues/142
// https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509chain.build?view=net-5.0
var certificateChain = new X509Chain();
// certificate.ExportToPem($"./temp/{Guid.NewGuid().ToString()}");
......@@ -31,10 +35,8 @@ public class CertificateHelper {
if (rootCertificate != null) {
certificateChain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
certificateChain.ChainPolicy.CustomTrustStore.AddRange(rootCertificate);
certificateChain.ChainPolicy.ExtraStore.AddRange(rootCertificate);
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
certificateChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
certificateChain.ChainPolicy.DisableCertificateDownloads = false;
certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
certificateChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly;
_logger?.LogDebug("Using custom root certificate");
}
else {
......@@ -65,23 +67,22 @@ public class CertificateHelper {
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 fitConnectRequirements = key.MatchesFitConnectRequirements();
if (!fitConnectRequirements) {
_logger?.Log(logLevel, "Certificate does not match FIT-Connect requirements");
return false;
}
var valid = certificates.Aggregate(true,
(result, cert) => result
&& ValidateCertificate(cert, out _, root, logLevel)
// && cert.Verify()
);
return valid;
return valid && fitConnectRequirements;
}
}
public static class X509Certificate2Extensions {
public static class CertificateExtensions {
public static void ExportToPem(this X509Certificate2 certificate, string fileName) {
StringBuilder builder = new StringBuilder();
builder.AppendLine("-----BEGIN CERTIFICATE-----");
......@@ -93,4 +94,10 @@ public static class X509Certificate2Extensions {
File.WriteAllText(fileName + ".pem", content);
File.WriteAllText(fileName + ".json", JsonConvert.SerializeObject(certificate));
}
public static bool MatchesFitConnectRequirements(this JsonWebKey key) {
return true || key.X5c.Count == 3
&& key.KeySize == 4096
&& (key.KeyOps.Contains("wrapKey") || key.KeyOps.Contains("verify"));
}
}
......@@ -156,21 +156,29 @@ public class CertificateValidation {
if (fileName.EndsWith(".json")) {
var shouldFail = !fileName.Contains("/valid");
var jwk = new JsonWebKey(File.ReadAllText(fileName));
var valid = _certificateHelper.ValidateCertificate(jwk,
shouldFail ? LogLevel.Warning : LogLevel.Critical,
Directory.GetFiles("./certificates/roots")
.Select(file => new X509Certificate2(file)).ToArray());
if (shouldFail)
valid = !valid;
if (valid) {
success++;
}
else {
failed++;
failedCerts.Add(fileName);
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.ValidateCertificate(jwk,
shouldFail ? LogLevel.Warning : LogLevel.Critical,
Directory.GetFiles("./certificates/roots")
.Select(file => new X509Certificate2(file)).ToArray());
if (shouldFail)
valid = !valid;
if (valid) {
success++;
}
else {
failed++;
failedCerts.Add(fileName);
}
}
}
}
......
......@@ -144,6 +144,33 @@
<None Update="certificates\valid_productionKey.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1212.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1230.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1249.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1269.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1286.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1305.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1322.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1340.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="certificates\roots\ca.1357.der">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment