From 96b74a3a01053e6b4d0c5e5c1caafad0c467412d Mon Sep 17 00:00:00 2001 From: yukon Date: Wed, 13 Dec 2017 19:39:16 +0800 Subject: [PATCH] [ROCKETMQ-315][ROCKETMQ-327] Enhance TLS feature (#202) * Add an interface DecryptionStrategy for SslHelper * Centralize the TLS related configurations * Use tls test mode by default * Add SSL related tests * Add tls related tests * Add tls config related unit tests * Pass TLS unit tests --- .../apache/rocketmq/broker/BrokerStartup.java | 9 +- .../apache/rocketmq/client/ClientConfig.java | 3 +- .../common/{SslMode.java => TlsMode.java} | 12 +- .../remoting/netty/NettyRemotingClient.java | 6 +- .../remoting/netty/NettyRemotingServer.java | 26 +- .../remoting/netty/NettySystemConfig.java | 22 -- .../rocketmq/remoting/netty/SslHelper.java | 133 -------- .../rocketmq/remoting/netty/TlsHelper.java | 234 ++++++++++++++ .../remoting/netty/TlsSystemConfig.java | 125 ++++++++ .../rocketmq/remoting/RemotingServerTest.java | 7 +- .../org/apache/rocketmq/remoting/TlsTest.java | 298 ++++++++++++++++++ .../src/test/resources/certs/badClient.key | 17 + .../src/test/resources/certs/badClient.pem | 18 ++ .../src/test/resources/certs/badServer.key | 16 + .../src/test/resources/certs/badServer.pem | 18 ++ remoting/src/test/resources/certs/ca.pem | 23 ++ remoting/src/test/resources/certs/client.key | 17 + remoting/src/test/resources/certs/client.pem | 18 ++ remoting/src/test/resources/certs/privkey.pem | 30 ++ remoting/src/test/resources/certs/server.key | 16 + remoting/src/test/resources/certs/server.pem | 18 ++ 21 files changed, 884 insertions(+), 182 deletions(-) rename remoting/src/main/java/org/apache/rocketmq/remoting/common/{SslMode.java => TlsMode.java} (87%) delete mode 100644 remoting/src/main/java/org/apache/rocketmq/remoting/netty/SslHelper.java create mode 100644 remoting/src/main/java/org/apache/rocketmq/remoting/netty/TlsHelper.java create mode 100644 remoting/src/main/java/org/apache/rocketmq/remoting/netty/TlsSystemConfig.java create mode 100644 remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java create mode 100644 remoting/src/test/resources/certs/badClient.key create mode 100644 remoting/src/test/resources/certs/badClient.pem create mode 100644 remoting/src/test/resources/certs/badServer.key create mode 100644 remoting/src/test/resources/certs/badServer.pem create mode 100644 remoting/src/test/resources/certs/ca.pem create mode 100644 remoting/src/test/resources/certs/client.key create mode 100644 remoting/src/test/resources/certs/client.pem create mode 100644 remoting/src/test/resources/certs/privkey.pem create mode 100644 remoting/src/test/resources/certs/server.key create mode 100644 remoting/src/test/resources/certs/server.pem diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java index a066652d..e768c7f9 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java @@ -32,10 +32,11 @@ import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.remoting.common.RemotingUtil; -import org.apache.rocketmq.remoting.common.SslMode; +import org.apache.rocketmq.remoting.common.TlsMode; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.NettyServerConfig; import org.apache.rocketmq.remoting.netty.NettySystemConfig; +import org.apache.rocketmq.remoting.netty.TlsSystemConfig; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.srvutil.ServerUtil; import org.apache.rocketmq.store.config.BrokerRole; @@ -43,6 +44,8 @@ import org.apache.rocketmq.store.config.MessageStoreConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_ENABLE; + public class BrokerStartup { public static Properties properties = null; public static CommandLine commandLine = null; @@ -98,7 +101,9 @@ public class BrokerStartup { final BrokerConfig brokerConfig = new BrokerConfig(); final NettyServerConfig nettyServerConfig = new NettyServerConfig(); final NettyClientConfig nettyClientConfig = new NettyClientConfig(); - nettyClientConfig.setUseTLS(NettySystemConfig.sslMode == SslMode.ENFORCING); + + nettyClientConfig.setUseTLS(Boolean.parseBoolean(System.getProperty(TLS_ENABLE, + String.valueOf(TlsSystemConfig.tlsMode == TlsMode.ENFORCING)))); nettyServerConfig.setListenPort(10911); final MessageStoreConfig messageStoreConfig = new MessageStoreConfig(); diff --git a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java index 8f255f01..a9eabfe6 100644 --- a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java +++ b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java @@ -19,6 +19,7 @@ package org.apache.rocketmq.client; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.UtilAll; import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.remoting.netty.TlsSystemConfig; /** * Client Common configuration @@ -45,7 +46,7 @@ public class ClientConfig { private String unitName; private boolean vipChannelEnabled = Boolean.parseBoolean(System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "true")); - private boolean useTLS; + private boolean useTLS = TlsSystemConfig.tlsEnable; public String buildMQClientId() { StringBuilder sb = new StringBuilder(); diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/common/SslMode.java b/remoting/src/main/java/org/apache/rocketmq/remoting/common/TlsMode.java similarity index 87% rename from remoting/src/main/java/org/apache/rocketmq/remoting/common/SslMode.java rename to remoting/src/main/java/org/apache/rocketmq/remoting/common/TlsMode.java index cb1e85a2..996ef0dd 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/common/SslMode.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/common/TlsMode.java @@ -25,7 +25,7 @@ package org.apache.rocketmq.remoting.common; *
  • enforcing: SSL is required, aka, non SSL connection will be rejected.
  • * */ -public enum SslMode { +public enum TlsMode { DISABLED("disabled"), PERMISSIVE("permissive"), @@ -33,14 +33,14 @@ public enum SslMode { private String name; - SslMode(String name) { + TlsMode(String name) { this.name = name; } - public static SslMode parse(String mode) { - for (SslMode sslMode: SslMode.values()) { - if (sslMode.name.equals(mode)) { - return sslMode; + public static TlsMode parse(String mode) { + for (TlsMode tlsMode : TlsMode.values()) { + if (tlsMode.name.equals(mode)) { + return tlsMode; } } diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java index 6dc0457e..dcc80cba 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java @@ -34,6 +34,7 @@ import io.netty.handler.timeout.IdleState; import io.netty.handler.timeout.IdleStateEvent; import io.netty.handler.timeout.IdleStateHandler; import io.netty.util.concurrent.DefaultEventExecutorGroup; +import java.io.IOException; import java.net.SocketAddress; import java.security.cert.CertificateException; import java.util.Collections; @@ -52,7 +53,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import javax.net.ssl.SSLException; import org.apache.rocketmq.remoting.ChannelEventListener; import org.apache.rocketmq.remoting.InvokeCallback; import org.apache.rocketmq.remoting.RPCHook; @@ -131,9 +131,9 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti if (nettyClientConfig.isUseTLS()) { try { - sslContext = SslHelper.buildSslContext(true); + sslContext = TlsHelper.buildSslContext(true); log.info("SSL enabled for client"); - } catch (SSLException e) { + } catch (IOException e) { log.error("Failed to create SSLContext", e); } catch (CertificateException e) { log.error("Failed to create SSLContext", e); diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java index ec1927a6..cd6ed470 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java @@ -37,6 +37,7 @@ import io.netty.handler.timeout.IdleState; import io.netty.handler.timeout.IdleStateEvent; import io.netty.handler.timeout.IdleStateHandler; import io.netty.util.concurrent.DefaultEventExecutorGroup; +import java.io.IOException; import java.net.InetSocketAddress; import java.security.cert.CertificateException; import java.util.NoSuchElementException; @@ -46,7 +47,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; -import javax.net.ssl.SSLException; import org.apache.rocketmq.remoting.ChannelEventListener; import org.apache.rocketmq.remoting.InvokeCallback; import org.apache.rocketmq.remoting.RPCHook; @@ -54,7 +54,7 @@ import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.common.Pair; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.common.RemotingUtil; -import org.apache.rocketmq.remoting.common.SslMode; +import org.apache.rocketmq.remoting.common.TlsMode; import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException; @@ -139,16 +139,16 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti }); } - SslMode sslMode = NettySystemConfig.sslMode; - log.info("Server is running in TLS {} mode", sslMode.getName()); + TlsMode tlsMode = TlsSystemConfig.tlsMode; + log.info("Server is running in TLS {} mode", tlsMode.getName()); - if (sslMode != SslMode.DISABLED) { + if (tlsMode != TlsMode.DISABLED) { try { - sslContext = SslHelper.buildSslContext(false); + sslContext = TlsHelper.buildSslContext(false); log.info("SSLContext created for server"); } catch (CertificateException e) { log.error("Failed to create SSLContext for server", e); - } catch (SSLException e) { + } catch (IOException e) { log.error("Failed to create SSLContext for server", e); } } @@ -189,7 +189,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti public void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, - new HandshakeHandler(NettySystemConfig.sslMode)) + new HandshakeHandler(TlsSystemConfig.tlsMode)) .addLast(defaultEventExecutorGroup, new NettyEncoder(), new NettyDecoder(), @@ -326,12 +326,12 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti class HandshakeHandler extends SimpleChannelInboundHandler { - private final SslMode sslMode; + private final TlsMode tlsMode; private static final byte HANDSHAKE_MAGIC_CODE = 0x16; - HandshakeHandler(SslMode sslMode) { - this.sslMode = sslMode; + HandshakeHandler(TlsMode tlsMode) { + this.tlsMode = tlsMode; } @Override @@ -344,7 +344,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti byte b = msg.getByte(0); if (b == HANDSHAKE_MAGIC_CODE) { - switch (sslMode) { + switch (tlsMode) { case DISABLED: ctx.close(); log.warn("Clients intend to establish a SSL connection while this server is running in SSL disabled mode"); @@ -366,7 +366,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti log.warn("Unknown TLS mode"); break; } - } else if (sslMode == SslMode.ENFORCING) { + } else if (tlsMode == TlsMode.ENFORCING) { ctx.close(); log.warn("Clients intend to establish an insecure connection while this server is running in SSL enforcing mode"); } diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java index b9c1f3fa..6357c03b 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java @@ -17,8 +17,6 @@ package org.apache.rocketmq.remoting.netty; -import org.apache.rocketmq.remoting.common.SslMode; - public class NettySystemConfig { public static final String COM_ROCKETMQ_REMOTING_NETTY_POOLED_BYTE_BUF_ALLOCATOR_ENABLE = "com.rocketmq.remoting.nettyPooledByteBufAllocatorEnable"; @@ -31,12 +29,6 @@ public class NettySystemConfig { public static final String COM_ROCKETMQ_REMOTING_CLIENT_ONEWAY_SEMAPHORE_VALUE = "com.rocketmq.remoting.clientOnewaySemaphoreValue"; - public static final String ORG_APACHE_ROCKETMQ_REMOTING_SSL_MODE = // - "org.apache.rocketmq.remoting.ssl.mode"; - - public static final String ORG_APACHE_ROCKETMQ_REMOTING_SSL_CONFIG_FILE = // - "org.apache.rocketmq.remoting.ssl.config.file"; - public static final boolean NETTY_POOLED_BYTE_BUF_ALLOCATOR_ENABLE = // Boolean.parseBoolean(System.getProperty(COM_ROCKETMQ_REMOTING_NETTY_POOLED_BYTE_BUF_ALLOCATOR_ENABLE, "false")); public static final int CLIENT_ASYNC_SEMAPHORE_VALUE = // @@ -47,18 +39,4 @@ public class NettySystemConfig { Integer.parseInt(System.getProperty(COM_ROCKETMQ_REMOTING_SOCKET_SNDBUF_SIZE, "65535")); public static int socketRcvbufSize = Integer.parseInt(System.getProperty(COM_ROCKETMQ_REMOTING_SOCKET_RCVBUF_SIZE, "65535")); - - /** - * For server, three SSL modes are supported: disabled, permissive and enforcing. - *
      - *
    1. disabled: SSL is not supported; any incoming SSL handshake will be rejected, causing connection closed.
    2. - *
    3. permissive: SSL is optional, aka, server in this mode can serve client connections with or without SSL;
    4. - *
    5. enforcing: SSL is required, aka, non SSL connection will be rejected.
    6. - *
    - */ - public static SslMode sslMode = // - SslMode.parse(System.getProperty(ORG_APACHE_ROCKETMQ_REMOTING_SSL_MODE, "permissive")); - - public static String sslConfigFile = // - System.getProperty(ORG_APACHE_ROCKETMQ_REMOTING_SSL_CONFIG_FILE, "/etc/rocketmq/ssl.properties"); } diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/SslHelper.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/SslHelper.java deleted file mode 100644 index ebadd968..00000000 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/SslHelper.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.apache.rocketmq.remoting.netty; - -import io.netty.handler.ssl.ClientAuth; -import io.netty.handler.ssl.OpenSsl; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import io.netty.handler.ssl.SslProvider; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.netty.handler.ssl.util.SelfSignedCertificate; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.security.cert.CertificateException; -import java.util.Properties; -import javax.net.ssl.SSLException; -import org.apache.rocketmq.remoting.common.RemotingHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SslHelper { - - private static final Logger LOGGER = LoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING); - - public static SslContext buildSslContext(boolean forClient) throws SSLException, CertificateException { - - File configFile = new File(NettySystemConfig.sslConfigFile); - boolean testMode = !(configFile.exists() && configFile.isFile() && configFile.canRead()); - Properties properties = null; - - if (!testMode) { - properties = new Properties(); - InputStream inputStream = null; - try { - inputStream = new FileInputStream(configFile); - properties.load(inputStream); - } catch (FileNotFoundException ignore) { - } catch (IOException ignore) { - } finally { - if (null != inputStream) { - try { - inputStream.close(); - } catch (IOException ignore) { - } - } - } - } - - SslProvider provider = null; - if (OpenSsl.isAvailable()) { - provider = SslProvider.OPENSSL; - LOGGER.info("Using OpenSSL provider"); - } else { - provider = SslProvider.JDK; - LOGGER.info("Using JDK SSL provider"); - } - - if (forClient) { - if (testMode) { - return SslContextBuilder - .forClient() - .sslProvider(SslProvider.JDK) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .build(); - } else { - SslContextBuilder sslContextBuilder = SslContextBuilder.forClient().sslProvider(SslProvider.JDK); - - if ("false".equals(properties.getProperty("client.auth.server"))) { - sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); - } else { - if (properties.containsKey("client.trustManager")) { - sslContextBuilder.trustManager(new File(properties.getProperty("client.trustManager"))); - } - } - - return sslContextBuilder.keyManager( - properties.containsKey("client.keyCertChainFile") ? new File(properties.getProperty("client.keyCertChainFile")) : null, - properties.containsKey("client.keyFile") ? new File(properties.getProperty("client.keyFile")) : null, - properties.containsKey("client.password") ? properties.getProperty("client.password") : null) - .build(); - } - } else { - - if (testMode) { - SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); - return SslContextBuilder - .forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) - .sslProvider(SslProvider.JDK) - .clientAuth(ClientAuth.OPTIONAL) - .build(); - } else { - return SslContextBuilder.forServer( - properties.containsKey("server.keyCertChainFile") ? new File(properties.getProperty("server.keyCertChainFile")) : null, - properties.containsKey("server.keyFile") ? new File(properties.getProperty("server.keyFile")) : null, - properties.containsKey("server.password") ? properties.getProperty("server.password") : null) - .sslProvider(provider) - .trustManager(new File(properties.getProperty("server.trustManager"))) - .clientAuth(parseClientAuthMode(properties.getProperty("server.auth.client"))) - .build(); - } - } - } - - private static ClientAuth parseClientAuthMode(String authMode) { - if (null == authMode || authMode.trim().isEmpty()) { - return ClientAuth.NONE; - } - - if ("optional".equalsIgnoreCase(authMode)) { - return ClientAuth.OPTIONAL; - } - - return ClientAuth.REQUIRE; - } -} diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/TlsHelper.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/TlsHelper.java new file mode 100644 index 00000000..3a74b4b6 --- /dev/null +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/TlsHelper.java @@ -0,0 +1,234 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.apache.rocketmq.remoting.netty; + +import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.OpenSsl; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslProvider; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.netty.handler.ssl.util.SelfSignedCertificate; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.util.Properties; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_AUTHSERVER; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_CERTPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_KEYPASSWORD; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_KEYPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_TRUSTCERTPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_AUTHCLIENT; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_CERTPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_KEYPASSWORD; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_KEYPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_NEED_CLIENT_AUTH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_TRUSTCERTPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_TEST_MODE_ENABLE; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientAuthServer; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientCertPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientKeyPassword; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientKeyPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientTrustCertPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerAuthClient; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerCertPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerKeyPassword; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerKeyPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerNeedClientAuth; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerTrustCertPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsTestModeEnable; + +public class TlsHelper { + + public interface DecryptionStrategy { + /** + * Decrypt the target encrpted private key file. + * + * @param privateKeyEncryptPath A pathname string + * @param forClient tells whether it's a client-side key file + * @return An input stream for a decrypted key file + * @throws IOException if an I/O error has occurred + */ + InputStream decryptPrivateKey(String privateKeyEncryptPath, boolean forClient) throws IOException; + } + + private static final Logger LOGGER = LoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING); + + private static DecryptionStrategy decryptionStrategy = new DecryptionStrategy() { + @Override + public InputStream decryptPrivateKey(final String privateKeyEncryptPath, + final boolean forClient) throws IOException { + return new FileInputStream(privateKeyEncryptPath); + } + }; + + + public static void registerDecryptionStrategy(final DecryptionStrategy decryptionStrategy) { + TlsHelper.decryptionStrategy = decryptionStrategy; + } + + public static SslContext buildSslContext(boolean forClient) throws IOException, CertificateException { + File configFile = new File(TlsSystemConfig.tlsConfigFile); + extractTlsConfigFromFile(configFile); + logTheFinalUsedTlsConfig(); + + SslProvider provider; + if (OpenSsl.isAvailable()) { + provider = SslProvider.OPENSSL; + LOGGER.info("Using OpenSSL provider"); + } else { + provider = SslProvider.JDK; + LOGGER.info("Using JDK SSL provider"); + } + + if (forClient) { + if (tlsTestModeEnable) { + return SslContextBuilder + .forClient() + .sslProvider(SslProvider.JDK) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .build(); + } else { + SslContextBuilder sslContextBuilder = SslContextBuilder.forClient().sslProvider(SslProvider.JDK); + + + if (!tlsClientAuthServer) { + sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); + } else { + if (!isNullOrEmpty(tlsClientTrustCertPath)) { + sslContextBuilder.trustManager(new File(tlsClientTrustCertPath)); + } + } + + return sslContextBuilder.keyManager( + !isNullOrEmpty(tlsClientCertPath) ? new FileInputStream(tlsClientCertPath) : null, + !isNullOrEmpty(tlsClientKeyPath) ? decryptionStrategy.decryptPrivateKey(tlsClientKeyPath, true) : null, + !isNullOrEmpty(tlsClientKeyPassword) ? tlsClientKeyPassword : null) + .build(); + } + } else { + + if (tlsTestModeEnable) { + SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); + return SslContextBuilder + .forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) + .sslProvider(SslProvider.JDK) + .clientAuth(ClientAuth.OPTIONAL) + .build(); + } else { + SslContextBuilder sslContextBuilder = SslContextBuilder.forServer( + !isNullOrEmpty(tlsServerCertPath) ? new FileInputStream(tlsServerCertPath) : null, + !isNullOrEmpty(tlsServerKeyPath) ? decryptionStrategy.decryptPrivateKey(tlsServerKeyPath, false) : null, + !isNullOrEmpty(tlsServerKeyPassword) ? tlsServerKeyPassword : null) + .sslProvider(provider); + + if (!tlsServerAuthClient) { + sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); + } else { + if (!isNullOrEmpty(tlsServerTrustCertPath)) { + sslContextBuilder.trustManager(new File(tlsServerTrustCertPath)); + } + } + + sslContextBuilder.clientAuth(parseClientAuthMode(tlsServerNeedClientAuth)); + return sslContextBuilder.build(); + } + } + } + + private static void extractTlsConfigFromFile(final File configFile) { + if (!(configFile.exists() && configFile.isFile() && configFile.canRead())) { + LOGGER.info("Tls config file doesn't exist, skip it"); + return; + } + + Properties properties; + properties = new Properties(); + InputStream inputStream = null; + try { + inputStream = new FileInputStream(configFile); + properties.load(inputStream); + } catch (IOException ignore) { + } finally { + if (null != inputStream) { + try { + inputStream.close(); + } catch (IOException ignore) { + } + } + } + + tlsTestModeEnable = Boolean.parseBoolean(properties.getProperty(TLS_TEST_MODE_ENABLE, String.valueOf(tlsTestModeEnable))); + tlsServerNeedClientAuth = properties.getProperty(TLS_SERVER_NEED_CLIENT_AUTH, tlsServerNeedClientAuth); + tlsServerKeyPath = properties.getProperty(TLS_SERVER_KEYPATH, tlsServerKeyPath); + tlsServerKeyPassword = properties.getProperty(TLS_SERVER_KEYPASSWORD, tlsServerKeyPassword); + tlsServerCertPath = properties.getProperty(TLS_SERVER_CERTPATH, tlsServerCertPath); + tlsServerAuthClient = Boolean.parseBoolean(properties.getProperty(TLS_SERVER_AUTHCLIENT, String.valueOf(tlsServerAuthClient))); + tlsServerTrustCertPath = properties.getProperty(TLS_SERVER_TRUSTCERTPATH, tlsServerTrustCertPath); + + tlsClientKeyPath = properties.getProperty(TLS_CLIENT_KEYPATH, tlsClientKeyPath); + tlsClientKeyPassword = properties.getProperty(TLS_CLIENT_KEYPASSWORD, tlsClientKeyPassword); + tlsClientCertPath = properties.getProperty(TLS_CLIENT_CERTPATH, tlsClientCertPath); + tlsClientAuthServer = Boolean.parseBoolean(properties.getProperty(TLS_CLIENT_AUTHSERVER, String.valueOf(tlsClientAuthServer))); + tlsClientTrustCertPath = properties.getProperty(TLS_CLIENT_TRUSTCERTPATH, tlsClientTrustCertPath); + } + + private static void logTheFinalUsedTlsConfig() { + LOGGER.info("Log the final used tls related configuration"); + LOGGER.info("{} = {}", TLS_TEST_MODE_ENABLE, tlsTestModeEnable); + LOGGER.info("{} = {}", TLS_SERVER_NEED_CLIENT_AUTH, tlsServerNeedClientAuth); + LOGGER.info("{} = {}", TLS_SERVER_KEYPATH, tlsServerKeyPath); + LOGGER.info("{} = {}", TLS_SERVER_KEYPASSWORD, tlsServerKeyPassword); + LOGGER.info("{} = {}", TLS_SERVER_CERTPATH, tlsServerCertPath); + LOGGER.info("{} = {}", TLS_SERVER_AUTHCLIENT, tlsServerAuthClient); + LOGGER.info("{} = {}", TLS_SERVER_TRUSTCERTPATH, tlsServerTrustCertPath); + + LOGGER.info("{} = {}", TLS_CLIENT_KEYPATH, tlsClientKeyPath); + LOGGER.info("{} = {}", TLS_CLIENT_KEYPASSWORD, tlsClientKeyPassword); + LOGGER.info("{} = {}", TLS_CLIENT_CERTPATH, tlsClientCertPath); + LOGGER.info("{} = {}", TLS_CLIENT_AUTHSERVER, tlsClientAuthServer); + LOGGER.info("{} = {}", TLS_CLIENT_TRUSTCERTPATH, tlsClientTrustCertPath); + } + + private static ClientAuth parseClientAuthMode(String authMode) { + if (null == authMode || authMode.trim().isEmpty()) { + return ClientAuth.NONE; + } + + for (ClientAuth clientAuth : ClientAuth.values()) { + if (clientAuth.name().equals(authMode.toUpperCase())) { + return clientAuth; + } + } + + return ClientAuth.NONE; + } + + /** + * Determine if a string is {@code null} or {@link String#isEmpty()} returns {@code true}. + */ + private static boolean isNullOrEmpty(String s) { + return s == null || s.isEmpty(); + } +} diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/TlsSystemConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/TlsSystemConfig.java new file mode 100644 index 00000000..403bd6c9 --- /dev/null +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/TlsSystemConfig.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.apache.rocketmq.remoting.netty; + +import io.netty.handler.ssl.SslContext; +import org.apache.rocketmq.remoting.common.TlsMode; + +public class TlsSystemConfig { + public static final String TLS_SERVER_MODE = "tls.server.mode"; + public static final String TLS_ENABLE = "tls.enable"; + public static final String TLS_CONFIG_FILE = "tls.config.file"; + public static final String TLS_TEST_MODE_ENABLE = "tls.test.mode.enable"; + + public static final String TLS_SERVER_NEED_CLIENT_AUTH = "tls.server.need.client.auth"; + public static final String TLS_SERVER_KEYPATH = "tls.server.keyPath"; + public static final String TLS_SERVER_KEYPASSWORD = "tls.server.keyPassword"; + public static final String TLS_SERVER_CERTPATH = "tls.server.certPath"; + public static final String TLS_SERVER_AUTHCLIENT = "tls.server.authClient"; + public static final String TLS_SERVER_TRUSTCERTPATH = "tls.server.trustCertPath"; + + public static final String TLS_CLIENT_KEYPATH = "tls.client.keyPath"; + public static final String TLS_CLIENT_KEYPASSWORD = "tls.client.keyPassword"; + public static final String TLS_CLIENT_CERTPATH = "tls.client.certPath"; + public static final String TLS_CLIENT_AUTHSERVER = "tls.client.authServer"; + public static final String TLS_CLIENT_TRUSTCERTPATH = "tls.client.trustCertPath"; + + + /** + * To determine whether use SSL in client-side, include SDK client and BrokerOuterAPI + */ + public static boolean tlsEnable = Boolean.parseBoolean(System.getProperty(TLS_ENABLE, "false")); + + /** + * To determine whether use test mode when initialize TLS context + */ + public static boolean tlsTestModeEnable = Boolean.parseBoolean(System.getProperty(TLS_TEST_MODE_ENABLE, "true")); + + /** + * Indicates the state of the {@link javax.net.ssl.SSLEngine} with respect to client authentication. + * This configuration item really only applies when building the server-side {@link SslContext}, + * and can be set to none, require or optional. + */ + public static String tlsServerNeedClientAuth = System.getProperty(TLS_SERVER_NEED_CLIENT_AUTH, "none"); + /** + * The store path of server-side private key + */ + public static String tlsServerKeyPath = System.getProperty(TLS_SERVER_KEYPATH, null); + + /** + * The password of the server-side private key + */ + public static String tlsServerKeyPassword = System.getProperty(TLS_SERVER_KEYPASSWORD, null); + + /** + * The store path of server-side X.509 certificate chain in PEM format + */ + public static String tlsServerCertPath = System.getProperty(TLS_SERVER_CERTPATH, null); + + /** + * To determine whether verify the client endpoint's certificate strictly + */ + public static boolean tlsServerAuthClient = Boolean.parseBoolean(System.getProperty(TLS_SERVER_AUTHCLIENT, "false")); + + /** + * The store path of trusted certificates for verifying the client endpoint's certificate + */ + public static String tlsServerTrustCertPath = System.getProperty(TLS_SERVER_TRUSTCERTPATH, null); + + /** + * The store path of client-side private key + */ + public static String tlsClientKeyPath = System.getProperty(TLS_CLIENT_KEYPATH, null); + + /** + * The password of the client-side private key + */ + public static String tlsClientKeyPassword = System.getProperty(TLS_CLIENT_KEYPASSWORD, null); + + /** + * The store path of client-side X.509 certificate chain in PEM format + */ + public static String tlsClientCertPath = System.getProperty(TLS_CLIENT_CERTPATH, null); + + /** + * To determine whether verify the server endpoint's certificate strictly + */ + public static boolean tlsClientAuthServer = Boolean.parseBoolean(System.getProperty(TLS_CLIENT_AUTHSERVER, "false")); + + /** + * The store path of trusted certificates for verifying the server endpoint's certificate + */ + public static String tlsClientTrustCertPath = System.getProperty(TLS_CLIENT_TRUSTCERTPATH, null); + + /** + * For server, three SSL modes are supported: disabled, permissive and enforcing. + * For client, use {@link TlsSystemConfig#tlsEnable} to determine whether use SSL. + *
      + *
    1. disabled: SSL is not supported; any incoming SSL handshake will be rejected, causing connection closed.
    2. + *
    3. permissive: SSL is optional, aka, server in this mode can serve client connections with or without SSL;
    4. + *
    5. enforcing: SSL is required, aka, non SSL connection will be rejected.
    6. + *
    + */ + public static TlsMode tlsMode = TlsMode.parse(System.getProperty(TLS_SERVER_MODE, "permissive")); + + /** + * A config file to store the above TLS related configurations, + * except {@link TlsSystemConfig#tlsMode} and {@link TlsSystemConfig#tlsEnable} + */ + public static String tlsConfigFile = System.getProperty(TLS_CONFIG_FILE, "/etc/rocketmq/tls.properties"); +} diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java index 31c26473..0ecfaaa5 100644 --- a/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java +++ b/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java @@ -67,8 +67,11 @@ public class RemotingServerTest { } public static RemotingClient createRemotingClient() { - NettyClientConfig config = new NettyClientConfig(); - RemotingClient client = new NettyRemotingClient(config); + return createRemotingClient(new NettyClientConfig()); + } + + public static RemotingClient createRemotingClient(NettyClientConfig nettyClientConfig) { + RemotingClient client = new NettyRemotingClient(nettyClientConfig); client.start(); return client; } diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java new file mode 100644 index 00000000..5e516dd7 --- /dev/null +++ b/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java @@ -0,0 +1,298 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.apache.rocketmq.remoting; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import org.apache.rocketmq.remoting.common.TlsMode; +import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; +import org.apache.rocketmq.remoting.netty.NettyClientConfig; +import org.apache.rocketmq.remoting.netty.TlsHelper; +import org.apache.rocketmq.remoting.protocol.LanguageCode; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_AUTHSERVER; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_CERTPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_KEYPASSWORD; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_KEYPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_TRUSTCERTPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_AUTHCLIENT; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_CERTPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_KEYPASSWORD; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_KEYPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_NEED_CLIENT_AUTH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_TRUSTCERTPATH; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientAuthServer; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientCertPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientKeyPassword; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientKeyPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientTrustCertPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsConfigFile; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsMode; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerAuthClient; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerCertPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerKeyPassword; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerKeyPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerNeedClientAuth; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerTrustCertPath; +import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsTestModeEnable; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; +import static org.junit.Assert.assertTrue; + +@RunWith(MockitoJUnitRunner.class) +public class TlsTest { + private RemotingServer remotingServer; + private RemotingClient remotingClient; + + @Rule + public TestName name = new TestName(); + + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); + + @Before + public void setUp() throws InterruptedException { + tlsMode = TlsMode.ENFORCING; + tlsTestModeEnable = false; + tlsServerNeedClientAuth = "require"; + tlsServerKeyPath = getCertsPath("server.key"); + tlsServerCertPath = getCertsPath("server.pem"); + tlsServerAuthClient = true; + tlsServerTrustCertPath = getCertsPath("ca.pem"); + tlsClientKeyPath = getCertsPath("client.key"); + tlsClientCertPath = getCertsPath("client.pem"); + tlsClientAuthServer = true; + tlsClientTrustCertPath = getCertsPath("ca.pem"); + tlsClientKeyPassword = "1234"; + tlsServerKeyPassword = ""; + + NettyClientConfig clientConfig = new NettyClientConfig(); + clientConfig.setUseTLS(true); + + if ("serverRejectsUntrustedClientCert".equals(name.getMethodName())) { + // Create a client. Its credentials come from a CA that the server does not trust. The client + // trusts both test CAs to ensure the handshake failure is due to the server rejecting the client's cert. + tlsClientKeyPath = getCertsPath("badClient.key"); + tlsClientCertPath = getCertsPath("badClient.pem"); + } else if ("serverAcceptsUntrustedClientCert".equals(name.getMethodName())) { + tlsClientKeyPath = getCertsPath("badClient.key"); + tlsClientCertPath = getCertsPath("badClient.pem"); + tlsServerAuthClient = false; + } + else if ("noClientAuthFailure".equals(name.getMethodName())) { + //Clear the client cert config to ensure produce the handshake error + tlsClientKeyPath = ""; + tlsClientCertPath = ""; + } else if ("clientRejectsUntrustedServerCert".equals(name.getMethodName())) { + tlsServerKeyPath = getCertsPath("badServer.key"); + tlsServerCertPath = getCertsPath("badServer.pem"); + } else if ("clientAcceptsUntrustedServerCert".equals(name.getMethodName())) { + tlsServerKeyPath = getCertsPath("badServer.key"); + tlsServerCertPath = getCertsPath("badServer.pem"); + tlsClientAuthServer = false; + } else if ("serverNotNeedClientAuth".equals(name.getMethodName())) { + tlsServerNeedClientAuth = "none"; + tlsClientKeyPath = ""; + tlsClientCertPath = ""; + } else if ("serverWantClientAuth".equals(name.getMethodName())) { + tlsServerNeedClientAuth = "optional"; + } else if ("serverWantClientAuth_ButClientNoCert".equals(name.getMethodName())) { + tlsServerNeedClientAuth = "optional"; + tlsClientKeyPath = ""; + tlsClientCertPath = ""; + } else if ("serverAcceptsUnAuthClient".equals(name.getMethodName())) { + tlsMode = TlsMode.PERMISSIVE; + tlsClientKeyPath = ""; + tlsClientCertPath = ""; + clientConfig.setUseTLS(false); + } else if ("serverRejectsSSLClient".equals(name.getMethodName())) { + tlsMode = TlsMode.DISABLED; + } + + remotingServer = RemotingServerTest.createRemotingServer(); + remotingClient = RemotingServerTest.createRemotingClient(clientConfig); + } + + @After + public void tearDown() { + remotingClient.shutdown(); + remotingServer.shutdown(); + tlsMode = TlsMode.PERMISSIVE; + } + + /** + * Tests that a client and a server configured using two-way SSL auth can successfully + * communicate with each other. + */ + @Test + public void basicClientServerIntegrationTest() throws Exception { + requestThenAssertResponse(); + } + + @Test + public void serverNotNeedClientAuth() throws Exception { + requestThenAssertResponse(); + } + + @Test + public void serverWantClientAuth_ButClientNoCert() throws Exception { + requestThenAssertResponse(); + } + + @Test + public void serverAcceptsUnAuthClient() throws Exception { + requestThenAssertResponse(); + } + + @Test + public void serverRejectsSSLClient() throws Exception { + try { + RemotingCommand response = remotingClient.invokeSync("localhost:8888", createRequest(), 1000 * 5); + failBecauseExceptionWasNotThrown(RemotingSendRequestException.class); + } catch (RemotingSendRequestException ignore) { + } + } + + /** + * Tests that a server configured to require client authentication refuses to accept connections + * from a client that has an untrusted certificate. + */ + @Test + public void serverRejectsUntrustedClientCert() throws Exception { + try { + RemotingCommand response = remotingClient.invokeSync("localhost:8888", createRequest(), 1000 * 5); + failBecauseExceptionWasNotThrown(RemotingSendRequestException.class); + } catch (RemotingSendRequestException ignore) { + } + } + + @Test + public void serverAcceptsUntrustedClientCert() throws Exception { + requestThenAssertResponse(); + } + + /** + * Tests that a server configured to require client authentication actually does require client + * authentication. + */ + @Test + public void noClientAuthFailure() throws Exception { + try { + RemotingCommand response = remotingClient.invokeSync("localhost:8888", createRequest(), 1000 * 3); + failBecauseExceptionWasNotThrown(RemotingSendRequestException.class); + } catch (RemotingSendRequestException ignore) { + } + } + + /** + * Tests that a client configured using GrpcSslContexts refuses to talk to a server that has an + * an untrusted certificate. + */ + @Test + public void clientRejectsUntrustedServerCert() throws Exception { + try { + RemotingCommand response = remotingClient.invokeSync("localhost:8888", createRequest(), 1000 * 3); + failBecauseExceptionWasNotThrown(RemotingSendRequestException.class); + } catch (RemotingSendRequestException ignore) { + } + } + + @Test + public void clientAcceptsUntrustedServerCert() throws Exception { + requestThenAssertResponse(); + } + + @Test + public void testTlsConfigThroughFile() throws Exception { + File file = tempFolder.newFile("tls.config"); + tlsTestModeEnable = true; + + tlsConfigFile = file.getAbsolutePath(); + + StringBuilder sb = new StringBuilder(); + sb.append(TLS_SERVER_NEED_CLIENT_AUTH + "=require\n"); + sb.append(TLS_SERVER_KEYPATH + "=/server.key\n"); + sb.append(TLS_SERVER_CERTPATH + "=/server.pem\n"); + sb.append(TLS_SERVER_KEYPASSWORD + "=2345\n"); + sb.append(TLS_SERVER_AUTHCLIENT + "=true\n"); + sb.append(TLS_SERVER_TRUSTCERTPATH + "=/ca.pem\n"); + sb.append(TLS_CLIENT_KEYPATH + "=/client.key\n"); + sb.append(TLS_CLIENT_KEYPASSWORD + "=1234\n"); + sb.append(TLS_CLIENT_CERTPATH + "=/client.pem\n"); + sb.append(TLS_CLIENT_AUTHSERVER + "=false\n"); + sb.append(TLS_CLIENT_TRUSTCERTPATH + "=/ca.pem\n"); + + writeStringToFile(file.getAbsolutePath(), sb.toString()); + TlsHelper.buildSslContext(false); + + assertThat(tlsServerNeedClientAuth).isEqualTo("require"); + assertThat(tlsServerKeyPath).isEqualTo("/server.key"); + assertThat(tlsServerCertPath).isEqualTo("/server.pem"); + assertThat(tlsServerKeyPassword).isEqualTo("2345"); + assertThat(tlsServerAuthClient).isEqualTo(true); + assertThat(tlsServerTrustCertPath).isEqualTo("/ca.pem"); + assertThat(tlsClientKeyPath).isEqualTo("/client.key"); + assertThat(tlsClientKeyPassword).isEqualTo("1234"); + assertThat(tlsClientCertPath).isEqualTo("/client.pem"); + assertThat(tlsClientAuthServer).isEqualTo(false); + assertThat(tlsClientTrustCertPath).isEqualTo("/ca.pem"); + + tlsConfigFile = "/notFound"; + } + + private static void writeStringToFile(String path, String content) { + try { + PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(path, true))); + out.println(content); + out.close(); + } catch (IOException ignore) { + } + } + + private static String getCertsPath(String fileName) { + File resourcesDirectory = new File("src/test/resources/certs"); + return resourcesDirectory.getAbsolutePath() + "/" + fileName; + } + + private static RemotingCommand createRequest() { + RequestHeader requestHeader = new RequestHeader(); + requestHeader.setCount(1); + requestHeader.setMessageTitle("Welcome"); + return RemotingCommand.createRequestCommand(0, requestHeader); + } + + private void requestThenAssertResponse() throws Exception { + RemotingCommand response = remotingClient.invokeSync("localhost:8888", createRequest(), 1000 * 3); + assertTrue(response != null); + assertThat(response.getLanguage()).isEqualTo(LanguageCode.JAVA); + assertThat(response.getExtFields()).hasSize(2); + assertThat(response.getExtFields().get("messageTitle")).isEqualTo("Welcome"); + } +} diff --git a/remoting/src/test/resources/certs/badClient.key b/remoting/src/test/resources/certs/badClient.key new file mode 100644 index 00000000..2dfd7ab1 --- /dev/null +++ b/remoting/src/test/resources/certs/badClient.key @@ -0,0 +1,17 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICoTAbBgkqhkiG9w0BBQMwDgQIc2h7vaLYK6gCAggABIICgNrkvD1Xxez79Jgk +WhRJg06CG8UthncfeuymR4hgp9HIneUzUHOoaf64mpxUbDWe3YOzA29REcBQsjF0 +Rpv+Uyg3cyDG14TmeRoSufOxB3MWLcIenoPPyNNtxe3XXmdkJTXX2YR0j7EOzH2v +qlmuxmN4A7UonV5RdGxCz0sm7bU7EyZKdLO/DwBNxlX7ukcVLxAAqsc7ondclYj0 +SFJKk1nzfysCsk/Pq+q3PAVVpG6x5RFaLVS7Zt+gU6IEp+0S0eeYukkTjGh9PMPl +wjCOcRiR3O+g4b3DevmW8TcoBqAZ2cFaf4lGhYlNBfa9PaQ3spJLL8l8xBbRIs8T +3UnaFIa49r9DO/ZpCwpDeUE+URCx/SpcO6lchWQhdEuFt+DnFKOPYDSCHtHJSWHf +9Z2bltjcYYPy/8nkPeqsO9vn4/r6jo+l7MYWKyWolLCW+7RYbpx5R2s4SBGtBP6w +bwQOtOASbpG+mqTf7+ARpffHaZm9cKoKwobXigjDojPeaBCg5DgRuLIS1tO46Pjg +USJ8sZilXifUwc6qRZ/2KiTSiJYCPMJD2ZTvK2Inkv2qzg6X3kw7CYCaW+iDL9zN +e3ES7bps1wZ6D8cGq80WUQgrtpaGAXLzIv4FvM5yDoqrre/dh/XDO9l2hYfUmRVv +rynKdSxjhhyHaK2ei8cX4LGEIlRNiu9ZIxSYeUAy37IJ0rVC7vtBWTh30JTeMRop +iIPmygBMX2FEhQ2l/eS2lRhiybR0QXA4kCeJkVQas3aMMBGp2ThPNahLpzP82B7V +f9137okQC95/KXRz/ZLYFsJtY/53206mG7gU/+dYsYI4slLAlnSe8k2sS0D9qkWJ +VV9F7PM= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/remoting/src/test/resources/certs/badClient.pem b/remoting/src/test/resources/certs/badClient.pem new file mode 100644 index 00000000..1d264d33 --- /dev/null +++ b/remoting/src/test/resources/certs/badClient.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC8zCCAdsCAQIwDQYJKoZIhvcNAQEFBQAwfDELMAkGA1UEBhMCemgxCzAJBgNV +BAgMAnpqMQswCQYDVQQHDAJoejEPMA0GA1UECgwGYXBhY2hlMREwDwYDVQQLDAhy +b2NrZXRtcTEOMAwGA1UEAwwFeXVrb24xHzAdBgkqhkiG9w0BCQEWEHl1a29uQGFw +YWNoZS5vcmcwHhcNMTcxMjExMDk0NDExWhcNMTgwMTEwMDk0NDExWjCBhjELMAkG +A1UEBhMCemgxCzAJBgNVBAgMAnpqMQswCQYDVQQHDAJoejEPMA0GA1UECgwGYXBh +Y2hlMREwDwYDVQQLDAhyb2NrZXRtcTEWMBQGA1UEAwwNZm9vYmFyLmNsaWVudDEh +MB8GCSqGSIb3DQEJARYSZm9vQGJhci5jbGllbnQuY29tMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQC+3bvrKGF1Y9/kN5UBtf8bXRtxn6L1W6mCRrX6aHBb+vQp +BEYk3Pwu/OLd7TkOC5zwjCIPIlwV4FaYnWh0KooqpmvXuKJLAQBFa8yGWERYys73 +9a/U31cu6lndnG2lZfb47NTy+KdzDYsqB4GfnASqA7PbxJHDU4Fu7wp7gN3HRQID +AQABMA0GCSqGSIb3DQEBBQUAA4IBAQBsFroSKr3MbCq1HjWpCLDEz2uS4LQV6L1G +smNfGNY17ELOcY9uweBBXOsfKVOEizYJJqatbJlz6FmPkIbfsGW2Wospkp1gvYMy +NGL27vX3rB5vOo5vdFITaaV9/dEu53A0iWdsn3wH/FJnMsqBmynb+/3FY+Lff9d1 +XBaXLr+DeBx4lrE8rWTvhWh8gqDkuNLBTygdH0+g8/xkqhQhLqjIlMCSnrG2cTfj +LewizVcX/VZ6DNC2M2vjEFbCShclZHocG80N7udl5KNsLEU2jyO1F61Q0yo+VYGS +7n8dRYgbOKyCjMdu69fAfZvp4aoy1SXqtjMphDh5R7y7mhP60e0A +-----END CERTIFICATE----- diff --git a/remoting/src/test/resources/certs/badServer.key b/remoting/src/test/resources/certs/badServer.key new file mode 100644 index 00000000..de4f7c58 --- /dev/null +++ b/remoting/src/test/resources/certs/badServer.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALBvxESq2VvSpJl1 +skv8SzyPYKgU8bZx37hEOCmoeYvd9gWNfeYZuITng2/5mpWX+zuAgKsgPU66YG0v +++dT5GBQPr0Imb25IMl3xOY2eEiLeMokYiWbnA1C+pw1a27zMqk6pgbcRaMfLdh5 +npusWtqBzZIxqo1TpaOGEmyQTNRlAgMBAAECgYBSigbUZOTIWxObov7lI0MDMsPx +/dJSGpWhe3CWtHUgJJdKY7XpJlE3A6Nuh+N0ZiQm4ufOpodnxDMGAXOj9ZAZY16Y +i7I0ayXepcpTqYqo0o0+ze2x7SECAXe26bqvLRuKG2hpUyM59vAmll9gmQM5n8z4 +ZzoAzqRqkRHdo5bTxQJBAOF6SwSSfb8KEtTjWpJ48W1PO/NmKbW3QsNCWuk/w5p7 +E8L2g3nwakJiFmVNCga74rUbcgbCkw7y/lLeM8yC74MCQQDIUgCN/vuHm+eT85xk +QoVKhDljXzLoog6wTUf5SMtrmUFTbQqyvw5xjHYdp3TWJM/Px8IyLxOr97sSnnft +l7/3AkEAukYLv6U+GRs7X4DMDIG6AjIZNwXJo4PYtfMVo+i3seHH+6MoDw8c2eaq +1dmFVPbXXgNkek04rHr2vIMxi90H/QJAAMOfUOtaFkhX986EGDXQwFoExgZE8XI8 +0BtbXO4UKJLrFuBhnBDygyhgAvjyjyaQzGAcs4hOcOd/BTEpj/R2PQJBANUKa9T9 +qWYhDhWN1Uj7qXhC1j2z/vTAzcYuwhpPRjt3RaVl27itI7cqiGquFhwfKZZFaOh5 +pnnWHv63YbGQ2Qc= +-----END PRIVATE KEY----- diff --git a/remoting/src/test/resources/certs/badServer.pem b/remoting/src/test/resources/certs/badServer.pem new file mode 100644 index 00000000..ada0a94f --- /dev/null +++ b/remoting/src/test/resources/certs/badServer.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC5DCCAcwCAQEwDQYJKoZIhvcNAQEFBQAwfDELMAkGA1UEBhMCemgxCzAJBgNV +BAgMAnpqMQswCQYDVQQHDAJoejEPMA0GA1UECgwGYXBhY2hlMREwDwYDVQQLDAhy +b2NrZXRtcTEOMAwGA1UEAwwFeXVrb24xHzAdBgkqhkiG9w0BCQEWEHl1a29uQGFw +YWNoZS5vcmcwHhcNMTcxMjExMDk0MzE3WhcNMTgwMTEwMDk0MzE3WjB4MQswCQYD +VQQGEwJ6aDELMAkGA1UECAwCemoxCzAJBgNVBAcMAmh6MQ8wDQYDVQQKDAZhcGFj +aGUxETAPBgNVBAsMCHJvY2tldG1xMQ8wDQYDVQQDDAZmb29iYXIxGjAYBgkqhkiG +9w0BCQEWC2Zvb0BiYXIuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw +b8REqtlb0qSZdbJL/Es8j2CoFPG2cd+4RDgpqHmL3fYFjX3mGbiE54Nv+ZqVl/s7 +gICrID1OumBtL/vnU+RgUD69CJm9uSDJd8TmNnhIi3jKJGIlm5wNQvqcNWtu8zKp +OqYG3EWjHy3YeZ6brFragc2SMaqNU6WjhhJskEzUZQIDAQABMA0GCSqGSIb3DQEB +BQUAA4IBAQAx+0Se3yIvUOe23oQp6UecaHtfXJCZmi1p5WbwJi7jUcYz78JB8oBj +tVsa+1jftJG+cJJxqgxo2IeIAVbcEteO19xm7dc8tgfH/Bl0rxQz4WEYKb2oF/EQ +eRgcvj4uZ0d9WuprAvJgA4r0Slu2ZZ0cVkzi06NevTweTBYIKFzHaPShqUWEw8ki +42V5jAtRve7sT0c4TH/01dd2fs3V4Ul3E2U3LOP6VizIfKckdht0Bh6B6/5L8wvH +4l1f4ni7w34vXGANpmTP2FGjQQ3kYjKL7GzgMphh3Kozhil6g1GLMhxvp6ccCA9W +m5g0cPa3RZnjI/FoD0lZ5S1Q5s9qXbLm +-----END CERTIFICATE----- diff --git a/remoting/src/test/resources/certs/ca.pem b/remoting/src/test/resources/certs/ca.pem new file mode 100644 index 00000000..d33cb49c --- /dev/null +++ b/remoting/src/test/resources/certs/ca.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyzCCArOgAwIBAgIJAKzXC2VLdPclMA0GCSqGSIb3DQEBBQUAMHwxCzAJBgNV +BAYTAnpoMQswCQYDVQQIDAJ6ajELMAkGA1UEBwwCaHoxDzANBgNVBAoMBmFwYWNo +ZTERMA8GA1UECwwIcm9ja2V0bXExDjAMBgNVBAMMBXl1a29uMR8wHQYJKoZIhvcN +AQkBFhB5dWtvbkBhcGFjaGUub3JnMB4XDTE3MTIxMTA5MjUxNFoXDTE4MDExMDA5 +MjUxNFowfDELMAkGA1UEBhMCemgxCzAJBgNVBAgMAnpqMQswCQYDVQQHDAJoejEP +MA0GA1UECgwGYXBhY2hlMREwDwYDVQQLDAhyb2NrZXRtcTEOMAwGA1UEAwwFeXVr +b24xHzAdBgkqhkiG9w0BCQEWEHl1a29uQGFwYWNoZS5vcmcwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDLUZi/zPj+7sYbfTng/gJeHpvvrWZkiudNwh1t +5kxAusrJyGBkGm+xmRPJeQPZzbhfwfrz/UiQSbjlyV4K+SEZuNIHBSU80aTnXFWg +wIgIAKvu3ZwYkcTjSDBvZv1DgbRkuqAB5ExsJ4vovoNqZcsLFLKsqT1G7lTAwRKU +/FTKgD4g/zvhEoolonzKuk7CPivfKWFzcTpe8zRQlI0O9+j9Pq38F+5yxP7atK/b +uYw36Efgt8nbkjusWIyXibpDMbAUroJNNYlFnunb+XKLpslkrIrfLGiMUq2Ru940 +ooQaANYWzogRQeIofsMN6H9CCRXtVIzcgJJU3wWXGXPRuNr7AgMBAAGjUDBOMB0G +A1UdDgQWBBTd3bmAcazOY2/TI/h4zaGhni+nJzAfBgNVHSMEGDAWgBTd3bmAcazO +Y2/TI/h4zaGhni+nJzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBp +KRcnYsVtFZJejyt02+7SaMudTNRgh5SexFWsl1O7qWUc+fMVgMHHDzGRbkdevcdZ +9uKDwUoa6M1wlOeosTTfQlH9b/AwW6QT7KqdpcpMXlmoV/PNCAVt2QeVclmplvqo +Rx8qUHNckvvzNZt1W6AkBG93P0BLK/3FMJDyYmxkstwnpBPf/3A+t5k2INUI7yQf +B3Tqzs/4iQ3idCLqz2WhTNUYpZOREtpJMcFaOdMsGNnIF+LvkKGij0MPVd/mwJtL +UvQXwbOWpCS7A73sWFqPnrSzpi4VwcvAsi8lUYXsc0H064oagb58zvYz3kXqybcb +KQntj5dP4C3lLHUTTcAV +-----END CERTIFICATE----- diff --git a/remoting/src/test/resources/certs/client.key b/remoting/src/test/resources/certs/client.key new file mode 100644 index 00000000..c30daea2 --- /dev/null +++ b/remoting/src/test/resources/certs/client.key @@ -0,0 +1,17 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICoTAbBgkqhkiG9w0BBQMwDgQI1vtPpDhOYRcCAggABIICgMHwgw0p9fx95R/+ +cWnNdEq8I3ZOOy2wDjammFvPrYXcCJzS3Xg/0GDJ8pdJRKrI7253e4u3mxf5oMuY +RrvpB3KfdelU1k/5QKqOxL/N0gQafQLViN53f6JelyBEAmO1UxQtKZtkTrdZg8ZP +0u1cPPWxmgNdn1Xx3taMw+Wo05ysHjnHJhOEDQ2WT3VXigiRmFSX3H567yjYMRD+ +zmvBq+qqR9JPbH9Cn7X1oRXX6c8VsZHWF/Ds0I4i+5zJxsSIuNZxjZw9XXNgXtFv +7FEFC0HDgDQQUY/FNPUbmjQUp1y0YxoOBjlyIqBIx5FWxu95p2xITS0OimQPFT0o +IngaSb+EKRDhqpLxxIVEbDdkQrdRqcmmLGJioAysExTBDsDwkaEJGOp44bLDM4QW +SIA9SB01omuCXgn7RjUyVXb5g0Lz+Nvsfp1YXUkPDO9hILfz3eMHDSW7/FzbB81M +r8URaTagQxBZnvIoCoWszLDXn3JwEjpZEA6y55Naptps3mMRf7+XMt42lX0e4y9a +ogNu5Zw/RZD9YcaTjC2z5XeKiMCs1Ymhy9iuzbo+eRGESqzvUE4VirtsiEwxJRci +JHAvuAl3X4XnpTty4ahOU+DihM9lALxdU68CN9++7mx581pYuvjzrV+Z5+PuptZX +AjCZmkZLDh8TCHSzWRqvP/Hcvo9BjW8l1Lq6tOa222PefSNCc6gs6Hq+jUghbabZ +/ux4WuFc0Zd6bfQWAZohSvd78/ixsdJPNGm2OP+LUIrEDKIkLuH1PM0uq4wzJZNu +Bo7oJ5iFWF67u3MC8oq+BqOVKDNWaCMi7iiSrN2XW8FBo/rpx4Lf/VYREL+Y0mP6 +vzJrZqw= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/remoting/src/test/resources/certs/client.pem b/remoting/src/test/resources/certs/client.pem new file mode 100644 index 00000000..31412fea --- /dev/null +++ b/remoting/src/test/resources/certs/client.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC8zCCAdsCAQIwDQYJKoZIhvcNAQEFBQAwfDELMAkGA1UEBhMCemgxCzAJBgNV +BAgMAnpqMQswCQYDVQQHDAJoejEPMA0GA1UECgwGYXBhY2hlMREwDwYDVQQLDAhy +b2NrZXRtcTEOMAwGA1UEAwwFeXVrb24xHzAdBgkqhkiG9w0BCQEWEHl1a29uQGFw +YWNoZS5vcmcwHhcNMTcxMjExMDkyOTUyWhcNMTgwMTEwMDkyOTUyWjCBhjELMAkG +A1UEBhMCemgxCzAJBgNVBAgMAnpqMQswCQYDVQQHDAJoejEPMA0GA1UECgwGYXBh +Y2hlMREwDwYDVQQLDAhyb2NrZXRtcTEWMBQGA1UEAwwNZm9vYmFyLmNsaWVudDEh +MB8GCSqGSIb3DQEJARYSZm9vQGJhci5jbGllbnQuY29tMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDoz5Uo2ZN+1ywSQXORv6kDbDXVQ72ZxBp7a6ltFLh4xdk/ +yz7bBjmryz+cAh759s8DEdngl2cCnSiM0r5NC91zox/12Di4EWt3IPdJVe1s5/VD +Bqt5zoxbYyDgz47c95cGALgLdTB/itBPgobghQYBanWPVBNLLltw19DLf1gd6QID +AQABMA0GCSqGSIb3DQEBBQUAA4IBAQDEpVFFcFILdnEXjyDSbgJ8rxXaUYV2aK+a +lgrYfoHBv83MlEuHbydmHBoTL7BmPIL7JCIfufvRnnyBwcECi0E6qFbvMYNoMy6b +OUiTq3nAnPSSoOgi2MxFxpGaOE0s2dp4K9U5nV6bXKLIwIZbJAiZT6aPVenNYJbv +4arzFDe0Yjs/l3VYn2k9TjiiU2fxaW/8Ikx6o9nGWLTKeX/WtXfBNISqOPIL5dPF +eaf0YKCVzvBQ3dIJiUyanRP1BCJJFrCsrPpyu4xFprbjRmDTnOpYB6CdIas5TMC8 +6HzB1fSFoltNEiCjlnLlfjpb5ueSLSbs6h1A7VH7NUEmLmncSlHf +-----END CERTIFICATE----- diff --git a/remoting/src/test/resources/certs/privkey.pem b/remoting/src/test/resources/certs/privkey.pem new file mode 100644 index 00000000..69555680 --- /dev/null +++ b/remoting/src/test/resources/certs/privkey.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIBTqUKpwFlcUCAggA +MBQGCCqGSIb3DQMHBAii5M3Oni0WEwSCBMj5amhdPBva0QxgsWWrSBkfvmc3QQbl +YQE5gHXzL5oaG0lbXCLQe19pr9jFckdDH8uPIi+aRie3WpZXzYLdihjsV0CgE7iy +90ac9fgzIZbJIk/WQIDgwUZm5dEYo2v+B0WwKiD5IHzlTlXM6HVv+DRdPwKjHjAt +TCcCSPUgjKVxHWFtQzY7mqo8P8wcNQHGkEfoQQub6tEsUDeesjS0FoK5Z2oYsmhW +d0PNuGXw3UIMbG109DmC2ILFuTf5WSc7mxI11qL9Z5wTmcFqN7KKb8+MIQEoteni +HICOFfKQWn8er14lmYw9anQAyaeyF/JnYkmVB8vaHBFYs/5EFZtvznpEIIhLKCuG +lve8PJQmfWuBlPdwwJhCXHrLvjfwku4jUF8febU0BHZ5HETaB195g8r9RWfdZcrG +f3fMO4Kq/YoP6oSxKhMP4L2pwj57EMV9N5P87ZyDFNp9BwgIjCawDRUc1Gi9YKak +rpDNabTCr0I3NW27VGGF9m/mby7BLragc01LgTH7SFWS+1D/61/V2YBDFmWn2yV4 +4eKGeBkR3w0m/nWWfNXko8UzM/hjJ4P7Njq8HXdvEpnbDRZWzwdTGWTEvn/TAI3h +j7vmWUHdpOQgb0WGlvEUx3V9wi2Fc1rCseHtYZgLf3KdKYHauPAMSON7KBtKaFuU +6685sUoJbhahN7ILfP3sDxM3VYjSvlPL00lgOdqDT/iO6pNXvnNnQROCCE4kcOQT +uSnEu+wmFHj+QlC60ftRl6zGVqjBxf1+TGmzTEByAOfZtEQ8V/clzRI4BCxYbCAG +mJSa+q1RSju8yClBkXGT2zfhUeNqJnXEIaD/uXCPVGg7hfLyCcVVSmL97aw9QAIe +lBJN/4bdxXLnJaHFKyztRe9N97JAKY9HAPMKKhKtqprWB7LedTIPHtXnpoSjyTrG +SEtlOTQ38s3v9bUPXqF7TYZb+ytj5bIQpl6+WqF9ZNj3gRyx7rcsILhBBg08olVQ +WZwr7LlIxUcDlrbYmrwd9lsMz2nOW2CLCD7mVqJQa2Wm35l6vJHQAI0WiQlHnopC +M2Y49JruWWim2lC8ZzHgTyiU54bIfkXKQxua8G5WGxpW4dDRrM1d0uYe9M1TOqvP +jFxq+XEIj/LntJpY7XIZs+33wuNLIVvkee9zsap++zYNH+KIGmbXz/HUO6gYeJYw +EeaBTLfXtNlgHV9TpMjj3Js6p8hMoVDx27kzPOXa3nrFbHiHmUYY39ZSBCE53Wew +SKIr/FlKtthzJwJkoMNxxsZ1QcI6WgmRANSC4oP9OyM+hPnWlISJZsy9UlXRZNEJ +1lI8P/FUbdk/hsRN98j4pb/hzI0yyG1tKaj0TBipjdEsxfthKdwS2sE1wG+F2hrg +A1jG+UOYmreQjCbrzEiq0J0H4wSL6/s/zN7SyXIWBG0UFalWFiehG5242mEOyX03 +0Yi94mPhF/kcqYsWZ/JJo6cq/EqgIeIqEzkbKx+TOsXk13K2y6apgvCxeHDDv3yT +DqQueRgFicl0319yEK8ARnREFBm8D5oqwMHjJzVzjrqhFGLW1jfQG9HEW5A+s8WF +d+2OtH1o/jVdAPXoP1DnxdF+G7fNXDI4cyjejC7uhLuxHCOx648UpRE9+mCiI2IO +LDM= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/remoting/src/test/resources/certs/server.key b/remoting/src/test/resources/certs/server.key new file mode 100644 index 00000000..30df6961 --- /dev/null +++ b/remoting/src/test/resources/certs/server.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOsmp4YtrIRsBdBQ +LyPImafCRynTJls3NNF4g6nZr9e0efBY830gw9kBebcm603sdZNl95fzRr2+srXi +5FJbG7Fmq1+F0xLNK/kKWirGtNMT2DubmhVdKyXYJSvInoGRkrQzbOG0MdAyzE6Q +O6OjjNN+xGkmadWyCyNF6S8YqMJTAgMBAAECgYEAj0OlnOIG0Ube4+N2VN7KfqKm +qJy0Ka6gx14dGUY/E7Qo9n27GujzaSq09RkJExiVKZBeIH1fBAtC5f2uDV7kpy0l +uNpTpQkbw0g2EQLxDsVwaUEYbu+t9qVeXoDd1vFeoXHBuRwvI9UW1BrxVtvKODia +5StU8Lw4yjcm2lQalwECQQD/sKj56thIsIY7D9qBHk7fnFLd8aYzhnP2GsbZX4V/ +T1KHRxr/8MqdNQX53DE5qcyM/Mqu95FIpTAniUtvcBujAkEA62+fAMYFTAEWj4Z4 +vCmcoPqfVPWhBKFR/wo3L8uUARiIzlbYNU3LIqC2s16QO50+bLUd41oVHNw9Y+uM +fxQpkQJACg/WpncSadHghmR6UchyjCQnsqo2wyJQX+fv2VAD/d2OPtqSem3sW0Fh +6dI7cax36zhrdXUyl2xAt92URV9hBwJALX93sdWSxnpbWsc449wCydVFH00MnfFz +AB+ARLtJ0eBk58M+qyZqgDmgtQ8sPmkH3EgwC3SoKdiiAIJPt2s1EQJBAKnISZZr +qB2F2PfAW2JJbQlrPyVzkxhv9XYdiVNOErmuxLFae3AI7nECgGuFBtvmeqzm2yRj +7RBMCmzyWG7MF3o= +-----END PRIVATE KEY----- diff --git a/remoting/src/test/resources/certs/server.pem b/remoting/src/test/resources/certs/server.pem new file mode 100644 index 00000000..b73e33ef --- /dev/null +++ b/remoting/src/test/resources/certs/server.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC5DCCAcwCAQEwDQYJKoZIhvcNAQEFBQAwfDELMAkGA1UEBhMCemgxCzAJBgNV +BAgMAnpqMQswCQYDVQQHDAJoejEPMA0GA1UECgwGYXBhY2hlMREwDwYDVQQLDAhy +b2NrZXRtcTEOMAwGA1UEAwwFeXVrb24xHzAdBgkqhkiG9w0BCQEWEHl1a29uQGFw +YWNoZS5vcmcwHhcNMTcxMjExMDkyNjIwWhcNMTgwMTEwMDkyNjIwWjB4MQswCQYD +VQQGEwJ6aDELMAkGA1UECAwCemoxCzAJBgNVBAcMAmh6MQ8wDQYDVQQKDAZhcGFj +aGUxETAPBgNVBAsMCHJvY2tldG1xMQ8wDQYDVQQDDAZmb29iYXIxGjAYBgkqhkiG +9w0BCQEWC2Zvb0BiYXIuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr +JqeGLayEbAXQUC8jyJmnwkcp0yZbNzTReIOp2a/XtHnwWPN9IMPZAXm3JutN7HWT +ZfeX80a9vrK14uRSWxuxZqtfhdMSzSv5CloqxrTTE9g7m5oVXSsl2CUryJ6BkZK0 +M2zhtDHQMsxOkDujo4zTfsRpJmnVsgsjRekvGKjCUwIDAQABMA0GCSqGSIb3DQEB +BQUAA4IBAQCmhSgxU5PRhBD2qahj2eWKcmz3FCevXgfyN/EUrwI2dZTU5fXPP+m9 +YBLAYUINI0eYGWt0wlGJ6UFyEgt1fcXP3gqsye9fjECmWoae1kVjvYdaxYGsEXrM +bxSum1D1bz6yRA+eSOaT5aesfw1ZL74AkIq5aRKQ4cgLGzlbIYeoa62XcAj6GrBo +V2s/mvKCc1FPrqnpUlTTYFM9eRbEyC7HkOm9c+NAy6FqoLFr3tegH+q8ZxENDw4k +z9gojQ6t1LDPOAmLGHwvMshHa841CwfOduSvzldtxzjnLVUvYB9cyXS1JXvuC9jj +Q6BOXIYI+0HVgkJbcPOIYDlgC+g6QJqf +-----END CERTIFICATE----- -- GitLab