Java Rconnection hangs when Rserve has TLS enabled - java

I have an Ubuntu VM with R and Rserve installed for remote calls. I start Rserve in debug mode from the terminal with:
R CMD Rserve.dbg
And this is the output:
Rserve 1.8-6 () (C)Copyright 2002-2013 Simon Urbanek
Loading config file /etc/Rserv.conf
conf> command="remote", parameter="enable"
conf> command="plaintext", parameter="disable"
conf> command="encoding", parameter="utf8"
conf> command="pwdfile", parameter="/etc/RserveAuth.txt"
conf> command="auth", parameter="required"
conf> command="qap", parameter="disable"
conf> command="qap.tls.port", parameter="6311"
conf> command="tls.key", parameter="server.key"
conf> command="tls.cert", parameter="server.crt"
conf> command="tls.ca", parameter="rootCA.crt"
Loaded config file /etc/Rserv.conf
R version 3.5.3 (2019-03-11) -- "Great Truth"
Copyright (C) 2019 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)
R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.
Natural language support but running in an English locale
R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.
Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.
- create_server(port = 6311, socket = <NULL>, mode = 0, flags = 0x800)
INFO: adding server 0x5618de18b9d0 (total 1 servers)
Rserve: Ok, ready to answer queries.
I generated the key and self-signed certificates with OPENSSL.
Now on the client side, I have a Java application just requesting the version of R that Rserve is sitting on top of as a test of functionality:
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.Rserve.RConnection;
public class RJava {
public static void main(String[] args) throws Exception{
//Run R code on remote R installation via Rserve.
String remoteIP="10.16.24.63"; //Ubuntu VM Box
int port=6311;
String user="TEST";
String pass="12345";
//Connect to the remote server.
RConnection connection = new RConnection(remoteIP,port);//Remote server
connection.login(user, pass);
//Run a command.
REXP x = connection.eval("R.version.string");
System.out.println(x.asString());
//Disconnect.
connection.close();
}
}
The problem is the client code hangs on the call to the RConnection constructor. I've let it go for ten minutes and nothing changes until I kill the server. On the server side I just see:
INFO: accepted connection for server 0x5618de18b9d0, calling connected
connection accepted.
I can't find any documentation to help at this point. Is this possibly a client configuration problem?
Also, if I remove all the TLS configuration items from Rserv.conf, Rserve will work as expected no problem with this client code, so I know it is set up correctly.

I figured this out on my own. It was in fact a client configuration problem. I needed to create the RConnection with an SSLSocket and also import the server certificate to the java truststore.
Relevant client code changed to this:
SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(remoteIP, port);
//Connect to the remote server.
RConnection connection = new RConnection(sslsocket);
N.B. the constructor RConnection(Socket s) is apparently not in the REngine jar, so I grabbed the source itself and put that in my project because it is included there.
Running at this point threw a javax.net.ssl.SSLHandshakeException because the cert wasn't in the truststore. So I withdrew the cert from the server using OPENSSL like this:
echo "" | openssl s_client -connect 10.16.24.63:6311 | openssl x509 -out server.crt
Then I moved that cert file to %JAVA_HOME%\jre\lib\security and ran this to import the certificate:
keytool -import -alias myAlias -file server.crt -keystore cacerts -storepass changeit
And it works! Wireshark confirms all the packets are now encrypted.
Resources:
https://stats-rosuda-devel.listserv.uni-augsburg.narkive.com/g5VM1afB/encryption-with-rserve-1-8-1
https://www.baeldung.com/java-ssl
Digital Certificate: How to import .cer file in to .truststore file using?

Related

The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "PKIX path building failed:

