You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cxf.apache.org by "Andrei Shakirin (JIRA)" <ji...@apache.org> on 2014/07/17 20:43:06 UTC

[jira] [Comment Edited] (CXF-5652) WebClient with SSL: javax.net.ssl.SSLHandshakeException handshake_failure

    [ https://issues.apache.org/jira/browse/CXF-5652?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14065338#comment-14065338 ] 

Andrei Shakirin edited comment on CXF-5652 at 7/17/14 6:43 PM:
---------------------------------------------------------------

Hi Vjacheslav,

I think I know now why pure JVM properties do not work in case of SSL client authentication.
The problem is that in case of client authentication client needs access to own private key in keystore to sign proof of possession. Later server check the signature using client public key and if signature is OK, client has proved that it owns appropriate private key.
To access private key in keystore client needs additional password (that can be different from keystore password). You applied this password in your code as well, but in your case keystore password and key password are equal:
{code}
Client client = ClientBuilder.newBuilder().keyStore(keyStore, trustpass).trustStore(ts).build();
{code}

It seems that java doesn't support providing private key password using JVM properties. At least all samples with client authentication I found initialize Connection using keyManagerFactory and SSLContext:
http://vafer.org/blog/20061010073725/ 
http://www.rap.ucar.edu/staff/paddy/cacerts/index.html 

Alternatively you can provide initialized SSLContext into ClientBuilder instead applying keystores:
{code}
...
		String keystorePwd = "keystorePassword";
                String keyPwd = "keyPassword";

		KeyStore keyStore = KeyStore.getInstance("JKS");
		keyStore.load(new FileInputStream("usr/stores/keystore.jks"), keystorePwd .toCharArray());
		KeyStore trustStore = KeyStore.getInstance("JKS");
		trustStore.load(new FileInputStream("usr/stores/keystore.jks"), keystorePwd .toCharArray());
		SSLContext context = initSecurityContext(keyStore, trustStore, keyPwd);
		
		Client client = ClientBuilder.newBuilder().sslContext(context).build();
...
	private static SSLContext initSecurityContext(KeyStore keyStore,
			KeyStore trustStore, String pwd) throws NoSuchAlgorithmException,
			NoSuchProviderException, KeyStoreException,
			UnrecoverableKeyException, KeyManagementException {
		KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
				.getDefaultAlgorithm());
		kmf.init(keyStore, pwd.toCharArray());
		TrustManagerFactory tmf = TrustManagerFactory
				.getInstance(TrustManagerFactory.getDefaultAlgorithm());
		tmf.init(trustStore);

		SSLContext context = SSLContext.getInstance("TLS", "SunJSSE");
		context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
		return context;
	}
{code}
This code works successfully with client authentication scenario.

Conclusion:
1. It is possible to use JVM properties to provide keystore with public certificate, but not to access private key (perhaps Sun/Oracle engineers don't open this option for security reasons). Therefore it will works on your client only for server authentication scenario. 
2. As alternative option you can provide pre-initialized SSLContext object to ClientBuilder.

Regards,
Andrei.


was (Author: ashakirin):
Hi Vjacheslav,

I think I know now why pure JVM properties do not work in case of SSL client authentication.
The problem is that in case of client authentication client needs access to own private key in keystore to sign proof of possession. Later server check the signature using client public key and if signature is OK, client has proved that it owns appropriate private key.
To access private key in keystore client needs additional password (that can be different from keystore password). You applied this password in your code as well, but in your case keystore password and key password are equal:
{code}
Client client = ClientBuilder.newBuilder().keyStore(keyStore, trustpass).trustStore(ts).build();
{code}

It seems that java doesn't support providing private key password using JVM properties. At least all samples with client authentication I found initialize Connection using keyManagerFactory and SSLContext:
http://vafer.org/blog/20061010073725/ 
http://www.rap.ucar.edu/staff/paddy/cacerts/index.html 

Alternatively you can provide initialized SSLContext into ClientBuilder instead applying keystores:
{code}
...
		String keystorePwd = "keystorePassword";
                String keyPwd = "keyPassword";

		KeyStore keyStore = KeyStore.getInstance("JKS");
		keyStore.load(new FileInputStream("c:/1/jks/keystore.jks"), keystorePwd .toCharArray());
		KeyStore trustStore = KeyStore.getInstance("JKS");
		trustStore.load(new FileInputStream("c:/1/jks/keystore.jks"), keystorePwd .toCharArray());
		SSLContext context = initSecurityContext(keyStore, trustStore, keyPwd);
		
		Client client = ClientBuilder.newBuilder().sslContext(context).build();
...
	private static SSLContext initSecurityContext(KeyStore keyStore,
			KeyStore trustStore, String pwd) throws NoSuchAlgorithmException,
			NoSuchProviderException, KeyStoreException,
			UnrecoverableKeyException, KeyManagementException {
		KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
				.getDefaultAlgorithm());
		kmf.init(keyStore, pwd.toCharArray());
		TrustManagerFactory tmf = TrustManagerFactory
				.getInstance(TrustManagerFactory.getDefaultAlgorithm());
		tmf.init(trustStore);

		SSLContext context = SSLContext.getInstance("TLS", "SunJSSE");
		context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
		return context;
	}
{code}
This code works successfully with client authentication scenario.

Conclusion:
1. It is possible to use JVM properties to provide keystore with public certificate, but not to access private key (perhaps Sun/Oracle engineers don't open this option for security reasons). Therefore it will works on your client only for server authentication scenario. 
2. As alternative option you can provide per-initialized SSLContext object to ClientBuilder.

Regards,
Andrei.

> WebClient with SSL: javax.net.ssl.SSLHandshakeException handshake_failure
> -------------------------------------------------------------------------
>
>                 Key: CXF-5652
>                 URL: https://issues.apache.org/jira/browse/CXF-5652
>             Project: CXF
>          Issue Type: Improvement
>          Components: JAX-RS
>    Affects Versions: 3.0.0-milestone2
>            Reporter: Vjacheslav Borisov
>            Assignee: Andrei Shakirin
>            Priority: Minor
>
> I got error when using WebClient with SSL using client certificate:
> javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 
> I found a way to fix this error
>             KeyStore keyStore = KeyStore.getInstance("JKS");
>             String trustpass = "chageit";
>             File truststore = new File("/home/slavb/.java/deployment/security/trusted.clientcerts");
>             keyStore.load(new FileInputStream(truststore), trustpass.toCharArray());
>             KeyStore ts = KeyStore.getInstance("JKS");
>             truststore = new File("/etc/ssl/certs/trusted.cacerts");
>             ts.load(new FileInputStream(truststore), "".toCharArray());
>             Client client = ClientBuilder.newBuilder().keyStore(keyStore, trustpass).
>                     trustStore(ts).build();
> And I have question, why WebClient is not working like embedded in java URLConnection or 
> apache http client when I specify system properties
> -Djavax.net.ssl.trustStore=/etc/ssl/certs/trusted.cacerts 
> -Djavax.net.ssl.keyStore=/home/slavb/.java/deployment/security/trusted.clientcerts 
> -Djavax.net.ssl.keyStorePassword=changeit
> (i got error javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure when using SSL web client)
> Why it is need to configure ssl in code?



--
This message was sent by Atlassian JIRA
(v6.2#6252)