SSL VPN connection to a Fortinet firewall with Java - java

I'm trying to create an SSL VPN connection to a Fortinet firewall with Java.
To build up a socket connection in Java is not a problem, but how do I authenticate to the firewall and create the VPN tunnel? Unfortunately, I haven't found any tutorials. Maybe someone can help me with that.
public static void main(String[] args) throws IOException {
String vpnHost = "fortigateVPNHost";
int vpnPort = 443;
String vpnUser = "vpnUser";
String vpnPassword = "vpnPassword";
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(vpnHost, vpnPort);
InputStream in = sslsocket.getInputStream();
OutputStream out = sslsocket.getOutputStream();
while (in.available() > 0) {
System.out.print(in.read());
}
System.out.println("Secured connection performed successfully");
}

In order to authenticate to the firewall, it must be configured from Fortinet GUI or CLI, adding the user group and adding the user in question; then the socket should automatically connect using the firewall configuration.

Related

Java Socket not using proxy from JAVA_TOOL_OPTIONS

How to make all Java connections to use proxy provided via JAVA_TOOL_OPTIONS environment variable?
The simple app I'm using as a test is taken from GitHub:
package to.noc.sslping;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.OutputStream;
public class SSLPing {
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("Usage: java -jar SSLPing.jar <host> <port>");
System.exit(1);
}
try {
String hostname = args[0];
int port = Integer.parseInt(args[1]);
System.out.println("About to connect to '" + hostname + "' on port " + port);
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(hostname, port);
// Hostname verification is not done by default in Java with raw SSL connections.
// The next 3 lines enable it.
SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
sslsocket.setSSLParameters(sslParams);
// we only send 1 byte, so don't buffer
sslsocket.setTcpNoDelay(true);
// Write a test byte to trigger the SSL handshake
OutputStream out = sslsocket.getOutputStream();
out.write(1);
// If no exception happened, we connected successfully
System.out.println("Successfully connected");
} catch (Exception e) {
e.printStackTrace();
}
}
}
What I want is to be able to provide the PROXY settings via environment variables without having to configure it in the Java code.
I found that it is possible to provide some settings via the JAVA_TOOL_OPTIONS env.
JAVA_TOOL_OPTIONS="-Dhttp.proxyHost=161.xxx.xxx.xxx
-Dhttp.proxyPort=8080
-Dhttp.proxySet=true
-Dhttps.proxyHost=161.xxx.xxx.xxx
-Dhttps.proxyPort=8080
-Dhttps.proxySet=true"
It is correctly seen by the command
java -jar SSLPing.jar google.com 443
Picked up JAVA_TOOL_OPTIONS: -Dhttp.proxyHost=161.xxx.xxx.xxx
-Dhttp.proxyPort=8080
-Dhttp.proxySet=true
-Dhttps.proxyHost=161.xxx.xxx.xxx
-Dhttps.proxyPort=8080
-Dhttps.proxySet=true
About to connect to 'google.com' on port 443
Successfully connected
However when I need to reach a particular URL that requires the proxy, it fails to connect.
How do I make any socket to use the proxy from JAVA_TOOL_OPTIONS env?
How to check if the sockets are using the proxy?

How to connect to an SSL Server in Java that doesn't send a certificate?