I'm new to SQL(Microsoft SQL Server Management) and I am trying to connect it with IntelliJ
I am getting the following error:
com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target".
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class MyJDBC {
public static void main(String[] args) {
String connectionURL = "jdbc:sqlserver://localhost:10020;databaseName=mydatabase;user=me;password=random_password";
try {
System.out.print("Connecting to the server......");
try (Connection connection = DriverManager.getConnection(connectionURL)) {
System.out.println("Connected to the Server.");
}
}catch (Exception e){
System.out.println("I am not connected to the Server");
e.printStackTrace();
}
}
}
I have this on my lib
LIB
Any help is appreciated it!
Add encrypt=true and trustServerCertificate=true to connection url.
String connectionURL = "jdbc:sqlserver://localhost:10020;databaseName=mydatabase;user=me;password=random_password;encrypt=true;trustServerCertificate=true";
Microsoft Blog Reference - link
Find below excerpt from it -
This is an issue in Java Certificate Store. As a quick workaround, if
you enable TrustServerCertificate=True in the connection string, the
connection from JDBC succeeds. When TrustServerCertificate is set to
true, the transport layer will use SSL to encrypt the channel and
bypass walking the certificate chain to validate trust. If
TrustServerCertificate is set to true and encryption is turned on, the
encryption level specified on the server will be used even if Encrypt
is set to false. The connection will fail otherwise. However, for
security considerations, it is not recommended to bypass the
certificate validation. Hence, to address the issue, follow the steps
below to change the connection string and import the required
certificates.
Change the connection string to point to the Java certificate path
String connectionUrl = "jdbc:sqlserver://localhost:1433;" +
"databaseName=AdventureWorks;integratedSecurity=true;" +
"encrypt=true; trustServerCertificate=false;" +
"trustStore= C:\Program Files\Java\jdk-14.0.2\lib\cacert;trustStorePassword=changeit";
Import all the certificates mentioned in this document.
Note: To import above certificates into the keystore cacerts, please
use below command and please note you must mention truststore and
truststore password in the connection string to successfully connect.
Steps to import missing certificates in Java Certificate Store
Download all the certs from here, store them in a location on client
host and then use keytool utility to import these certificates into
the truststore. Please follow the below steps:
Save all the certificates from the above MS doc. Keytool utility is in
the bin folder of your default Java location (C:\Program
Files\Java\jdk-14.0.2\bin). You need to use command prompt to navigate
to that location. Then you can use the keytool command to import the
certificate previously saved. When prompted for password insert the
key in the password as “changeit”
Example of commands:
keytool -importcert -trustcacerts -alias TLS1 -file
"C:\Users\Documents\Microsoft RSA TLS CA 01.crt" -keystore "C:\Program
Files\Java\jdk-14.0.2\lib\security\cacerts"
keytool -importcert -trustcacerts -alias TLS2 -file
"C:\Users\Documents\Microsoft RSA TLS CA 02.crt" -keystore "C:\Program
Files\Java\jdk-14.0.2\lib\security\cacerts"
Below worked for me:
jdbc:sqlserver://Host;trustServerCertificate=true;integratedSecurity=true;authenticationScheme=NTLM

Error while consuming secure SOAP base web service in JAVA

I am new in JAVA, Consuming web service(.wsdl) in Web Service Client project. I import the client certificate in java cacerts store in jrd. My code is as follows:
System.setProperty("javax.net.ssl.trustStore","[PATH]/cacerts.jks");
System.setProperty("javax.net.ssl.trustStorePassword","changeit");
ServicesProxy service = new ServicesProxy();
ServiceRequest request = new ServiceRequest(1498);
ServiceResponse response = service.getDetails(request);
I'm failed to handshake, I am getting the following exception:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
I have no clue why there is an exception. Any help will be appreciated.
You probably have to add the key chain in the certificate (PEM format).
CA Root -> Intermediate Cert -> Cert.
Or the certificate cannot be found in the keystore, do you use the correct alias etc.
And I do not recognize the SOAP JAX-WS implementation you use.
Not a solution to your problem, but maybe it helps to find it:
You can start your client with the VM parameter -Djavax.net.debug=all which will give you a lot of information about the SSL connection.
Check here for details about the output:
https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/ReadDebug.html
Use -Djavax.net.ssl.trustStore property directly instead.
One more thing the server you use in that also u need to place the jks for handshake.
For example server is JBoss then bin
I guess your cacert is not correct or the path is unaccessible. I followed the instructions given here
Use SSL Poke to verify connectivity
Download SSLPoke.class
Execute the class as follows, changing the URL and port:
$JAVA_HOME/bin/java SSLPoke yoururl 443
A successful connection would look like this:
$JAVA_HOME/bin/java SSLPoke yoururl 443
Successfully connected
Try to use a different truststore to connect
$JAVA_HOME/bin/java -Djavax.net.ssl.trustStore=[PATH]/cacerts.jks SSLPoke yoururl 443
If it fails the truststore does not contain the proper certificates.
How to solve it
The solution is extracted from here
Fetch the certificate again from the server:
openssl s_client -connect yoururl:443
You need openssl. Save the output to a file called public.crt. This is how your file should look like:
-----BEGIN CERTIFICATE-----
< Bunch of lines of your certificate >
-----END CERTIFICATE-----
Import the certificate:
$JAVA_HOME/bin/keytool -import -alias -keystore $JAVA_HOME/jre/lib/security/cacerts -file public.crt
Enter the password if prompted (the default is changeit)
Recommendation
In the same post it is not recommended to use a configured trustStore different than the JVM cacert because then java could not access other root certificates.
This is a quite common error while dealing with soap services over SSL, I've had it a few times.
Your certificate may not be correctly installed in your truststore.
You can use openssl to check and install the correct certificate in the truststore, as explained here
Hi Looks like certificates are not imported correctly or path used in code not pointing to correct keystore.
I hope following steps in below article will help you.
http://magicmonster.com/kb/prg/java/ssl/pkix_path_building_failed.html

