cxf-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Andrei Shakirin (JIRA)" <j...@apache.org>
Subject [jira] [Comment Edited] (CXF-5652) WebClient with SSL: javax.net.ssl.SSLHandshakeException handshake_failure
Date Thu, 17 Jul 2014 18:43:06 GMT

    [ 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)

Mime
View raw message