SSL pinning validation failed: javax.net.ssl.SSLHandshakeException

402 Views Asked by At

I'm encountering an javax.net.ssl.SSLHandshakeException with the message "SSL pinning validation failed" when implementing SSL pinning in my Android application. I have already verified that I'm using the correct SHA-256 key for pinning.

Here's the relevant code snippet:

package 
import android.os.Build;

import androidx.annotation.RequiresApi;

import com.android.volley.toolbox.HurlStack;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Base64;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class CustomHurlStack extends HurlStack implements HurlStack.UrlRewriter {

private String sha256Pin;

public CustomHurlStack(String sha256Pin) {
    this.sha256Pin = sha256Pin;
}

@Override
protected HttpURLConnection createConnection(java.net.URL url) throws IOException {
    HttpURLConnection connection = super.createConnection(url);

    if (connection instanceof HttpsURLConnection) {
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) connection;

        try {
            // Configure SSL socket factory with SSL pinning
            SSLSocketFactory sslSocketFactory = createSSLSocketFactory();
            httpsURLConnection.setSSLSocketFactory(sslSocketFactory);

            // Set hostname verifier to bypass hostname verification
            httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
    }

    return connection;
}

private SSLSocketFactory createSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException {
    TrustManager[] trustManagers = new TrustManager[]{new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // Perform any necessary client certificate checks
        }

        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // Perform the SSL pinning check
            for (X509Certificate certificate : chain) {
                String publicKeySha256 = null;
                try {
                    publicKeySha256 = calculatePublicKeySha256(certificate.getPublicKey());
                } catch (NoSuchAlgorithmException e) {
                    throw new RuntimeException(e);
                }
                if (!sha256Pin.equals(publicKeySha256)) {
                    throw new CertificateException("SSL pinning validation failed");
                }
            }
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }};

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, trustManagers, null);

    return sslContext.getSocketFactory();
}
@Override
public String rewriteUrl(String originalUrl) {
    // Implement any URL rewriting logic if needed
    // You can modify the original URL and return the modified URL
    return originalUrl;
}

@RequiresApi(api = Build.VERSION_CODES.O)
private String calculatePublicKeySha256(PublicKey publicKey) throws NoSuchAlgorithmException {
    byte[] publicKeyBytes = publicKey.getEncoded();

    MessageDigest digest = MessageDigest.getInstance("SHA-256");

    byte[] sha256Bytes = digest.digest(publicKeyBytes);

    return Base64.getEncoder().encodeToString(sha256Bytes);
}
}

Here's relevant code snippet of API call:

 String sha256Pin = Customize.getInstance().getSslPublicKey(); // Replace with your custom SHA256 pin
            CustomHurlStack customHurlStack = new CustomHurlStack(sha256Pin);
            RequestQueue sRequestQueue = Volley.newRequestQueue(mContext, customHurlStack);

I have followed the steps mentioned in the documentation and other online resources, but I'm still unable to resolve the issue. Here are the details of my setup:

  • Android version: Android 10
  • Library/Framework used: Volley 1.2.1
  • SHA-256 key used: -----

I have also tried the following troubleshooting steps without success:

  • Verifying the SHA-256 key: I have double-checked the SHA-256 key and ensured that it matches the server's public key.
  • Debugging and logging: I have added debug logs to track the SSL pinning process, but the error still occurs.
  • Testing in a different environment: I have tested the SSL pinning implementation with a different server, but the issue persists.

I would appreciate any insights, suggestions, or possible solutions to resolve this SSL pinning validation error. Thank you in advance for your help.

0

There are 0 best solutions below