diff --git a/client/pom.xml b/client/pom.xml
index 8e056ac68..a17bc85f7 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -22,6 +22,7 @@
2.2
3.0.1
1.2.78
+ 1.69
@@ -239,5 +240,10 @@
fastjson
${fastjson.version}
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ ${bouncycastle.version}
+
diff --git a/client/src/main/fbthrift/com/facebook/thrift/transport/TSocket.java b/client/src/main/fbthrift/com/facebook/thrift/transport/TSocket.java
index 47160f930..e95168876 100644
--- a/client/src/main/fbthrift/com/facebook/thrift/transport/TSocket.java
+++ b/client/src/main/fbthrift/com/facebook/thrift/transport/TSocket.java
@@ -70,6 +70,37 @@ public TSocket(Socket socket) throws TTransportException {
}
}
+ /**
+ * Constructor that takes an already created socket that comes alone with timeout
+ * and connectionTimeout.
+ *
+ * @param socket Already created socket object
+ * @param timeout Socket timeout
+ * @param connectionTimeout Socket connection timeout
+ * @throws TTransportException if there is an error setting up the streams
+ */
+ public TSocket(Socket socket, int timeout, int connectionTimeout) throws TTransportException {
+ socket_ = socket;
+ try {
+ socket_.setSoLinger(false, 0);
+ socket_.setTcpNoDelay(true);
+ socket_.setSoTimeout(timeout);
+ connectionTimeout_ = connectionTimeout;
+ } catch (SocketException sx) {
+ LOGGER.warn("Could not configure socket.", sx);
+ }
+
+ if (isOpen()) {
+ try {
+ inputStream_ = new BufferedInputStream(socket_.getInputStream());
+ outputStream_ = new BufferedOutputStream(socket_.getOutputStream());
+ } catch (IOException iox) {
+ close();
+ throw new TTransportException(TTransportException.NOT_OPEN, iox);
+ }
+ }
+ }
+
/**
* Creates a new unconnected socket that will connect to the given host on the given port.
*
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/NebulaPoolConfig.java b/client/src/main/java/com/vesoft/nebula/client/graph/NebulaPoolConfig.java
index 3e1f70110..60bba75ea 100644
--- a/client/src/main/java/com/vesoft/nebula/client/graph/NebulaPoolConfig.java
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/NebulaPoolConfig.java
@@ -6,6 +6,8 @@
package com.vesoft.nebula.client.graph;
+import com.vesoft.nebula.client.graph.data.SSLParam;
+
public class NebulaPoolConfig {
// The min connections in pool for all addresses
private int minConnsSize = 0;
@@ -27,6 +29,28 @@ public class NebulaPoolConfig {
// the wait time to get idle connection, unit ms
private int waitTime = 0;
+ // set to true to turn on ssl encrypted traffic
+ private boolean enableSsl = false;
+
+ // ssl param is required if ssl is turned on
+ private SSLParam sslParam = null;
+
+ public boolean isEnableSsl() {
+ return enableSsl;
+ }
+
+ public void setEnableSsl(boolean enableSsl) {
+ this.enableSsl = enableSsl;
+ }
+
+ public SSLParam getSslParam() {
+ return sslParam;
+ }
+
+ public void setSslParam(SSLParam sslParam) {
+ this.sslParam = sslParam;
+ }
+
public int getMinConnSize() {
return minConnsSize;
}
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/data/CASignedSSLParam.java b/client/src/main/java/com/vesoft/nebula/client/graph/data/CASignedSSLParam.java
new file mode 100644
index 000000000..9667c70f9
--- /dev/null
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/data/CASignedSSLParam.java
@@ -0,0 +1,32 @@
+/* Copyright (c) 2021 vesoft inc. All rights reserved.
+ *
+ * This source code is licensed under Apache 2.0 License,
+ * attached with Common Clause Condition 1.0, found in the LICENSES directory.
+ */
+
+package com.vesoft.nebula.client.graph.data;
+
+public class CASignedSSLParam extends SSLParam {
+ private String caCrtFilePath;
+ private String crtFilePath;
+ private String keyFilePath;
+
+ public CASignedSSLParam(String caCrtFilePath, String crtFilePath, String keyFilePath) {
+ super(SignMode.CA_SIGNED);
+ this.caCrtFilePath = caCrtFilePath;
+ this.crtFilePath = crtFilePath;
+ this.keyFilePath = keyFilePath;
+ }
+
+ public String getCaCrtFilePath() {
+ return caCrtFilePath;
+ }
+
+ public String getCrtFilePath() {
+ return crtFilePath;
+ }
+
+ public String getKeyFilePath() {
+ return keyFilePath;
+ }
+}
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/data/SSLParam.java b/client/src/main/java/com/vesoft/nebula/client/graph/data/SSLParam.java
new file mode 100644
index 000000000..1a19ec48d
--- /dev/null
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/data/SSLParam.java
@@ -0,0 +1,25 @@
+/* Copyright (c) 2021 vesoft inc. All rights reserved.
+ *
+ * This source code is licensed under Apache 2.0 License,
+ * attached with Common Clause Condition 1.0, found in the LICENSES directory.
+ */
+
+package com.vesoft.nebula.client.graph.data;
+
+public abstract class SSLParam {
+ public enum SignMode {
+ NONE,
+ SELF_SIGNED,
+ CA_SIGNED
+ }
+
+ private SignMode signMode;
+
+ public SSLParam(SignMode signMode) {
+ this.signMode = signMode;
+ }
+
+ public SignMode getSignMode() {
+ return signMode;
+ }
+}
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/data/SelfSignedSSLParam.java b/client/src/main/java/com/vesoft/nebula/client/graph/data/SelfSignedSSLParam.java
new file mode 100644
index 000000000..d10046a6d
--- /dev/null
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/data/SelfSignedSSLParam.java
@@ -0,0 +1,32 @@
+/* Copyright (c) 2021 vesoft inc. All rights reserved.
+ *
+ * This source code is licensed under Apache 2.0 License,
+ * attached with Common Clause Condition 1.0, found in the LICENSES directory.
+ */
+
+package com.vesoft.nebula.client.graph.data;
+
+public class SelfSignedSSLParam extends SSLParam {
+ private String crtFilePath;
+ private String keyFilePath;
+ private String password;
+
+ public SelfSignedSSLParam(String crtFilePath, String keyFilePath, String password) {
+ super(SignMode.SELF_SIGNED);
+ this.crtFilePath = crtFilePath;
+ this.keyFilePath = keyFilePath;
+ this.password = password;
+ }
+
+ public String getCrtFilePath() {
+ return crtFilePath;
+ }
+
+ public String getKeyFilePath() {
+ return keyFilePath;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+}
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/net/ConnObjectPool.java b/client/src/main/java/com/vesoft/nebula/client/graph/net/ConnObjectPool.java
index ac043fa2d..9e2ebd4ab 100644
--- a/client/src/main/java/com/vesoft/nebula/client/graph/net/ConnObjectPool.java
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/net/ConnObjectPool.java
@@ -9,7 +9,7 @@
public class ConnObjectPool extends BasePooledObjectFactory {
private final NebulaPoolConfig config;
- private LoadBalancer loadBalancer;
+ private final LoadBalancer loadBalancer;
private static final int retryTime = 3;
public ConnObjectPool(LoadBalancer loadBalancer, NebulaPoolConfig config) {
@@ -28,7 +28,15 @@ public SyncConnection create() throws IOErrorException {
SyncConnection conn = new SyncConnection();
while (retry-- > 0) {
try {
- conn.open(address, config.getTimeout());
+ if (config.isEnableSsl()) {
+ if (config.getSslParam() == null) {
+ throw new IllegalArgumentException("SSL Param is required when enableSsl "
+ + "is set to true");
+ }
+ conn.open(address, config.getTimeout(), config.getSslParam());
+ } else {
+ conn.open(address, config.getTimeout());
+ }
return conn;
} catch (IOErrorException e) {
if (retry == 0) {
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/net/Connection.java b/client/src/main/java/com/vesoft/nebula/client/graph/net/Connection.java
index 1cbd1ba3e..5f94f1c84 100644
--- a/client/src/main/java/com/vesoft/nebula/client/graph/net/Connection.java
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/net/Connection.java
@@ -1,6 +1,7 @@
package com.vesoft.nebula.client.graph.net;
import com.vesoft.nebula.client.graph.data.HostAddress;
+import com.vesoft.nebula.client.graph.data.SSLParam;
import com.vesoft.nebula.client.graph.exception.IOErrorException;
public abstract class Connection {
@@ -10,6 +11,9 @@ public HostAddress getServerAddress() {
return this.serverAddr;
}
+ public abstract void open(HostAddress address, int timeout, SSLParam sslParam)
+ throws IOErrorException;
+
public abstract void open(HostAddress address, int timeout) throws IOErrorException;
public abstract void reopen() throws IOErrorException;
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/net/NebulaPool.java b/client/src/main/java/com/vesoft/nebula/client/graph/net/NebulaPool.java
index b5c6cd567..6fe80a2ba 100644
--- a/client/src/main/java/com/vesoft/nebula/client/graph/net/NebulaPool.java
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/net/NebulaPool.java
@@ -85,7 +85,9 @@ public boolean init(List addresses, NebulaPoolConfig config)
checkConfig(config);
this.waitTime = config.getWaitTime();
List newAddrs = hostToIp(addresses);
- this.loadBalancer = new RoundRobinLoadBalancer(newAddrs, config.getTimeout());
+ this.loadBalancer = config.isEnableSsl()
+ ? new RoundRobinLoadBalancer(newAddrs, config.getTimeout(), config.getSslParam())
+ : new RoundRobinLoadBalancer(newAddrs, config.getTimeout());
ConnObjectPool objectPool = new ConnObjectPool(this.loadBalancer, config);
this.objectPool = new GenericObjectPool<>(objectPool);
GenericObjectPoolConfig objConfig = new GenericObjectPoolConfig();
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/net/RoundRobinLoadBalancer.java b/client/src/main/java/com/vesoft/nebula/client/graph/net/RoundRobinLoadBalancer.java
index 661dcaa80..9e7c9402a 100644
--- a/client/src/main/java/com/vesoft/nebula/client/graph/net/RoundRobinLoadBalancer.java
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/net/RoundRobinLoadBalancer.java
@@ -1,6 +1,7 @@
package com.vesoft.nebula.client.graph.net;
import com.vesoft.nebula.client.graph.data.HostAddress;
+import com.vesoft.nebula.client.graph.data.SSLParam;
import com.vesoft.nebula.client.graph.exception.IOErrorException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -21,6 +22,8 @@ public class RoundRobinLoadBalancer implements LoadBalancer {
private final AtomicInteger pos = new AtomicInteger(0);
private final int delayTime = 60; // unit seconds
private final ScheduledExecutorService schedule = Executors.newScheduledThreadPool(1);
+ private SSLParam sslParam;
+ private boolean enabledSsl;
public RoundRobinLoadBalancer(List addresses, int timeout) {
this.timeout = timeout;
@@ -31,6 +34,12 @@ public RoundRobinLoadBalancer(List addresses, int timeout) {
schedule.scheduleAtFixedRate(this::scheduleTask, 0, delayTime, TimeUnit.SECONDS);
}
+ public RoundRobinLoadBalancer(List addresses, int timeout, SSLParam sslParam) {
+ this(addresses,timeout);
+ this.sslParam = sslParam;
+ this.enabledSsl = true;
+ }
+
public void close() {
schedule.shutdownNow();
}
@@ -63,7 +72,11 @@ public void updateServersStatus() {
public boolean ping(HostAddress addr) {
try {
Connection connection = new SyncConnection();
- connection.open(addr, this.timeout);
+ if (enabledSsl) {
+ connection.open(addr, this.timeout, sslParam);
+ } else {
+ connection.open(addr, this.timeout);
+ }
connection.close();
return true;
} catch (IOErrorException e) {
diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/net/SyncConnection.java b/client/src/main/java/com/vesoft/nebula/client/graph/net/SyncConnection.java
index 08a5e0a3b..4e6a77161 100644
--- a/client/src/main/java/com/vesoft/nebula/client/graph/net/SyncConnection.java
+++ b/client/src/main/java/com/vesoft/nebula/client/graph/net/SyncConnection.java
@@ -15,23 +15,64 @@
import com.facebook.thrift.transport.TTransportException;
import com.facebook.thrift.utils.StandardCharsets;
import com.vesoft.nebula.ErrorCode;
+import com.vesoft.nebula.client.graph.data.CASignedSSLParam;
import com.vesoft.nebula.client.graph.data.HostAddress;
+import com.vesoft.nebula.client.graph.data.SSLParam;
+import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam;
import com.vesoft.nebula.client.graph.exception.AuthFailedException;
import com.vesoft.nebula.client.graph.exception.IOErrorException;
import com.vesoft.nebula.graph.AuthResponse;
import com.vesoft.nebula.graph.ExecutionResponse;
import com.vesoft.nebula.graph.GraphService;
+import com.vesoft.nebula.util.SslUtil;
+import java.io.IOException;
+import javax.net.ssl.SSLSocketFactory;
public class SyncConnection extends Connection {
protected TTransport transport = null;
protected TProtocol protocol = null;
private GraphService.Client client = null;
private int timeout = 0;
+ private SSLParam sslParam = null;
+ private boolean enabledSsl = false;
+
+ @Override
+ public void open(HostAddress address, int timeout, SSLParam sslParam) throws IOErrorException {
+ try {
+ SSLSocketFactory sslSocketFactory;
+
+ this.serverAddr = address;
+ this.timeout = timeout <= 0 ? Integer.MAX_VALUE : timeout;
+ this.enabledSsl = true;
+ this.sslParam = sslParam;
+ if (sslParam.getSignMode() == SSLParam.SignMode.CA_SIGNED) {
+ sslSocketFactory =
+ SslUtil.getSSLSocketFactoryWithCA((CASignedSSLParam) sslParam);
+ } else {
+ sslSocketFactory =
+ SslUtil.getSSLSocketFactoryWithoutCA((SelfSignedSSLParam) sslParam);
+ }
+ if (sslSocketFactory == null) {
+ throw new IOErrorException(IOErrorException.E_UNKNOWN,
+ "SSL Socket Factory Creation failed");
+ }
+ this.transport = new TSocket(
+ sslSocketFactory.createSocket(address.getHost(),
+ address.getPort()), this.timeout, this.timeout);
+ this.protocol = new TCompactProtocol(transport);
+ client = new GraphService.Client(protocol);
+ } catch (TException e) {
+ throw new IOErrorException(IOErrorException.E_UNKNOWN, e.getMessage());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
@Override
public void open(HostAddress address, int timeout) throws IOErrorException {
- this.serverAddr = address;
try {
+ this.enabledSsl = false;
+ this.serverAddr = address;
this.timeout = timeout <= 0 ? Integer.MAX_VALUE : timeout;
this.transport = new TSocket(
address.getHost(), address.getPort(), this.timeout, this.timeout);
@@ -56,7 +97,11 @@ public void open(HostAddress address, int timeout) throws IOErrorException {
@Override
public void reopen() throws IOErrorException {
close();
- open(serverAddr, timeout);
+ if (enabledSsl) {
+ open(serverAddr, timeout, sslParam);
+ } else {
+ open(serverAddr, timeout);
+ }
}
public AuthResult authenticate(String user, String password)
@@ -143,6 +188,7 @@ public boolean ping() {
execute(0, "YIELD 1;");
return true;
} catch (IOErrorException e) {
+ e.printStackTrace();
return false;
}
}
diff --git a/client/src/main/java/com/vesoft/nebula/util/SslUtil.java b/client/src/main/java/com/vesoft/nebula/util/SslUtil.java
new file mode 100644
index 000000000..e75087e10
--- /dev/null
+++ b/client/src/main/java/com/vesoft/nebula/util/SslUtil.java
@@ -0,0 +1,213 @@
+/* Copyright (c) 2021 vesoft inc. All rights reserved.
+ *
+ * This source code is licensed under Apache 2.0 License,
+ * attached with Common Clause Condition 1.0, found in the LICENSES directory.
+ */
+
+package com.vesoft.nebula.util;
+
+import com.vesoft.nebula.client.graph.data.CASignedSSLParam;
+import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam;
+import java.io.FileReader;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMDecryptorProvider;
+import org.bouncycastle.openssl.PEMEncryptedKeyPair;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SslUtil {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SslUtil.class);
+
+ public static SSLSocketFactory getSSLSocketFactoryWithCA(CASignedSSLParam param) {
+ final String caCrtFile = param.getCaCrtFilePath();
+ final String crtFile = param.getCrtFilePath();
+ final String keyFile = param.getKeyFilePath();
+ final String password = "";
+ try {
+ //Add BouncyCastle as a Security Provider
+ Security.addProvider(new BouncyCastleProvider());
+
+ // Load client private key
+ PEMParser reader = null;
+ Object keyObject;
+ try {
+ reader = new PEMParser(new FileReader(keyFile));
+ keyObject = reader.readObject();
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ PEMDecryptorProvider provider =
+ new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
+ JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC");
+
+ KeyPair key;
+
+ if (keyObject instanceof PEMEncryptedKeyPair) {
+ key = keyConverter.getKeyPair(((PEMEncryptedKeyPair) keyObject)
+ .decryptKeyPair(provider));
+ } else {
+ key = keyConverter.getKeyPair((PEMKeyPair) keyObject);
+ }
+
+ // Load Certificate Authority (CA) certificate
+ X509CertificateHolder caCertHolder;
+ try {
+ reader = new PEMParser(new FileReader(caCrtFile));
+ caCertHolder = (X509CertificateHolder) reader.readObject();
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ // CA certificate is used to authenticate server
+ JcaX509CertificateConverter certificateConverter =
+ new JcaX509CertificateConverter().setProvider("BC");
+ KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ X509Certificate caCert = certificateConverter.getCertificate(caCertHolder);
+ caKeyStore.load(null, null);
+ caKeyStore.setCertificateEntry("ca-certificate", caCert);
+
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(caKeyStore);
+
+ // Load client certificate
+ X509CertificateHolder certHolder;
+ try {
+ reader = new PEMParser(new FileReader(crtFile));
+ certHolder = (X509CertificateHolder) reader.readObject();
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ // Client key and certificates are sent to server so it can authenticate the client
+ KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ X509Certificate cert = certificateConverter.getCertificate(certHolder);
+ clientKeyStore.load(null, null);
+ clientKeyStore.setCertificateEntry("certificate", cert);
+ clientKeyStore.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(),
+ new Certificate[]{cert});
+
+ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
+ KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(clientKeyStore, password.toCharArray());
+
+ // Create SSL socket factory
+ SSLContext context = SSLContext.getInstance("TLSv1.3");
+ context.init(keyManagerFactory.getKeyManagers(),
+ trustManagerFactory.getTrustManagers(), null);
+
+ // Return the newly created socket factory object
+ return context.getSocketFactory();
+
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage());
+ }
+
+ return null;
+ }
+
+ public static SSLSocketFactory getSSLSocketFactoryWithoutCA(SelfSignedSSLParam param) {
+ final String crtFile = param.getCrtFilePath();
+ final String keyFile = param.getKeyFilePath();
+ final String password = param.getPassword();
+ try {
+ // Add BouncyCastle as a Security Provider
+ Security.addProvider(new BouncyCastleProvider());
+
+ // Load client private key
+ PEMParser reader = null;
+ Object keyObject;
+ try {
+ reader = new PEMParser(new FileReader(keyFile));
+ keyObject = reader.readObject();
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ PEMDecryptorProvider provider =
+ new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
+ JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC");
+
+ KeyPair key;
+
+ if (keyObject instanceof PEMEncryptedKeyPair) {
+ key = keyConverter.getKeyPair(((PEMEncryptedKeyPair) keyObject)
+ .decryptKeyPair(provider));
+ } else {
+ key = keyConverter.getKeyPair((PEMKeyPair) keyObject);
+ }
+
+ // certificate is used to authenticate server
+ JcaX509CertificateConverter certificateConverter =
+ new JcaX509CertificateConverter().setProvider("BC");
+
+ // Load client certificate
+ X509CertificateHolder certHolder;
+ try {
+ reader = new PEMParser(new FileReader(crtFile));
+ certHolder = (X509CertificateHolder) reader.readObject();
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ X509Certificate cert = certificateConverter.getCertificate(certHolder);
+ // certificate is used to authenticate server
+ KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ keyStore.load(null, null);
+ keyStore.setCertificateEntry("certificate", cert);
+
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(keyStore);
+
+ // Client key and certificates are sent to server so it can authenticate the client
+ KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ clientKeyStore.load(null, null);
+ clientKeyStore.setCertificateEntry("certificate", cert);
+ clientKeyStore.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(),
+ new Certificate[]{cert});
+
+ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
+ KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(clientKeyStore, password.toCharArray());
+
+ // Create SSL socket factory
+ SSLContext context = SSLContext.getInstance("TLSv1.3");
+ context.init(keyManagerFactory.getKeyManagers(),
+ trustManagerFactory.getTrustManagers(), null);
+
+ // Return the newly created socket factory object
+ return context.getSocketFactory();
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage());
+ }
+
+ return null;
+ }
+}
diff --git a/client/src/test/java/com/vesoft/nebula/client/graph/data/TestDataFromServer.java b/client/src/test/java/com/vesoft/nebula/client/graph/data/TestDataFromServer.java
index aebb7ef88..d71442857 100644
--- a/client/src/test/java/com/vesoft/nebula/client/graph/data/TestDataFromServer.java
+++ b/client/src/test/java/com/vesoft/nebula/client/graph/data/TestDataFromServer.java
@@ -451,4 +451,84 @@ public void testErrorForJson() {
assert false;
}
}
+
+ @Test
+ public void testSelfSignedSsl() {
+ Session sslSession = null;
+ NebulaPool sslPool = new NebulaPool();
+ try {
+ Runtime runtime = Runtime.getRuntime();
+ runtime.exec("docker-compose -f src/test/resources/docker-compose"
+ + "-selfsigned.yaml up -d").waitFor(20,TimeUnit.SECONDS);
+
+ NebulaPoolConfig nebulaSslPoolConfig = new NebulaPoolConfig();
+ nebulaSslPoolConfig.setMaxConnSize(100);
+ nebulaSslPoolConfig.setEnableSsl(true);
+ nebulaSslPoolConfig.setSslParam(new SelfSignedSSLParam(
+ "src/test/resources/ssl/selfsigned.pem",
+ "src/test/resources/ssl/selfsigned.key",
+ "vesoft"));
+ Assert.assertTrue(sslPool.init(Arrays.asList(new HostAddress("127.0.0.1", 8669)),
+ nebulaSslPoolConfig));
+ sslSession = sslPool.getSession("root", "nebula", true);
+
+ String ngql = "YIELD 1";
+ JSONObject resp = JSON.parseObject(sslSession.executeJson(ngql));
+ String rowData = resp.getJSONArray("results").getJSONObject(0).getJSONArray("data")
+ .getJSONObject(0).getJSONArray("row").toJSONString();
+ String exp = "[1]";
+ Assert.assertEquals(rowData, exp);
+
+ runtime.exec("docker-compose -f src/test/resources/docker-compose"
+ + "-selfsigned.yaml down").waitFor(60,TimeUnit.SECONDS);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assert false;
+ } finally {
+ if (sslSession != null) {
+ sslSession.release();
+ }
+ sslPool.close();
+ }
+ }
+
+ @Test
+ public void testCASignedSsl() {
+ Session sslSession = null;
+ NebulaPool sslPool = new NebulaPool();
+ try {
+ Runtime runtime = Runtime.getRuntime();
+ runtime.exec("docker-compose -f src/test/resources/docker-compose"
+ + "-casigned.yaml up -d").waitFor(20,TimeUnit.SECONDS);
+
+ NebulaPoolConfig nebulaSslPoolConfig = new NebulaPoolConfig();
+ nebulaSslPoolConfig.setMaxConnSize(100);
+ nebulaSslPoolConfig.setEnableSsl(true);
+ nebulaSslPoolConfig.setSslParam(new CASignedSSLParam(
+ "src/test/resources/ssl/casigned.pem",
+ "src/test/resources/ssl/casigned.crt",
+ "src/test/resources/ssl/casigned.key"));
+ Assert.assertTrue(sslPool.init(Arrays.asList(new HostAddress("127.0.0.1", 8669)),
+ nebulaSslPoolConfig));
+ sslSession = sslPool.getSession("root", "nebula", true);
+
+ String ngql = "YIELD 1";
+ JSONObject resp = JSON.parseObject(sslSession.executeJson(ngql));
+ String rowData = resp.getJSONArray("results").getJSONObject(0).getJSONArray("data")
+ .getJSONObject(0).getJSONArray("row").toJSONString();
+ String exp = "[1]";
+ Assert.assertEquals(rowData, exp);
+
+ runtime.exec("docker-compose -f src/test/resources/docker-compose"
+ + "-casigned.yaml down").waitFor(60,TimeUnit.SECONDS);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assert false;
+ } finally {
+ if (sslSession != null) {
+ sslSession.release();
+ }
+ sslPool.close();
+ }
+ }
}
diff --git a/client/src/test/resources/docker-compose-casigned.yaml b/client/src/test/resources/docker-compose-casigned.yaml
new file mode 100644
index 000000000..bfdd1b96d
--- /dev/null
+++ b/client/src/test/resources/docker-compose-casigned.yaml
@@ -0,0 +1,135 @@
+version: '3.4'
+services:
+ metad-casigned:
+ image: vesoft/nebula-metad:nightly
+ environment:
+ USER: root
+ TZ: "${TZ}"
+ command:
+ - --meta_server_addrs=172.29.1.1:8559
+ - --local_ip=172.29.1.1
+ - --ws_ip=172.29.1.1
+ - --port=8559
+ - --data_path=/data/meta
+ - --log_dir=/logs
+ - --v=0
+ - --minloglevel=0
+ - --heartbeat_interval_secs=2
+ - --expired_time_factor=2
+ - --ws_h2_port=11000
+ - --cert_path=/share/resources/test.derive.crt
+ - --key_path=/share/resources/test.derive.key
+ - --password_path=/share/resources/test.ca.password
+ - --enable_ssl=true
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://172.29.1.1:11000/status"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 20s
+ ports:
+ - "8559:8559"
+ - 11000
+ - 11002
+ volumes:
+ - ./data/meta:/data/meta:Z
+ - ./logs/meta:/logs:Z
+ - ./ssl:/share/resources:Z
+ networks:
+ nebula-net-casigned:
+ ipv4_address: 172.29.1.1
+ restart: on-failure
+ cap_add:
+ - SYS_PTRACE
+
+ storaged-casigned:
+ image: vesoft/nebula-storaged:nightly
+ environment:
+ USER: root
+ TZ: "${TZ}"
+ command:
+ - --meta_server_addrs=172.29.1.1:8559
+ - --local_ip=172.29.2.1
+ - --ws_ip=172.29.2.1
+ - --port=8779
+ - --data_path=/data/storage
+ - --log_dir=/logs
+ - --v=0
+ - --minloglevel=0
+ - --heartbeat_interval_secs=2
+ - --timezone_name=+08:00:00
+ - --ws_h2_port=12000
+ - --cert_path=/share/resources/test.derive.crt
+ - --key_path=/share/resources/test.derive.key
+ - --password_path=/share/resources/test.ca.password
+ - --enable_ssl=true
+ depends_on:
+ - metad-casigned
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://172.29.2.1:12000/status"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 20s
+ ports:
+ - "8779:8779"
+ - 12000
+ - 12002
+ volumes:
+ - ./data/storage:/data/storage:Z
+ - ./logs/storage:/logs:Z
+ - ./ssl:/share/resources:Z
+ networks:
+ nebula-net-casigned:
+ ipv4_address: 172.29.2.1
+ restart: on-failure
+ cap_add:
+ - SYS_PTRACE
+
+ graphd-casigned:
+ image: vesoft/nebula-graphd:nightly
+ environment:
+ USER: root
+ TZ: "${TZ}"
+ command:
+ - --meta_server_addrs=172.29.1.1:8559
+ - --port=8669
+ - --ws_ip=172.29.3.1
+ - --log_dir=/logs
+ - --v=0
+ - --minloglevel=0
+ - --heartbeat_interval_secs=2
+ - --timezone_name=+08:00:00
+ - --ws_h2_port=13000
+ - --cert_path=/share/resources/test.derive.crt
+ - --key_path=/share/resources/test.derive.key
+ - --password_path=/share/resources/test.ca.password
+ - --enable_ssl=true
+ depends_on:
+ - metad-casigned
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://172.29.3.1:13000/status"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 20s
+ ports:
+ - "8669:8669"
+ - 13000
+ - 13002
+ volumes:
+ - ./logs/graph:/logs:Z
+ - ./ssl:/share/resources:Z
+ networks:
+ nebula-net-casigned:
+ ipv4_address: 172.29.3.1
+ restart: on-failure
+ cap_add:
+ - SYS_PTRACE
+
+networks:
+ nebula-net-casigned:
+ ipam:
+ driver: default
+ config:
+ - subnet: 172.29.0.0/16
diff --git a/client/src/test/resources/docker-compose-selfsigned.yaml b/client/src/test/resources/docker-compose-selfsigned.yaml
new file mode 100644
index 000000000..aeac1a60a
--- /dev/null
+++ b/client/src/test/resources/docker-compose-selfsigned.yaml
@@ -0,0 +1,135 @@
+version: '3.4'
+services:
+ metad-selfsigned:
+ image: vesoft/nebula-metad:nightly
+ environment:
+ USER: root
+ TZ: "${TZ}"
+ command:
+ - --meta_server_addrs=172.29.1.1:8559
+ - --local_ip=172.29.1.1
+ - --ws_ip=172.29.1.1
+ - --port=8559
+ - --data_path=/data/meta
+ - --log_dir=/logs
+ - --v=0
+ - --minloglevel=0
+ - --heartbeat_interval_secs=2
+ - --expired_time_factor=2
+ - --ws_h2_port=11000
+ - --cert_path=/share/resources/test.derive.crt
+ - --key_path=/share/resources/test.derive.key
+ - --password_path=/share/resources/test.ca.password
+ - --enable_ssl=true
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://172.29.1.1:11000/status"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 20s
+ ports:
+ - "8559:8559"
+ - 11000
+ - 11002
+ volumes:
+ - ./data/meta:/data/meta:Z
+ - ./logs/meta:/logs:Z
+ - ./ssl:/share/resources:Z
+ networks:
+ nebula-net-selfsigned:
+ ipv4_address: 172.29.1.1
+ restart: on-failure
+ cap_add:
+ - SYS_PTRACE
+
+ storaged-selfsigned:
+ image: vesoft/nebula-storaged:nightly
+ environment:
+ USER: root
+ TZ: "${TZ}"
+ command:
+ - --meta_server_addrs=172.29.1.1:8559
+ - --local_ip=172.29.2.1
+ - --ws_ip=172.29.2.1
+ - --port=8779
+ - --data_path=/data/storage
+ - --log_dir=/logs
+ - --v=0
+ - --minloglevel=0
+ - --heartbeat_interval_secs=2
+ - --timezone_name=+08:00:00
+ - --ws_h2_port=12000
+ - --cert_path=/share/resources/test.derive.crt
+ - --key_path=/share/resources/test.derive.key
+ - --password_path=/share/resources/test.ca.password
+ - --enable_ssl=true
+ depends_on:
+ - metad-selfsigned
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://172.29.2.1:12000/status"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 20s
+ ports:
+ - "8779:8779"
+ - 12000
+ - 12002
+ volumes:
+ - ./data/storage:/data/storage:Z
+ - ./logs/storage:/logs:Z
+ - ./ssl:/share/resources:Z
+ networks:
+ nebula-net-selfsigned:
+ ipv4_address: 172.29.2.1
+ restart: on-failure
+ cap_add:
+ - SYS_PTRACE
+
+ graphd-selfsigned:
+ image: vesoft/nebula-graphd:nightly
+ environment:
+ USER: root
+ TZ: "${TZ}"
+ command:
+ - --meta_server_addrs=172.29.1.1:8559
+ - --port=8669
+ - --ws_ip=172.29.3.1
+ - --log_dir=/logs
+ - --v=0
+ - --minloglevel=0
+ - --heartbeat_interval_secs=2
+ - --timezone_name=+08:00:00
+ - --ws_h2_port=13000
+ - --cert_path=/share/resources/test.derive.crt
+ - --key_path=/share/resources/test.derive.key
+ - --password_path=/share/resources/test.ca.password
+ - --enable_ssl=true
+ depends_on:
+ - metad-selfsigned
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://172.29.3.1:13000/status"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 20s
+ ports:
+ - "8669:8669"
+ - 13000
+ - 13002
+ volumes:
+ - ./logs/graph:/logs:Z
+ - ./ssl:/share/resources:Z
+ networks:
+ nebula-net-selfsigned:
+ ipv4_address: 172.29.3.1
+ restart: on-failure
+ cap_add:
+ - SYS_PTRACE
+
+networks:
+ nebula-net-selfsigned:
+ ipam:
+ driver: default
+ config:
+ - subnet: 172.29.0.0/16
diff --git a/client/src/test/resources/ssl/casigned.crt b/client/src/test/resources/ssl/casigned.crt
new file mode 100644
index 000000000..fe1add667
--- /dev/null
+++ b/client/src/test/resources/ssl/casigned.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICljCCAX4CCQC9uuUY+ah8qzANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJD
+TjAeFw0yMTA5MjkwNzM4MDRaFw0yNDAxMDIwNzM4MDRaMA0xCzAJBgNVBAYTAkNO
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuo7hKpcs+VQKbGRq0fUL
++GcSfPfJ8mARtIeI8WfU0j1vI5KNujI//G2olOGEueDCw4OO0UbdjnsFpgj2awAo
+rj4ga2W6adQHK8qHY6q/Rdqv0oDCrcePMtQ8IwbFjNWOXC4bn7GcV7mzOkigdcj8
+UPkSeaqI9XxBRm3OoDX+T8h6cDLrm+ncKB8KKe/QApKH4frV3HYDqGtN49zuRs6F
+iurFbXDGVAZEdFEJl38IQJdmE2ASOzEHZbxWKzO/DZr/Z2+L1CuycZIwuITcnddx
+b2Byx/opwX4HlyODeUBbyDp+hd+GkasmIcpOlIDw9OXIvrcajKvzLEbqGt2ThsxX
+QwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAxzxtbYBQ2WgBGrpzOX4TxsuSaigqo
+YJ5zbVEHtwbsbBTZ7UJvRc9IyhrOL5Ui4PJI85chh1GpGqOmMoYSaWdddaIroilQ
+56bn5haB8ezAMnLXbPuf97UENO0RIkyzt63XPIUkDnwlzOukIq50qgsYEDuiioM/
+wpCqSbMJ4iK/SlSSUWw3cKuAHvFfLv7hkC6AhvT7yfaCNDs29xEQUCD12XlIdFGH
+FjMgVMcvcIePQq5ZcmSfVMge9jPjPx/Nj9SVauF5z5pil9qHG4jyXPGThiiJ3CE4
+GU5d/Qfe7OeiYI3LaoVufZ5pZnR9nMnpzqU46w9gY7vgi6bAhNwsCDr3
+-----END CERTIFICATE-----
diff --git a/client/src/test/resources/ssl/casigned.key b/client/src/test/resources/ssl/casigned.key
new file mode 100644
index 000000000..3561e7ab8
--- /dev/null
+++ b/client/src/test/resources/ssl/casigned.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAuo7hKpcs+VQKbGRq0fUL+GcSfPfJ8mARtIeI8WfU0j1vI5KN
+ujI//G2olOGEueDCw4OO0UbdjnsFpgj2awAorj4ga2W6adQHK8qHY6q/Rdqv0oDC
+rcePMtQ8IwbFjNWOXC4bn7GcV7mzOkigdcj8UPkSeaqI9XxBRm3OoDX+T8h6cDLr
+m+ncKB8KKe/QApKH4frV3HYDqGtN49zuRs6FiurFbXDGVAZEdFEJl38IQJdmE2AS
+OzEHZbxWKzO/DZr/Z2+L1CuycZIwuITcnddxb2Byx/opwX4HlyODeUBbyDp+hd+G
+kasmIcpOlIDw9OXIvrcajKvzLEbqGt2ThsxXQwIDAQABAoIBAH4SEBe4EaxsHp8h
+PQ6linFTNis9SDuCsHRPIzv/7tIksfZYE27Ahn0Pndz+ibMTMIrvXJQQT6j5ede6
+NswYT2Vwlnf9Rvw9TJtLQjMYMCoEnsyiNu047oxq4DjLWrTRnGKuxfwlCoI9++Bn
+NAhkyh3uM44EsIk0bugpTHj4A+PlbUPe7xdEI/6XpaZrRN9oiejJ4VxZAPgFGiTm
+uNF5qg16+0900Pfj5Y/M4vXmn+gq39PO/y0FlTpaoEuYZiZZS3xHGmSVhlt8LIgI
+8MdMRaKTfNeNITaqgOWh9pAW4xmK48/KfLgNPQgtDHjMJpgM0BbcBOayOY8Eio0x
+Z66G2AECgYEA9vj/8Fm3CKn/ogNOO81y9kIs0iPcbjasMnQ3UXeOdD0z0+7TM86F
+Xj3GK/z2ecvY7skWtO5ZUbbxp4aB7omW8Ke9+q8XPzMEmUuAOTzxQkAOxdr++HXP
+TILy0hNX2cmiLQT1U60KoZHzPZ5o5hNIQPMt7hN12ERWcIfR/MUZa5UCgYEAwWCP
+6Y7Zso1QxQR/qfjuILET3/xU+ZmqSRDvzJPEiGI3oeWNG4L6cKR+XTe0FWZBAmVk
+Qq/1qXmdBnf5S7azffoJe2+H/m3kHJSprIiAAWlBN2e+kFlNfBhtkgia5NvsrjRw
+al6mf/+weRD1FiPoZY3e1wBKoqro7aI8fE5gwXcCgYEAnEI05OROeyvb8qy2vf2i
+JA8AfsBzwkPTNWT0bxX+yqrCdO/hLyEWnubk0IYPiEYibgpK1JUNbDcctErVQJBL
+MN5gxBAt3C2yVi8/5HcbijgvYJ3LvnYDf7xGWAYnCkOZ2XQOqC+Oz2UhijYE1rUS
+fQ2fXMdxQzERo8c7Y/tstvUCgYBuixy5jwezokUB20h/ieXWmmOaL00EQmutyRjM
+AczfigXzbp3zlDRGIEJ8V1OCyClxjTR7SstMTlENWZgRSCfjZAP3pBJBx+AW1oUI
+NB+4rsqxOYUeT26T+gLo8DJbkb0C+Mcqh2D22tuu2ZrBRVWceDVjAq+nvbvZ3Fxn
+UwbMkQKBgQCxL3aA6ART6laIxT/ZqMhV0ZcaoDJogjF+4I4bhlO4ivWGWJ4RpEDn
+ziFb6+M/4pe4vCou9yuAof6WTKM8JG4rok0yxhN3V6QGP49TjtrfkkrEPCtB2LSI
+N1+YRSTrS5VDcl8h8JH7fpghRnXHONEyIqasYVqsbxKzNyLV/z2rkw==
+-----END RSA PRIVATE KEY-----
diff --git a/client/src/test/resources/ssl/casigned.pem b/client/src/test/resources/ssl/casigned.pem
new file mode 100644
index 000000000..412ba3161
--- /dev/null
+++ b/client/src/test/resources/ssl/casigned.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEGzCCAwOgAwIBAgIUDcmZFpL4PcdCXfLRBK8bR2vb39cwDQYJKoZIhvcNAQEL
+BQAwgZwxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwI
+SGFuZ3pob3UxFDASBgNVBAoMC1Zlc29mdCBJbmMuMRAwDgYDVQQLDAdzZWN0aW9u
+MRYwFAYDVQQDDA1zaHlsb2NrIGh1YW5nMScwJQYJKoZIhvcNAQkBFhhzaHlsb2Nr
+Lmh1YW5nQHZlc29mdC5jb20wHhcNMjEwODE5MDkyNDQ3WhcNMjUwODE4MDkyNDQ3
+WjCBnDELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFpoZWppYW5nMREwDwYDVQQHDAhI
+YW5nemhvdTEUMBIGA1UECgwLVmVzb2Z0IEluYy4xEDAOBgNVBAsMB3NlY3Rpb24x
+FjAUBgNVBAMMDXNoeWxvY2sgaHVhbmcxJzAlBgkqhkiG9w0BCQEWGHNoeWxvY2su
+aHVhbmdAdmVzb2Z0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AMEAgpamCQHl+8JnUHI6/VmJHjDLYJLTliN/CwpFrhMqIVjJ8wG57WYLpXpn91Lz
+eHu52LkVzcikybIJ2a+LOTvnhNFdbmTbqDtrb+s6wM/sO+nF6tU2Av4e5zhyKoeR
+LL+rHMk3nymohbdN4djySFmOOU5A1O/4b0bZz4Ylu995kUawdiaEo13BzxxOC7Ik
+Gge5RyDcm0uLXZqTAPy5Sjv/zpOyj0AqL1CJUH7XBN9OMRhVU0ZX9nHWl1vgLRld
+J6XT17Y9QbbHhCNEdAmFE5kEFgCvZc+MungUYABlkvoj86TLmC/FMV6fWdxQssyd
+hS+ssfJFLaTDaEFz5a/Tr48CAwEAAaNTMFEwHQYDVR0OBBYEFK0GVrQx+wX1GCHy
+e+6fl4X+prmYMB8GA1UdIwQYMBaAFK0GVrQx+wX1GCHye+6fl4X+prmYMA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHqP8P+ZUHmngviHLSSN1ln5
+Mx4BCkVeFRUaFx0yFXytV/iLXcG2HpFg3A9rAFoYgCDwi1xpsERnBZ/ShTv/eFOc
+IxBY5yggx3/lGi8tAgvUdarhd7mQO67UJ0V4YU3hAkbnZ8grHHXj+4hfgUpY4ok6
+yaed6HXwknBb9W8N1jZI8ginhkhjaeRCHdMiF+fBvNCtmeR1bCml1Uz7ailrpcaT
+Mf84+5VYuFEnaRZYWFNsWNCOBlJ/6/b3V10vMXzMmYHqz3xgAq0M3fVTFTzopnAX
+DLSzorL/dYVdqEDCQi5XI9YAlgWN4VeGzJI+glkLOCNzHxRNP6Qev+YI+7Uxz6I=
+-----END CERTIFICATE-----
diff --git a/client/src/test/resources/ssl/selfsigned.key b/client/src/test/resources/ssl/selfsigned.key
new file mode 100644
index 000000000..6006d0f27
--- /dev/null
+++ b/client/src/test/resources/ssl/selfsigned.key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,6D12ED8559E80FA3
+
+tv9epnwlt4dP6Q5ee0dACOyFA5BTwYTdoMykQRJrKGwfaNeXUXn+sQ/U/oFHp1Wx
+O8VZE+z2aHpiFSTw+Eh6MPt86X5yVG3tpeVO6dErvr8Kd+NpuI8zn7rNoOFRh8wD
+33EFcQMLQPneDl10O18hooIoi0qwp1pd63hYZPwEhB3eOrM5Mnv9OVJs65bzYfyf
+Wku33YWYxeqlDvMCsou8PZnv/M2wYsr7+QoTcNmGKP45igMthMDBzwgF+q0p9ZZU
+N11c6ojAs01kfuqFf3vKfHNYe6zsBiNhnUuEy8enXSxD5E7tR/OI8aEzPLdk7fmN
+/UsMK2LE0Yd5iS3O1x/1ZjSBxJ+M/UzzCO692GTAiD6Hc13iJOavq/vt1mEPjfCD
+neF38Bhb5DfFi+UAHrz6EHMreamGCzP82us2maIs7mSTq7nXDZfbBc7mBDLAUUnT
+J6tlrTyc+DQXzkJa6jmbxJhcsWm6XvjIBEzSXVHxEDPLnZICQk3VXODjCXTD75Rg
+0WaS78Ven7DW8wn07q3VzWAFDKaet3VI+TVTv7EfIavlfiA6LSshaENdFLeHahNE
+s/V/j5K3Pg6+WQcZRgOsfqIwUCSQxY13R6TTdaaCkLay5BggF5iiAO3pkqsJiadf
+w843Ak4USBptymJxoZgJyFtQHpQyNiFfsAbs9BaYbg2evvE7/VQhLk0gQ7HgQMeJ
+wgxEQqZQKDCCSugSzY1YEGXKnrZYCKyipzyyH936mE15zNwhYp/Pi2020+gmtP3h
+CDfcPs1yeLI2/1JuimafbuKsv9xchWa6ASU8p8Q7wTLtUj9ylLKyA4A/75pK0DXG
+Hv/q0O+UfhAMD438SoPBle7RSvIsDU1VjUqstlNybBglBZxGIME7/18+Ms7U32wh
+4xFkZwxT2nqFgyk37tXMdMz9UBh12/AXR9NU4XY37C3Ao2TDT7/0DvU6KdJhsDpv
+rGcaC2zzhko+0CPrLlk52KbqP003JXiWvOSI+FylyPPDB/YGitmndJUuQblf3u/E
+l+tGi9MeSBQeWKV6D3AVnO05AZjfTUzSK0vw4DgNh5YPNJvLy31B7kDAS88vyGI1
+t6MBwjW4/tz/nS/p1Go3mSzBhPkIsCrZE+ar7lH8p8JqkLl4fXIMaVKIfyfJdzyS
+lkh3K7bOGDPegxxxaWdb+EnC7k+1R3EOU7uJFW61HyrGI3q6Y7kOl5aYSJ5Ge1Uv
+PycFWHWVTHq/R7HRE6HIJzGe/PnLIbStXLDFeivjfcYq1YaSaF8Vl+xg+0u3ULOl
+P6IuPTph6dlcgttRZVl3ETcF0T+2wfbUwgjf0ZiguCJfR2jLGhPl1KBg0Kd9cTSY
+zI3YMMd2G8hApt/QFlm4Ry8CqaJUmDcjDNIJT3M+RldUgfz37NsX05cA5e9+I1AL
+2406F/v5U9gWsYx7HuwJtQrDzYYDbl1GD4H+qHFJE5JYhPP4AyWYxJ1NR5dqyvrt
++3r5+xlwZrS76c10RsBWL7th8ZEzRxOZxbtLwbf4bG/tIGfQP2sTnWwA+qym6b2S
+sRduqOTP+xwnhOq/ZKn8lfsDfhT8CPnKHBsd09kM9y/UWuxFe0upLydRLE/Wsb9s
+-----END RSA PRIVATE KEY-----
diff --git a/client/src/test/resources/ssl/selfsigned.password b/client/src/test/resources/ssl/selfsigned.password
new file mode 100644
index 000000000..143be9ab9
--- /dev/null
+++ b/client/src/test/resources/ssl/selfsigned.password
@@ -0,0 +1 @@
+vesoft
diff --git a/client/src/test/resources/ssl/selfsigned.pem b/client/src/test/resources/ssl/selfsigned.pem
new file mode 100644
index 000000000..412ba3161
--- /dev/null
+++ b/client/src/test/resources/ssl/selfsigned.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEGzCCAwOgAwIBAgIUDcmZFpL4PcdCXfLRBK8bR2vb39cwDQYJKoZIhvcNAQEL
+BQAwgZwxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwI
+SGFuZ3pob3UxFDASBgNVBAoMC1Zlc29mdCBJbmMuMRAwDgYDVQQLDAdzZWN0aW9u
+MRYwFAYDVQQDDA1zaHlsb2NrIGh1YW5nMScwJQYJKoZIhvcNAQkBFhhzaHlsb2Nr
+Lmh1YW5nQHZlc29mdC5jb20wHhcNMjEwODE5MDkyNDQ3WhcNMjUwODE4MDkyNDQ3
+WjCBnDELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFpoZWppYW5nMREwDwYDVQQHDAhI
+YW5nemhvdTEUMBIGA1UECgwLVmVzb2Z0IEluYy4xEDAOBgNVBAsMB3NlY3Rpb24x
+FjAUBgNVBAMMDXNoeWxvY2sgaHVhbmcxJzAlBgkqhkiG9w0BCQEWGHNoeWxvY2su
+aHVhbmdAdmVzb2Z0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AMEAgpamCQHl+8JnUHI6/VmJHjDLYJLTliN/CwpFrhMqIVjJ8wG57WYLpXpn91Lz
+eHu52LkVzcikybIJ2a+LOTvnhNFdbmTbqDtrb+s6wM/sO+nF6tU2Av4e5zhyKoeR
+LL+rHMk3nymohbdN4djySFmOOU5A1O/4b0bZz4Ylu995kUawdiaEo13BzxxOC7Ik
+Gge5RyDcm0uLXZqTAPy5Sjv/zpOyj0AqL1CJUH7XBN9OMRhVU0ZX9nHWl1vgLRld
+J6XT17Y9QbbHhCNEdAmFE5kEFgCvZc+MungUYABlkvoj86TLmC/FMV6fWdxQssyd
+hS+ssfJFLaTDaEFz5a/Tr48CAwEAAaNTMFEwHQYDVR0OBBYEFK0GVrQx+wX1GCHy
+e+6fl4X+prmYMB8GA1UdIwQYMBaAFK0GVrQx+wX1GCHye+6fl4X+prmYMA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHqP8P+ZUHmngviHLSSN1ln5
+Mx4BCkVeFRUaFx0yFXytV/iLXcG2HpFg3A9rAFoYgCDwi1xpsERnBZ/ShTv/eFOc
+IxBY5yggx3/lGi8tAgvUdarhd7mQO67UJ0V4YU3hAkbnZ8grHHXj+4hfgUpY4ok6
+yaed6HXwknBb9W8N1jZI8ginhkhjaeRCHdMiF+fBvNCtmeR1bCml1Uz7ailrpcaT
+Mf84+5VYuFEnaRZYWFNsWNCOBlJ/6/b3V10vMXzMmYHqz3xgAq0M3fVTFTzopnAX
+DLSzorL/dYVdqEDCQi5XI9YAlgWN4VeGzJI+glkLOCNzHxRNP6Qev+YI+7Uxz6I=
+-----END CERTIFICATE-----
diff --git a/client/src/test/resources/ssl/test.ca.key b/client/src/test/resources/ssl/test.ca.key
new file mode 100644
index 000000000..6006d0f27
--- /dev/null
+++ b/client/src/test/resources/ssl/test.ca.key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,6D12ED8559E80FA3
+
+tv9epnwlt4dP6Q5ee0dACOyFA5BTwYTdoMykQRJrKGwfaNeXUXn+sQ/U/oFHp1Wx
+O8VZE+z2aHpiFSTw+Eh6MPt86X5yVG3tpeVO6dErvr8Kd+NpuI8zn7rNoOFRh8wD
+33EFcQMLQPneDl10O18hooIoi0qwp1pd63hYZPwEhB3eOrM5Mnv9OVJs65bzYfyf
+Wku33YWYxeqlDvMCsou8PZnv/M2wYsr7+QoTcNmGKP45igMthMDBzwgF+q0p9ZZU
+N11c6ojAs01kfuqFf3vKfHNYe6zsBiNhnUuEy8enXSxD5E7tR/OI8aEzPLdk7fmN
+/UsMK2LE0Yd5iS3O1x/1ZjSBxJ+M/UzzCO692GTAiD6Hc13iJOavq/vt1mEPjfCD
+neF38Bhb5DfFi+UAHrz6EHMreamGCzP82us2maIs7mSTq7nXDZfbBc7mBDLAUUnT
+J6tlrTyc+DQXzkJa6jmbxJhcsWm6XvjIBEzSXVHxEDPLnZICQk3VXODjCXTD75Rg
+0WaS78Ven7DW8wn07q3VzWAFDKaet3VI+TVTv7EfIavlfiA6LSshaENdFLeHahNE
+s/V/j5K3Pg6+WQcZRgOsfqIwUCSQxY13R6TTdaaCkLay5BggF5iiAO3pkqsJiadf
+w843Ak4USBptymJxoZgJyFtQHpQyNiFfsAbs9BaYbg2evvE7/VQhLk0gQ7HgQMeJ
+wgxEQqZQKDCCSugSzY1YEGXKnrZYCKyipzyyH936mE15zNwhYp/Pi2020+gmtP3h
+CDfcPs1yeLI2/1JuimafbuKsv9xchWa6ASU8p8Q7wTLtUj9ylLKyA4A/75pK0DXG
+Hv/q0O+UfhAMD438SoPBle7RSvIsDU1VjUqstlNybBglBZxGIME7/18+Ms7U32wh
+4xFkZwxT2nqFgyk37tXMdMz9UBh12/AXR9NU4XY37C3Ao2TDT7/0DvU6KdJhsDpv
+rGcaC2zzhko+0CPrLlk52KbqP003JXiWvOSI+FylyPPDB/YGitmndJUuQblf3u/E
+l+tGi9MeSBQeWKV6D3AVnO05AZjfTUzSK0vw4DgNh5YPNJvLy31B7kDAS88vyGI1
+t6MBwjW4/tz/nS/p1Go3mSzBhPkIsCrZE+ar7lH8p8JqkLl4fXIMaVKIfyfJdzyS
+lkh3K7bOGDPegxxxaWdb+EnC7k+1R3EOU7uJFW61HyrGI3q6Y7kOl5aYSJ5Ge1Uv
+PycFWHWVTHq/R7HRE6HIJzGe/PnLIbStXLDFeivjfcYq1YaSaF8Vl+xg+0u3ULOl
+P6IuPTph6dlcgttRZVl3ETcF0T+2wfbUwgjf0ZiguCJfR2jLGhPl1KBg0Kd9cTSY
+zI3YMMd2G8hApt/QFlm4Ry8CqaJUmDcjDNIJT3M+RldUgfz37NsX05cA5e9+I1AL
+2406F/v5U9gWsYx7HuwJtQrDzYYDbl1GD4H+qHFJE5JYhPP4AyWYxJ1NR5dqyvrt
++3r5+xlwZrS76c10RsBWL7th8ZEzRxOZxbtLwbf4bG/tIGfQP2sTnWwA+qym6b2S
+sRduqOTP+xwnhOq/ZKn8lfsDfhT8CPnKHBsd09kM9y/UWuxFe0upLydRLE/Wsb9s
+-----END RSA PRIVATE KEY-----
diff --git a/client/src/test/resources/ssl/test.ca.password b/client/src/test/resources/ssl/test.ca.password
new file mode 100644
index 000000000..143be9ab9
--- /dev/null
+++ b/client/src/test/resources/ssl/test.ca.password
@@ -0,0 +1 @@
+vesoft
diff --git a/client/src/test/resources/ssl/test.ca.pem b/client/src/test/resources/ssl/test.ca.pem
new file mode 100644
index 000000000..412ba3161
--- /dev/null
+++ b/client/src/test/resources/ssl/test.ca.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEGzCCAwOgAwIBAgIUDcmZFpL4PcdCXfLRBK8bR2vb39cwDQYJKoZIhvcNAQEL
+BQAwgZwxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwI
+SGFuZ3pob3UxFDASBgNVBAoMC1Zlc29mdCBJbmMuMRAwDgYDVQQLDAdzZWN0aW9u
+MRYwFAYDVQQDDA1zaHlsb2NrIGh1YW5nMScwJQYJKoZIhvcNAQkBFhhzaHlsb2Nr
+Lmh1YW5nQHZlc29mdC5jb20wHhcNMjEwODE5MDkyNDQ3WhcNMjUwODE4MDkyNDQ3
+WjCBnDELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFpoZWppYW5nMREwDwYDVQQHDAhI
+YW5nemhvdTEUMBIGA1UECgwLVmVzb2Z0IEluYy4xEDAOBgNVBAsMB3NlY3Rpb24x
+FjAUBgNVBAMMDXNoeWxvY2sgaHVhbmcxJzAlBgkqhkiG9w0BCQEWGHNoeWxvY2su
+aHVhbmdAdmVzb2Z0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AMEAgpamCQHl+8JnUHI6/VmJHjDLYJLTliN/CwpFrhMqIVjJ8wG57WYLpXpn91Lz
+eHu52LkVzcikybIJ2a+LOTvnhNFdbmTbqDtrb+s6wM/sO+nF6tU2Av4e5zhyKoeR
+LL+rHMk3nymohbdN4djySFmOOU5A1O/4b0bZz4Ylu995kUawdiaEo13BzxxOC7Ik
+Gge5RyDcm0uLXZqTAPy5Sjv/zpOyj0AqL1CJUH7XBN9OMRhVU0ZX9nHWl1vgLRld
+J6XT17Y9QbbHhCNEdAmFE5kEFgCvZc+MungUYABlkvoj86TLmC/FMV6fWdxQssyd
+hS+ssfJFLaTDaEFz5a/Tr48CAwEAAaNTMFEwHQYDVR0OBBYEFK0GVrQx+wX1GCHy
+e+6fl4X+prmYMB8GA1UdIwQYMBaAFK0GVrQx+wX1GCHye+6fl4X+prmYMA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHqP8P+ZUHmngviHLSSN1ln5
+Mx4BCkVeFRUaFx0yFXytV/iLXcG2HpFg3A9rAFoYgCDwi1xpsERnBZ/ShTv/eFOc
+IxBY5yggx3/lGi8tAgvUdarhd7mQO67UJ0V4YU3hAkbnZ8grHHXj+4hfgUpY4ok6
+yaed6HXwknBb9W8N1jZI8ginhkhjaeRCHdMiF+fBvNCtmeR1bCml1Uz7ailrpcaT
+Mf84+5VYuFEnaRZYWFNsWNCOBlJ/6/b3V10vMXzMmYHqz3xgAq0M3fVTFTzopnAX
+DLSzorL/dYVdqEDCQi5XI9YAlgWN4VeGzJI+glkLOCNzHxRNP6Qev+YI+7Uxz6I=
+-----END CERTIFICATE-----
diff --git a/client/src/test/resources/ssl/test.ca.srl b/client/src/test/resources/ssl/test.ca.srl
new file mode 100644
index 000000000..877d296b7
--- /dev/null
+++ b/client/src/test/resources/ssl/test.ca.srl
@@ -0,0 +1 @@
+4AF2EBB941EA7EE8358ECC7E51C2F1A38EE18873
diff --git a/client/src/test/resources/ssl/test.derive.crt b/client/src/test/resources/ssl/test.derive.crt
new file mode 100644
index 000000000..8f03073e2
--- /dev/null
+++ b/client/src/test/resources/ssl/test.derive.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDvjCCAqYCFEry67lB6n7oNY7MflHC8aOO4YhzMA0GCSqGSIb3DQEBCwUAMIGc
+MQswCQYDVQQGEwJDTjERMA8GA1UECAwIWmhlamlhbmcxETAPBgNVBAcMCEhhbmd6
+aG91MRQwEgYDVQQKDAtWZXNvZnQgSW5jLjEQMA4GA1UECwwHc2VjdGlvbjEWMBQG
+A1UEAwwNc2h5bG9jayBodWFuZzEnMCUGCSqGSIb3DQEJARYYc2h5bG9jay5odWFu
+Z0B2ZXNvZnQuY29tMB4XDTIxMDgyNDEwNTExMloXDTIzMTEyNzEwNTExMlowgZkx
+CzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3po
+b3UxFDASBgNVBAoMC1Zlc29mdCBJbmMuMRAwDgYDVQQLDAdzZWN0aW9uMRMwEQYD
+VQQDDApTaHlsb2NrIEhnMScwJQYJKoZIhvcNAQkBFhhzaHlsb2NrLmh1YW5nQHZl
+c29mdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHk1PQtaCG
+S31nvxKuT6pzVQuOsA2hEIDzBZuoBK3blezBB16fjUWG2wHG/r9Oss5YzOly4viL
+1oFLsNdYg27EFH7pcGfdSUmZa6LHILegJTmLa1aB4lRG9EsvPIxNuo637CW2z6EW
+ElVKXn2N1G1vW3fpKGxJ+d1ovaFfBliO0sK+myW+vYdKrNg70WqKKCoCIlIjEWw3
+vQdrmvhuhIBbG1bXkXbJwIepBdb4wGSx8qsgs93I6/je/K/iJaPJIqdH8loo6fSo
+DBUiNA87ZsQdtbBeuk7QuF71SxD5+E8wCMtFMwRGmL0vYMPwkaurKxwEs49e8eTz
+RvIrNtyYgVo7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGBpm5OLXn02kWr1ENU5
+FOOVryD41SCmPy8hLwQ2MCXd446UfTXc5TTlllksaePn373ZANLUe78vUCoVPjOh
+dU5GxyOKtubXovI+yuvMS11u00KtgiAd5qa+IhX3c/P60bh4+fdKZ9ViyLsG+IpQ
++XDYT2uekLyjXXJU6h1raW7M1VY9FcDC63moXz0WgWJ/9tJgB0ZQkVcL+2UpveoZ
+Whf9P0xAzCmNSrR7CMhdeRN2vBQQaHXk/64wkHncdkz/NglVl00rh4MtBKZ6Cqze
+uZvgrxOJNzB4aXBMHO7sWzw1VSfS79CZm4H39hBWGiVEkr3yZYQbboDRY6F5dQyc
+BZc=
+-----END CERTIFICATE-----
diff --git a/client/src/test/resources/ssl/test.derive.csr b/client/src/test/resources/ssl/test.derive.csr
new file mode 100644
index 000000000..89b26237e
--- /dev/null
+++ b/client/src/test/resources/ssl/test.derive.csr
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIDEjCCAfoCAQAwgZkxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzER
+MA8GA1UEBwwISGFuZ3pob3UxFDASBgNVBAoMC1Zlc29mdCBJbmMuMRAwDgYDVQQL
+DAdzZWN0aW9uMRMwEQYDVQQDDApTaHlsb2NrIEhnMScwJQYJKoZIhvcNAQkBFhhz
+aHlsb2NrLmh1YW5nQHZlc29mdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDHk1PQtaCGS31nvxKuT6pzVQuOsA2hEIDzBZuoBK3blezBB16fjUWG
+2wHG/r9Oss5YzOly4viL1oFLsNdYg27EFH7pcGfdSUmZa6LHILegJTmLa1aB4lRG
+9EsvPIxNuo637CW2z6EWElVKXn2N1G1vW3fpKGxJ+d1ovaFfBliO0sK+myW+vYdK
+rNg70WqKKCoCIlIjEWw3vQdrmvhuhIBbG1bXkXbJwIepBdb4wGSx8qsgs93I6/je
+/K/iJaPJIqdH8loo6fSoDBUiNA87ZsQdtbBeuk7QuF71SxD5+E8wCMtFMwRGmL0v
+YMPwkaurKxwEs49e8eTzRvIrNtyYgVo7AgMBAAGgMzAVBgkqhkiG9w0BCQcxCAwG
+dmVzb2Z0MBoGCSqGSIb3DQEJAjENDAtWZXNvZnQgSW5jLjANBgkqhkiG9w0BAQsF
+AAOCAQEAjmyCyxziJMR8NILRAwmfYcBB90CbTFMMEyWy402KxoXcyVZBGO2eukIq
+gaF2ywuh6yuTPtGsdVMVTWDQ4RLYpoQoR5Blu+M8Or8rhZSfMYXi79Ne3abSF28E
+eWjBmh2Ys0GtaThlufJBWE+vWPH2iEGrSRTg1fvBLBzAW6nXU2svoTrKfDcEoY5z
+xB0CKhBoewoIZ2FPBmBAnIWHfXR/vQ76QIoNdfQ4nT8iXuLRoNjRlvVU4AUDwKtu
+keRDrnmJ7A5eqTlleCMzra2MAp9Na9gojXlGQP9q9V8nFtSvbjYAoH0ezWpdWj4+
+Rtu9EK4JkDymmmZcneFapExZrRLt0A==
+-----END CERTIFICATE REQUEST-----
diff --git a/client/src/test/resources/ssl/test.derive.key b/client/src/test/resources/ssl/test.derive.key
new file mode 100644
index 000000000..a011917b3
--- /dev/null
+++ b/client/src/test/resources/ssl/test.derive.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAx5NT0LWghkt9Z78Srk+qc1ULjrANoRCA8wWbqASt25XswQde
+n41FhtsBxv6/TrLOWMzpcuL4i9aBS7DXWINuxBR+6XBn3UlJmWuixyC3oCU5i2tW
+geJURvRLLzyMTbqOt+wlts+hFhJVSl59jdRtb1t36ShsSfndaL2hXwZYjtLCvpsl
+vr2HSqzYO9FqiigqAiJSIxFsN70Ha5r4boSAWxtW15F2ycCHqQXW+MBksfKrILPd
+yOv43vyv4iWjySKnR/JaKOn0qAwVIjQPO2bEHbWwXrpO0Lhe9UsQ+fhPMAjLRTME
+Rpi9L2DD8JGrqyscBLOPXvHk80byKzbcmIFaOwIDAQABAoIBAEZ50URHjzs9VziW
+sdsaSN/XbXBi3T0+Xbr0BQatOFPtuqBjoNeJBL9dgWArP5Vj8RhMrDekzQ5cnmYD
+OdiI+UmGz1ZSGmt7YOErsFzPQejsnEiOjArryMURqacxo34jXhi27I6E/aaUrMfJ
+XF8EX+zOCSct3ie1c6l0JZMv43/zbzP2vMFEdfnVfZA2Kxo5l3I4rjuxHUEWHzrb
+EgM4a2+y7LQrut75zP9zWEZAqim/VEIEj24Gqj+Vocb6cHlc31KzKaEz7Ra5ha2J
+kN2CQRKCzoMupVL5E6dWMiDVjUyUXdUgjSCIW2H+E1ONgvxA78jJx7+Dzj+/bWxH
+h/vr3dkCgYEA9Aev7PGoGF0eapZY3crehvtCn1v4YLheh0dk4EpbpbEx0rQaG3h7
+YYCf7euxMvoTsKPETHAUG/s/RZV1DNOjxs8GKgEIVaRYEf1VZeDXudtnyKBwCMAL
+5CKHRBvfmNG9n+PpQQlrIAZGej7HU+/IzEVsrD2A5DeH9IVpMNvrX10CgYEA0V1r
+aydbBP+Ma/fiG5UDa8l4GdLzvAoW2cY6ZhQX4NiLTK91MwA/QOQcVMvJAN2KpPHC
+kGDRT7IhMs66cMxl0ImIJ2QSnv8HRNmBBSdUtJx1S6nV2u0VfgP61oNT/YbLR/Jk
+CAIl1qe7Q8IsrMbPxCbt8g+D8Wr9C3pdYYqFvncCgYEAicGdKmDwx3Apr3nYCLxx
+CjnkzhkZCWCK3EsNQyA2xD5XJd7NrhxBajU2ExUuHtzVKK4KLixG7dTTTvCj9u2y
+UpSjoiqbDd2MaftcrfpTTXPyDmujUw02qT5kpaomexpLtWrvTeuHMbjZKEEwPM3r
+yISYaFL/49UFRp/ZVd+P63ECgYAX1B0ctf77A6bUxwK6Buy7wNNlhQful+tf39rX
+sWPCWIMKOFILevS4Cv5afFMlQRG9kjKFwi8wdeKnaLX5jpnr8StI6G/iHr6SDHtN
+vds7Ly9+bBcF8sPmcseC0LGngkbyqljOPIhX9QEwRhJVm88b0R511WQ7/uRMASJN
+rrloIwKBgCxYlu1xvvEuQNoIux/yKAEJ1h4Ta2zc5upjw0uDKMi0UNIbNhgdFOvj
+LuVbxTRU8WktrLNk3T0rsopKsTbEZVg6Yuv8ZLkEiNYTzhUbn2Y5yM3bnoVwyOns
+pTtqmBtvDZxaRCYdIQG3b09IvrewDk26AOtNHdeKw883G2muP/vA
+-----END RSA PRIVATE KEY-----
diff --git a/examples/src/main/java/com/vesoft/nebula/examples/GraphClientExample.java b/examples/src/main/java/com/vesoft/nebula/examples/GraphClientExample.java
index 6b78cbb80..f9e0c1ce7 100644
--- a/examples/src/main/java/com/vesoft/nebula/examples/GraphClientExample.java
+++ b/examples/src/main/java/com/vesoft/nebula/examples/GraphClientExample.java
@@ -8,9 +8,12 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
+import com.vesoft.nebula.ErrorCode;
import com.vesoft.nebula.client.graph.NebulaPoolConfig;
+import com.vesoft.nebula.client.graph.data.CASignedSSLParam;
import com.vesoft.nebula.client.graph.data.HostAddress;
import com.vesoft.nebula.client.graph.data.ResultSet;
+import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam;
import com.vesoft.nebula.client.graph.data.ValueWrapper;
import com.vesoft.nebula.client.graph.net.NebulaPool;
import com.vesoft.nebula.client.graph.net.Session;
@@ -79,7 +82,7 @@ private static void printResult(ResultSet resultSet) throws UnsupportedEncodingE
public static void main(String[] args) {
NebulaPool pool = new NebulaPool();
- Session session = null;
+ Session session;
try {
NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig();
nebulaPoolConfig.setMaxConnSize(100);
@@ -146,22 +149,62 @@ public static void main(String[] args) {
{
String queryForJson = "YIELD 1";
String resp = session.executeJson(queryForJson);
- JSONObject errors = JSON.parseObject(resp).getJSONArray("result").getJSONObject(0)
- .getJSONObject("errors");
- if (!errors.getString("errorCode").equals("0")) {
+ JSONObject errors = JSON.parseObject(resp).getJSONArray("errors").getJSONObject(0);
+ if (errors.getInteger("code") != 0) {
log.error(String.format("Execute: `%s', failed: %s",
- queryForJson, errors.getString("errorMsg")));
+ queryForJson, errors.getString("message")));
+ System.exit(1);
+ }
+ System.out.println(resp);
+ }
+
+ {
+ NebulaPoolConfig nebulaSslPoolConfig = new NebulaPoolConfig();
+ nebulaSslPoolConfig.setMaxConnSize(100);
+ nebulaSslPoolConfig.setEnableSsl(true);
+ nebulaSslPoolConfig.setSslParam(new CASignedSSLParam(
+ "examples/src/main/resources/ssl/casigned.pem",
+ "examples/src/main/resources/ssl/casigned.crt",
+ "examples/src/main/resources/ssl/casigned.key"));
+ NebulaPool sslPool = new NebulaPool();
+ sslPool.init(Arrays.asList(new HostAddress("192.168.8.123", 9669)),
+ nebulaSslPoolConfig);
+ String queryForJson = "YIELD 1";
+ Session sslSession = sslPool.getSession("root", "nebula", false);
+ String resp = sslSession.executeJson(queryForJson);
+ JSONObject errors = JSON.parseObject(resp).getJSONArray("errors").getJSONObject(0);
+ if (errors.getInteger("code") != ErrorCode.SUCCEEDED.getValue()) {
+ log.error(String.format("Execute: `%s', failed: %s",
+ queryForJson, errors.getString("message")));
+ System.exit(1);
+ }
+ System.out.println(resp);
+ }
+
+ {
+ NebulaPoolConfig nebulaSslPoolConfig = new NebulaPoolConfig();
+ nebulaSslPoolConfig.setMaxConnSize(100);
+ nebulaSslPoolConfig.setEnableSsl(true);
+ nebulaSslPoolConfig.setSslParam(new SelfSignedSSLParam(
+ "examples/src/main/resources/ssl/selfsigned.pem",
+ "examples/src/main/resources/ssl/selfsigned.key",
+ "vesoft"));
+ NebulaPool sslPool = new NebulaPool();
+ sslPool.init(Arrays.asList(new HostAddress("192.168.8.123", 9669)),
+ nebulaSslPoolConfig);
+ String queryForJson = "YIELD 1";
+ Session sslSession = sslPool.getSession("root", "nebula", false);
+ String resp = sslSession.executeJson(queryForJson);
+ JSONObject errors = JSON.parseObject(resp).getJSONArray("errors").getJSONObject(0);
+ if (errors.getInteger("code") != ErrorCode.SUCCEEDED.getValue()) {
+ log.error(String.format("Execute: `%s', failed: %s",
+ queryForJson, errors.getString("message")));
System.exit(1);
}
System.out.println(resp);
}
} catch (Exception e) {
e.printStackTrace();
- } finally {
- if (session != null) {
- session.release();
- }
- pool.close();
}
}
}
diff --git a/examples/src/main/resources/ssl/casigned.crt b/examples/src/main/resources/ssl/casigned.crt
new file mode 100644
index 000000000..fe1add667
--- /dev/null
+++ b/examples/src/main/resources/ssl/casigned.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICljCCAX4CCQC9uuUY+ah8qzANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJD
+TjAeFw0yMTA5MjkwNzM4MDRaFw0yNDAxMDIwNzM4MDRaMA0xCzAJBgNVBAYTAkNO
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuo7hKpcs+VQKbGRq0fUL
++GcSfPfJ8mARtIeI8WfU0j1vI5KNujI//G2olOGEueDCw4OO0UbdjnsFpgj2awAo
+rj4ga2W6adQHK8qHY6q/Rdqv0oDCrcePMtQ8IwbFjNWOXC4bn7GcV7mzOkigdcj8
+UPkSeaqI9XxBRm3OoDX+T8h6cDLrm+ncKB8KKe/QApKH4frV3HYDqGtN49zuRs6F
+iurFbXDGVAZEdFEJl38IQJdmE2ASOzEHZbxWKzO/DZr/Z2+L1CuycZIwuITcnddx
+b2Byx/opwX4HlyODeUBbyDp+hd+GkasmIcpOlIDw9OXIvrcajKvzLEbqGt2ThsxX
+QwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAxzxtbYBQ2WgBGrpzOX4TxsuSaigqo
+YJ5zbVEHtwbsbBTZ7UJvRc9IyhrOL5Ui4PJI85chh1GpGqOmMoYSaWdddaIroilQ
+56bn5haB8ezAMnLXbPuf97UENO0RIkyzt63XPIUkDnwlzOukIq50qgsYEDuiioM/
+wpCqSbMJ4iK/SlSSUWw3cKuAHvFfLv7hkC6AhvT7yfaCNDs29xEQUCD12XlIdFGH
+FjMgVMcvcIePQq5ZcmSfVMge9jPjPx/Nj9SVauF5z5pil9qHG4jyXPGThiiJ3CE4
+GU5d/Qfe7OeiYI3LaoVufZ5pZnR9nMnpzqU46w9gY7vgi6bAhNwsCDr3
+-----END CERTIFICATE-----
diff --git a/examples/src/main/resources/ssl/casigned.key b/examples/src/main/resources/ssl/casigned.key
new file mode 100644
index 000000000..3561e7ab8
--- /dev/null
+++ b/examples/src/main/resources/ssl/casigned.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAuo7hKpcs+VQKbGRq0fUL+GcSfPfJ8mARtIeI8WfU0j1vI5KN
+ujI//G2olOGEueDCw4OO0UbdjnsFpgj2awAorj4ga2W6adQHK8qHY6q/Rdqv0oDC
+rcePMtQ8IwbFjNWOXC4bn7GcV7mzOkigdcj8UPkSeaqI9XxBRm3OoDX+T8h6cDLr
+m+ncKB8KKe/QApKH4frV3HYDqGtN49zuRs6FiurFbXDGVAZEdFEJl38IQJdmE2AS
+OzEHZbxWKzO/DZr/Z2+L1CuycZIwuITcnddxb2Byx/opwX4HlyODeUBbyDp+hd+G
+kasmIcpOlIDw9OXIvrcajKvzLEbqGt2ThsxXQwIDAQABAoIBAH4SEBe4EaxsHp8h
+PQ6linFTNis9SDuCsHRPIzv/7tIksfZYE27Ahn0Pndz+ibMTMIrvXJQQT6j5ede6
+NswYT2Vwlnf9Rvw9TJtLQjMYMCoEnsyiNu047oxq4DjLWrTRnGKuxfwlCoI9++Bn
+NAhkyh3uM44EsIk0bugpTHj4A+PlbUPe7xdEI/6XpaZrRN9oiejJ4VxZAPgFGiTm
+uNF5qg16+0900Pfj5Y/M4vXmn+gq39PO/y0FlTpaoEuYZiZZS3xHGmSVhlt8LIgI
+8MdMRaKTfNeNITaqgOWh9pAW4xmK48/KfLgNPQgtDHjMJpgM0BbcBOayOY8Eio0x
+Z66G2AECgYEA9vj/8Fm3CKn/ogNOO81y9kIs0iPcbjasMnQ3UXeOdD0z0+7TM86F
+Xj3GK/z2ecvY7skWtO5ZUbbxp4aB7omW8Ke9+q8XPzMEmUuAOTzxQkAOxdr++HXP
+TILy0hNX2cmiLQT1U60KoZHzPZ5o5hNIQPMt7hN12ERWcIfR/MUZa5UCgYEAwWCP
+6Y7Zso1QxQR/qfjuILET3/xU+ZmqSRDvzJPEiGI3oeWNG4L6cKR+XTe0FWZBAmVk
+Qq/1qXmdBnf5S7azffoJe2+H/m3kHJSprIiAAWlBN2e+kFlNfBhtkgia5NvsrjRw
+al6mf/+weRD1FiPoZY3e1wBKoqro7aI8fE5gwXcCgYEAnEI05OROeyvb8qy2vf2i
+JA8AfsBzwkPTNWT0bxX+yqrCdO/hLyEWnubk0IYPiEYibgpK1JUNbDcctErVQJBL
+MN5gxBAt3C2yVi8/5HcbijgvYJ3LvnYDf7xGWAYnCkOZ2XQOqC+Oz2UhijYE1rUS
+fQ2fXMdxQzERo8c7Y/tstvUCgYBuixy5jwezokUB20h/ieXWmmOaL00EQmutyRjM
+AczfigXzbp3zlDRGIEJ8V1OCyClxjTR7SstMTlENWZgRSCfjZAP3pBJBx+AW1oUI
+NB+4rsqxOYUeT26T+gLo8DJbkb0C+Mcqh2D22tuu2ZrBRVWceDVjAq+nvbvZ3Fxn
+UwbMkQKBgQCxL3aA6ART6laIxT/ZqMhV0ZcaoDJogjF+4I4bhlO4ivWGWJ4RpEDn
+ziFb6+M/4pe4vCou9yuAof6WTKM8JG4rok0yxhN3V6QGP49TjtrfkkrEPCtB2LSI
+N1+YRSTrS5VDcl8h8JH7fpghRnXHONEyIqasYVqsbxKzNyLV/z2rkw==
+-----END RSA PRIVATE KEY-----
diff --git a/examples/src/main/resources/ssl/casigned.pem b/examples/src/main/resources/ssl/casigned.pem
new file mode 100644
index 000000000..412ba3161
--- /dev/null
+++ b/examples/src/main/resources/ssl/casigned.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEGzCCAwOgAwIBAgIUDcmZFpL4PcdCXfLRBK8bR2vb39cwDQYJKoZIhvcNAQEL
+BQAwgZwxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwI
+SGFuZ3pob3UxFDASBgNVBAoMC1Zlc29mdCBJbmMuMRAwDgYDVQQLDAdzZWN0aW9u
+MRYwFAYDVQQDDA1zaHlsb2NrIGh1YW5nMScwJQYJKoZIhvcNAQkBFhhzaHlsb2Nr
+Lmh1YW5nQHZlc29mdC5jb20wHhcNMjEwODE5MDkyNDQ3WhcNMjUwODE4MDkyNDQ3
+WjCBnDELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFpoZWppYW5nMREwDwYDVQQHDAhI
+YW5nemhvdTEUMBIGA1UECgwLVmVzb2Z0IEluYy4xEDAOBgNVBAsMB3NlY3Rpb24x
+FjAUBgNVBAMMDXNoeWxvY2sgaHVhbmcxJzAlBgkqhkiG9w0BCQEWGHNoeWxvY2su
+aHVhbmdAdmVzb2Z0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AMEAgpamCQHl+8JnUHI6/VmJHjDLYJLTliN/CwpFrhMqIVjJ8wG57WYLpXpn91Lz
+eHu52LkVzcikybIJ2a+LOTvnhNFdbmTbqDtrb+s6wM/sO+nF6tU2Av4e5zhyKoeR
+LL+rHMk3nymohbdN4djySFmOOU5A1O/4b0bZz4Ylu995kUawdiaEo13BzxxOC7Ik
+Gge5RyDcm0uLXZqTAPy5Sjv/zpOyj0AqL1CJUH7XBN9OMRhVU0ZX9nHWl1vgLRld
+J6XT17Y9QbbHhCNEdAmFE5kEFgCvZc+MungUYABlkvoj86TLmC/FMV6fWdxQssyd
+hS+ssfJFLaTDaEFz5a/Tr48CAwEAAaNTMFEwHQYDVR0OBBYEFK0GVrQx+wX1GCHy
+e+6fl4X+prmYMB8GA1UdIwQYMBaAFK0GVrQx+wX1GCHye+6fl4X+prmYMA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHqP8P+ZUHmngviHLSSN1ln5
+Mx4BCkVeFRUaFx0yFXytV/iLXcG2HpFg3A9rAFoYgCDwi1xpsERnBZ/ShTv/eFOc
+IxBY5yggx3/lGi8tAgvUdarhd7mQO67UJ0V4YU3hAkbnZ8grHHXj+4hfgUpY4ok6
+yaed6HXwknBb9W8N1jZI8ginhkhjaeRCHdMiF+fBvNCtmeR1bCml1Uz7ailrpcaT
+Mf84+5VYuFEnaRZYWFNsWNCOBlJ/6/b3V10vMXzMmYHqz3xgAq0M3fVTFTzopnAX
+DLSzorL/dYVdqEDCQi5XI9YAlgWN4VeGzJI+glkLOCNzHxRNP6Qev+YI+7Uxz6I=
+-----END CERTIFICATE-----
diff --git a/examples/src/main/resources/ssl/selfsigned.key b/examples/src/main/resources/ssl/selfsigned.key
new file mode 100644
index 000000000..6006d0f27
--- /dev/null
+++ b/examples/src/main/resources/ssl/selfsigned.key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,6D12ED8559E80FA3
+
+tv9epnwlt4dP6Q5ee0dACOyFA5BTwYTdoMykQRJrKGwfaNeXUXn+sQ/U/oFHp1Wx
+O8VZE+z2aHpiFSTw+Eh6MPt86X5yVG3tpeVO6dErvr8Kd+NpuI8zn7rNoOFRh8wD
+33EFcQMLQPneDl10O18hooIoi0qwp1pd63hYZPwEhB3eOrM5Mnv9OVJs65bzYfyf
+Wku33YWYxeqlDvMCsou8PZnv/M2wYsr7+QoTcNmGKP45igMthMDBzwgF+q0p9ZZU
+N11c6ojAs01kfuqFf3vKfHNYe6zsBiNhnUuEy8enXSxD5E7tR/OI8aEzPLdk7fmN
+/UsMK2LE0Yd5iS3O1x/1ZjSBxJ+M/UzzCO692GTAiD6Hc13iJOavq/vt1mEPjfCD
+neF38Bhb5DfFi+UAHrz6EHMreamGCzP82us2maIs7mSTq7nXDZfbBc7mBDLAUUnT
+J6tlrTyc+DQXzkJa6jmbxJhcsWm6XvjIBEzSXVHxEDPLnZICQk3VXODjCXTD75Rg
+0WaS78Ven7DW8wn07q3VzWAFDKaet3VI+TVTv7EfIavlfiA6LSshaENdFLeHahNE
+s/V/j5K3Pg6+WQcZRgOsfqIwUCSQxY13R6TTdaaCkLay5BggF5iiAO3pkqsJiadf
+w843Ak4USBptymJxoZgJyFtQHpQyNiFfsAbs9BaYbg2evvE7/VQhLk0gQ7HgQMeJ
+wgxEQqZQKDCCSugSzY1YEGXKnrZYCKyipzyyH936mE15zNwhYp/Pi2020+gmtP3h
+CDfcPs1yeLI2/1JuimafbuKsv9xchWa6ASU8p8Q7wTLtUj9ylLKyA4A/75pK0DXG
+Hv/q0O+UfhAMD438SoPBle7RSvIsDU1VjUqstlNybBglBZxGIME7/18+Ms7U32wh
+4xFkZwxT2nqFgyk37tXMdMz9UBh12/AXR9NU4XY37C3Ao2TDT7/0DvU6KdJhsDpv
+rGcaC2zzhko+0CPrLlk52KbqP003JXiWvOSI+FylyPPDB/YGitmndJUuQblf3u/E
+l+tGi9MeSBQeWKV6D3AVnO05AZjfTUzSK0vw4DgNh5YPNJvLy31B7kDAS88vyGI1
+t6MBwjW4/tz/nS/p1Go3mSzBhPkIsCrZE+ar7lH8p8JqkLl4fXIMaVKIfyfJdzyS
+lkh3K7bOGDPegxxxaWdb+EnC7k+1R3EOU7uJFW61HyrGI3q6Y7kOl5aYSJ5Ge1Uv
+PycFWHWVTHq/R7HRE6HIJzGe/PnLIbStXLDFeivjfcYq1YaSaF8Vl+xg+0u3ULOl
+P6IuPTph6dlcgttRZVl3ETcF0T+2wfbUwgjf0ZiguCJfR2jLGhPl1KBg0Kd9cTSY
+zI3YMMd2G8hApt/QFlm4Ry8CqaJUmDcjDNIJT3M+RldUgfz37NsX05cA5e9+I1AL
+2406F/v5U9gWsYx7HuwJtQrDzYYDbl1GD4H+qHFJE5JYhPP4AyWYxJ1NR5dqyvrt
++3r5+xlwZrS76c10RsBWL7th8ZEzRxOZxbtLwbf4bG/tIGfQP2sTnWwA+qym6b2S
+sRduqOTP+xwnhOq/ZKn8lfsDfhT8CPnKHBsd09kM9y/UWuxFe0upLydRLE/Wsb9s
+-----END RSA PRIVATE KEY-----
diff --git a/examples/src/main/resources/ssl/selfsigned.password b/examples/src/main/resources/ssl/selfsigned.password
new file mode 100644
index 000000000..143be9ab9
--- /dev/null
+++ b/examples/src/main/resources/ssl/selfsigned.password
@@ -0,0 +1 @@
+vesoft
diff --git a/examples/src/main/resources/ssl/selfsigned.pem b/examples/src/main/resources/ssl/selfsigned.pem
new file mode 100644
index 000000000..412ba3161
--- /dev/null
+++ b/examples/src/main/resources/ssl/selfsigned.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEGzCCAwOgAwIBAgIUDcmZFpL4PcdCXfLRBK8bR2vb39cwDQYJKoZIhvcNAQEL
+BQAwgZwxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwI
+SGFuZ3pob3UxFDASBgNVBAoMC1Zlc29mdCBJbmMuMRAwDgYDVQQLDAdzZWN0aW9u
+MRYwFAYDVQQDDA1zaHlsb2NrIGh1YW5nMScwJQYJKoZIhvcNAQkBFhhzaHlsb2Nr
+Lmh1YW5nQHZlc29mdC5jb20wHhcNMjEwODE5MDkyNDQ3WhcNMjUwODE4MDkyNDQ3
+WjCBnDELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFpoZWppYW5nMREwDwYDVQQHDAhI
+YW5nemhvdTEUMBIGA1UECgwLVmVzb2Z0IEluYy4xEDAOBgNVBAsMB3NlY3Rpb24x
+FjAUBgNVBAMMDXNoeWxvY2sgaHVhbmcxJzAlBgkqhkiG9w0BCQEWGHNoeWxvY2su
+aHVhbmdAdmVzb2Z0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AMEAgpamCQHl+8JnUHI6/VmJHjDLYJLTliN/CwpFrhMqIVjJ8wG57WYLpXpn91Lz
+eHu52LkVzcikybIJ2a+LOTvnhNFdbmTbqDtrb+s6wM/sO+nF6tU2Av4e5zhyKoeR
+LL+rHMk3nymohbdN4djySFmOOU5A1O/4b0bZz4Ylu995kUawdiaEo13BzxxOC7Ik
+Gge5RyDcm0uLXZqTAPy5Sjv/zpOyj0AqL1CJUH7XBN9OMRhVU0ZX9nHWl1vgLRld
+J6XT17Y9QbbHhCNEdAmFE5kEFgCvZc+MungUYABlkvoj86TLmC/FMV6fWdxQssyd
+hS+ssfJFLaTDaEFz5a/Tr48CAwEAAaNTMFEwHQYDVR0OBBYEFK0GVrQx+wX1GCHy
+e+6fl4X+prmYMB8GA1UdIwQYMBaAFK0GVrQx+wX1GCHye+6fl4X+prmYMA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHqP8P+ZUHmngviHLSSN1ln5
+Mx4BCkVeFRUaFx0yFXytV/iLXcG2HpFg3A9rAFoYgCDwi1xpsERnBZ/ShTv/eFOc
+IxBY5yggx3/lGi8tAgvUdarhd7mQO67UJ0V4YU3hAkbnZ8grHHXj+4hfgUpY4ok6
+yaed6HXwknBb9W8N1jZI8ginhkhjaeRCHdMiF+fBvNCtmeR1bCml1Uz7ailrpcaT
+Mf84+5VYuFEnaRZYWFNsWNCOBlJ/6/b3V10vMXzMmYHqz3xgAq0M3fVTFTzopnAX
+DLSzorL/dYVdqEDCQi5XI9YAlgWN4VeGzJI+glkLOCNzHxRNP6Qev+YI+7Uxz6I=
+-----END CERTIFICATE-----