hc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Oleg Kalnichevski (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (HTTPCLIENT-1585) Client certificate not submitted half the time
Date Thu, 04 Dec 2014 19:44:12 GMT

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

Oleg Kalnichevski commented on HTTPCLIENT-1585:
-----------------------------------------------

What does this exactly have to do with HttpClient? All you have to do is to turn on SSL debugging
on and find out why the cert presented by the server gets rejected by the client.

Oleg

> Client certificate not submitted half the time
> ----------------------------------------------
>
>                 Key: HTTPCLIENT-1585
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-1585
>             Project: HttpComponents HttpClient
>          Issue Type: Bug
>          Components: HttpClient
>    Affects Versions: 4.3.5, 5.0
>         Environment: Fedora 20 on a Thinkpad T540p, Sun JDK 1.6,1.7,1.8
>            Reporter: Jim Scarborough
>              Labels: clientcertificate
>
> h1. Overview
> The http client submits the client certificate when requested about half the time.  This
may well be a bug in the underlying SSLSocketImpl or nearby code.  I welcome assistance in
determining which layer has the bug.
> h1. Stack trace
> {code:none}
> javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
> 	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
> 	at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
> 	at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
> 	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
> 	at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1705)
> 	at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:122)
> 	at sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:982)
> 	at sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:1154)
> 	at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1066)
> 	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:341)
> 	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:878)
> 	at sun.security.ssl.Handshaker.process_record(Handshaker.java:814)
> 	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
> 	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
> 	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
> 	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
> 	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:275)
> 	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
> 	at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:123)
> 	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:318)
> 	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
> 	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
> 	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
> 	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
> 	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
> 	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
> 	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
> 	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
> {code}
> h1. Steps to reproduce
> h2. 1. Set up certificates
> create server key/cert pair. use FQDN as First Last name
> {{keytool -keystore server_keystore -alias server -genkey -keyalg RSA}}
>   
> export server cert to a curl usable format.
> {{keytool -exportcert -alias server -keystore server_keystore -rfc -file server.pem}}
>  
> create client key/cert pair. use email as First Last name
> {{keytool -keystore client_keystore -alias client -genkey -keyalg RSA}}
>  
>  export client key/cert pair to a firefox usablabe format.
> {{keytool -importkeystore -srckeystore client_keystore -destkeystore client_keystore.pkcs12
-srcstoretype JKS -deststoretype PKCS12 -srcstorepass password -deststorepass password -srcalias
client -destalias client -srckeypass password -destkeypass password}}
>  
>  export client key/cert pair to a curl usable format.
> {{openssl pkcs12 -in client_keystore.pkcs12 -out client.crt.pem -clcerts -nokeys}}
> {{openssl pkcs12 -in client_keystore.pkcs12 -out client.key.pem -nocerts -nodes}}
>  
> h2. 2. Set up Jetty, configure it to require a client cert
>  
> {{vim jetty-ssl.xml}}
>  
> {code:xml}
>    <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property
name="jetty.keystore" default="etc/server_keystore"/></Set>
>    <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="password"/></Set>
>    <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password"
default="password"/></Set>
>    <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property
name="jetty.truststore" default="etc/client_keystore"/></Set>
>    <Set name="TrustStorePassword"><Property name="jetty.truststore.password"
default="password"/></Set>
>    <Set name="NeedClientAuth"><Property name="jetty.ssl.needClientAuth" default="true"/></Set>
> {code}
> {{vim jetty-https.xml}}
>  
> {code:xml}
>     <Set name="port"><Property name="https.port" default="8443" /></Set>
> {code}
> {{vim start.ini}}
>  
> {code:none}
>     jetty.dump.stop=false
>     etc/jetty-ssl.xml
>     etc/jetty-https.xml
> {code}
> h2. 3. Verify Jetty works
>  
> Copy the exported certs to your machine. 
>  
> Go to https://FQDN:8443 in the browser with and without the cert to make sure it works
>  
> or use curl
>  
> curl -L -v --cacert server.pem -E ./client.crt.pem --key ./client.key.pem https://localhost:8443
> h2. 4. Run this code against it:
> {code:title=HttpsClientCertificateTest.java|borderStyle=solid}
> import javax.net.ssl.SSLHandshakeException;
> import javax.net.ssl.SSLParameters;
> import javax.net.ssl.SSLSocket;
> import javax.net.ssl.SSLSocketFactory;
> import java.net.Socket;
> import com.google.common.io.Resources;
> import junit.framework.AssertionFailedError;
> import org.junit.Test;
> import static org.junit.Assert.*;
> public class HttpsClientCertificateTest {
>     @Test
>     public void testClientCertificate() throws Exception {
>         int success=0;
>         int failure=0;
>         for (int i=0;i<40;i++) {
>             try {
>                 String testKeystorePath = Resources.getResource("test-keystore").toString();
>                 String testClientCertPath = Resources.getResource("test-clientstore").toString();
>                 assertEquals("protected\n",secureContentFor("https://localhost:8443/",
testKeystorePath, testClientCertPath));
>                 success++;
>             } catch (AssertionFailedError e) {
>                 e.printStackTrace();
>                 failure++;
>             } catch (SSLHandshakeException e) {
>                 e.printStackTrace();
>                 failure++;
>             }
>         }
>         assertEquals("failed " + failure + "/" + (success+failure) + " succeeded " +
(success*100/(success+failure)) + "%",0,failure);
>     }
>     static String secureContentFor(String url, String clientKeyStore, String clientTrustStore)
throws Exception {
>         KeyStore trustStore = readKeyStore(clientTrustStore);
>         KeyStore keyStore = readKeyStore(clientKeyStore);
>         // Trust own CA and all self-signed certs
>         SSLContext sslcontext = SSLContexts.custom()
>                 .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
>                 .loadKeyMaterial(keyStore, "password".toCharArray())
>                 .loadKeyMaterial(trustStore, "password".toCharArray())
>                 .useTLS()
>                 .build();
>         // Allow TLSv1 protocol only
>         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
>                 sslcontext,
>                 new String[] { "TLSv1" }, // supported protocols
>                 null,  // supported cipher suites
>                 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
>         CloseableHttpClient httpClient = HttpClients.custom()
>                 .setSSLSocketFactory(sslsf)
>                 .build();
>         HttpGet get = new HttpGet(url);
>         HttpResponse response = httpClient.execute(get);
>         String content = EntityUtils.toString(response.getEntity());
>         return content;
>     }
>     static KeyStore readKeyStore(String resourceURL) throws KeyStoreException, IOException,
NoSuchAlgorithmException, CertificateException {
>         KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
>         FileInputStream instream = new FileInputStream(new URL(resourceURL).getFile());
>         try {
>             trustStore.load(instream, "password".toCharArray());
>         } finally {
>             instream.close();
>         }
>         return trustStore;
>     }
> }
> {code}
> h1. Actual results
> Exceptions as noted above, and some ultimate failure note like this:
> java.lang.AssertionError: failed 19/40 succeeded 52% 
> Expected :0
> Actual   :19
> h2. Expected results
> No exceptions, test passes



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org


Mime
View raw message