diff --git a/build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml b/build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml index 821b7255619f..69f864b741af 100644 --- a/build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml +++ b/build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml @@ -143,4 +143,11 @@ + + + + + + + diff --git a/http-client-spi/src/main/java/software/amazon/awssdk/http/SdkHttpConfigurationOption.java b/http-client-spi/src/main/java/software/amazon/awssdk/http/SdkHttpConfigurationOption.java index 52e91eaaa3c7..ac90fd0ba72f 100644 --- a/http-client-spi/src/main/java/software/amazon/awssdk/http/SdkHttpConfigurationOption.java +++ b/http-client-spi/src/main/java/software/amazon/awssdk/http/SdkHttpConfigurationOption.java @@ -97,6 +97,13 @@ public final class SdkHttpConfigurationOption extends AttributeMap.Key { public static final SdkHttpConfigurationOption REAP_IDLE_CONNECTIONS = new SdkHttpConfigurationOption<>("ReapIdleConnections", Boolean.class); + /** + * The {@link TlsKeyManagersProvider} that will be used by the HTTP client when authenticating with a + * TLS host. + */ + public static final SdkHttpConfigurationOption TLS_KEY_MANAGERS_PROVIDER = + new SdkHttpConfigurationOption<>("TlsKeyManagersProvider", TlsKeyManagersProvider.class); + private static final Duration DEFAULT_SOCKET_READ_TIMEOUT = Duration.ofSeconds(30); private static final Duration DEFAULT_SOCKET_WRITE_TIMEOUT = Duration.ofSeconds(30); private static final Duration DEFAULT_CONNECTION_TIMEOUT = Duration.ofSeconds(2); @@ -110,6 +117,8 @@ public final class SdkHttpConfigurationOption extends AttributeMap.Key { private static final Protocol DEFAULT_PROTOCOL = Protocol.HTTP1_1; + private static final TlsKeyManagersProvider DEFAULT_TLS_KEY_MANAGERS_PROVIDER = SystemPropertyTlsKeyManagersProvider.create(); + public static final AttributeMap GLOBAL_HTTP_DEFAULTS = AttributeMap .builder() .put(READ_TIMEOUT, DEFAULT_SOCKET_READ_TIMEOUT) @@ -123,6 +132,7 @@ public final class SdkHttpConfigurationOption extends AttributeMap.Key { .put(PROTOCOL, DEFAULT_PROTOCOL) .put(TRUST_ALL_CERTIFICATES, DEFAULT_TRUST_ALL_CERTIFICATES) .put(REAP_IDLE_CONNECTIONS, DEFAULT_REAP_IDLE_CONNECTIONS) + .put(TLS_KEY_MANAGERS_PROVIDER, DEFAULT_TLS_KEY_MANAGERS_PROVIDER) .build(); private final String name; diff --git a/http-client-spi/src/main/java/software/amazon/awssdk/http/TlsKeyManagersProvider.java b/http-client-spi/src/main/java/software/amazon/awssdk/http/TlsKeyManagersProvider.java index ed4e41f00576..1571814e8c69 100644 --- a/http-client-spi/src/main/java/software/amazon/awssdk/http/TlsKeyManagersProvider.java +++ b/http-client-spi/src/main/java/software/amazon/awssdk/http/TlsKeyManagersProvider.java @@ -17,6 +17,7 @@ import javax.net.ssl.KeyManager; import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.internal.http.NoneTlsKeyManagersProvider; /** * Provider for the {@link KeyManager key managers} to be used by the SDK when @@ -31,4 +32,11 @@ public interface TlsKeyManagersProvider { * @return The {@link KeyManager}s, or {@code null}. */ KeyManager[] keyManagers(); + + /** + * @return A provider that returns a {@code null} array of {@link KeyManager}s. + */ + static TlsKeyManagersProvider noneProvider() { + return NoneTlsKeyManagersProvider.getInstance(); + } } diff --git a/http-client-spi/src/main/java/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProvider.java b/http-client-spi/src/main/java/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProvider.java new file mode 100644 index 000000000000..9e5d165ef708 --- /dev/null +++ b/http-client-spi/src/main/java/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.internal.http; + +import javax.net.ssl.KeyManager; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.http.TlsKeyManagersProvider; + +/** + * Simple implementation of {@link TlsKeyManagersProvider} that return a null array. + *

+ * Use this provider if you don't want the client to present any certificates to the remote TLS host. + */ +@SdkInternalApi +public final class NoneTlsKeyManagersProvider implements TlsKeyManagersProvider { + private static final NoneTlsKeyManagersProvider INSTANCE = new NoneTlsKeyManagersProvider(); + + private NoneTlsKeyManagersProvider() { + } + + @Override + public KeyManager[] keyManagers() { + return null; + } + + public static NoneTlsKeyManagersProvider getInstance() { + return INSTANCE; + } +} diff --git a/http-client-spi/src/test/java/software/amazon/awssdk/http/TlsKeyManagersProviderTest.java b/http-client-spi/src/test/java/software/amazon/awssdk/http/TlsKeyManagersProviderTest.java new file mode 100644 index 000000000000..79412f79c334 --- /dev/null +++ b/http-client-spi/src/test/java/software/amazon/awssdk/http/TlsKeyManagersProviderTest.java @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; + +public class TlsKeyManagersProviderTest { + + @Test + public void noneProvider_returnsProviderThatReturnsNull() { + assertThat(TlsKeyManagersProvider.noneProvider().keyManagers()).isNull(); + } +} diff --git a/http-client-spi/src/test/java/software/amazon/awssdk/http/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProviderTest.java b/http-client-spi/src/test/java/software/amazon/awssdk/http/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProviderTest.java new file mode 100644 index 000000000000..2e3098e62de4 --- /dev/null +++ b/http-client-spi/src/test/java/software/amazon/awssdk/http/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProviderTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.software.amazon.awssdk.internal.http; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; +import software.amazon.awssdk.internal.http.NoneTlsKeyManagersProvider; + +public class NoneTlsKeyManagersProviderTest { + @Test + public void getInstance_returnsNonNull() { + assertThat(NoneTlsKeyManagersProvider.getInstance()).isNotNull(); + } + + @Test + public void keyManagers_returnsNull() { + assertThat(NoneTlsKeyManagersProvider.getInstance().keyManagers()).isNull(); + } + + @Test + public void getInstance_returnsSingletonInstance() { + NoneTlsKeyManagersProvider provider1 = NoneTlsKeyManagersProvider.getInstance(); + NoneTlsKeyManagersProvider provider2 = NoneTlsKeyManagersProvider.getInstance(); + assertThat(provider1 == provider2).isTrue(); + } +} diff --git a/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java b/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java index e4c6c9fe10da..b86a74a78604 100644 --- a/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java +++ b/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java @@ -26,6 +26,7 @@ import static software.amazon.awssdk.http.SdkHttpConfigurationOption.MAX_CONNECTIONS; import static software.amazon.awssdk.http.SdkHttpConfigurationOption.READ_TIMEOUT; import static software.amazon.awssdk.http.SdkHttpConfigurationOption.REAP_IDLE_CONNECTIONS; +import static software.amazon.awssdk.http.SdkHttpConfigurationOption.TLS_KEY_MANAGERS_PROVIDER; import static software.amazon.awssdk.utils.NumericUtils.saturatedCast; import java.io.IOException; @@ -381,6 +382,10 @@ public interface Builder extends SdkHttpClient.Builder /** * Configure the {@link TlsKeyManagersProvider} that will provide the {@link javax.net.ssl.KeyManager}s to use * when constructing the SSL context. + *

+ * The default used by the client will be {@link SystemPropertyTlsKeyManagersProvider}. Configure an instance of + * {@link software.amazon.awssdk.internal.http.NoneTlsKeyManagersProvider} or another implementation of + * {@link TlsKeyManagersProvider} to override it. */ Builder tlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider); } @@ -392,7 +397,6 @@ private static final class DefaultBuilder implements Builder { private Boolean expectContinueEnabled; private HttpRoutePlanner httpRoutePlanner; private CredentialsProvider credentialsProvider; - private TlsKeyManagersProvider tlsKeyManagersProvider = SystemPropertyTlsKeyManagersProvider.create(); private DefaultBuilder() { } @@ -521,7 +525,7 @@ public Builder credentialsProvider(CredentialsProvider credentialsProvider) { @Override public Builder tlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider) { - this.tlsKeyManagersProvider = tlsKeyManagersProvider; + standardOptions.put(TLS_KEY_MANAGERS_PROVIDER, tlsKeyManagersProvider); return this; } @@ -565,7 +569,7 @@ public HttpClientConnectionManager create(ApacheHttpClient.DefaultBuilder config private ConnectionSocketFactory getPreferredSocketFactory(ApacheHttpClient.DefaultBuilder configuration, AttributeMap standardOptions) { // TODO v2 custom socket factory - return new SdkTlsSocketFactory(getSslContext(configuration.tlsKeyManagersProvider, standardOptions), + return new SdkTlsSocketFactory(getSslContext(standardOptions), getHostNameVerifier(standardOptions)); } @@ -575,7 +579,7 @@ private HostnameVerifier getHostNameVerifier(AttributeMap standardOptions) { : SSLConnectionSocketFactory.getDefaultHostnameVerifier(); } - private SSLContext getSslContext(TlsKeyManagersProvider keyManagersProvider, AttributeMap standardOptions) { + private SSLContext getSslContext(AttributeMap standardOptions) { TrustManager[] trustManagers = null; if (standardOptions.get(SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES)) { log.warn(() -> "SSL Certificate verification is disabled. This is not a safe setting and should only be " @@ -583,10 +587,8 @@ private SSLContext getSslContext(TlsKeyManagersProvider keyManagersProvider, Att trustManagers = trustAllTrustManager(); } - KeyManager[] keyManagers = null; - if (keyManagersProvider != null) { - keyManagers = keyManagersProvider.keyManagers(); - } + TlsKeyManagersProvider provider = standardOptions.get(TLS_KEY_MANAGERS_PROVIDER); + KeyManager[] keyManagers = provider.keyManagers(); try { SSLContext sslcontext = SSLContext.getInstance("TLS"); diff --git a/http-clients/apache-client/src/test/java/software/amazon/awssdk/http/apache/ApacheClientTlsAuthTest.java b/http-clients/apache-client/src/test/java/software/amazon/awssdk/http/apache/ApacheClientTlsAuthTest.java index cb00b6e96bfb..314049947c96 100644 --- a/http-clients/apache-client/src/test/java/software/amazon/awssdk/http/apache/ApacheClientTlsAuthTest.java +++ b/http-clients/apache-client/src/test/java/software/amazon/awssdk/http/apache/ApacheClientTlsAuthTest.java @@ -21,6 +21,8 @@ import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.instanceOf; import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE; import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE_PASSWORD; import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE_TYPE; @@ -30,11 +32,14 @@ import java.net.URI; import javax.net.ssl.SSLException; import org.apache.http.NoHttpResponseException; +import org.hamcrest.Matchers; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import software.amazon.awssdk.http.FileStoreTlsKeyManagersProvider; import software.amazon.awssdk.http.HttpExecuteRequest; import software.amazon.awssdk.http.HttpExecuteResponse; @@ -43,6 +48,7 @@ import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.TlsKeyManagersProvider; +import software.amazon.awssdk.internal.http.NoneTlsKeyManagersProvider; /** * Tests to ensure that {@link ApacheHttpClient} can properly support TLS @@ -53,6 +59,9 @@ public class ApacheClientTlsAuthTest extends ClientTlsAuthTestBase { private static TlsKeyManagersProvider keyManagersProvider; private SdkHttpClient client; + @Rule + public ExpectedException thrown = ExpectedException.none(); + @BeforeClass public static void setUp() throws IOException { ClientTlsAuthTestBase.setUp(); @@ -108,14 +117,9 @@ public void canMakeHttpsRequestWhenKeyProviderConfigured() throws IOException { @Test public void requestFailsWhenKeyProviderNotConfigured() throws IOException { - client = ApacheHttpClient.builder().build(); - try { - makeRequestWithHttpClient(client); - fail("HTTP request should have failed"); - } catch (NoHttpResponseException | SSLException | SocketException expected) { - // The client doesn't seem to consistently throw a single error, - // and can also vary depending on actual JVM used. - } + thrown.expect(anyOf(instanceOf(NoHttpResponseException.class), instanceOf(SSLException.class))); + client = ApacheHttpClient.builder().tlsKeyManagersProvider(NoneTlsKeyManagersProvider.getInstance()).build(); + makeRequestWithHttpClient(client); } @Test @@ -151,6 +155,22 @@ public void defaultTlsKeyManagersProviderIsSystemPropertyProvider() throws IOExc } } + @Test + public void defaultTlsKeyManagersProviderIsSystemPropertyProvider_explicitlySetToNull() throws IOException { + System.setProperty(SSL_KEY_STORE.property(), clientKeyStore.toAbsolutePath().toString()); + System.setProperty(SSL_KEY_STORE_TYPE.property(), CLIENT_STORE_TYPE); + System.setProperty(SSL_KEY_STORE_PASSWORD.property(), STORE_PASSWORD); + + client = ApacheHttpClient.builder().tlsKeyManagersProvider(null).build(); + try { + makeRequestWithHttpClient(client); + } finally { + System.clearProperty(SSL_KEY_STORE.property()); + System.clearProperty(SSL_KEY_STORE_TYPE.property()); + System.clearProperty(SSL_KEY_STORE_PASSWORD.property()); + } + } + private HttpExecuteResponse makeRequestWithHttpClient(SdkHttpClient httpClient) throws IOException { SdkHttpRequest httpRequest = SdkHttpFullRequest.builder() .method(SdkHttpMethod.GET) diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java index ff76b6720657..751c3d77937e 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java @@ -23,6 +23,7 @@ import static software.amazon.awssdk.http.SdkHttpConfigurationOption.MAX_PENDING_CONNECTION_ACQUIRES; import static software.amazon.awssdk.http.SdkHttpConfigurationOption.READ_TIMEOUT; import static software.amazon.awssdk.http.SdkHttpConfigurationOption.REAP_IDLE_CONNECTIONS; +import static software.amazon.awssdk.http.SdkHttpConfigurationOption.TLS_KEY_MANAGERS_PROVIDER; import static software.amazon.awssdk.http.SdkHttpConfigurationOption.WRITE_TIMEOUT; import static software.amazon.awssdk.http.nio.netty.internal.NettyConfiguration.EVENTLOOP_SHUTDOWN_FUTURE_TIMEOUT_SECONDS; import static software.amazon.awssdk.http.nio.netty.internal.NettyConfiguration.EVENTLOOP_SHUTDOWN_QUIET_PERIOD_SECONDS; @@ -48,6 +49,8 @@ import software.amazon.awssdk.http.Protocol; import software.amazon.awssdk.http.SdkHttpConfigurationOption; import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.http.SystemPropertyTlsKeyManagersProvider; +import software.amazon.awssdk.http.TlsKeyManagersProvider; import software.amazon.awssdk.http.async.AsyncExecuteRequest; import software.amazon.awssdk.http.async.SdkAsyncHttpClient; import software.amazon.awssdk.http.nio.netty.internal.AwaitCloseChannelPoolMap; @@ -354,6 +357,18 @@ public interface Builder extends SdkAsyncHttpClient.Builder + * If no provider is configured, the client will default to {@link SystemPropertyTlsKeyManagersProvider}. To + * disable any automatic resolution via the system properties, use {@link TlsKeyManagersProvider#noneProvider()}. + * + * @param keyManagersProvider The {@code TlsKeyManagersProvider}. + * @return The builder for method chaining. + */ + Builder tlsKeyManagersProvider(TlsKeyManagersProvider keyManagersProvider); } /** @@ -361,7 +376,6 @@ public interface Builder extends SdkAsyncHttpClient.Builder mock(KeyManager.class)) + .toArray(KeyManager[]::new); + + KeyManager[] arg = Arrays.copyOf(keyManagers, keyManagers.length); + StaticKeyManagerFactorySpi spi = new StaticKeyManagerFactorySpi(arg); + for (int i = 0; i < keyManagers.length; ++i) { + arg[i] = null; + } + + assertThat(spi.engineGetKeyManagers()).containsExactly(keyManagers); + } + + @Test + public void engineGetKeyManagers_returnsProvidedList() { + KeyManager[] keyManagers = IntStream.range(0,8) + .mapToObj(i -> mock(KeyManager.class)) + .toArray(KeyManager[]::new); + + StaticKeyManagerFactorySpi spi = new StaticKeyManagerFactorySpi(keyManagers); + + assertThat(spi.engineGetKeyManagers()).containsExactly(keyManagers); + } + + @Test(expected = UnsupportedOperationException.class) + public void engineInit_storeAndPasswords_throws() { + StaticKeyManagerFactorySpi staticKeyManagerFactorySpi = new StaticKeyManagerFactorySpi(new KeyManager[0]); + staticKeyManagerFactorySpi.engineInit(null, null); + } + + @Test(expected = UnsupportedOperationException.class) + public void engineInit_spec_throws() { + StaticKeyManagerFactorySpi staticKeyManagerFactorySpi = new StaticKeyManagerFactorySpi(new KeyManager[0]); + staticKeyManagerFactorySpi.engineInit(null); + } +} diff --git a/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/internal/StaticKeyManagerFactoryTest.java b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/internal/StaticKeyManagerFactoryTest.java new file mode 100644 index 000000000000..1f5c8713e769 --- /dev/null +++ b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/internal/StaticKeyManagerFactoryTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.http.nio.netty.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import java.util.stream.IntStream; +import javax.net.ssl.KeyManager; +import org.junit.Test; + +/** + * Tests for {@link StaticKeyManagerFactory}. + */ +public class StaticKeyManagerFactoryTest { + + @Test + public void createReturnFactoryWithCorrectKeyManagers() { + KeyManager[] keyManagers = IntStream.range(0,8) + .mapToObj(i -> mock(KeyManager.class)) + .toArray(KeyManager[]::new); + + StaticKeyManagerFactory staticKeyManagerFactory = StaticKeyManagerFactory.create(keyManagers); + + assertThat(staticKeyManagerFactory.getKeyManagers()) + .containsExactly(keyManagers); + } + +} diff --git a/http-clients/netty-nio-client/src/test/resources/software/amazon/awssdk/http/netty/client1.p12 b/http-clients/netty-nio-client/src/test/resources/software/amazon/awssdk/http/netty/client1.p12 new file mode 100644 index 000000000000..a56e38c196b5 Binary files /dev/null and b/http-clients/netty-nio-client/src/test/resources/software/amazon/awssdk/http/netty/client1.p12 differ diff --git a/http-clients/netty-nio-client/src/test/resources/software/amazon/awssdk/http/netty/server-keystore b/http-clients/netty-nio-client/src/test/resources/software/amazon/awssdk/http/netty/server-keystore new file mode 100644 index 000000000000..55e8a7998c2d Binary files /dev/null and b/http-clients/netty-nio-client/src/test/resources/software/amazon/awssdk/http/netty/server-keystore differ