Yes, chooseClientAlias returned null! I think that may be a problem with my certificate.
I check it and let you know! Marco 2012/8/24 Brian Carlstrom <[email protected]> > yes, basically during the handshake if a client cert is requested, the > chooseClientAlias is called to select one. the selected key is > specified by the returned String alias. Then it calls back with that > alias to lookup the private key and certs. Since you are receiving a > null in getPrivateKey, that seems to imply that chooseClientAlias > returned null. Can you confirm that? > > So the next question is why it can't choose one. the arguments are > used to filter the KeyStore contents. so it will look for an RSA or > DSA cert, issued by one of the specified issuers. I will say that the > issuers list is concerning. typically servers don't actually send that > and if the server is sending something bogus, it might be over > constraining the chooseClientAlias function. However, you can of > course workaround by having your proxy implement your own logic for > selecting the alias to use from the KeyStore, even if you can't change > the server configuration. > > -bri > > On Fri, Aug 24, 2012 at 3:04 AM, Marco Serioli <[email protected]> wrote: > > I've tryed to implement X509KeyManager in my own MyX509KeyManager class: > > > > class MyX509KeyManager implements X509KeyManager { > > > > private X509KeyManager defaultKeyManager; > > public MyX509KeyManager(KeyManager[] keyManagers){ > > for (KeyManager keyManager : keyManagers){ > > if (keyManager instanceof X509KeyManager){ > > defaultKeyManager = (X509KeyManager) keyManager; > > } > > } > > > > } > > @Override > > public String chooseClientAlias(String[] keyType, Principal[] issuers, > > Socket socket) { > > return defaultKeyManager.chooseClientAlias(keyType, issuers, socket); > > } > > > > @Override > > public String chooseServerAlias(String keyType, Principal[] issuers, > Socket > > socket) { > > return defaultKeyManager.chooseServerAlias(keyType, issuers, socket); > > } > > > > @Override > > public X509Certificate[] getCertificateChain(String alias) { > > return defaultKeyManager.getCertificateChain(alias); > > } > > > > @Override > > public String[] getClientAliases(String keyType, Principal[] issuers) { > > return defaultKeyManager.getClientAliases(keyType, issuers); > > } > > > > @Override > > public PrivateKey getPrivateKey(String alias) { > > return defaultKeyManager.getPrivateKey("tomcat"); > > } > > > > @Override > > public String[] getServerAliases(String keyType, Principal[] issuers) { > > return defaultKeyManager.getServerAliases(keyType, issuers); > > } > > } > > > > > > And to do: > > > > final KeyManagerFactory kmf = > > KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); > > kmf.init(keyStore, keyStorePassword.toCharArray()); > > KeyManager keyManager = new MyX509KeyManager(kmf.getKeyManagers()); > > > > KeyManager[] keyManagerArray = kmf.getKeyManagers(); > > keyManagerArray[0] = keyManager; > > sslCtx.init(keyManagerArray, tmf.getTrustManagers(), new SecureRandom()); > > > > During debugging I can see that first call is on > > > > public String chooseClientAlias(String[] keyType, Principal[] issuers, > > Socket socket) > > > > called with parameter > > > > keyType[0]="RSA" > > keyType[1]="DSA" > > > > issuers[0] ->X500Principal -> toString() = > > OID.1.2.840.113549.1.9.1=#16156D2E736572696F6C694063706D61706176652E6974, > > CN=www.apaveitaliacpm.it, OU=IT, O=Apave Italia CPM, L=Bienno, > ST=Brescia, > > C=IT > > issuers[1] ->X500Principal -> toString() = CN=Apave Italia CPM, OU=IT, > > O=Apave Italia CPM, L=Bienno, ST=Brescia, C=IT > > > > socket = SSL socket over > > Socket[addr=192.168.168.13/192.168.168.13,port=8443,localport=48330] > > > > The second method called is: > > > > public PrivateKey getPrivateKey(String alias) > > > > > > where I have noticed that alias parameter is null. > > > > Could it be a problem? > > > > Il giorno venerdì 24 agosto 2012 07:49:19 UTC+2, Brian Carlstrom ha > scritto: > >> > >> Well, the non-OpenSSL provider seems to be hitting another issue > >> > >> http://code.google.com/p/android/issues/detail?id=31903 > >> > >> that is not fixed even it the 4.1 release. However, the nature of that > >> bug seems to indicate the problem, that no client certificate was > >> returned by the KeyManager. > >> > >> I'd advise writing a proxy X509KeyManager > >> ( > http://developer.android.com/reference/javax/net/ssl/X509KeyManager.html) > >> as a wrapper around the result returned from kmf.getKeyManagers(). > >> getKeyManagers is going to return a length 1 array with a > >> X509KeyManager. Just replace the element with your own that implements > >> each method by just logging and then calling through the original one. > >> Then we can see if your key manager really is getting called. you can > >> do the same with the SSLSocketFactory passed to setSSLSocketFactory to > >> make sure that it really is calling your SSLSocketFactory. > >> > >> -bri > >> > >> On Thu, Aug 23, 2012 at 9:36 PM, Marco Serioli <[email protected]> > wrote: > >> > Thank you for your quick answer! > >> > > >> > I've tried to get the non-OpenSSL provider and then log the error > >> > message. > >> > Here is the result: > >> > > >> > java.lang.NullPointerException > >> > at > >> > > >> > > org.apache.harmony.xnet.provider.jsse.ClientHandshakeImpl.processServerHelloDone(ClientHandshakeImpl.java:515) > >> > at > >> > > >> > > org.apache.harmony.xnet.provider.jsse.ClientHandshakeImpl.unwrap(ClientHandshakeImpl.java:297) > >> > at > >> > > >> > > org.apache.harmony.xnet.provider.jsse.SSLRecordProtocol.unwrap(SSLRecordProtocol.java:408) > >> > at > >> > > >> > > org.apache.harmony.xnet.provider.jsse.SSLSocketImpl.doHandshake(SSLSocketImpl.java:737) > >> > at > >> > > >> > > org.apache.harmony.xnet.provider.jsse.SSLSocketImpl.startHandshake(SSLSocketImpl.java:446) > >> > at > >> > > >> > > org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.setupSecureSocket(HttpConnection.java:167) > >> > at > >> > > >> > > org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:479) > >> > at > >> > > >> > > org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeConnection(HttpsURLConnectionImpl.java:419) > >> > at > >> > > >> > > org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:217) > >> > at > >> > > >> > > org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:177) > >> > at > >> > > >> > > org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:72) > >> > at > >> > > >> > > org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46) > >> > at > >> > > >> > > org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:63) > >> > at > >> > > >> > > org.springframework.http.client.InterceptingClientHttpRequest$RequestExecution.execute(InterceptingClientHttpRequest.java:91) > >> > at > >> > > >> > > it.cpmapave.mt.interceptors.MyClientHttpRequestInterceptor.intercept(MyClientHttpRequestInterceptor.java:29) > >> > at > >> > > >> > > org.springframework.http.client.InterceptingClientHttpRequest$RequestExecution.execute(InterceptingClientHttpRequest.java:81) > >> > at > >> > > >> > > org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:67) > >> > at > >> > > >> > > org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46) > >> > at > >> > > >> > > org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:63) > >> > at > >> > > >> > > org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:475) > >> > at > >> > > >> > > org.springframework.web.client.RestTemplate.execute(RestTemplate.java:438) > >> > at > >> > > >> > > org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:414) > >> > at > >> > > it.cpmapave.mt.rest.OrderRestClient_.getOrders(OrderRestClient_.java:58) > >> > at > >> > > >> > > it.cpmapave.mt.ui.MainActivity$FetchSecuredResourceTask.doInBackground(MainActivity.java:144) > >> > at > >> > > >> > > it.cpmapave.mt.ui.MainActivity$FetchSecuredResourceTask.doInBackground(MainActivity.java:1) > >> > at android.os.AsyncTask$2.call(AsyncTask.java:252) > >> > at > java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) > >> > at java.util.concurrent.FutureTask.run(FutureTask.java:137) > >> > at > >> > > >> > > java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1081) > >> > at > >> > > >> > > java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:574) > >> > at java.lang.Thread.run(Thread.java:1020) > >> > > >> > Please let me know how to take a tcpdump of the SSL handshake if you > >> > feel it > >> > useful to solve the problem! > >> > > >> > Thank you! > >> > Marco > >> > > >> > 2012/8/24 Brian Carlstrom <[email protected]> > >> >> > >> >> I'm responsible for the SSLSocket code and more recently for the > >> >> HttpURLConnection code. That code does look right to me on a quick > >> >> review. One thing you could try to see if you can get a better > >> >> diagnostic using the non-OpenSSL provider by saying > >> >> SSLContext.getInstance("TLS", "HarmonyJSSE"); > >> >> > >> >> I'd also try to get a tcpdump of the handshake to see what might be > >> >> going wrong in case the issue is just problem negotiating an cipher > >> >> suite in common between both sides. I think the emulator might have > >> >> tcpdump installed, I could provide some notes on how to run it. > >> >> > >> >> I might also log with Log.e(TAG, "message", e); so that it will print > >> >> the full stack of the exception in case their is more detail, but i'm > >> >> not expecting much here. I'm really hoping that the other SSLSocket > >> >> impl which give more user friendly messages than OpenSSL > >> >> > >> >> -bri > >> >> > >> >> On Thu, Aug 23, 2012 at 4:21 AM, Marco Serioli <[email protected]> > >> >> wrote: > >> >> > I'm developing an android application on v13 target sdk and I'm > >> >> > trying > >> >> > to > >> >> > secure connection from android device to my tomcat server v6 with > SSL > >> >> > enabling also clientAuth. I'm using self-signed certificates. > >> >> > > >> >> > Only for introduce my project (I think the error is not due to > this): > >> >> > I'm > >> >> > using spring-android RestTemplate using a custom > >> >> > ClientHttpRequestFactory. > >> >> > Because of android sdk version I'm sure that spring will use > >> >> > HttpUrlConnection and not HttpClient! So I'm extending > >> >> > SimpleclientHttpRequestFactory and overriding the > >> >> > openConnectionMethod. > >> >> > I > >> >> > need to do this to trust my self-signed certificates and to use my > >> >> > client > >> >> > authentication certificate! > >> >> > > >> >> > So I init my sslContext and set to HttpURLConnection in this way: > >> >> > > >> >> > private SSLSocketFactory getSSLSocketFactory() throws > >> >> > KeyStoreException, > >> >> > KeyManagementException, NoSuchAlgorithmException, > >> >> > CertificateException, > >> >> > IOException, UnrecoverableKeyException{ > >> >> > final InputStream trustStoreLocation = > >> >> > mContext.getResources().openRawResource(R.raw.trust_store); > >> >> > final String trustStorePassword = "........"; > >> >> > > >> >> > final InputStream keyStoreLocation = > >> >> > mContext.getResources().openRawResource(R.raw.key_store); > >> >> > final String keyStorePassword = "........"; > >> >> > > >> >> > final KeyStore trustStore = KeyStore.getInstance("BKS"); > >> >> > trustStore.load(trustStoreLocation, > >> >> > trustStorePassword.toCharArray()); > >> >> > > >> >> > final KeyStore keyStore = KeyStore.getInstance("BKS"); > >> >> > keyStore.load(keyStoreLocation, > keyStorePassword.toCharArray()); > >> >> > > >> >> > final TrustManagerFactory tmf = > >> >> > > >> >> > > >> >> > > TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); > >> >> > tmf.init(trustStore); > >> >> > > >> >> > final KeyManagerFactory kmf = > >> >> > > >> >> > > KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); > >> >> > kmf.init(keyStore, keyStorePassword.toCharArray()); > >> >> > > >> >> > final SSLContext sslCtx = SSLContext.getInstance("TLS"); > >> >> > sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new > >> >> > SecureRandom()); > >> >> > > >> >> > return sslCtx.getSocketFactory(); > >> >> > } > >> >> > > >> >> > @Override > >> >> > protected HttpURLConnection openConnection(URL url, Proxy proxy) > >> >> > throws > >> >> > IOException { > >> >> > final HttpURLConnection httpUrlConnection = > >> >> > super.openConnection(url, > >> >> > proxy); > >> >> > if (url.getProtocol().toLowerCase().equals("https")) { > >> >> > try { > >> >> > > >> >> > > >> >> > > >> >> > > ((HttpsURLConnection)httpUrlConnection).setSSLSocketFactory(getSSLSocketFactory()); > >> >> > > >> >> > ((HttpsURLConnection)httpUrlConnection).setHostnameVerifier(new > >> >> > NullHostnameVerifier()); > >> >> > } catch (Exception e) { > >> >> > if (LogConfig.ERROR_LOGS_ENABLED){ > >> >> > Log.e(LOG_TAG, e.getMessage()); > >> >> > } > >> >> > > >> >> > } > >> >> > return httpUrlConnection; > >> >> > } > >> >> > > >> >> > private static class NullHostnameVerifier implements > HostnameVerifier > >> >> > { > >> >> > public boolean verify(String hostname, SSLSession session) { > >> >> > return true; > >> >> > } > >> >> > } > >> >> > > >> >> > When tomcat clientAuth is disabled it works fine. > >> >> > > >> >> > But when tomcat client authentication is enabled, trying to > establish > >> >> > connection from android device I got this exception: > >> >> > > >> >> > error:140943F2:SSL routines:SSL3_READ_BYTES:sslv3 alert unexpected > >> >> > message > >> >> > (external/openssl/ssl/s3_pkt.c:1232 0x19bf40:0x00000003); nested > >> >> > exception > >> >> > is javax.net.ssl.SSLProtocolException: SSL handshake terminated: > >> >> > ssl=0x182c70: Failure in SSL library, usually a protocol error > >> >> > > >> >> > I've tryed to install the client certificate on my web browser for > >> >> > testing > >> >> > purpose and everything goes ok! So I think it's a problem of my > >> >> > android > >> >> > application! > >> >> > > >> >> > Have you ever got this kind of exception? > >> >> > > >> >> > -- > >> >> > You received this message because you are subscribed to the Google > >> >> > Groups > >> >> > "Android Security Discussions" group. > >> >> > To view this discussion on the web visit > >> >> > > >> >> > > https://groups.google.com/d/msg/android-security-discuss/-/82sSkozTixAJ. > >> >> > To post to this group, send email to > >> >> > [email protected]. > >> >> > To unsubscribe from this group, send email to > >> >> > [email protected]. > >> >> > For more options, visit this group at > >> >> > http://groups.google.com/group/android-security-discuss?hl=en. > >> > > >> > > > > > -- > > You received this message because you are subscribed to the Google Groups > > "Android Security Discussions" group. > > To view this discussion on the web visit > > https://groups.google.com/d/msg/android-security-discuss/-/PT7WLNR-HJkJ. > > > > To post to this group, send email to > > [email protected]. > > To unsubscribe from this group, send email to > > [email protected]. > > For more options, visit this group at > > http://groups.google.com/group/android-security-discuss?hl=en. > -- You received this message because you are subscribed to the Google Groups "Android Security Discussions" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/android-security-discuss?hl=en.
