I am testing SSL communication between client and server locally. So I generated certificate using OpenSSL commands. Added this certificate in cacert file. Also generated .p12 file.
I am using the same .p12 file in server and client. This is the server code
Server server = component.getServers().add(Protocol.HTTPS, port);
Series<Parameter> params = server.getContext().getParameters();
params.add("keystorePath", ".p12 file path");
params.add("keystoreType", "PKCS12");
params.add("needClientAuthentication","true");
component.getDefaultHost().attach("", "/AA"), new AAClass());
component.start();
And this is client code:
Client client = trustAllCerts();
clientResource = new ClientResource(url);
clientResource.setNext(client);
try{
clientText = clientResource.post"");
}
catch(ResourceException e){
e.printStackTrace();
}
public Client trustAllCerts() {
Client client = null;
try {
client = new Client(new Context(), Protocol.HTTPS);
Context context = client.getContext();
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
context.getAttributes().put("sslContextFactory", new SslContextFactory() {
public void init(Series<Parameter> parameters) {
}
public SSLContext createSslContext() {
return sslContext;
}
});
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
context.getAttributes().put("hostnameVerifier", new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
sslContext.init(null, new TrustManager[] { tm }, null);
} catch (KeyManagementException e) {
LOGGER.error("Exception in Key Management" + e);
} catch (NoSuchAlgorithmException e) {
LOGGER.error("Exception in Algorithm Used" + e);
}
return client;
}
I am getting following exception:
Restlet-1299242, fatal error: 42: null cert chain
javax.net.ssl.SSLHandshakeException: null cert chain
%% Invalidated: [Session-25, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256]
Restlet-1299242, SEND TLSv1.2 ALERT: fatal, description = bad_certificate
Restlet-1299242, WRITE: TLSv1.2 Alert, length = 2
Restlet-1299242, fatal: engine already closed. Rethrowing javax.net.ssl.SSLHandshakeException: null cert chain
Restlet-1299242, called closeInbound()
Restlet-1299242, fatal: engine already closed. Rethrowing javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?
Restlet-1299242, called closeOutbound()
Restlet-1299242, closeOutboundInternal()
I tried to add keystore and truststore using System.setProperty() but it didn't work.
Please help. Thanks in advance.
This is already a mistake. The client and the server are different identities and should not have the same private key, public key, or certificate.
I suggest you ditch all the OpenSSL stuff and start again with the
keytool
as follows:-trustcacerts
option; and import the signed certificate using the same alias you used when creating the keypair and CSR.You're done. Forget about
trustAllCerts
, customTrustManagers
, and custom code of any kind whatsoeverjavax.net.ssl.keyStore
andjavax.net.ssl.keyStorePassword
Steps (1) and (2) are how it is intended to be done. Depart from those and you are in for trouble and strife.
One option is to read the p12/pfx-file, get the certificates and use them to programmatically construct KeyStores and TrustStores. If the input is one pfx-file containing a CA root certificate and a related client certificate, the methods shown in the class
SslUtils
below will let you do that.There is one caveat though: the default Restlet server (version 2.3.4) will not pickup the certificates send by the client. I did manage to work-around this issue (it is not pretty though), see my answer on this question.
I will focus on configuring the secure connections here, but all source code and a working example is available in the restlet-clientcert Github project. The Github project is a result of me thinking I know what I'm doing, having no luck and no experience with Restlet, but biting the bullet anyway so I can feel a little bit better knowing that I could get this basic stuff to work.
On the server side, use a custom
ServerSslContextFactory
that programmatically configures the usedSSLContext
. Register the custom factory with:and attach a "guard" to extract the client certificate info:
The
ServerSslContextFactory
:On the client side, a similar thing:
Also set a
hostnameVerifier
(as shown in your question) to not verify hostnames.The
ClientSslContextFactory
:And finally the
SslUtils
class containing the "read and reconstruct" methods (full version including "get email-address from certificate" methods is available in the previously mentioned Github project):On a side-node: Java is transitioning the default keystore type from JKS to PKCS12 (see JEP 229).
You probably didn't add the full certificate chain in your keystore, and just included the keypair itself. In that case, the client just receives the public key, but it cannot validate if that key can be trusted. The certificate chain is there to be able to check if the signatures on the public key match, and lead up to a trusted certificate authority.
See e.g: Adding certificate chain to p12(pfx) certificate
You can do it the java way, too, using e.g. portecle: http://portecle.sourceforge.net/import-ca-reply.html, but you also need to combine the certificate chain in one file to import. Just copy-paste all certificates after one another, starting from your own, and ending with the root CA.
This way, the resulting pfx file can be used on the server to return the certificate chain to the client.
First, lets create a JKS formatted keystore. PKCS12 is usually used in browser and on default java applications uses JKS (as far as I know). Java also supports PKCS12 but I do not know exact parameters for it.
Preparing JKS File
Lets look in our PKCS12 file and get the certificate aliases that we want to extract our JKS file.
Note the aliases you want to export. And now lets create a JKS file.
This will ask bunch of questions. You can fill them as you like. Now, you can export your aliases from *.p12 file to *.jks file.
If you do not have any PKCS12 file, or your certificates are in CER, DER or PEM format you can add your certificates to your keystore using the command below.
And please be sure that you imported, your certificate, your certificate provider's certificate (intermediate certificate) and root certificate.
Now you can check that your JKS file contains all the certificates you are needed.
Setting up Server
You can use your JKS file both on client and server side. According to Restlet documentation you can use JKS file like this to provide HTTPS connection.
After that if you check your port from browser you must see a secure sign. Or you can use some online tool(like this one) to check your certificate.
Setting up Client
Now lets look at client side. Since you are developing both side of the application you can use already created JKS file.
While testing or in other circumstances, your certificate hostname and your actual hostname may not match. In order to disable hostname checks you can add this block to your application.
Some Thoughts
Since I cannot test it on my locale, I am not exactly sure that your client and server JKS file must be the same. You may only need to add your own certificate to your server.jks. SSL and certificates are always tricky for me. I usually get it work after some trial and error. I hope this will help you.
Also, You may also want to consider, using a reverse proxy kind of web server like Apache2 or Nginx. If you want to use them, you must merge your certificates to a single file. If you look at your certificate file you see that each file (your own certificate, intermediate certificate and root certificate) is like this
You need to simply add one to other to create a merged certificate. And than use that certificate to end SSL on Apache2 or Nginx. This is what I usually do. But on client side you still need to create JKS files.