I'm working on a project that I want to add SSL to, so I created a simple client/server test implementation to see if it worked and I get a NoSuchAlgorithmException. The following is my server code which is throwing the exception:
import java.io.*;
import java.net.*;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.*;
public class SslServer
{
private static final int PORT = 5555;
public static void main(String[] args)
{
SecureRandom sr = new SecureRandom();
sr.nextInt();
try {
//client.public is the keystore file that holds the client's public key (created with keytool)
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("client.public"), "clientpublicpw".toCharArray());
//server.private is the key pair for the server (created with keytool)
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("server.private"), "serverprivatepw".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(clientKeyStore);
//This next line is where the exception occurs
KeyManagerFactory kmf = KeyManagerFactory.getInstance("TLS");
kmf.init(serverKeyStore, "serverprivatepw".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr);
SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
SSLServerSocket ss = (SSLServerSocket)sf.createServerSocket(SslServer.PORT);
ss.setNeedClientAuth(true);
BufferedReader in = new BufferedReader(new InputStreamReader(ss.accept().getInputStream()));
String line = null;
while((line = in.readLine()) != null)
{
System.out.println(line);
}
in.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
}
The stacktrace I get is:
java.security.NoSuchAlgorithmException: TLS KeyManagerFactory not available
at sun.security.jca.GetInstance.getInstance(Unknown Source)
at javax.net.ssl.KeyManagerFactory.getInstance(Unknown Source)
at SslServer.main(SslServer.java:32)
I tried replacing "TLS" with "SSL" and I still got the same exception. That Didn't make sense to me. How can TLS and SSL not be supported? This is my first time trying to implement SSL and it seems difficult to find good resources about this with code examples that are well explained. Can anyone tell me why I am getting this exception or point out something wrong with my code?
There are a number of problems:
TLS
(Transport Layer Security), not TSL
(for the SSLContext
).TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
(The default will be PKIX
on the Oracle JRE`)KeyManagerFactory
is SunX509
(TLS
doesn't exist here). Again, use getDefaultAlgorithm()
.FileInputStream
once you've read them.setNeedClientAuth(true)
is only useful on the server side). It would be clearer to call it something else than "client store" if it's effectively your keystore. (In addition, since you seem to be learning how to make this work, I'd suggest trying without client-certificate authentication first, in which case, the server won't need a truststore: use null
as a second parameter of SSLContext.init(...)
to use the default value.).jks
for your JKS
keystore, this will save you headaches later.null
for the SecureRandom
in SSLContext.init(...)
: this will use the default value according to the security provider.Something like this should work better:
KeyStore trustStore = KeyStore.getInstance("JKS");
InputStream tsis = new FileInputStream("trustedcerts.jks");
trustStore.load(tsis, "clientpublicpw".toCharArray());
tsis.close();
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
InputStream ksis = new FileInputStream("server.jks");
clientKeyStore.load(ksis.close(), "serverprivatepw".toCharArray());
ksis.close();
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(serverKeyStore, "serverprivatepw".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
SSLServerSocket ss = (SSLServerSocket)sf.createServerSocket(SslServer.PORT);
ss.setNeedClientAuth(true);
See http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#SupportClasses for examples, and for the names of the supported algorithm. It seems that "SunX509" and "NewSunX509" are the algorithms supported by KeyManagerFactory. And the protocol is named TLS, not TSL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With