From ff99ecc48f0ba9ea5e4dd1276d32ababef33332b Mon Sep 17 00:00:00 2001
From: Henry Borasch <Henry.Borasch@sinc.de>
Date: Tue, 7 Feb 2023 13:53:27 +0100
Subject: [PATCH] added certificates, load certificates for validation

---
 .../fitko/fitconnect/core/util/FileUtil.java  | 49 +++++++++++++
 .../validation/DefaultValidationService.java  | 72 ++++++++++---------
 ...nnect-zustelldienst-produktivumgebung.json | 15 ++++
 .../PCA-1-Verwaltung-14.pem                   | 27 +++++++
 .../PCA-1-Verwaltung-15.pem                   | 27 +++++++
 .../PCA-1-Verwaltung-17.pem                   | 37 ++++++++++
 .../PCA-1-Verwaltung-20.pem                   | 37 ++++++++++
 .../PCA-1-Verwaltung-23.pem                   | 37 ++++++++++
 .../DefaultValidationServiceTest.java         | 41 ++++++++++-
 9 files changed, 306 insertions(+), 36 deletions(-)
 create mode 100644 core/src/main/java/dev/fitko/fitconnect/core/util/FileUtil.java
 create mode 100644 core/src/main/resources/certificates/cert-grp-fit-connect-zustelldienst-produktivumgebung.json
 create mode 100644 core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-14.pem
 create mode 100644 core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-15.pem
 create mode 100644 core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-17.pem
 create mode 100644 core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-20.pem
 create mode 100644 core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-23.pem