Unable to connect to MySQL database with SunCertPathBuilderException

I'm trying to connect to MySQL database:
static final String URL="jdbc:mysql://localhost:3306/demo_hotels?useSSL=true&autoReconnect=true&serverTimezone=UTC";
static final String USERNAME="demo";
static final String PASSWORD="demo";
public static void main(String[] args) {
try {
DriverManager.registerDriver(new FabricMySQLDriver());
connection=DriverManager.getConnection(URL, USERNAME, PASSWORD);
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new
JdbcConnection(connection));
Liquibase liquibase = new liquibase.Liquibase("db/db.changelog.xml",
new ClassLoaderResourceAccessor(), database);
liquibase.update(new Contexts(), new LabelExpression());
database.close();
} catch (SQLException | LiquibaseException e) {
e.printStackTrace();
}
This was working. But now I'm trying to execute this code on another machine and it doesn't work:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
at com.pazukdev.auxiliary_services.DBService.main(DBService.java:69)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed:
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
Why did it stop to work?
Old machine: java version 1.8.0_112, Windows 7, MySQL Server 5.7.21
New machine: java version 1.8.0_172, Windows 10, MySQL Server 8.0.11
I found some information about such kind of exceptions. It look like I have some triobles with SSL certificate: Accept server's self-signed ssl certificate in Java client
But Option 2 with TrustManager not works - I have the same Exception.
I tried to type in cmd:
<JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit
But I have no eny effect from this Option 1 too.
Maybe I'm doing something wrong..
I'm not Java developer, but I have some doubts and questions here.
Do you actually need for ?useSSL=true if you're using local db?
What are the results of your cmd execution? Did you have correctly exported server.cer file corresponds to your local host? With necessary keypass and storepass?
I had a global problem with database and connection to it. It was caused by that now I installed all the MySQL stuff in its lastest versions. And on my old machine I have the older versions of that software. So, I even had some exceptions trying to execute some of my old MySQL queries in new software.
I installed the same versions of MySQL Server and Connector/ODBC as I have on old machine (5.7.21 and 5.3.10 respectively) and got connection working properly as before.

How to fix SSL - No available certificate

I want to make a server SSL socket connection using the following code:
int port = 12000;
ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
ServerSocket ssocket = ssocketFactory.createServerSocket(port);
// Listen for connections
Socket socket = ssocket.accept();
I get a "javax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled." when doing the accept.
I created a Keystore that contains a RSA key using:
keytool -genkeypair -alias ClubConnectionCert -keyalg RSA -validity 7 -keystore ClubConnectionKeystore
and I start my Program with the following options:
-Djavax.net.ssl.keyStore=ClubConnectionKeystore -Djavax.net.ssl.keyStorePassword=mypassword
Do I miss some code to read in the Keystore, or how can I test/debug that the given keystore is actually used?
I executed your code and I confirm it's working fine.
Make sure javax.net.ssl.keyStore points exactly to your keystore file.
I put my keystore file at the root of my project.
Perhaps try absolute path to your keystore.
Make sure the -D parameters are set as JVM params, not Program options (in your IDE).
Good luck, you're about to make it work.

SSL Connection from Java client

I'm creating a Java client program that will be sending sensitive information to a Tomcat server. So I need to use SSL Connection so information will be encrypted.
I need to use self-signed untrusted certificate but having problems making connection from java client.
I have successfully setup Tomcat 5.5 to use SSL and tested it through Firefox, which displays warning of self-signed certificate.
I followed the Tomcat 5.5 SSL setup and they mentioned to create a keystore:
keytool -genkey -alias tomcat -keyalg RSA
Then I did an export of the above:
keytool -export -keystore .keystore -alias tomcat -file localhost.cer
Then I did an import of the above certificate into client machine:
keytool -import -alias tomcat -file localhost.cer -keystore "C:\Program Files"\Java\jdk1.6.0_17\jre\lib\security\cacerts"
But when running client I get:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
This is the client code:
URL url = new URL("https://localhost:8443");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
Now I just started playing with these certificates today and I'm new to keystores, so please be patient.
Can someone please explain how to export and import the certificate created in Tomcat to client machine?
Thank you.
Atlassian has good instructions on how to fix this.
http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services
Another approach is to install less unforgiving certificate validators, but that should only be done as a last resort.
Use Apache HTTP Cleint jar and follow this SSL Guide.
EasySSLProtocolSocketFactory can be used to create SSL connections that allow the target server to authenticate with a self-signed certificate.
I think you should input password using "changeit".

Categories