From cfed04d5b4cff5782653d2482da59ce3634ad01c Mon Sep 17 00:00:00 2001 From: Felix Dittrich Date: Mon, 7 Feb 2022 16:14:17 +0100 Subject: [PATCH 1/4] Add support for multiple TrustAnchors --- .../connector/DgcGatewayConnectorUtils.java | 10 +++---- .../DgcGatewayDownloadConnectorBuilder.java | 27 ++++++++++++++----- .../DownloadConnectorBuilderTest.java | 3 ++- .../connector/DownloadConnectorUtilsTest.java | 8 ++++-- ...edSignedCertificateMessageBuilderTest.java | 1 + .../SignedCertificateMessageParserTest.java | 14 +++++----- 6 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/main/java/eu/europa/ec/dgc/gateway/connector/DgcGatewayConnectorUtils.java b/src/main/java/eu/europa/ec/dgc/gateway/connector/DgcGatewayConnectorUtils.java index ec90ef5..8ee993f 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/connector/DgcGatewayConnectorUtils.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/connector/DgcGatewayConnectorUtils.java @@ -73,7 +73,7 @@ class DgcGatewayConnectorUtils { private final KeyStore trustAnchorKeyStore; @Setter - private X509CertificateHolder trustAnchor; + private List trustAnchors; @PostConstruct @@ -87,7 +87,7 @@ void init() throws KeyStoreException, CertificateEncodingException, IOException log.error("Could not find TrustAnchor Certificate in Keystore"); throw new KeyStoreException("Could not find TrustAnchor Certificate in Keystore"); } - trustAnchor = certificateUtils.convertCertificate(trustAnchorCert); + trustAnchors = Collections.singletonList(certificateUtils.convertCertificate(trustAnchorCert)); } public boolean trustListItemSignedByCa(TrustListItemDto certificate, X509CertificateHolder ca) { @@ -142,7 +142,7 @@ public boolean trustListItemSignedByCa(TrustListItemDto certificate, Map trustListItemSignedByCa(certificate, ca)); } - boolean checkTrustAnchorSignature(TrustListItemDto trustListItem, X509CertificateHolder trustAnchor) { + boolean checkTrustAnchorSignature(TrustListItemDto trustListItem, List trustAnchors) { SignedCertificateMessageParser parser = new SignedCertificateMessageParser( trustListItem.getSignature(), trustListItem.getRawData()); @@ -155,7 +155,7 @@ boolean checkTrustAnchorSignature(TrustListItemDto trustListItem, X509Certificat return false; } - return parser.getSigningCertificate().equals(trustAnchor); + return trustAnchors.stream().anyMatch(trustAnchor -> parser.getSigningCertificate().equals(trustAnchor)); } X509CertificateHolder getCertificateFromTrustListItem(TrustListItemDto trustListItem) { @@ -187,7 +187,7 @@ public List fetchCertificatesAndVerifyByTrustAnchor(Certi return downloadedCertificates.getBody().stream() .filter(this::checkThumbprintIntegrity) - .filter(c -> this.checkTrustAnchorSignature(c, trustAnchor)) + .filter(c -> this.checkTrustAnchorSignature(c, trustAnchors)) .map(this::getCertificateFromTrustListItem) .filter(Objects::nonNull) .collect(Collectors.toList()); diff --git a/src/main/java/eu/europa/ec/dgc/gateway/connector/DgcGatewayDownloadConnectorBuilder.java b/src/main/java/eu/europa/ec/dgc/gateway/connector/DgcGatewayDownloadConnectorBuilder.java index eaa7dea..178d9c4 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/connector/DgcGatewayDownloadConnectorBuilder.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/connector/DgcGatewayDownloadConnectorBuilder.java @@ -17,7 +17,9 @@ import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.UUID; import javax.net.ssl.SSLContext; import lombok.AllArgsConstructor; @@ -60,7 +62,7 @@ public class DgcGatewayDownloadConnectorBuilder { private String url; private KeyStore mtlsTrustStore; private KeyStore mtlsKeyStore; - private X509CertificateHolder trustAnchor; + private final List trustAnchors = new ArrayList<>(); private HttpHost proxy; private int cacheMagAge = -1; private boolean enableSslHostnameValidation = true; @@ -79,13 +81,24 @@ public DgcGatewayDownloadConnectorBuilder withUrl(String url) { } /** - * Set the TrustAnchor to validate the received entities. + * Add multiple TrustAnchors to validate the received entities. + * Required. + * + * @param certs X509 Certificates which are allowed as TrustAnchor. + */ + public DgcGatewayDownloadConnectorBuilder withTrustAnchors(List certs) { + this.trustAnchors.addAll(certs); + return this; + } + + /** + * Add one TrustAnchor to validate the received entities. * Required. * * @param cert X509 Certificate which is the TrustAnchor. */ public DgcGatewayDownloadConnectorBuilder withTrustAnchor(X509CertificateHolder cert) { - this.trustAnchor = cert; + this.trustAnchors.add(cert); return this; } @@ -140,7 +153,7 @@ public DgcGatewayDownloadConnectorBuilder withMtlsAuthCert(X509CertificateHolder } /** - * Set the trusted Server Certificate of target DGCG. + * Add a trusted Server Certificate to trustlist of target DGCG. * Default: Trust all incomming Certificates. * * @param cert X509 Certificate @@ -233,10 +246,10 @@ public DgcGatewayDownloadConnector build() throws DgcGatewayDownloadConnectorBui "URL is not set"); } - if (this.trustAnchor == null) { + if (this.trustAnchors.isEmpty()) { throw new DgcGatewayDownloadConnectorBuilderException( DgcGatewayDownloadConnectorBuilderException.Reason.NOT_READY, - "TrustAnchor is not set"); + "At least one TrustAnchor is required."); } DgcGatewayConnectorConfigProperties properties = new DgcGatewayConnectorConfigProperties(); @@ -260,7 +273,7 @@ public DgcGatewayDownloadConnector build() throws DgcGatewayDownloadConnectorBui DgcGatewayConnectorUtils connectorUtils = new DgcGatewayConnectorUtils(certificateUtils, restClient, null, null); - connectorUtils.setTrustAnchor(trustAnchor); + connectorUtils.setTrustAnchors(trustAnchors); return new DgcGatewayDownloadConnector(connectorUtils, restClient, properties, trustListMapper); } diff --git a/src/test/java/eu/europa/ec/dgc/gateway/connector/DownloadConnectorBuilderTest.java b/src/test/java/eu/europa/ec/dgc/gateway/connector/DownloadConnectorBuilderTest.java index ce678de..c7518c2 100644 --- a/src/test/java/eu/europa/ec/dgc/gateway/connector/DownloadConnectorBuilderTest.java +++ b/src/test/java/eu/europa/ec/dgc/gateway/connector/DownloadConnectorBuilderTest.java @@ -9,6 +9,7 @@ import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.time.temporal.ChronoUnit; +import java.util.Collections; import java.util.Objects; import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; @@ -86,7 +87,7 @@ void testConnectorUsesClientCertificate() throws Exception { .withTrustedServerCert(certificateUtils.convertCertificate(serverCertificate)) .withUrl(server.url("/test").toString()) .withSslHostnameValidation(false) - .withTrustAnchor(certificateUtils.convertCertificate(trustAnchorCertificate)) + .withTrustAnchors(Collections.singletonList(certificateUtils.convertCertificate(trustAnchorCertificate))) .build(); connector.getTrustedCertificates(); diff --git a/src/test/java/eu/europa/ec/dgc/gateway/connector/DownloadConnectorUtilsTest.java b/src/test/java/eu/europa/ec/dgc/gateway/connector/DownloadConnectorUtilsTest.java index 00550cf..5c8241f 100644 --- a/src/test/java/eu/europa/ec/dgc/gateway/connector/DownloadConnectorUtilsTest.java +++ b/src/test/java/eu/europa/ec/dgc/gateway/connector/DownloadConnectorUtilsTest.java @@ -33,6 +33,7 @@ import java.security.cert.X509Certificate; import java.time.ZonedDateTime; import java.util.Base64; +import java.util.Collections; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -146,7 +147,9 @@ void testTrustListItemSignedByTrustAnchor() throws Exception { cscaTrustListItem.setThumbprint(certificateUtils.getCertThumbprint(csca)); cscaTrustListItem.setRawData(Base64.getEncoder().encodeToString(csca.getEncoded())); - Assertions.assertTrue(connectorUtils.checkTrustAnchorSignature(cscaTrustListItem, certificateUtils.convertCertificate(testKeyStore.getTrustAnchor()))); + Assertions.assertTrue( + connectorUtils.checkTrustAnchorSignature(cscaTrustListItem, + Collections.singletonList(certificateUtils.convertCertificate(testKeyStore.getTrustAnchor())))); } @Test @@ -169,7 +172,8 @@ void testTrustListItemSignedByTrustAnchorFailed() throws Exception { cscaTrustListItem.setThumbprint(certificateUtils.getCertThumbprint(csca)); cscaTrustListItem.setRawData(Base64.getEncoder().encodeToString(csca.getEncoded())); - Assertions.assertFalse(connectorUtils.checkTrustAnchorSignature(cscaTrustListItem, certificateUtils.convertCertificate(testKeyStore.getTrustAnchor()))); + Assertions.assertFalse(connectorUtils.checkTrustAnchorSignature(cscaTrustListItem, + Collections.singletonList(certificateUtils.convertCertificate(testKeyStore.getTrustAnchor())))); } @Test diff --git a/src/test/java/eu/europa/ec/dgc/signing/DeprecatedSignedCertificateMessageBuilderTest.java b/src/test/java/eu/europa/ec/dgc/signing/DeprecatedSignedCertificateMessageBuilderTest.java index 0801947..b36b3bd 100644 --- a/src/test/java/eu/europa/ec/dgc/signing/DeprecatedSignedCertificateMessageBuilderTest.java +++ b/src/test/java/eu/europa/ec/dgc/signing/DeprecatedSignedCertificateMessageBuilderTest.java @@ -39,6 +39,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@SuppressWarnings("deprecation") class DeprecatedSignedCertificateMessageBuilderTest { KeyPair payloadKeyPair, signingKeyPair; diff --git a/src/test/java/eu/europa/ec/dgc/signing/SignedCertificateMessageParserTest.java b/src/test/java/eu/europa/ec/dgc/signing/SignedCertificateMessageParserTest.java index 7069434..9454638 100644 --- a/src/test/java/eu/europa/ec/dgc/signing/SignedCertificateMessageParserTest.java +++ b/src/test/java/eu/europa/ec/dgc/signing/SignedCertificateMessageParserTest.java @@ -62,7 +62,7 @@ void setupTestData() throws Exception { signingCertificate = CertificateTestUtils.generateCertificate(signingKeyPair, "DE", "SigningCertificate"); builder = new SignedCertificateMessageBuilder() - .withPayloadCertificate(new X509CertificateHolder(payloadCertificate.getEncoded())) + .withPayload(new X509CertificateHolder(payloadCertificate.getEncoded())) .withSigningCertificate(new X509CertificateHolder(signingCertificate.getEncoded()), signingKeyPair.getPrivate()); } @@ -72,7 +72,7 @@ void parserShouldParseByteArray() throws IOException, CertificateEncodingExcepti Base64.getEncoder().encode(builder.build())); Assertions.assertEquals(SignedCertificateMessageParser.ParserState.SUCCESS, parser.getParserState()); - Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayloadCertificate().getEncoded()); + Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); checkSignatureFromParser(parser.getSignature()); @@ -87,7 +87,7 @@ void parserShouldParseByteArrayWithDetachedPayload() throws IOException, Certifi Base64.getEncoder().encode(payloadCertificate.getEncoded())); Assertions.assertEquals(SignedCertificateMessageParser.ParserState.SUCCESS, parser.getParserState()); - Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayloadCertificate().getEncoded()); + Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); Assertions.assertEquals(new String(cms), parser.getSignature()); @@ -102,7 +102,7 @@ void parserShouldParseByteArrayWithDetachedPayloadAsString() throws IOException, Base64.getEncoder().encodeToString(payloadCertificate.getEncoded())); Assertions.assertEquals(SignedCertificateMessageParser.ParserState.SUCCESS, parser.getParserState()); - Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayloadCertificate().getEncoded()); + Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); checkSignatureFromParser(parser.getSignature()); @@ -114,7 +114,7 @@ void parserShouldParseString() throws IOException, CertificateEncodingException builder.buildAsString()); Assertions.assertEquals(SignedCertificateMessageParser.ParserState.SUCCESS, parser.getParserState()); - Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayloadCertificate().getEncoded()); + Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); checkSignatureFromParser(parser.getSignature()); @@ -127,7 +127,7 @@ void parserShouldParseStringWithDetachedPayload() throws IOException, Certificat Base64.getEncoder().encode(payloadCertificate.getEncoded())); Assertions.assertEquals(SignedCertificateMessageParser.ParserState.SUCCESS, parser.getParserState()); - Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayloadCertificate().getEncoded()); + Assertions.assertArrayEquals(payloadCertificate.getEncoded(), parser.getPayload().getEncoded()); Assertions.assertArrayEquals(signingCertificate.getEncoded(), parser.getSigningCertificate().getEncoded()); Assertions.assertTrue(parser.isSignatureVerified()); checkSignatureFromParser(parser.getSignature()); @@ -280,7 +280,7 @@ private void checkSignatureFromParser(String signature) throws CertificateEncodi signature, Base64.getEncoder().encodeToString(payloadCertificate.getEncoded())); Assertions.assertEquals(SignedCertificateMessageParser.ParserState.SUCCESS, parser.getParserState()); - Assertions.assertEquals(new X509CertificateHolder(payloadCertificate.getEncoded()), parser.getPayloadCertificate()); + Assertions.assertEquals(new X509CertificateHolder(payloadCertificate.getEncoded()), parser.getPayload()); Assertions.assertEquals(new X509CertificateHolder(signingCertificate.getEncoded()), parser.getSigningCertificate()); Assertions.assertTrue(parser.isSignatureVerified()); Assertions.assertEquals(signature, parser.getSignature()); From f0fccf10876693dc98de99317f25a0a5590106b7 Mon Sep 17 00:00:00 2001 From: Felix Dittrich Date: Mon, 7 Feb 2022 16:22:25 +0100 Subject: [PATCH 2/4] Remove Spring Boot Starter Web Upgrade Spring Boot to 2.6.3 --- pom.xml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 4619e23..85f1f97 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ UTF-8 6.5.2 - 2.6.2 + 2.6.3 3.1.0 11.7 1.70 @@ -77,12 +77,6 @@ ${spring.boot.version} true - - org.springframework.boot - spring-boot-starter-web - ${spring.boot.version} - true - org.springframework.boot spring-boot-configuration-processor From 6e03ecbea3a888785baf1cee6f4e70f272472c07 Mon Sep 17 00:00:00 2001 From: Felix Dittrich Date: Mon, 7 Feb 2022 16:31:45 +0100 Subject: [PATCH 3/4] Add Jackson Dependency --- pom.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 85f1f97..0908598 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ 1.4.2.Final 2.11.0 4.5.1 - 2.13.0 + 2.13.1 4.9.3 3.1.2 3.9.1.2184 @@ -124,6 +124,11 @@ jackson-databind ${jackson.version} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + org.springframework.boot From cdda568742022b04955c30cff24af3504b8d9b86 Mon Sep 17 00:00:00 2001 From: Felix Dittrich Date: Mon, 7 Feb 2022 17:01:47 +0100 Subject: [PATCH 4/4] OWASP --- pom.xml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0908598..a7b7407 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ UTF-8 UTF-8 - 6.5.2 + 6.5.3 2.6.3 3.1.0 11.7 @@ -87,6 +87,12 @@ org.springframework.cloud spring-cloud-starter-openfeign ${spring.cloud.version} + + + org.springframework + spring-web + + io.github.openfeign @@ -155,6 +161,11 @@ spring-security-crypto 5.5.1 + + org.springframework + spring-web + 5.3.15 +