簡體   English   中英

Android 5.1.1 SSL例程:SSL23_GET_SERVER_HELLO:sslv3警報握手失敗

[英]Android 5.1.1 SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

它正在提供此SSLhandshakeException。 當應用程序在Android5.1(Android版本> = 4.4)上運行時,會給出異常。 我在Android 4.3上進行了測試,效果很好。 這可能是什么原因? 請幫忙

W/System.err(14221): javax.net.ssl.SSLHandshakeException: Handshake failed
W/System.err(14221):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:390)
W/System.err(14221):    at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:623)
W/System.err(14221):    at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:585)
W/System.err(14221):    at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:75)
W/System.err(14221):    at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:88)
W/System.err(14221):    at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:175)
W/System.err(14221):    at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:111)
W/System.err(14221):    at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:134)
W/System.err(14221):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
W/System.err(14221):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)
W/System.err(14221):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)
W/System.err(14221):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:365)
W/System.err(14221):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:768)
W/System.err(14221):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:700)
W/System.err(14221):    at com.up.testjavasdkdemo.ssltest.HttpHandler.makeRequestWithRetries(HttpHandler.java:75)
W/System.err(14221):    at com.up.testjavasdkdemo.ssltest.HttpHandler.doInBackground(HttpHandler.java:132)
W/System.err(14221):    at android.os.AsyncTask$2.call(AsyncTask.java:292)
W/System.err(14221):    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err(14221):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
W/System.err(14221):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
W/System.err(14221):    at java.lang.Thread.run(Thread.java:818)
W/System.err(14221): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb7c985b0: Failure in SSL library, usually a protocol error
W/System.err(14221): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:770 0xae157cc5:0x00000000)
W/System.err(14221):    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
W/System.err(14221):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:318)
W/System.err(14221):    ... 20 more
I/SSLTest (14221): onFailure:javax.net.ssl.SSLHandshakeException: Handshake failed  strMsg:Handshake failed
W/System.err(14221): javax.net.ssl.SSLHandshakeException: Handshake failed
W/System.err(14221):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:390)
W/System.err(14221):    at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:623)
W/System.err(14221):    at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:585)
W/System.err(14221):    at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:75)
W/System.err(14221):    at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:88)
W/System.err(14221):    at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:175)
W/System.err(14221):    at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:111)
W/System.err(14221):    at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:134)
W/System.err(14221):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
W/System.err(14221):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)
W/System.err(14221):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)
W/System.err(14221):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:365)
W/System.err(14221):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:768)
W/System.err(14221):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:700)
W/System.err(14221):    at com.up.testjavasdkdemo.ssltest.HttpHandler.makeRequestWithRetries(HttpHandler.java:75)
W/System.err(14221):    at com.up.testjavasdkdemo.ssltest.HttpHandler.doInBackground(HttpHandler.java:132)
W/System.err(14221):    at android.os.AsyncTask$2.call(AsyncTask.java:292)
W/System.err(14221):    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err(14221):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
W/System.err(14221):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
W/System.err(14221):    at java.lang.Thread.run(Thread.java:818)
W/System.err(14221): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb7c985b0: Failure in SSL library, usually a protocol error
W/System.err(14221): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:770 0xae157cc5:0x00000000)
W/System.err(14221):    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
W/System.err(14221):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:318)
W/System.err(14221):    ... 20 more
    Use this class like this while connecting :

public void httpEX(Context context) throws Exception {
            KeyStore trustStore = KeyStore.getInstance(KeyStore  
                    .getDefaultType());  
            trustStore.load(null, null);  

            SSLSocketFactory sf= new SSLSocketFactoryEx(context, trustStore);   

        BasicHttpParams httpParams = new BasicHttpParams();

        ConnManagerParams.setTimeout(httpParams, socketTimeout);
        ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections));
        ConnManagerParams.setMaxTotalConnections(httpParams, 10);

        HttpConnectionParams.setSoTimeout(httpParams, socketTimeout);
        HttpConnectionParams.setConnectionTimeout(httpParams, socketTimeout);
        HttpConnectionParams.setTcpNoDelay(httpParams, true);
        HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);

        HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", sf, 443));
        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
        httpContext = new SyncBasicHttpContext(new BasicHttpContext());



        httpClient = new DefaultHttpClient(cm, httpParams);

        httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
            public void process(HttpRequest request, HttpContext context) {
                if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
                    request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
                }
                for (String header : clientHeaderMap.keySet()) {
                    request.addHeader(header, clientHeaderMap.get(header));
                }
            }
        });

        httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
            public void process(HttpResponse response, HttpContext context) {
                final HttpEntity entity = response.getEntity();
                if (entity == null) {
                    return;
                }
                final Header encoding = entity.getContentEncoding();
                if (encoding != null) {
                    for (HeaderElement element : encoding.getElements()) {
                        if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
                            response.setEntity(new InflatingEntity(response.getEntity()));
                            break;
                        }
                    }
                }
            }
        });

        clientHeaderMap = new HashMap<String, String>();
    }