I have a situation where an Open SSL server is running without a certificate as follows :
openssl s_server -accept 4443 -nocert
How do I connect to this server using Java? Also, how do I start my server in Java to accept no certificate?
I have attached the code for Client.java and Server.java that I have been using.
Error while running the attached code on the client side:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
at Client.main(Client.java:27)
Error on the Server Side :
ERROR
140387701290656:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1358:
shutting down SSL
CONNECTION CLOSED
ACCEPT
Client.java
public class Client {
public static void main(String[] arstring) {
try {
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", 4443);
//sslsocket.setEnabledCipherSuites(sslsocket.getSupportedCipherSuites());
sslsocket.setEnabledCipherSuites(new String[] { "TLS_DH_anon_WITH_AES_128_CBC_SHA" }); //Added upon suggestion from Steffan
boolean test = sslsocket.isConnected();
System.out.println(test);
InputStream inputstream = sslsocket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
System.out.println("1");
OutputStream outputstream = sslsocket.getOutputStream();
System.out.println("2");
OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream,"UTF-8");
String str = "hello\n";
outputstreamwriter.write(str,0,str.length());
//outputstreamwriter.flush();
BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);
String string = null;
int count = 0;
string = bufferedreader.readLine();
while (true) {
System.out.println(string);
System.out.flush();
System.out.println(++count);
string = bufferedreader.readLine();
if (inputstream.available()==0)
break;
else{
System.out.print("StreamData:");
System.out.println(inputstream.available());
}
}
System.out.println("Out");
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
Server.java
public class Server {
public static void main(String[] arstring) {
try {
SSLServerSocketFactory sslServersocketFactory =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslServersocketFactory.createServerSocket(4443);
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
if (sslSocket.isConnected())
System.out.println("Connected to a client");
InputStream inputStream = sslSocket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String command = "";
String response = "";
while ((command = bufferedReader.readLine()) != null) {
System.out.println("Command Recieved: "+command);
if (command.toLowerCase().compareTo("hello")==0)
response = "Bingo !! You got it write!\n";
else
response = "Type Hello to see a response\n";
OutputStream outputStream = sslSocket.getOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream,"UTF-8");
outputStreamWriter.write(response, 0, response.length());
outputStreamWriter.flush();
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
Edit:
I think I need to use the anonymous DH Cipher but it's still not working. May be I am doing it wrong. The code has been edited too.
How to connect to an SSL Server in Java that doesn't send a certificate?
If its not sending a certificate, then its probably using (1) one of the preshared keys cipher suites, like TLS-SRP or TLS-PSK, or (2) its using Anonymous Diffie-Hellman.
The preshared key cipher suites are usually choices because they provide mutual authentication and channel binding.
Anonymous Diffie-Hellman is usually a bad choice because it lacks server authentication.
I have a situation where an Open SSL server is running without a certificate as follows : openssl s_server -accept 4443 -nocert
Well, there you have it.
How do I connect to this server using Java? Also, how do I start my server in Java to accept no certificate?
Use a cipher suite that includes an anonymous exchange, like:
ADH-DES-CBC3-SHA
ADH-AES128-SHA
ADH-AES256-SHA
ADH-CAMELLIA128-SHA
ADH-CAMELLIA256-SHA
ADH-SEED-SHA
ADH-AES128-SHA256
ADH-AES256-SHA256
ADH-AES128-GCM-SHA256
ADH-AES256-GCM-SHA384
You can get the mapping of ADH-AES128-SHA to TLS_DH_anon_WITH_AES_128_CBC_SHA at the openssl ciphers man page.
You might try the command:
openssl s_server -accept 4443 -tls1 -nocert -cipher "HIGH"
By enabling TLS1, you side step any potential issues where one side or the other disables SSLv2 and SSLv3 (which is a good thing), but you only provide SSLv3 (which is a bad thing).
The cipher suite list string "HIGH" includes ADH by default (in production, usually you do "HIGH:!ADH:!RC4:!MD5...").

Connect multiple android devices to a "main" pc app

I want to create and run an application (in java) in a computer and allow multiple users to use their android devices as input devices to that main app. It must be in real time for every device.
For example: To do some follow up exercises after a training session. Users would register them selves (a simple form that would send strings to the main app on the PC) then they get some questions and every question as a timer, so who answers correctly and faster gets a better grade.
What's the best way to get this done? And yes, if it makes it easier, the connections can be through internet/LAN.
It looks like there are two parts to this. The first is a database system to handle user registration etc... look into SQL for that. There are many approaches. In terms of getting multiple phones connected to a computer PC you will need a server that can handle threads and a client for the phone.
A server needs server sockets. Server sockets can accept more than one connected client at a time. A threaded server might look like this:
public class ServerThread extends Thread
{
//is the thread running
private boolean running = true;
//ports for the server sockets
private final int dataPort;
private final int filePort;
private final String certificateDir;
private final char[] password;
private Vector<ClientHandlerThread> connectedClients = new Vector<ClientHandlerThread>(20, 5);
private Properties userProperties = new Properties();
public ServerThread(int dataPort,
int filePort,
String certificateDir,
char[] password,
Properties userProperties)
{
this.dataPort = dataPort;
this.filePort = filePort;
this.certificateDir = certificateDir;
this.password = password;
this.userProperties = userProperties;
}
public void run()
{
/*
* We need a server socket that can accept traffic. I use one for file traffic and one
* for data traffic although one socket could be used.
*/
SSLServerSocket sslDataTraffic = null;
SSLServerSocket sslFileTraffic = null;
SSLServerSocketFactory sslFac = null;
/*
* Everything in the following block is related to creating a SSL security manager.
* If you don't need validated communications you don't have to use SSL. Just normal
* sockets.
*/
try
{
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(certificateDir), password);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance((KeyManagerFactory.getDefaultAlgorithm()));
kmf.init(keyStore, password);
System.setProperty("https.protocols", "SSL");
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
sslFac = ctx.getServerSocketFactory();
}
catch(Exception e)
{
System.out.println("FAILED.");
e.printStackTrace();
System.exit(-1);
}
try
{
//create data server socket
System.out.print("Creating data socket......... ");
sslDataTraffic = (SSLServerSocket) sslFac.createServerSocket(dataPort);
System.out.println("DONE. Est. on:" + dataPort);
//create file server socket
System.out.print("Creating file socket......... ");
sslFileTraffic = (SSLServerSocket) sslFac.createServerSocket(filePort);
System.out.println("DONE. Est. on:" + filePort);
}
catch (IOException e)
{
System.out.println("FAILED.");
System.out.println(e.toString() + " ::: " + e.getCause());
System.exit(-1);
}
/*
* This block is used to print the ip the server is running on. Easy to incorporate this here
* so the information doesn't have to be gathered form another source.
*/
try
{
System.out.print("Finishing.................... ");
Socket s = new Socket("google.com", 80);
System.out.println("DONE.");
System.out.println("Server online at: " + s.getLocalAddress().getHostAddress());
System.out.println("====================*====================");
s.close();
}
catch (IOException e)
{
e.printStackTrace();
}
/*
* This is the block that accepts connections from clients.
*/
try
{
while (running)
{
//wait here until a connection is bound to new sockets through the server sockets
SSLSocket sslDataTrafficSocketInstance = (SSLSocket) sslDataTraffic.accept();
SSLSocket sslFileTrafficSocketInstance = (SSLSocket) sslFileTraffic.accept();
//sockets to communicate with the client are created. Lets put them in a thread so
//we can continue to accept new clients while we work with the newly and previously
//connected clients
//create a new thread
ClientHandlerThread c = new ClientHandlerThread(
sslDataTrafficSocketInstance,
sslFileTrafficSocketInstance,
userProperties);
//start thread
c.start();
//add newly connected client to the list of connected clients
connectedClients.add(c);
}
}
catch (IOException e)
{
System.out.println("Fatal server error, terminating server and client handler threads");
stopServer();
}
}
}
The constructor of the ClientHandlerThread class looks like this:
private PrintWriter writer;
private BufferedReader reader;
private InputStream inputStream;
private OutputStream outputStream;
public ClientHandlerThread(
SSLSocket dataSocket,
SSLSocket fileSocket,
Properties userProperties)
{
this.dataSocket = dataSocket;
this.fileSocket = fileSocket;
this.userProperties = userProperties;
try
{
this.reader = new BufferedReader(new InputStreamReader(this.dataSocket.getInputStream()));
this.writer = new PrintWriter(this.dataSocket.getOutputStream());
this.inputStream = fileSocket.getInputStream();
this.outputStream = fileSocket.getOutputStream();
}
catch (IOException e)
{
e.printStackTrace();
}
}
Notice streams are created from the sockets. This is what opens the communication channel to the client. The thread can send a receive data and requests. What requests you write and the way you handle them is up to you.
The client will look very similar to the server but with one big difference. The client needs to initialize the handshake. One side must send data first to initialize the communication. Since the client is connecting to the server I typically have the client send the first set of data. The client's connection code might look like this method:
private void connect()
{
try
{
SSLSocketFactory sslFac;
SSLSocket dataSocket = null;
SSLSocket fileSocket = null;
/*
* This block is nearly identical to the security block for the server side.
*/
try
{
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(certificateDir), password.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance((KeyManagerFactory.getDefaultAlgorithm()));
kmf.init(keyStore, password.toCharArray());
System.setProperty("https.protocols", "SSL");
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
sslFac = ctx.getSocketFactory();
String ip = "<THE SERVER'S IP ADDRESS>";
dataSocket = (SSLSocket) sslFac.createSocket(ip, dataPort);
fileSocket = (SSLSocket) sslFac.createSocket(ip, filePort);
}
catch(Exception e)
{
System.out.println("FAILED.");
e.printStackTrace();
System.exit(-1);
}
reader = new BufferedReader(new InputStreamReader(dataSocket.getInputStream()));
writer = new PrintWriter(dataSocket.getOutputStream());
OutputStream fileOut = fileSocket.getOutputStream();
writer.println("CLIENT_HANDSHAKE_INIT");
writer.flush();
}
}
At this point you should have a client connected to a server and the client should have initialized the handshake. You have streams open to each other on both ends allowing the server and client to communicate. At this point you can begin polishing and building up the server and client to do what you actually want to do. The code I've provided is missing a dew parts that you will need to fill in as you tailor the system to your specific needs. I provided this system as an example for you to follow. A few notes. Remember someone has to start the handshake for communication to take place. Remember the streams must be flushed for the data to transmit. This security model does not apply to public connections. I was strictly trying to prevent outside connections from being successful. You will need to do more research on SSL if you need secured connections.
Hope this gave you some ideas about the server-client model and what you want to do with it.
Cheers,
Will

Java Server Socket - Only works locally (TCP)

I have a server/client application written in java. Basically when the client tries to connect to the server locally (127.0.0.1 as IP) everything works fine. However when I use my personal IP address (home address) I get a connection timeout error.
*I have portforwarded correctly, tested using port check tool
*I also checked using netstat -a in command prompt
*I am hosting on port 9005
here is some of my client code, where I assume I am doing somthing wrong:
public void run() throws UnknownHostException, IOException{
String serverAddress = "xx.xx.xx.xxx"; //My actual IP is here in the program
Socket socket = new Socket(serverAddress, 9005);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
String playerName = JOptionPane.showInputDialog(
this,
"Choose Username:",
"Name Selection",
JOptionPane.PLAIN_MESSAGE);
out.println("NEW "+playerName);
I'm fairly new to server programing in Java, any suggestions would be appreciated.
I can post more code if requested, just didn't want to post a mountain of it.
thanks.
EDIT: here is some server code:
private final static int PORT = 9005;
public static void main(String[] args) throws Exception {
Server s = new Server();
s.setSize(50,100);
s.setDefaultCloseOperation(s.EXIT_ON_CLOSE);
s.setVisible(true);
System.out.println("Server running");
ServerSocket listener = new ServerSocket(PORT);
try {
while (true) {
new Handler(listener.accept()).start();
}

MySQL jdbc + SSL

I set system properties for a SSL-enabled MySQL client, which worked fine:
System.setProperty("javax.net.ssl.trustStore","truststore");
System.setProperty("javax.net.ssl.trustStorePassword","12345");
String url = "jdbc:mysql://abc.com:3306/test?" +
"user=abc&password=123" +
"&useUnicode=true" +
"&characterEncoding=utf8&useSSL=true"
A couple days ago I found the client couldn't connect to another web site in which a commercially signed SSL certificate is installed. Obviously the overriding keystores didn't work with regular https connections.
Then I decided to build my version of SocketFactory based on StandardSocketFactory.java in MySQL Connector/J source.
I added a method to create Socket objects in public Socket connect(String hostname, int portNumber, Properties props) method.
private Socket createSSLSocket(InetAddress address, int port) {
Socket socket;
try {
InputStream trustStream = new FileInputStream(new File("truststore"));
KeyStore trustStore = KeyStore.getInstance("JKS");
// load the stream to your store
trustStore.load(trustStream, trustPassword);
// initialize a trust manager factory with the trusted store
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX", "SunJSSE"); trustFactory.init(trustStore);
// get the trust managers from the factory
TrustManager[] trustManagers = trustFactory.getTrustManagers();
// initialize an ssl context to use these managers and set as default
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, null);
if(address == null) {
socket = sslContext.getSocketFactory().createSocket();
} else {
socket = sslContext.getSocketFactory().createSocket(address, port);
}
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
return null;
}
return socket;
}
The url passed to jdbc driver is changed to:
String url = "jdbc:mysql://abc.com:3306/test?" +
"user=abc&password=123" +
"&useUnicode=true" +
"&characterEncoding=utf8&useSSL=true" +
"&socketFactory=" + MySocketFactory.class.getName();
The client did execute my version createSSLSocket() and return a Socket object. However, I got the following Exceptions after continuing the execution:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
javax.net.ssl.SSLException:
Unrecognized SSL message, plaintext connection?
I'm sure the MySQL was up and running, the address and port passed to createSSLSocket() were correct. Could anyone help? The client has to communicate to 2 sites at the same time: an HTTPS web server and a self-signed MySQL server.

Categories