I'm using CXF to develop REST web services. I have an apache who accept SSL connection using certificate.
I want to test my code with org.apache.cxf.jaxrs.client.WebClient class, but I can't communicate with apache because of:
javax.net.ssl.SSLException: java.lang.IllegalArgumentException:
SSLv2Hello cannot be enabled unless at least one other supported
version is also enabled.
I tried to configure HttpConduit like this:
TLSClientParameters tlsParams = new TLSClientParameters();
KeyStore trustStore = KeyStore.getInstance(KEYSTORE_TYPE);
InputStream inputStream = WesRctAbstractTestcase.class.getClassLoader().getResourceAsStream(KEYSTORE_PATH);
trustStore.load(inputStream, KEYSTORE_PASSWORD.toCharArray());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
TrustManager[] tms = trustFactory.getTrustManagers();
tlsParams.setTrustManagers(tms);
tlsParams.setSecureSocketProtocol("SSL");
tlsParams.setDisableCNCheck(true);
httpConduit.setTlsClientParameters(tlsParams);
I don't understand what is missing.
Related
New to gRPC using java and I am not able to find a way how to enable ssl while using truststore and clientstore. I have been able to enable ssl by pointing to individual certificates but not using the truststore. Any leads will be really helpful.
You only need to convert the KeyStore for CA cert (truststore) to a TrustManagerFactory and the KeyStore for client cert/key (clientstore) to a KeyManagerFactory.
The former can be done with
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm();
tmf.init(truststore);
and the latter can be done with
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientstore, password);
Then, if you are using Netty transport, you can build the SslContext with
SslContext sslContext = GrpcSslContexts.forClient().trustManager(tmf).keyManager(kmf).build();
See its SslContextBuilder Javadoc.
Lastly, build gRPC channel with
NettyChannelBuilder.forAddress(host, port).sslContext(sslContext).build();
If you are using Okhttp transport, you need to build the SSLSocketFactory with
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
SSLSocketFactory sslSocketFactory = context. getSocketFactory()
and build gRPC channel with
OkHttpChannelBuilder.forAddress(host, port).sslSocketFactory(sslSocketFactory).build();
I'm using a Java SE Jersey client to connect to a HTTPS resource which uses two-way SSL.
My SSLContext looks like this:
private SSLContext getSSLContext() {
SslConfigurator sslConfig = SslConfigurator.newInstance()
.keyStoreFile("src/main/certificates/testcert.p12")
.keyPassword("mypassword");
return sslConfig.createSSLContext();
}
The problem is that the client certificate is never sent.
I get error "Warning: no suitable certificate found - continuing without client authentication" and I've tracked the reason to the fact that the client certificate isn't issued to one of the Cert Authorities listed in the server's CertificateRequest message to the client. I know from testing with cURL that the server will accept the certificate regardless. The endpoint is a public test system.
My question: How do I force-send my client certificate? (i.e. my Java SE client should ignore the fact that the testcert.p12 certificate's issuer is not the list of issuers that the server has said it would accept)
Please, don't point me to answers that are about disabling check of the server's certificate or about using self-signed certificates. The server's certificate is just fine.
UPDATE
It turned out my problem was another one. I debug by setting system property javax.net.debug=all. After examining the resulting output it looked to me as if the keystore was empty, even after doing the above. So no wonder why "no suitable certificate found".
Jersey has this 'clever' SslConfigurator class which is there to help you set up an SSLContext. Perhaps just too clever for me, because I couldn't make it work with the above code. So instead, I now configure my SSLContext like below:
KeyStore ks = KeyStore.getInstance("PKCS12");
FileInputStream fis = new FileInputStream("src/main/certificates/testcert.p12");
ks.load(fis, "mypassword".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "mypassword".toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);
// now use 'sc' in Jersey
This works for me where Jersey's helper class didn't. I fully sympathize with Jersey's idea of a helper class for SSLContext, because JSSE seems overly complex here for such a simple use case. Well, well.
You can't. It would be a TLS protocol violation, and therefore there is no API to support it. The various TLS APIs will only send a client certificate if:
It was requested, and
A client certificate can be found that conforms to what is specified in the CertificateRequest message.
You will have to arrange for your server to trust your client certificate, either by getting it signed by a CA or by exporting it to the server's trusted certificate store, whatever form that takes at the server.
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.
I am setting up a licensing servlet in Java together with a client app that will post request for new licenses and validate existing licenses at that server. The servlet runs in Tomcat. I've configured Tomcat so that it only allows connections to the servlet over https, and this works just fine.
I have created a self-signed certificate using 'keytool -genkey -alias www.mysite.com -keyalg RSA -keystore license.store' which creates a file license.store and pointed tomcat to this keystoreFile with its password asdf1234.
When I just try to connect from the client to the servlet over https in Java, I receive the familiar PKIX path building failed because the certificate is not in the truststore. I tried to fixed this using this suggestion resulting in the code below:
private SSLSocketFactory getSSLFactory() throws Exception {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream is = this.getClass().getResourceAsStream("license.store");
if(is ==null) {
return null;
}
keyStore.load(is, "asdf1234".toCharArray());
is.close();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
return ctx.getSocketFactory();
}
After which I call:
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.setSSLSocketFactory(getSSLFactory());
which results in a succesfull connection.
Now the problem is that I only get this to work when I copy the license.store to the client and load that into the KeyStore.load(). It doesn't strike me as very safe to copy the private key and its password that the server uses to the client. Is there any way to extract only the public key from the license.store and use that? I've been searching this forum and others for a day now and just can't seem to get it.
You shouldn't be generating a public-private key pair, but rather import the certificate of the server into your (the client's) Java truststore. The certificate is not a secret, and thus does not provide a security risk on the client side. See the -import option for keytool. Here's in an example.
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.