我已解決了這個問題。Android5.1默認禁用SSL_RSA_WITH_RC4_128_MD5密碼套件。 我需要更改SSLSocketFactoryEx.java類,實現方法:`@Override
public Socket createSocket(Socket socket,String host,int port,
boolean autoClose)引發IOException,UnknownHostException {SSLSocket S =(SSLSocket)sslContext.getSocketFactory()。createSocket(套接字,主機,端口,autoClose);

    String[] availableCiphers =S.getEnabledCipherSuites();
    for (String cipherSuite : availableCiphers) {
        logwarn("cipherSuite ====c========== " + cipherSuite);
      }
    List<String> aa = new ArrayList<String>();

    for(int i = 0; i < availableCiphers.length; i++)
    {
        aa.add(availableCiphers[i]);
    }
    aa.add("SSL_RSA_WITH_RC4_128_MD5");
    aa.add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
    String[] m_ciphers = aa.toArray(new String[0]);
    logwarn("new ====preferredCiphers========== " + m_ciphers.length);
    S.setEnabledCipherSuites(m_ciphers);
    return S;
    }`   
I made a custom socketFactory class called SSLSocketFactoryEx.java

import com.android.org.bouncycastle.util.encoders.Base64;
import com.pos.hsm.PKCS11Wrapper;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyFactory;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Principal;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ssl.SSLSocketFactory;
import Decoder.BASE64Decoder;

import android.content.Context;
import android.content.res.AssetManager;
//import org.apache.commons.codec.binary.Base64;
import android.util.Log;
public class SSLSocketFactoryEx extends SSLSocketFactory {      
    private static final String[] TLS_SUPPORT_VERSION = {"TLSv1.1", "TLSv1.2"};//Android 5.1 default enable SSLv3

    SSLContext sslContext =SSLContext.getInstance("SSL");
    public SSLSocketFactoryEx(final Context context, KeyStore truststore)      
            throws NoSuchAlgorithmException, KeyManagementException,      
            KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager trustManager = new X509TrustManager() {

            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                logwarn("alias =========getAcceptedIssuers===== ");
                return new X509Certificate[0];      
            }      

            @Override      
            public void checkClientTrusted(      
                    java.security.cert.X509Certificate[] chain, String authType)      
                    throws java.security.cert.CertificateException {
                logwarn("=====================checkServerTrusted===================");
                if(chain != null)logwarn("length = " + chain.length);
                try {
                    CertificateFactory factory = CertificateFactory.getInstance("X.509");
                    X509Certificate cert = null;
                    X509Certificate ca;
                    ByteArrayInputStream bais;

                    if(chain != null && chain.length > 0){
                        bais = new ByteArrayInputStream(chain[0].getEncoded());
                        cert = (X509Certificate) factory.generateCertificate(bais);
                        bais.close();
                    } else {
                        throw new CertificateException("There is no certificate");
                    }
                    byte[] trust = RSASignature.readFileByBytes(context, "trust01.crt");
                    logwarn("trust cert = " + new String(trust));
                    bais = new ByteArrayInputStream(trust);
                    CertificateFactory myCertificateFactory;
                    ca = (X509Certificate)factory.generateCertificate(bais);
                    bais.close();
                    cert.verify(ca.getPublicKey());
                }catch (Exception e){
                    logwarn("TrustManager checkServerTrusted failed!");
                    e.printStackTrace();
                    throw new CertificateException(e);
                }
            }