diff --git a/core/src/main/java/dev/fitko/fitconnect/core/util/FileUtil.java b/core/src/main/java/dev/fitko/fitconnect/core/util/FileUtil.java
new file mode 100644
index 000000000..bea28d98f
--- /dev/null
+++ b/core/src/main/java/dev/fitko/fitconnect/core/util/FileUtil.java
@@ -0,0 +1,49 @@
+package dev.fitko.fitconnect.core.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class FileUtil {
+
+    public static List<String> loadContentOfFilesInDirectory(String directoryPath) {
+
+        File folder = new File(Objects.requireNonNull(FileUtil.class.getClassLoader().getResource(directoryPath)).getFile());
+
+        return Arrays.stream(Objects.requireNonNull(folder.listFiles())).map(file -> {
+            try {
+                return Files.readString(file.toPath());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }).collect(Collectors.toList());
+    }
+
+    public static String loadContentOfFile(String filePath) {
+
+        try {
+            return Files.readString(new File(Objects.requireNonNull(FileUtil.class.getClassLoader().getResource(filePath)).getFile()).toPath());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static X509Certificate convertToX509Certificate(String certificateString) {
+
+        InputStream certificateInputStream = new ByteArrayInputStream(certificateString.getBytes());
+        try {
+            return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certificateInputStream);
+        } catch (CertificateException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java b/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java
index 3beb22d5b..6459fffbe 100644
--- a/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java
+++ b/core/src/main/java/dev/fitko/fitconnect/core/validation/DefaultValidationService.java
@@ -20,6 +20,7 @@ import dev.fitko.fitconnect.api.exceptions.ValidationException;
 import dev.fitko.fitconnect.api.services.crypto.MessageDigestService;
 import dev.fitko.fitconnect.api.services.schema.SchemaProvider;
 import dev.fitko.fitconnect.api.services.validation.ValidationService;
+import dev.fitko.fitconnect.core.util.FileUtil;
 import dev.fitko.fitconnect.core.util.Strings;
 import dev.fitko.fitconnect.jwkvalidator.JWKValidator;
 import dev.fitko.fitconnect.jwkvalidator.JWKValidatorBuilder;
@@ -45,7 +46,6 @@ import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -58,7 +58,8 @@ public class DefaultValidationService implements ValidationService {
     private static final Logger LOGGER = LoggerFactory.getLogger(DefaultValidationService.class);
     private static final ObjectMapper MAPPER = new ObjectMapper().setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
     private static final JsonSchemaFactory SCHEMA_FACTORY = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
-    public static final String VALID_SCHEMA_URL_EXPRESSION = "https://schema\\.fitko\\.de/fit-connect/metadata/1\\.\\d+\\.\\d+/metadata.schema.json";
+    private static final String VALID_SCHEMA_URL_EXPRESSION = "https://schema\\.fitko\\.de/fit-connect/metadata/1\\.\\d+\\.\\d+/metadata.schema.json";
+    private static final String TRUSTED_ROOT_CERTIFICATE_FOLDER = "trusted-root-certificates";
 
     private final MessageDigestService messageDigestService;
     private final SchemaProvider schemaProvider;
@@ -170,7 +171,7 @@ public class DefaultValidationService implements ValidationService {
 
         String expectedHmac = this.messageDigestService.calculateHMAC(timestamp + "." + httpBody, callbackSecret);
         if (!hmac.equals(expectedHmac)) {
-            return  ValidationResult.error(new ValidationException("HMAC provided by callback does not match the expected result."));
+            return ValidationResult.error(new ValidationException("HMAC provided by callback does not match the expected result."));
         }
 
         return ValidationResult.ok();
@@ -195,24 +196,6 @@ public class DefaultValidationService implements ValidationService {
         return ValidationResult.error(new ValidationException(errorsToSingleString(errors)));
     }
 
-    private void validateWithX509AndProxy(final List<String> pemCerts, final RSAKey publicKey, final KeyOperation purpose) throws JWKValidationException {
-        final var proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(config.getHttpProxyHost(), config.getHttpProxyPort()));
-        LOGGER.info("Using proxy {} for key validation", proxy);
-        addLogLevel(withX5CValidation()
-                .withProxy(proxy)
-                .withRootCertificatesAsPEM(pemCerts))
-                .validate(publicKey, purpose);
-    }
-
-
-    private void validateWithX509AndWithoutProxy(final List<String> pemCerts, final RSAKey publicKey, final KeyOperation purpose) throws JWKValidationException {
-        LOGGER.info("No proxy set for validation");
-        addLogLevel(withX5CValidation()
-                .withoutProxy()
-                .withRootCertificatesAsPEM(pemCerts))
-                .validate(publicKey, purpose);
-    }
-
     private JWKValidator addLogLevel(final JWKValidatorBuilder.JWKValidatorX5CErrorHandling validator) {
         if (validateSilent()) {
             return validator.withoutThrowingExceptions().withErrorLogLevel(LogLevel.WARN).build();
@@ -226,32 +209,53 @@ public class DefaultValidationService implements ValidationService {
         withoutX5CValidation().withErrorLogLevel(validateSilent() ? LogLevel.WARN : LogLevel.ERROR).build().validate(publicKey, purpose);
     }
 
-    private void validateCertChain(final RSAKey publicKey, final KeyOperation purpose) throws JWKValidationException, CertificateEncodingException {
-        final List<String> pemCerts = getPemCerts(publicKey.getParsedX509CertChain());
+    void validateCertChain(final RSAKey publicKey, final KeyOperation purpose) throws JWKValidationException {
+
+        final List<String> trustedRootCertificates = this.loadTrustedRootCertificates();
         LOGGER.info("Validation public key with XC5 certificate chain checks");
         if (isProxySet()) {
-            validateWithX509AndProxy(pemCerts, publicKey, purpose);
+            validateWithX509AndProxy(trustedRootCertificates, publicKey, purpose);
         } else {
-            validateWithX509AndWithoutProxy(pemCerts, publicKey, purpose);
+            validateWithX509AndWithoutProxy(trustedRootCertificates, publicKey, purpose);
         }
     }
 
-    private List<String> getPemCerts(final List<X509Certificate> certChain) throws CertificateEncodingException {
-        final List<String> pemCerts = new ArrayList<>();
-        for (final X509Certificate cert : certChain) {
-            pemCerts.add(getEncodedString(cert));
-        }
-        return pemCerts;
-    }
+    private List<String> loadTrustedRootCertificates() {
+
+        List<X509Certificate> trustedRootCertificates = FileUtil.loadContentOfFilesInDirectory(TRUSTED_ROOT_CERTIFICATE_FOLDER)
+                .stream().map(FileUtil::convertToX509Certificate).collect(Collectors.toList());
+        List<String> encodedCertificates = trustedRootCertificates.stream().map(cert -> {
+            try {
+                return Base64.encode(cert.getEncoded()).toString();
+            } catch (CertificateEncodingException e) {
+                throw new RuntimeException(e);
+            }
+        }).collect(Collectors.toList());
 
-    private String getEncodedString(final X509Certificate x509Certificate) throws CertificateEncodingException {
-        return Base64.encode(x509Certificate.getEncoded()).toString();
+        return encodedCertificates;
     }
 
     private boolean isProxySet() {
         return config.getHttpProxyPort() != null && Strings.isNotNullOrEmpty(config.getHttpProxyHost());
     }
 
+    private void validateWithX509AndProxy(final List<String> trustedRootCertificates, final RSAKey publicKey, final KeyOperation purpose) throws JWKValidationException {
+        final var proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(config.getHttpProxyHost(), config.getHttpProxyPort()));
+        LOGGER.info("Using proxy {} for key validation", proxy);
+        addLogLevel(withX5CValidation()
+                .withProxy(proxy)
+                .withRootCertificatesAsPEM(trustedRootCertificates))
+                .validate(publicKey);
+    }
+
+    private void validateWithX509AndWithoutProxy(final List<String> trustedRootCertificates, final RSAKey publicKey, final KeyOperation purpose) throws JWKValidationException {
+        LOGGER.info("No proxy set for validation");
+        addLogLevel(withX5CValidation()
+                .withoutProxy()
+                .withRootCertificatesAsPEM(trustedRootCertificates))
+                .validate(publicKey);
+    }
+
     private boolean validateSilent() {
         return config.getCurrentEnvironment().isAllowInsecurePublicKey();
     }
diff --git a/core/src/main/resources/certificates/cert-grp-fit-connect-zustelldienst-produktivumgebung.json b/core/src/main/resources/certificates/cert-grp-fit-connect-zustelldienst-produktivumgebung.json
new file mode 100644
index 000000000..7fc4f9f25
--- /dev/null
+++ b/core/src/main/resources/certificates/cert-grp-fit-connect-zustelldienst-produktivumgebung.json
@@ -0,0 +1,15 @@
+{
+  "alg": "PS512",
+  "e": "AQAB",
+  "key_ops": [
+    "verify"
+  ],
+  "kid": "u1ZTGUSSqcNoqGfAhN2lV1viizqNs3pbKloXzbrXlHg-verify",
+  "kty": "RSA",
+  "n": "stC7Pvf_zSLUaC134eYuNVylUf7DHwDCaB4Av4j1If5phSRu0uaIZdLIxF6yvfaPQybza4U3Eh1NSl9Ur5ymF0oL7rzxzDIByCneo3yEz4Z0r5hBVYkzz3YSqqT8fXeWJ7E9WbPVqm0QBXzR4coAncGTfDJb17ALYMNhUKGPYKdfFqY7KDYxvJkXrH2CxW_PQGIbonic3SB22JRgqfGzyWkVWaQHyOac9mewU1JPnExwtkZEZ6Z2g9LnBCooV9jprD3AdQ9ZyfsFannYSM4Ai6uW6qMdru5fQx5QebTy2uDkdb7M77rxgl80nvYLgEuL0TckMlKceSb3bja3gWkQlWSWfjBXHhbSUQ2VvxugyLLB7JLVmLiLvKTc3jStvzWHQEjjkg8iGw1uyJYblYXdZkO55iQE7c4sBoGBqI3bGNm0qe1RTzXaNH9y0hzr5IGjAWSksqQ7GwC6SiK3h4HbiIWkXKwST6Jl9R4px8QVF_POzxlLGCLLKVyM02imuzVpDRHpxWYTRSH7Xw72NlsNqOHJKjJnckJIwEI2vHHv7vZaqioU7EHdIpj9x00wPHqJ-x3yGI_1uFzXQb-B9Y1rgrX8xSkYunU5AN2EfREH5WE9bk80sCjGCMs7vefyfZjQymJw7yG9QLAt_o7Fuv8x0pxprNMT5RqDXmwPQQpQJ-8",
+  "x5c": [
+    "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"
+  ]
+}
\ No newline at end of file
diff --git a/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-14.pem b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-14.pem
new file mode 100644
index 000000000..f4182592f
--- /dev/null
+++ b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-14.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEhjCCA26gAwIBAgIFAMZqKTUwDQYJKoZIhvcNAQELBQAwRjELMAkGA1UEBhMC
+REUxGTAXBgNVBAoTEFBLSS0xLVZlcndhbHR1bmcxHDAaBgNVBAMTE1BDQS0xLVZl
+cndhbHR1bmctMTQwHhcNMTMxMjAxMDAwMDAwWhcNMjMxMjMxMjM1OTU5WjBGMQsw
+CQYDVQQGEwJERTEZMBcGA1UEChMQUEtJLTEtVmVyd2FsdHVuZzEcMBoGA1UEAxMT
+UENBLTEtVmVyd2FsdHVuZy0xNDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC
+ggEBAIJoqiA4T2iN/qq+0g/xdJ1rpsB/yozONjC0mmlSeBoBKtArrxg51GYFl/Ep
+WzEF3QffcE5jg4xEgcNk8CXJDKPKHAldLsYEohx5So8EJsuGRLrjkt6SC5Kf1+aM
+Vq7mt9qUPIuvloaQWiVkNvDFNSeam+K0I/zjK++0xHuQRACIaUbtmShuahKHlJR3
+DUM6CT9uWQB6FWv+qRAo6xsmHP/bYSMAv5/Z0bOnLZ6cruZ+QPGPksP0VX9M2pXY
+cecYAlbYzuNYWAUhmx1P/ZhbBa0SKhDTO+JpHeCnKRiLt7MKPnUPyAtib7600CsI
+TvFAjem9JanXKV0wK4sIsAMvg00CARGjggF7MIIBdzAPBgNVHRMBAf8EBTADAQH/
+MD8GA1UdIAQ4MDYwNAYLKwYBBAG9dAECAQMwJTAjBggrBgEFBQcCARYXaHR0cHM6
+Ly93d3cuYnNpLmJ1bmQuZGUwgbwGA1UdHwSBtDCBsTBioGCgXoZcbGRhcDovL3g1
+MDAuYnVuZC5kZS9DTj1QQ0EtMS1WZXJ3YWx0dW5nLTE0LE89UEtJLTEtVmVyd2Fs
+dHVuZyxDPURFP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3QwS6BJoEeGRWh0dHA6
+Ly94NTAwLmJ1bmQuZGUvY2dpLWJpbi9zaG93X2F0dHI/Y249UENBLTEtVmVyd2Fs
+dHVuZy0xNCZhdHRyPWNybDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBPzjBBU
+Oufi9p0vosZp9r10O+QYMDUGA1UdEQQuMCyBEVYtUEtJQGJzaS5idW5kLmRlhhdo
+dHRwczovL3d3dy5ic2kuYnVuZC5kZTANBgkqhkiG9w0BAQsFAAOCAQEAFAHRjPm6
+D4Om2S5P1Gcya4W+AUr5bbMFxTvi+Jl1odoIDtBkKkYQ0rv6HOx8kzBaOzwM7InU
+8/Cp3P4yHpPL6dSBgtopqkZ5xDCRoeLIzRtwKzctev2sQi9UgXu8HOW4N8A+abNB
+dEj5ehviHztZXlHuhfXAEQA6Q/Gc0XR5CWd5yQkirWFFaIhtINHs3UckH8dsC+Se
+5AVpq7mG+DtOMtaMQRTg3ElBBdNivQ0jRz4hIur1B4TrhNNZZxUhkzTjAZ7EoA6w
+2nZwPs29xgPt39Qf+3s/EfdoWzrTflrJ8tlBBueJTkI+PXIufURzDC40ciFm8g2Q
+XJpE4ye1vXCZgg==
+-----END CERTIFICATE-----
diff --git a/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-15.pem b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-15.pem
new file mode 100644
index 000000000..1a2ced199
--- /dev/null
+++ b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-15.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEiDCCA3CgAwIBAgIFAKSHzIkwDQYJKoZIhvcNAQELBQAwRjELMAkGA1UEBhMC
+REUxGTAXBgNVBAoTEFBLSS0xLVZlcndhbHR1bmcxHDAaBgNVBAMTE1BDQS0xLVZl
+cndhbHR1bmctMTUwHhcNMTUwODE4MDkwMTI4WhcNMjUwODE4MjM1OTU5WjBGMQsw
+CQYDVQQGEwJERTEZMBcGA1UEChMQUEtJLTEtVmVyd2FsdHVuZzEcMBoGA1UEAxMT
+UENBLTEtVmVyd2FsdHVuZy0xNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAJ7vMHkXf9JYOROTvOez3qM8c47Lv/wqIkauT0+m9IuPG/DSnzv8cTNqaOwH
+Zt3ga9dwiL5GMbfIDfyx49j56HBPQafS8E8N6v5XOHYemzrmTeD6e09tVsugoaEt
+pSN1VPNF3JKQM7vyl2IxWakSVgBtWffNrV1/X4199jDXrInsyNxMiyG20RLMEY3D
+BwUVyiK/yJPoWob3vIF4gSxode/i1h6IvsS//sJYll85BGPivNtRQA20JkcRZc/l
+wh+B+6WFIhEmNpoR5qN8nPVuWw7u2PEl9aptJgIUivSGuVueu9aikfQRiBZ0AqwI
+OGg7PrLG3rg8OOrqzr4z38YxL28CAwEAAaOCAXswggF3MA8GA1UdEwEB/wQFMAMB
+Af8wPwYDVR0gBDgwNjA0BgsrBgEEAb10AQIBAzAlMCMGCCsGAQUFBwIBFhdodHRw
+czovL3d3dy5ic2kuYnVuZC5kZTCBvAYDVR0fBIG0MIGxMGKgYKBehlxsZGFwOi8v
+eDUwMC5idW5kLmRlL0NOPVBDQS0xLVZlcndhbHR1bmctMTUsTz1QS0ktMS1WZXJ3
+YWx0dW5nLEM9REU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDBLoEmgR4ZFaHR0
+cDovL3g1MDAuYnVuZC5kZS9jZ2ktYmluL3Nob3dfYXR0cj9jbj1QQ0EtMS1WZXJ3
+YWx0dW5nLTE1JmF0dHI9Y3JsMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU1ikn
+WlJeLd3JZ+o81or280pnKTwwNQYDVR0RBC4wLIERVi1QS0lAYnNpLmJ1bmQuZGWG
+F2h0dHBzOi8vd3d3LmJzaS5idW5kLmRlMA0GCSqGSIb3DQEBCwUAA4IBAQBdqWrx
+75QWqRUwsDyHiKQle99K7PgqnVY5YR9SOswl7MT7jzK7yGfdGK5gQzyHDpGsoPJ/
+uIR2IkMb/pFFDA5D+Csw9mComooqP0n9wQCx64B1Q7o5DBvWftf4SCElTkbzSnR0
+qKqcP6U0I3If7OvPIgCiV3fM2EqEqAsFwvMtsd5gymLloR2LzUSCTdQbgq+bleR+
+G7mzDLw2QUgeVCP58RsSYECAPnRcY1qP9r0zuw2vILQuWZrBs5SY8ml6an730wmV
+3kUftPb2r8QDq2ZCRbNTcpuV5KYnXykEiUKPtBbyLdcV/LCPLk70zpe1dzAplr3X
+GFI0v+/UY+SXm8fI
+-----END CERTIFICATE-----
diff --git a/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-17.pem b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-17.pem
new file mode 100644
index 000000000..7bf9bd30e
--- /dev/null
+++ b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-17.pem
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGiDCCBHCgAwIBAgIFAKdNgZUwDQYJKoZIhvcNAQELBQAwRjELMAkGA1UEBhMC
+REUxGTAXBgNVBAoTEFBLSS0xLVZlcndhbHR1bmcxHDAaBgNVBAMTE1BDQS0xLVZl
+cndhbHR1bmctMTcwHhcNMTYxMjAxMDAwMDAwWhcNMjYxMjMxMjM1OTU5WjBGMQsw
+CQYDVQQGEwJERTEZMBcGA1UEChMQUEtJLTEtVmVyd2FsdHVuZzEcMBoGA1UEAxMT
+UENBLTEtVmVyd2FsdHVuZy0xNzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAJYQHveQAaTZlo4uZqQB4E7NuiMFngaOwJHGL7cpAOdFYYe4pV828HWJkDVh
+zKkeZbM229Weqs8DlPTIX34Ec/XPstJY3cQX4r93WeKoA1SMt2KX0CoPOAFz5BaG
+C9KG+GSAwc052FGjxCr+Uf0NyhPHFCWoH3hN+H9rNrLV+CnKDWVQB+LjuZIiou4N
+WLG1vSOQAPTSRcsghFScecab+HvfsnWkwNGrRJd0M0QxtZ+/1MnoeH4UfIazhYpM
+gR3/+EdlLcGrzDvLaPcncXChJBL2bCDhVTsw2w1zlVQeGXZF9s2e0nXy4k4OvNmP
+QgzFDNkQ2O6qAKJoTUnPgc2PGnvD1EopUKLuRM4orFOJZurTA1rHLJhNtfsgzx3B
+/1clBBN2cSF339atYW/k4TGn9tVZi/1ecZdNjetvhlMuhq6dm7IwfpqIke0iRP6k
+A8NdUckdalHyN3fVn+YTGJG/Mdb42KHdd3GTbPR5Eq3U3uydHCYkodT13jnQfVXH
+PTFsMWzo++rz76Q0stqGpw/ZGkY4+L5uPCtShn+pOrE8bR67GhIwWsl6fVc97G30
+8Lg6q7O/6nFJMJ9bC/mwt273CoTntCFAI/FOTOCYSPdDGp2YBfEbld19u75XzY62
+w67uNSRYTbS0x1C1q7JltAZJDqAmBqC21ywUCm1rJLZDTGYhAgMBAAGjggF7MIIB
+dzAPBgNVHRMBAf8EBTADAQH/MD8GA1UdIAQ4MDYwNAYLKwYBBAG9dAECAQMwJTAj
+BggrBgEFBQcCARYXaHR0cHM6Ly93d3cuYnNpLmJ1bmQuZGUwgbwGA1UdHwSBtDCB
+sTBioGCgXoZcbGRhcDovL3g1MDAuYnVuZC5kZS9DTj1QQ0EtMS1WZXJ3YWx0dW5n
+LTE3LE89UEtJLTEtVmVyd2FsdHVuZyxDPURFP2NlcnRpZmljYXRlUmV2b2NhdGlv
+bkxpc3QwS6BJoEeGRWh0dHA6Ly94NTAwLmJ1bmQuZGUvY2dpLWJpbi9zaG93X2F0
+dHI/Y249UENBLTEtVmVyd2FsdHVuZy0xNyZhdHRyPWNybDAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFHP4cgAoNWzXx+2NtTIUPcXrSsSrMDUGA1UdEQQuMCyBEVYt
+UEtJQGJzaS5idW5kLmRlhhdodHRwczovL3d3dy5ic2kuYnVuZC5kZTANBgkqhkiG
+9w0BAQsFAAOCAgEAf+FXmZcM5ZvaUl3P8tqwKhoG01iXLVXZjzljKbzyGOy4Ut56
+BfiepIjIOUtqMmSKxXm7/dVmmjeoHRgwGV9DTO9A4x/HTNPN76f77NmJzrGliXB1
+lFWfUwou4wdJUh/phqjK6gJ2dGGP2JdxjTE7FKifb4nuWL64zsLr5lxn+nZ6mtl0
+oqgsYDHtXXqhoBZrpyi9kzYWg9c3XWZS2iO2LNJzFQf+xjrlNtbV4Nw1kTBQwzJV
+3+MWLOlV4TOSoFitY/A8ufxjUtHIuL7QvgWdIwZz5jU8W3rctDvoJmnUMPkj61As
+5OEguVSQbf/opLdLNw6xKyOxrhfi+GZhcNdqmk1AplOIhNM5wX6/LuXOOn9u3Nqx
+rxIqFk7EGapMvmtmI5vnzxWaRbVBj3gQwnB4sKtKMhm7+axebY0fRyXA3j9J17Iz
+/4qjSDU4dCk4qwOg2TlnQzq2rwZs7CGuzTwXh05ofQnNSMpEma95/J7gmZ9R8rmN
+LFUcP43QjINrX52Q9Tz3s4pvf2W041C3neusmnnaSCPlNJJIRe0qNqMHmZUKwsFM
+XSzuM6TcY33eIf/aqfum5voXUgAx+f/G51r17dtBiewkYDqi2U38plHtzjLvPUy4
+m1vxNXN7p2wLFTtYw3OTKTHw9ejjuoPBHNHoLzAgatC1WjTgbFsfR7D3wAA=
+-----END CERTIFICATE-----
diff --git a/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-20.pem b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-20.pem
new file mode 100644
index 000000000..1afb21031
--- /dev/null
+++ b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-20.pem
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGiDCCBHCgAwIBAgIFANoFi14wDQYJKoZIhvcNAQELBQAwRjELMAkGA1UEBhMC
+REUxGTAXBgNVBAoTEFBLSS0xLVZlcndhbHR1bmcxHDAaBgNVBAMTE1BDQS0xLVZl
+cndhbHR1bmctMjAwHhcNMTkxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBGMQsw
+CQYDVQQGEwJERTEZMBcGA1UEChMQUEtJLTEtVmVyd2FsdHVuZzEcMBoGA1UEAxMT
+UENBLTEtVmVyd2FsdHVuZy0yMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAIEgWIZDMqr9t0pxV6TJ/dVSxv7UQPItIL9nY2D1PExxuPR2knOGBdWCWxXX
+Zdhz3C4XsD8o9INUz3BFDYzvo48PtZitzAawNhgQ09WaBJpqbQkrGrpATAsXSREL
+dSxi1vx7yeaMLMc1zH6iwo/Xd7pcQLxiJkgN2lhw4ORoNk4HBYwGcPjz/eEctrRy
+EbN1R3WSarg6+J58AKoatNVxw+XTaLmnYthHoJHeCI67nl/Ecrs6rmTivGvVi5PV
+RAQ0fCAsR702if0SL1F+YdDd2no+HX/2Kf2HR+/zuvIpctY/iRDRth/vf1IZL8Bx
+KHg1NY7i/7wmR3JxyQHnWWL6puOofDLq8i947e4aVHHBP7o6KbOAwau72Goa6XAr
+ttzVvDkKuI1wdka+wjNOsXsFJ+D6fSYCKC6x+nX/VCtfm2A0+JeetZV3ovUz387E
+l1MGRvxlHcuFWukj/pB6t0lvbJqnkxyq0ZGVweeFHyK6/TxFW2u+2fD/wJOKH+5y
+Quo4vKJxvrIK1UeFgRP5LCro+EYCC0kWYfyw9/wMZJDA3h7GbPR4FtNWH6deXGqr
+oY+HO3PPFM9o3Jz+xMkrla3kcEeRDjVMGFnSJhr61SvTqhrqYrj9nqx3du3e/mux
++7FxF6m3sYX8ICYppeuGxO1CGMVbC1uqh1gsnVsKv9RRUEw9AgMBAAGjggF7MIIB
+dzAPBgNVHRMBAf8EBTADAQH/MD8GA1UdIAQ4MDYwNAYLKwYBBAG9dAECAQMwJTAj
+BggrBgEFBQcCARYXaHR0cHM6Ly93d3cuYnNpLmJ1bmQuZGUwgbwGA1UdHwSBtDCB
+sTBioGCgXoZcbGRhcDovL3g1MDAuYnVuZC5kZS9DTj1QQ0EtMS1WZXJ3YWx0dW5n
+LTIwLE89UEtJLTEtVmVyd2FsdHVuZyxDPURFP2NlcnRpZmljYXRlUmV2b2NhdGlv
+bkxpc3QwS6BJoEeGRWh0dHA6Ly94NTAwLmJ1bmQuZGUvY2dpLWJpbi9zaG93X2F0
+dHI/Y249UENBLTEtVmVyd2FsdHVuZy0yMCZhdHRyPWNybDAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFPOPHzb4BN01+d4qhA1jggfppHFCMDUGA1UdEQQuMCyBEVYt
+UEtJQGJzaS5idW5kLmRlhhdodHRwczovL3d3dy5ic2kuYnVuZC5kZTANBgkqhkiG
+9w0BAQsFAAOCAgEARNpaiEE3gm/gLIfLn0d8TQF8DxHmRFszIhb8NVCXJWlMJn2J
+/UW+XzARsJiB4J0X6tvJcV9AjPwmvlgqAdlo/fce3UwLLPHqrSMuF/xS0Do2CeV1
+OjgXC9OZmuJshPCthSqReAh9h5cllKMsMaS/gM0i1o5QOCpa/0bTDxlTZ0exQw+4
+I4O7gi5SABaYyWJhYzLr1EIROaGcvJk78olGQMYnX4CNq3PDXy9HZiKPh3K07V2J
+8GM36iGxF1haTnjGopmtcUQ2lP/Ng2P0qwCFZ1UFIxIOTX5//O/rRhAroFdP+NwT
+cdJ4S4xPHNffUWPFCrT8ghEj9Hgy7H/uAtgw5PpnYieevKFjRlOvd/vp9tKjvGre
+GnU7xxS3xDbuRuNinQyJWVV/29KReumysi27qTS2cJxIYk2WLvt/1eMZt52xzK32
+G5Pn8ocCK2gMFz7ldyH3jTa5BQFuzFSJ05P1tnVkUpeKlU4aSt8GtW884ifvwhkw
+OKyAFAQRXvQSFkE505Kzy/6JZcanoy7e/pRlDBtN70MfBOQl8ucVzAVs/tuuTJAg
+3cVCmHv/hlEgVRVPaUJXhtX1u+5yUWMEm2380uW9w9/PAbdtm0kfRb19p32YMkDi
+hREyKz/Kpgl5NvoU71RRVqISeJhqJ/k2qYfyYRkPRzUiP9qzyyFS7WE8sXs=
+-----END CERTIFICATE-----
diff --git a/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-23.pem b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-23.pem
new file mode 100644
index 000000000..c4ff11151
--- /dev/null
+++ b/core/src/main/resources/trusted-root-certificates/PCA-1-Verwaltung-23.pem
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGiDCCBHCgAwIBAgIFAKXvkjAwDQYJKoZIhvcNAQELBQAwRjELMAkGA1UEBhMC
+REUxGTAXBgNVBAoTEFBLSS0xLVZlcndhbHR1bmcxHDAaBgNVBAMTE1BDQS0xLVZl
+cndhbHR1bmctMjMwHhcNMjIxMjAxMDAwMDAwWhcNMzIxMjMxMjM1OTU5WjBGMQsw
+CQYDVQQGEwJERTEZMBcGA1UEChMQUEtJLTEtVmVyd2FsdHVuZzEcMBoGA1UEAxMT
+UENBLTEtVmVyd2FsdHVuZy0yMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAMXZeBfphlB9m/8J8wVxSjEtOqfdftHEiQeITx31Md9by7+ppxHKzhQcDrRU
+3QxZnpNuoj+pIz73ZTPzBuz8PnW5BMnzPYK/0+TJiWDiUmWQ4NxwgHxV+S1KLX6S
+gkwr3L6C3VuC54rVnGeDTV6RyVzzQBpaGv1H7E2HRJh7MP3adV+Wk9DyvR4m6AE7
+6R8rI8qCv99pso2y5mAR0ulfA9zyNKxBooYSefGxQgNn+Fwb+41TBMv3iDEro7x5
+3tGHsOC/8F+xOxBe093/P2GHtEdGdAKeo6hhEq8encG0+uHIj4SljiTzKZw7PYcK
+LLZvvUyCytSuFA5Z4nRXLO2hsdqaJfT1+qecs1uJjYx0ZlzVGEsIWOpKtbB9vcvq
+IkYspykCsWcBnf1tB9F+IERw59jsGD9nZKWIgHRgI5fqHzaf0A+LwbeIO4Fn1keY
+wmYF8bNFtMCWW51ukrTQjoOc7EaE9S460E7pdmCG4NGau/bN8iQQf/cDBuRvlEpG
+aN7NeaEXWFbOBHyJKWqpquJBABFVZFaaQpBxWlnnV+o1EZ5IZPtefHFSGMxycJRb
+m6pVfGmuEo+z7xYClLH1gMDHiIDKy+RbLNMyVWUh5viu28EU29CXA7Nx6LmfLwvl
+Gr1vyCu4UAXOTrRZwff0X19tk5TjHy/SK9jnXkKURe9WuKW1AgMBAAGjggF7MIIB
+dzAPBgNVHRMBAf8EBTADAQH/MD8GA1UdIAQ4MDYwNAYLBAB/AAcDBgEBAQQwJTAj
+BggrBgEFBQcCARYXaHR0cHM6Ly93d3cuYnNpLmJ1bmQuZGUwgbwGA1UdHwSBtDCB
+sTBioGCgXoZcbGRhcDovL3g1MDAuYnVuZC5kZS9DTj1QQ0EtMS1WZXJ3YWx0dW5n
+LTIzLE89UEtJLTEtVmVyd2FsdHVuZyxDPURFP2NlcnRpZmljYXRlUmV2b2NhdGlv
+bkxpc3QwS6BJoEeGRWh0dHA6Ly94NTAwLmJ1bmQuZGUvY2dpLWJpbi9zaG93X2F0
+dHI/Y249UENBLTEtVmVyd2FsdHVuZy0yMyZhdHRyPWNybDAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFJ2BqFcYkLlZ9LOTo6q+LLqE9BnGMDUGA1UdEQQuMCyBEVYt
+UEtJQGJzaS5idW5kLmRlhhdodHRwczovL3d3dy5ic2kuYnVuZC5kZTANBgkqhkiG
+9w0BAQsFAAOCAgEAQiNGSGjBukYu5TRDaw2J7RPcDZltf/Nz6dmwzo1gXFb7ALnd
+X+Kv9OLxqTKcpywwI017xgRjzxoLlk8PZNkxl+2fuY0vqvW/c8ys2/KjXGHTgwKm
+xwvDov8vBfQxl4fXiFPxeixZujT0YZKVJ2L+6HcqzrNVNDpgNzpeLPVZxNZc0rOz
+3jxnCGwGH0mskPAMjObn9KizDge1Zve9l10jaPyyKeZq+MDhHtbwxBEICC8yCx4W
++FcETRJpQSmfP7Yr33cbitb+IaQpUf9pPRqIRUfc8Zc/lOBv49q2N+iOrCNv5XHw
+mS5HnuQ4yvSJBNgVqU+dTHvcZZVjSXCTpdwmzlmJpEtPFtJks09Ug1TYU0gQY1JU
+KW3rfndKCcsXcYA0Frvm/EA3arwbXIQRdiz1cQchHSn+IVRiUY7H9Am7ktHhPpM9
+haNpg7rfLQJnYyKKZxEs2LI84oPqRNvHBVFMFO2rY+K9HG/HWV3SixQtLAvLQOAe
+vIXuLdCZJMG8O/3Of0xLlGC/GhCXoP0g4lr7KluUzUTZj6K1q0b8NgVUqLtNiKfY
+58BefTEwUv4kSMmyQQAH69sx2wLKVKTqkOP3c81jDhf7OQs41cMGu+HRXtgy4FEI
+F3WfIOCHR3z1jJckcZwjh4WoaOgv8sGxubwjGLi2ZelCjt9ZKql+oF5LWvY=
+-----END CERTIFICATE-----
diff --git a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java
index 77c185249..ed542d5d5 100644
--- a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java
+++ b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java
@@ -23,20 +23,26 @@ import dev.fitko.fitconnect.api.domain.validation.ValidationResult;
 import dev.fitko.fitconnect.api.exceptions.ValidationException;
 import dev.fitko.fitconnect.api.services.crypto.MessageDigestService;
 import dev.fitko.fitconnect.api.services.schema.SchemaProvider;
-import dev.fitko.fitconnect.api.services.validation.ValidationService;
 import dev.fitko.fitconnect.core.crypto.HashService;
 import dev.fitko.fitconnect.core.schema.SchemaResourceProvider;
 import dev.fitko.fitconnect.core.testutil.LogCaptor;
+import dev.fitko.fitconnect.core.util.FileUtil;
 import dev.fitko.fitconnect.jwkvalidator.exceptions.JWKValidationException;
+import dev.fitko.fitconnect.jwkvalidator.exceptions.LogLevel;
 import org.hamcrest.CoreMatchers;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 import java.net.URI;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.text.ParseException;
 import java.time.ZonedDateTime;
 import java.util.*;
+import java.util.stream.Collectors;
 
+import static dev.fitko.fitconnect.jwkvalidator.JWKValidator.withX5CValidation;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -46,7 +52,7 @@ import static org.mockito.Mockito.*;
 
 class DefaultValidationServiceTest {
 
-    private ValidationService underTest;
+    private DefaultValidationService underTest;
     private MessageDigestService hashService;
     private static final LogCaptor logs = new LogCaptor();
     private SchemaProvider schemaProvider;
@@ -424,6 +430,37 @@ class DefaultValidationServiceTest {
         assertThat(validationResult.getError().getMessage(), CoreMatchers.is("HMAC provided by callback does not match the expected result."));
     }
 
+    @Test
+    public void isTransmissionServiceCertificateIsValidAccordingToRootVpki() throws JOSEException, JWKValidationException, CertificateEncodingException, ParseException {
+
+        RSAKey rsaKey = RSAKey.parse(FileUtil.loadContentOfFile("certificates/cert-grp-fit-connect-zustelldienst-produktivumgebung.json"));
+
+        this.underTest.validateCertChain(rsaKey, KeyOperation.VERIFY);
+    }
+
+    @Test
+    public void validateWithLibrary() throws JOSEException, JWKValidationException, ParseException {
+
+        /*X509Certificate x509CertificateToCheck = FileUtil.convertToX509Certificate(
+                FileUtil.loadContentOfFile("certificates/cert-grp-fit-connect-zustelldienst-produktivumgebung.json"));*/
+        RSAKey rsaKey = RSAKey.parse(FileUtil.loadContentOfFile("certificates/cert-grp-fit-connect-zustelldienst-produktivumgebung.json"));
+
+        List<X509Certificate> trustedX509RootCertificates = FileUtil.loadContentOfFilesInDirectory("trusted-root-certificates")
+                .stream().map(FileUtil::convertToX509Certificate).collect(Collectors.toList());
+        List<String> base64EncodedCertificates = trustedX509RootCertificates.stream().map(cert -> {
+            try {
+                return Base64.encode(cert.getEncoded()).toString();
+            } catch (CertificateEncodingException e) {
+                throw new RuntimeException(e);
+            }
+        }).collect(Collectors.toList());
+
+        withX5CValidation()
+                .withoutProxy()
+                .withRootCertificatesAsPEM(base64EncodedCertificates).withoutThrowingExceptions().withErrorLogLevel(LogLevel.ERROR).build()
+                .validate(rsaKey);
+    }
+
     private String getResource(final String filename) throws IOException {
         return new String(DefaultValidationServiceTest.class.getResourceAsStream(filename).readAllBytes());
     }
-- 
GitLab