Java: establish SSL connection without authentication - java

I am trying to create an application where I have a server that hosts files and a client that wants to retrieve those files.
I am currently trying to establish a SSL connection between the client and the server, however, I only want the encryption part of SSL not the authentication (I do not want to go through the troubles of creating and managing keystores etc).
All the sample code I have found has used TLS which requires authentication. I was wondering what implementation does not use authentication? I read that there is a Diffie Hellman handshake but I was wondering if there was any other cipher suite besides TLS I could use?
SSLSocketFactory factory = null;
try {
SSLContext ctx;
KeyManagerFactory kmf;
KeyStore ks;
char[] passphrase = "passphrase".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
is there a different SSLContext I could use that will not require me to create a KeyManagerFactory or a Keystore?

If you really want this and you have some other means of avoiding the man in the middle attacks you will now be vulnerable to, just enable the anonymous cipher suites.

Related

SunMSCAPI not working when calling wcf

I know there is many similar questions, but i could not find any help in any previous question. I am trying to communicate with a wcf service from a java client, i used the auto generated stubs created by netbeans to achieve that. the wcf service is protected with client certificate authentication using TLS(1.2). I cannot make it work to use the SunMSCAPI provider (meaning i want to use the windows user local store to use the certificate as a client. (if there is another way or library to make it possible to use windows certificate local stores please share with me).
This SSLContext is not working to call the web service:
IService servicePort = service.getWSHttpBindingIService();
SSLContext sslContext = SSLContext.getInstance(sslVersion);
**KeyStore keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
keystore.load(null, null);**
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, null);
KeyManager[] keyManagers = kmf.getKeyManagers();
sslContext.init(keyManagers, null, null);
BindingProvider bindingProvider = ((BindingProvider) servicePort);
bindingProvider.getRequestContext()
.put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory",sslContext.getSocketFactory());
The error i get is, when debugging i can see the keys and the certificates in the KeyManagers array correctly:
com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 403: Forbidden
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.checkStatusCode(HttpTransportPipe.java:310)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.createResponsePacket(HttpTransportPipe.java:259)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:217)
at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:130)
at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:124)
at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:1121)
at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:1035)
at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:1004)
at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:862)
at com.sun.xml.internal.ws.client.Stub.process(Stub.java:448)
at com.sun.xml.internal.ws.client.sei.SEIStub.doProcess(SEIStub.java:178)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:93)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:77)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:147)
the pfx is installed in user local store correctly, because i used it in c# and it worked many times.
in the java code above also, when i use pfx directly instead of SunMSCAPI provider, it works:
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(pfxStream, pfxPassword.toCharArray());
kmf.init(ks, pfxPassword.toCharArray());
I am using windows 10. any help would be appriciated.
I got the SunMSCAPi idea from the following link:
Digital Signature SunMSCAPI provider & MS Crypto API
It looks like the issue was that there is many certificates in my localstore and according to my research KeyManager selects the first Key found that meet the criteria, meaning that it will not necessarily pick my certificate among them. i solved this issue, by creating a decorator over X509KeyManager that chooses my desired certificate alias. got the idea from this QA:
How I can tell alias of the wanted key-entry to SSLSocket before connecting?

Securing communication between multiplatform clients (Desktop and Android primarily) with desktop server through SSL/TLS

I went through the JSSE Reference Guide + Stack Overflow most common explanations about SSL/TLS and I haven't really found anything that encapsulates everything what I need.
The project that I'm currently working on is about connecting multiplatform clients (Android or Desktop) on a desktop server which is connected to the robot (it is working in the local network which has parallel TCP and UDP connection -> TCP is used for sending some kind of commands for the robot from the client to the server and UDP is used for updating the robot position on the map which is sent from the server to the client).
Maybe I was a little half-cocked so I tried to implement the Android piece of code without really informing myself about everything that possibly could go wrong. The code below represents the code on the server side (which is desktop application) and client side (android application).
Server:
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(new FileInputStream(PATH_TO_KEYSTORE), PASSWORD.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, PASSWORD.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
KeyManager[] keyManagers = kmf.getKeyManagers();
context.init(keyManagers, null, null);
SSLServerSocketFactory factory = context.getServerSocketFactory();
serverSocket = (SSLServerSocket) factory.createServerSocket(port);
serverSocket.setSoTimeout(0);
Android client:
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(Gdx.files.internal(PATH_TO_KEYSTORE).read(), PASSWORD.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keystore);
SSLContext context = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = tmf.getTrustManagers();
context.init(null, trustManagers, null);
SSLSocketFactory sslSocketFactory = context.getSocketFactory();
sslSocket = (SSLSocket) sslSocketFactory.createSocket(address, port);
Variable PATH_TO_KEYSTORE is a path to the file which was generated using this command keytool -genkey -keystore server.keystore. I know that I shouldn't have the same keystore for server and client, but I don't know how can I do it the other way which is one of my questions too.
After executing this piece of code, exception happened which said Wrong version of key store. and then I figured out that I am totally lost.
Anyway, I have several questions that bother me in this matter:
Is it possible to secure communication both for TCP and UDP using the SSL/TLS?
Is it possible to create a uniform way to generate keystores that will work for every platform (since I figured out on an example above that Android does not support JKS)?
If the answer on question No. 2. is NO, how can I secure the communication in separate ways (how to generate keystores for Android and Desktop version separately)?
When everything works out like it should (in a static way), is there a way to generate keystore for client dynamically, in other words: how can one generate his private key in the Android piece of code (which ultimately means that every client will have its own generated private key)?

How to disable weak cipher suits in java application server for ssl

I have a custom Java application server running. I am seeing that there are some weak cipher suits supported by the server for example some 112 bit ciphers. I want to disable those. Where can I don that. Also I want to enable TLSv1.2. The following is the code to initialize the socket.
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(sslstore), sslstorepass.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, sslcertpass.toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, new SecureRandom());
SSLServerSocketFactory ssf = sc.getServerSocketFactory();
serverSocket = ssf.createServerSocket(port);
System.out.println("Socket initialized");
JAVA allows cipher suites to be removed/excluded from use in the security policy file called java.security that’s located in your JRE: $PATH/[JRE]/lib/security The jdk.tls.disabledAlgorithms property in the policy file controls TLS cipher selection. The jdk.certpath.disabledAlgorithms controls the algorithms you will come across in SSL certificates. Oracle has more information about this here
In the security policy file, if you entered the following: jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 4096 It would make it, so that MD5, SHA1, DSA are never allowed, and RSA is allowed only if the key is at least 4096 bits.
To solve the tls version issue. Just have to put SSLContext sc = SSLContext.getInstance("TLSv1.2"); It will support all the versions.

