From e9e5bcaf13aea191c028ef5585c6bddb1a56248f Mon Sep 17 00:00:00 2001 From: Sebastian Becker Date: Tue, 8 Oct 2024 10:09:47 +0200 Subject: [PATCH] feat: use certificates for trust management (#26) Signed-off-by: Sebastian Becker --- .../httpclient/CompositeX509TrustManager.java | 6 +- .../carbynestack/httpclient/CsHttpClient.java | 22 +++----- .../httpclient/ExtendedSSLContextBuilder.java | 6 +- .../httpclient/X509TrustManagerUtils.java | 31 +++++++---- .../httpclient/SslValidationIT.java | 22 +++++--- src/test/resources/cli_test.key | 52 ++++++++++++++++++ src/test/resources/cli_test.pem | 30 ++++++++++ src/test/resources/keyStore.jks | Bin 0 -> 4334 bytes src/test/resources/keyStoreA.jks | Bin 3950 -> 0 bytes 9 files changed, 128 insertions(+), 41 deletions(-) create mode 100644 src/test/resources/cli_test.key create mode 100644 src/test/resources/cli_test.pem create mode 100644 src/test/resources/keyStore.jks delete mode 100644 src/test/resources/keyStoreA.jks diff --git a/src/main/java/io/carbynestack/httpclient/CompositeX509TrustManager.java b/src/main/java/io/carbynestack/httpclient/CompositeX509TrustManager.java index 76ab4a2..068c415 100644 --- a/src/main/java/io/carbynestack/httpclient/CompositeX509TrustManager.java +++ b/src/main/java/io/carbynestack/httpclient/CompositeX509TrustManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/java-http-client. * * SPDX-License-Identifier: Apache-2.0 @@ -13,10 +13,10 @@ import java.util.List; import javax.net.ssl.X509TrustManager; -class CompositeX509TrustManager implements X509TrustManager { +public class CompositeX509TrustManager implements X509TrustManager { private final List managers; - CompositeX509TrustManager(List managers) { + public CompositeX509TrustManager(List managers) { this.managers = new ArrayList<>(managers); } diff --git a/src/main/java/io/carbynestack/httpclient/CsHttpClient.java b/src/main/java/io/carbynestack/httpclient/CsHttpClient.java index a81ed76..99641dd 100644 --- a/src/main/java/io/carbynestack/httpclient/CsHttpClient.java +++ b/src/main/java/io/carbynestack/httpclient/CsHttpClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/java-http-client. * * SPDX-License-Identifier: Apache-2.0 @@ -13,10 +13,7 @@ import java.io.File; import java.io.IOException; import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Stream; import javax.net.ssl.X509TrustManager; import org.apache.http.Header; @@ -72,17 +69,12 @@ public CsHttpClient( sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build(), new NoopHostnameVerifier()); } else { - List> custom = new ArrayList<>(); - for (File f : withTrustedCertificates) { - custom.add(X509TrustManagerUtils.getX509TrustManager(f)); - } List allTrustManagers = - Stream.concat( - custom.stream(), - Stream.of(X509TrustManagerUtils.getDefaultX509TrustManager())) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(toList()); + Stream.of(X509TrustManagerUtils.getX509TrustManager(withTrustedCertificates), + X509TrustManagerUtils.getDefaultX509TrustManager()) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); SSLContextBuilder sslContextBuilder = ExtendedSSLContextBuilder.create(new CompositeX509TrustManager(allTrustManagers)); sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build()); diff --git a/src/main/java/io/carbynestack/httpclient/ExtendedSSLContextBuilder.java b/src/main/java/io/carbynestack/httpclient/ExtendedSSLContextBuilder.java index 178332e..0e0e33b 100644 --- a/src/main/java/io/carbynestack/httpclient/ExtendedSSLContextBuilder.java +++ b/src/main/java/io/carbynestack/httpclient/ExtendedSSLContextBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/java-http-client. * * SPDX-License-Identifier: Apache-2.0 @@ -16,14 +16,14 @@ import javax.net.ssl.X509TrustManager; import org.apache.http.ssl.SSLContextBuilder; -class ExtendedSSLContextBuilder extends SSLContextBuilder { +public class ExtendedSSLContextBuilder extends SSLContextBuilder { private final X509TrustManager trustManager; private ExtendedSSLContextBuilder(X509TrustManager trustManager) { this.trustManager = trustManager; } - static ExtendedSSLContextBuilder create(X509TrustManager trustManager) { + public static ExtendedSSLContextBuilder create(X509TrustManager trustManager) { return new ExtendedSSLContextBuilder(trustManager); } diff --git a/src/main/java/io/carbynestack/httpclient/X509TrustManagerUtils.java b/src/main/java/io/carbynestack/httpclient/X509TrustManagerUtils.java index 503fe69..d749495 100644 --- a/src/main/java/io/carbynestack/httpclient/X509TrustManagerUtils.java +++ b/src/main/java/io/carbynestack/httpclient/X509TrustManagerUtils.java @@ -1,26 +1,29 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/java-http-client. * * SPDX-License-Identifier: Apache-2.0 */ package io.carbynestack.httpclient; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Files; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; 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.Optional; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; -final class X509TrustManagerUtils { +public final class X509TrustManagerUtils { - static Optional getX509TrustManager(KeyStore keyStore) + public static Optional getX509TrustManager(KeyStore keyStore) throws NoSuchAlgorithmException, KeyStoreException { TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); @@ -31,17 +34,23 @@ static Optional getX509TrustManager(KeyStore keyStore) .findFirst(); } - static Optional getDefaultX509TrustManager() + public static Optional getDefaultX509TrustManager() throws NoSuchAlgorithmException, KeyStoreException { return getX509TrustManager((KeyStore) null); } - static Optional getX509TrustManager(File file) + public static Optional getX509TrustManager(List certs) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException { - try (FileInputStream fis = new FileInputStream(file)) { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(fis, null); + CertificateFactory certificateFactory = CertificateFactory.getInstance("X509"); + keyStore.load(null); + for (File certificate : certs) { + X509Certificate x509Certificate = + (X509Certificate) + certificateFactory.generateCertificate(Files.newInputStream(certificate.toPath())); + keyStore.setCertificateEntry( + x509Certificate.getSubjectX500Principal().getName(), x509Certificate); + } return getX509TrustManager(keyStore); } - } } diff --git a/src/test/java/io/carbynestack/httpclient/SslValidationIT.java b/src/test/java/io/carbynestack/httpclient/SslValidationIT.java index cc71139..d177f66 100644 --- a/src/test/java/io/carbynestack/httpclient/SslValidationIT.java +++ b/src/test/java/io/carbynestack/httpclient/SslValidationIT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/java-http-client. * * SPDX-License-Identifier: Apache-2.0 @@ -18,6 +18,7 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.security.cert.CertificateException; import java.util.Collections; import java.util.Objects; import javax.net.ssl.SSLContext; @@ -28,8 +29,11 @@ import org.junit.jupiter.api.extension.RegisterExtension; public class SslValidationIT { - private static final String KEY_STORE_A_PATH = - Objects.requireNonNull(SslValidationIT.class.getClassLoader().getResource("keyStoreA.jks")) + private static final String KEY_STORE_PATH = + Objects.requireNonNull(SslValidationIT.class.getClassLoader().getResource("keyStore.jks")) + .getPath(); + private static final String CERTIFICATE_PATH = + Objects.requireNonNull(SslValidationIT.class.getClassLoader().getResource("cli_test.pem")) .getPath(); private static final String KEY_STORE_A_PASSWORD = "verysecure"; private static final String GOOGLE_DIRECTIONS_REST_URI = @@ -44,7 +48,7 @@ public class SslValidationIT { wireMockConfig() .dynamicPort() .dynamicHttpsPort() - .keystorePath(KEY_STORE_A_PATH) + .keystorePath(KEY_STORE_PATH) .keystorePassword(KEY_STORE_A_PASSWORD) .keyManagerPassword(KEY_STORE_A_PASSWORD)) .build(); @@ -82,7 +86,7 @@ public void givenTrustedCertificate_whenGettingObject_thenSucceeds() CsHttpClient csHttpClient = CsHttpClient.builder() .withFailureType(String.class) - .withTrustedCertificates(Collections.singletonList(new File(KEY_STORE_A_PATH))) + .withTrustedCertificates(Collections.singletonList(new File(CERTIFICATE_PATH))) .build(); assertThat(csHttpClient.getForObject(testUri, String.class)).isEqualTo(SUCCESS_RESPONSE_STRING); } @@ -99,7 +103,7 @@ public void givenSslValidationDisabled_whenGettingObject_thenSucceeds() } @Test - public void givenNonExistingTrustStore_whenBuildingClient_thenThrows() { + public void givenNonExistingCertificate_whenBuildingClient_thenThrows() { File nonExistingFile = new File(""); assertThatThrownBy( () -> @@ -108,7 +112,7 @@ public void givenNonExistingTrustStore_whenBuildingClient_thenThrows() { .withTrustedCertificates(Collections.singletonList(nonExistingFile)) .build()) .isExactlyInstanceOf(CsHttpClientException.class) - .hasCauseInstanceOf(IOException.class); + .hasCauseInstanceOf(CertificateException.class); } @Test @@ -137,12 +141,12 @@ public void givenOfficiallyTrustedTarget_whenGettingEntity_thenSucceedWithBadReq @Test public void - givenOfficiallyTrustedTargetAndCustomTruststore_whenGettingEntity_thenSucceedWithBadRequest() + givenOfficiallyTrustedTargetAndCustomCertificate_whenGettingEntity_thenSucceedWithBadRequest() throws CsHttpClientException, URISyntaxException { CsHttpClient csHttpClient = CsHttpClient.builder() .withFailureType(GoogleDirectionsResponse.class) - .withTrustedCertificates(Collections.singletonList(new File(KEY_STORE_A_PATH))) + .withTrustedCertificates(Collections.singletonList(new File(CERTIFICATE_PATH))) .build(); CsResponseEntity csResponseEntity = csHttpClient.getForEntity(new URI(GOOGLE_DIRECTIONS_REST_URI), String.class); diff --git a/src/test/resources/cli_test.key b/src/test/resources/cli_test.key new file mode 100644 index 0000000..c18012b --- /dev/null +++ b/src/test/resources/cli_test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +jPpR6xcsp11tDuNLwFR5oXtjlurS +-----END PRIVATE KEY----- diff --git a/src/test/resources/cli_test.pem b/src/test/resources/cli_test.pem new file mode 100644 index 0000000..af136e8 --- /dev/null +++ b/src/test/resources/cli_test.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFJTCCAw2gAwIBAgIUKn+PjY2heJxokM2T9kyjvbEzNqkwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MTAwMTA3MDYzMFoXDTM0MDky +OTA3MDYzMFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA1LwXNTCD2hEYwNqoEK14QEEKfaTi8qjTeRiArlvfufRH +1UGWgqXtCGgxKcn6hbsCe+gKXUVaM8jV8/JOZkE7LtggMekYwUDwu36FQ469Ikbm +TjFnF+M9twq3Vte5VZaMJQidSzjzMp2zTxuDPZENCEpEecZPHNAqSQpCCofAW0TH +Vi8EwCMKFG+v2rUhJcTMmQrfY7rN1aGI4Wued3UjLkbAMthNdIZbcwPgtEkDHreG +hvQXhtJkIxBEJevHANaXq8utzusaf2GxYNA4bYNG3ryxksMJatv+fMDIu/eRTmBU +hO92tfhd8YRJGjSRdmuKdtJ2Z6QafDVay7ZsUV/ifM+Iwc3YSGEhpZuzT8kjFcld +iEMPTTPwHQ6tRTT8yRUDbFtYwYQwpuIvs56wiaf6sACi+Vf2f8Wnc4XD5TRAZrn5 +n0LEzVw0qF0iCvY+fgF8bFEfLrZbGENjqhESN+Z2b5jNQjiXrcUriu47vdpcCtqs +8+U5hOFLO7uy9tyBI3w3dNIQqOHyPwt9FsgI+OdicaugjgY+z+iKQCKO7UPERiES +Lhtl9PJSlJ8fb7R6W4jfyxlXkfRcuYChtjCsWXCTXR5rp2tQO9A1OeklrYvS9hxi +w3CZGSEuZfRYBMArtfbrGO1NB+KJDXQpph3JDvE0BWHEG/e7f4k0zn554jlmfD8C +AwEAAaNvMG0wHQYDVR0OBBYEFFnntPA4FCI6uUF41u3Xf6E0CbF+MB8GA1UdIwQY +MBaAFFnntPA4FCI6uUF41u3Xf6E0CbF+MA8GA1UdEwEB/wQFMAMBAf8wGgYDVR0R +BBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4ICAQDPitpt2wJe +jnVU+yuS7a8BO/Rcj1oahrpG9wGgUfitI+vbIymBTVXWPFJw//QkBpkLRUH/WNJi +8ukIbRy/05v3Pqm+sJW9Jqp6G7cJV+cx29XgDGq0+g1JWtGRECobcADunE53Pu7J +vpgnnAGuQXshcv2ae7V/YGJnYY0vPncfTPnBr3EWzXba/nUhbB+laVXw6epUU8K2 +fru9oVwmKDpKup9Gej93nr08V6EtgjmPVMdkqUSk9ZxXOoS0a4AvNVaSv9lRjc5F +KiePdJz14x4AYFIUBRxiWCiNeMkustmvaTyJdhz/P8Y4py7nSff3kzwm/x0dF13N +fhTk+xNXBiI6C+a7pkgqvBpc+7ZjKe5kOqIujHcpIkk85YgZO9saKPZUanhuqJV8 +3CKdoCfFQyGMydoXhB7CWay0puUJ4pCml7Xe5EuYQxTPN/KDZ5Isxb76qCRuuZzB +Ifo21Xaa6iJSszH7KTCtvEmDuSKdTaiAx/EA+nERg4ipQO0JKbVNf4JpxyVA6dSl +XtfzMS4Ho+2sQw2Fh1kkgY+KX0YZyopCAERVBLMgV5dbNNaOlnmYjU2GVFXy+VIX +Q2QJgBxbUm8H2Og5LQWhp14WRfNmLampVBa49wx8qVxpkkprk3DauO6F4fSyCkYf ++mkzUQn+6cmtZCYBQWeoXjlWJeYwei04cQ== +-----END CERTIFICATE----- diff --git a/src/test/resources/keyStore.jks b/src/test/resources/keyStore.jks new file mode 100644 index 0000000000000000000000000000000000000000..cd60b192e58e19578e7b6429dbfbd2abbea67a8c GIT binary patch literal 4334 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 E04~AyEdT%j literal 0 HcmV?d00001 diff --git a/src/test/resources/keyStoreA.jks b/src/test/resources/keyStoreA.jks deleted file mode 100644 index 54891bc95b478b89c473f1c3562864fb71eace7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3950 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