Android中DefaultHttpClient连接HTTPS遇SSL握手失败及无对等证书问题求助
Hey there, let's tackle this SSL handshake issue you're facing. First off, the initial no peer certificate error and the subsequent SSLHandshakeException: Handshake failed both stem from problems in the SSL/TLS trust chain or protocol compatibility between your client and the server. Let's break down what's going wrong and fix it step by step.
What's Likely Causing This
Looking at your custom SSLSocketFactory and client setup, two key issues might be at play:
- You're loading an empty
KeyStore(trustStore.load(null, null)), but your factory code throws anIllegalArgumentExceptionwhen the truststore is null. This means your custom trust logic isn't actually being applied correctly. - Protocol version mismatch: Modern servers often drop support for older protocols like SSLv3 or TLSv1.0, but your factory defaults to a generic
TLSsetting which might not include newer, required versions like TLSv1.2 or TLSv1.3.
Fixes to Try
Option 1: Trust All Certificates (For Testing Only!)
If you're working in a test environment and just need to get past the handshake quickly, modify your SSLSocketFactory to bypass all certificate checks. Never use this in production—it defeats the purpose of SSL security.
public class TrustAllSSLSocketFactory extends SSLSocketFactory { private SSLContext sslContext = SSLContext.getInstance("TLS"); public TrustAllSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); // Create a trust manager that accepts any certificate X509TrustManager trustManager = new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) {} @Override public void checkServerTrusted(X509Certificate[] chain, String authType) {} @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } }; sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom()); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } }
Then update your client initialization code to use this factory and enforce modern TLS versions:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); TrustAllSSLSocketFactory sf = new TrustAllSSLSocketFactory(trustStore); sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); // Force modern TLS versions to match server support String[] supportedProtocols = {"TLSv1.2", "TLSv1.3"}; sf.setEnabledProtocols(supportedProtocols); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); return new DefaultHttpClient(ccm, params);
Option 2: Import Server Certificate (Production-Grade Solution)
For production, you need to properly trust the server's valid certificate. Here's how:
- Export the server certificate: Use a browser to visit
https://mywebsite.com:443, download the certificate file (save it asmywebsite.cer). - Import the certificate into a BKS keystore: Use the
keytoolcommand (you'll need the BouncyCastle library for BKS format):
keytool -importcert -file mywebsite.cer -keystore mytruststore.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
- Load the trusted keystore in your code:
// Load the keystore from your app's assets (adjust path as needed) InputStream inputStream = getApplicationContext().getAssets().open("mytruststore.bks"); KeyStore trustStore = KeyStore.getInstance("BKS"); trustStore.load(inputStream, "your-keystore-password".toCharArray()); SSLSocketFactory sf = new SSLSocketFactory(trustStore); // Use strict hostname verification for security sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); // Rest of your client setup code remains the same...
Extra Troubleshooting Checks
- Verify the server's supported TLS versions: Use an SSL testing tool to confirm which protocols your server accepts, then match them in your client code.
- Check certificate validity: Ensure the server's certificate isn't expired, and the domain name matches the certificate's CN/SAN fields.
- Rule out network interference: Corporate firewalls or proxies sometimes intercept SSL connections—test from a different network if possible.
内容的提问来源于stack exchange,提问作者Thanawat test

