David Pauli
David Pauli

Reputation: 89

Get "No peer certificate" in Android 4.3

I want to connect to a SSL-certificated server with certificate.

import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.params.BasicHttpParams;

[...]

SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory sslSocketFactory = new SSLSocketFactory( keyStore, profile.getIdentityPassPhrase(), trustStore );
sslSocketFactory.setHostnameVerifier( new AllowAllHostnameVerifier() );
registry.register( new Scheme( "http", PlainSocketFactory.getSocketFactory(), 80) );
registry.register( new Scheme( "https", sslSocketFactory, 443 ) );

// Create a new HttpClient and Post Header
HttpParams httpParams = new BasicHttpParams();
httpParams.setBooleanParameter( "http.protocol.expect-continue", true );
HttpProtocolParams.setVersion( httpParams, HTTP_VERSION );
HttpProtocolParams.setContentCharset( httpParams, CONTENT_CHARSET );
HttpConnectionParams.setConnectionTimeout( httpParams, TIMEOUT_MILLISEC );
HttpConnectionParams.setSoTimeout( httpParams, TIMEOUT_MILLISEC );

httpClient = new DefaultHttpClient( new ThreadSafeClientConnManager( httpParams, registry ), httpParams );

In Android 4.2.2 (and lower) it works fine. But on Android 4.3 it throws error message

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

Where is the error? Why it works with API 17 and lower, but not with API 18?

EDIT The exception is thrown in HttpClient-class (org.apache.http.client) while executing //execute//-function. What changed in 4.3 in these function but in 4.2.2 not? Android GIT says there is no important changing: https://android.googlesource.com/platform/external/apache-http/

Upvotes: 2

Views: 1399

Answers (1)

Dominik Goltermann
Dominik Goltermann

Reputation: 4306

I've found a solution to my problem. I used openssl s_client -connect my_server.com:443 -CApath /etc/ssl/certs/ to check my ssl certificate. It returned the wrong certificate! It turned out that i had two different vHosts set up with different ssl certificates on the same ip. This requires the client to handle this: http://en.wikipedia.org/wiki/Server_Name_Indication .

As it turns out Android seems not to handle this, at least when using this code:

String responseString = "";

    HttpClient httpclient = new DefaultHttpClient();
    HttpResponse response;
    try {
        response = httpclient.execute(new HttpGet(uri[0]));
        StatusLine statusLine = response.getStatusLine();
        if(statusLine.getStatusCode() == HttpStatus.SC_OK || statusLine.getStatusCode() == 428){
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            response.getEntity().writeTo(out);
            out.close();
            responseString = out.toString();
        } else{
            //Closes the connection.
            response.getEntity().getContent().close();
            throw new IOException(statusLine.getReasonPhrase());
        }
    } catch (ClientProtocolException e) {
        Log.e("err",e.getMessage());
    } catch (IOException e) {
        Log.e("err",e.getMessage());
    }
    return responseString;

I removed the second vHost so that in every situation only one certificate is returned from the server. Now the javax.net.ssl.SSLPeerUnverifiedException: No peer certificate exception disappeared.

Upvotes: 1

Related Questions