Java: how to add SSL client-side authentication

I have this code to connect the server with a client using SSL, and now I want to add client-side authentication:
(I have a server keystore (JCEKS type) and a client keystore (JKS type), the server uses a truststore (cacerts) where I imported both certificates because I also want to use this truststore for client authentication)
Client code:
System.setProperty("javax.net.ssl.trustStore", cerServer);
System.setProperty("javax.net.ssl.trustStoreType","JCEKS");
System.setProperty("javax.net.ssl.trustStorePassword", pwdCacerts);
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", port);
Server Code:
KeyStore ks = LoadKeyStore(new File(serverKeyStore), pwdKeyStore, "JCEKS");
KeyManagerFactory kmf;
kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, pwdKeyStore.toCharArray());
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(kmf.getKeyManagers(),null, null);
SSLServerSocketFactory ssf = sc.getServerSocketFactory();
sslserversocket = (SSLServerSocket) ssf.createServerSocket(port);
thanks in advance for any help.
edit:
I add this code in the server side:
System.setProperty("javax.net.ssl.trustStore", cacerts);
System.setProperty("javax.net.ssl.trustStoreType","JKS");
System.setProperty("javax.net.ssl.trustStorePassword", pwdCacerts);
but if I delete the client certificate in cacerts, the connection doesn't give me error and for that I think it's wrong that way
If you want your system to use client-certificate authentication, you'll need
the server to request (or require) a client certificate. This is done by setting setWantClientAuth(true) on the server socket (or setNeedClientAuth, respectively). You'll also need the server to advertise the CA it accepts, which is normally done by using a truststore on the server that contains the CA by which the client-certificate chain was issued (this seems to be what you've done by setting javax.net.ssl.trustStore* on the server).
the client to be configured with a keystore containing the client certificate (possible the chain if there are intermediate CAs) and its private key. This can be done by setting the javax.net.ssl.keyStore* (which may affect other connections) or by using a KeyManagerFactory in the same way as you've done it on the server side.
If you use setWantClientAuth(true), you might still not get an error, since the server will accept connections that don't have a client-certificate (the server would then check the SSLSession's peer certificates to see whether there was a cert or not). setNeedClientAuth(true) would break the connection when the client doesn't present a certificate.

Java Client to connect to Server with Openssl and Client Auth

I have to write a Java Client to connect to an SSL server. The server uses openssl certificate, and is configured to do Client Auth.
I can't seem to locate any useful resources online that can help me (who doesn't know anything about openssl and much about SSL) to understand who to go about implementing my Client Side.
Help!
The twist here is that you are using client authentication, so you need a private key and a certificate to identify yourself. You provide this to JSSE by specifying KeyManagers when you initialize an SSLContext.
Customizable Setup
Following are the basic steps. The JSSE API was significantly improved in Java 6, but I'll stick with Java 5, in case you're stuck on that version.
KeyStore tks = KeyStore.getInstance(KeyStore.getDefaultType());
tks.load(...); /* Load the trust key store with root CAs. */
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(tks);
KeyStore iks = KeyStore.getInstance(KeyStore.getDefaultType());
iks.load(...); /* Load the identity key store with your key/cert. */
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(iks, password);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SocketFactory factory = ctx.getSocketFactory();
Socket socket = factory.createSocket(host, port);
System Configuration
An alternative "zero-config" scenario can be used when using the SunJSSE provider. I believe many other providers (like IBM) have followed the same pattern and will work as well. The mechanism uses system properties, and is described in detail by the JSSE Reference Guide.
For client authentication, the important properties are javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword. The values should be the path to the user's key store and the password for that key store's "key entries", respectively.
When using these properties, you can create a new SSLSocket that supports client authentication like this:
SocketFactory factory = SSLSocketFactory.getDefault();
Socket socket = factory.createSocket(host, port);
Since you are using the "default" SSLSocketFactory, which depends on the system-wide properties, all sockets created in the JVM will authenticate with the same certificate. If you need more control than that, you have to use the "Customizable Setup" above.
Java includes SSL support in the standard API. Have a look at these classes in the 1.5.0 javadoc:
SSLSocket if you're doing the comms logic yourself.
HttpsURLConnection if the server side speaks HTTP
You could use httpclient. Have a look at this SSL guide.

Categories