            @Override      
            public void checkServerTrusted(      
                    java.security.cert.X509Certificate[] chain, String authType)      
                    throws java.security.cert.CertificateException {      
                logwarn("=====================checkServerTrusted===================");
                if(chain != null)logwarn("length = " + chain.length);
                try {
                    CertificateFactory factory = CertificateFactory.getInstance("X.509");
                    X509Certificate cert = null;
                    X509Certificate ca;
                    ByteArrayInputStream bais;
                    if(chain != null && chain.length > 0){
                        bais = new ByteArrayInputStream(chain[0].getEncoded());
                        cert = (X509Certificate) factory.generateCertificate(bais);
                        bais.close();
                    } else {
                        throw new CertificateException("There is no certificate");
                    }
                    byte[] trust =  RSASignature.readFileByBytes(context, "trust01.crt");
                    logwarn("trust cert = " + new String(trust));
                    bais = new ByteArrayInputStream(trust);
                    CertificateFactory myCertificateFactory;
                    ca = (X509Certificate)factory.generateCertificate(bais);
                    bais.close();
                    cert.verify(ca.getPublicKey());
                }catch (Exception e){
                    logwarn("TrustManager checkServerTrusted failed!");
                    e.printStackTrace();
                    throw new CertificateException(e);
                }
            }      
        };
        X509KeyManager keyManager = new X509KeyManager() {
            @Override
            public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {

                logwarn("=====================chooseClientAlias===================");
                if(keyType != null && keyType.length > 0){
                    for(int i = 0; i < keyType.length; i++){
                        logwarn("keyType["+i+"]=" + keyType[i]);
                    }
                }
                if(issuers != null && issuers.length > 0){
                    for(int i = 0; i < issuers.length; i++){
                        logwarn("issuers["+i+"]=" + issuers[i].getName());
                    }
                }
                return "pk2048";
            }

            @Override
            public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
                logwarn("=====================chooseServerAlias===================");
                logwarn("keyType================" + keyType);
                if(issuers != null && issuers.length > 0){
                    for(int i = 0; i < issuers.length; i++){
                        logwarn("issuers["+i+"]=" + issuers[i].getName());
                    }
                }
                return "trust01";
            }

            @Override
            public X509Certificate[] getCertificateChain(String alias) {
                logwarn("=====================getCertificateChain===================");
                logwarn("alias ============== " + alias);
                byte[] publickey = RSASignature.readFileByBytes(context, "client2048.crt");
                InputStream ceris = new ByteArrayInputStream(publickey);
                CertificateFactory myCertificateFactory;
                try {
                    myCertificateFactory = CertificateFactory.getInstance("X.509");
                    X509Certificate cer = (X509Certificate)myCertificateFactory.generateCertificate(ceris);
                    ceris.close();
                    return new X509Certificate[]{cer};
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return new X509Certificate[0];
            }

            @Override
            public String[] getClientAliases(String keyType, Principal[] issuers) {
                logwarn("=====================getClientAliases===================");
                logwarn("keyType================" + keyType);
                if(issuers != null && issuers.length > 0){
                    for(int i = 0; i < issuers.length; i++){
                        logwarn("issuers["+i+"]=" + issuers[i].getName());
                    }
                }
                return new String[0];
            }

            @Override
            public String[] getServerAliases(String keyType, Principal[] issuers) {
                logwarn("=====================getServerAliases===================");
                logwarn("keyType================" + keyType);
                if(issuers != null && issuers.length > 0){
                    for(int i = 0; i < issuers.length; i++){
                        logwarn("issuers["+i+"]=" + issuers[i].getName());
                    }
                }
                return new String[0];
            }

            @Override
            public PrivateKey getPrivateKey(String alias) {
                logwarn("=====================getPrivateKey===================");
                logwarn("alias ============== " + alias);
                byte[] keyData = RSASignature.readFileByBytes(context, alias + ".crt");
                String keyString = new String(keyData);
                keyString = keyString.replaceAll("\n", "");
                Pattern pattern =Pattern.compile("-----BEGIN RSA PRIVATE KEY-----(.*?)-----END RSA PRIVATE KEY-----");
                Matcher matcher=pattern.matcher(keyString);
                while (matcher.find()) {
                    keyData = matcher.group(1).getBytes();
                }
                try {
                    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decode(keyData));//PKCS8EncodedKeySpec(Base64.decodeBase64(keyData));
                    KeyFactory keyFactory = KeyFactory.getInstance("RSA","BC");
                    PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
                    return privateK;
                }catch (Exception e){
                    e.printStackTrace();
                }
                return null;
            }
        };
        //sslContext.init(null, new TrustManager[] { tm }, null);
        sslContext.init(new KeyManager[]{keyManager}, new TrustManager[]{trustManager}, null);

    }      

    @Override      
    public Socket createSocket(Socket socket, String host, int port,      
            boolean autoClose) throws IOException, UnknownHostException { 
        //injectHostname(socket, host);
        SSLSocket S = (SSLSocket) sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
        String[] enProtocols = S.getEnabledProtocols();
        for (String cipherSuite : enProtocols) {
            logwarn("enProtocols ====c========== " + cipherSuite);
          }
        String[] Protocols = S.getSupportedProtocols();
        for (String cipherSuite : Protocols) {
            logwarn("Protocols ====c========== " + cipherSuite);
          }
        S.setEnabledProtocols(TLS_SUPPORT_VERSION);
         enProtocols = S.getEnabledProtocols();
        for (String cipherSuite : enProtocols) {
            logwarn("enProtocols ====en========== " + cipherSuite);
          }
        Protocols = S.getSupportedProtocols();
        for (String cipherSuite : Protocols) {
            logwarn("Protocols ====add========== " + cipherSuite);
          }
        String[] original =S.getEnabledCipherSuites();
        for (String cipherSuite : original) {
            logwarn("cipherSuite ====c========== " + cipherSuite);
          }
        return sslContext.getSocketFactory().createSocket(socket, host, port,      
                autoClose);      
    }      
    private void injectHostname(Socket socket, String host) {
        try {
            Field field = InetAddress.class.getDeclaredField("hostName");
            field.setAccessible(true);
            field.set(socket.getInetAddress(), host);
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    }
    @Override      
    public Socket createSocket() throws IOException {
        SSLSocket S = (SSLSocket) sslContext.getSocketFactory().createSocket();
        S.setEnabledProtocols(TLS_SUPPORT_VERSION);
        String[] original =S.getEnabledCipherSuites();
        for (String cipherSuite : original) {
            logwarn("cipherSuite ============== " + cipherSuite);
          }
        return sslContext.getSocketFactory().createSocket();      
    }
    void logwarn(String msg) {
        Log.d("AndroidSSLSocketFactory", msg);
    }
}  

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM