Android 4.x中的SSL客户端身份验证

我想创建一个连接到服务器的应用程序。 该服务器使用SSL客户端验证。 应用程序的用户应该能够选择证书并允许使用它,就像它在浏览器应用程序中实现的一样。

在浏览器应用程序中,身份验证按预期工作,所以我使用的证书是有效的。

当我尝试在我的应用程序中连接时,出现以下错误:

javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException:
SSL handshake terminated: ssl=0x2a2d3b38:
Failure in SSL library, usually a protocol error
error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
(external/openssl/ssl/s3_pkt.c:1290 0x2a2df880:0x00000003)

我试图按照我的实现Android文档。

  • 在ICS中统一密钥存储访问
  • HttpsURLConnection的
  • 以下是我的示例Activity的代码:

    public class ClientCertificateActivity extends Activity implements
        KeyChainAliasCallback {
    
    protected static final String TAG = "CERT_TEST";
    private String alias;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        choseCertificate();
        LinearLayout layout = new LinearLayout(this);
        Button connectToServer = new Button(this);
        connectToServer.setText("Try to connect to Server");
        connectToServer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        connectToServer.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                connectToServer();
            }
        });
        layout.addView(connectToServer);
        addContentView(layout, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    }
    
    protected void connectToServer() {
        final Context ctx = this;
        new AsyncTask<Void, Void, Boolean>() {
    
            private Exception error;
    
            @Override
            protected Boolean doInBackground(Void... arg) {
                try {
                    PrivateKey pk = KeyChain.getPrivateKey(ctx, alias);
                    X509Certificate[] chain = KeyChain.getCertificateChain(ctx,
                            alias);
    
                    KeyStore keyStore = KeyStore.getInstance("AndroidCAStore");
                    TrustManagerFactory tmf = TrustManagerFactory
                            .getInstance(TrustManagerFactory
                                    .getDefaultAlgorithm());
                    tmf.init(keyStore);
    
                    SSLContext context = SSLContext.getInstance("TLS");
                    context.init(null, tmf.getTrustManagers(), null);
    
                    URL url = new URL("https://usecert.example.com/");
                    HttpsURLConnection urlConnection = (HttpsURLConnection) url
                            .openConnection();
                    urlConnection.setSSLSocketFactory(context
                            .getSocketFactory());
                    InputStream in = urlConnection.getInputStream();
    
                    return true;
                } catch (Exception e) {
                    e.printStackTrace();
                    error = e;
                    return false;
                }
            }
    
            @Override
            protected void onPostExecute(Boolean valid) {
                if (error != null) {
                    Toast.makeText(ctx, "Error: " + error.getMessage(),
                            Toast.LENGTH_LONG).show();
                    return;
                }
                Toast.makeText(ctx, "Success: ", Toast.LENGTH_SHORT).show();
            }
        }.execute();
    
    }
    
    protected void choseCertificate() {
        KeyChain.choosePrivateKeyAlias(this, this,
                new String[] { "RSA", "DSA" }, null, "m.ergon.ch", 443, null);
    }
    
    @Override
    public void alias(String alias) {
        this.alias = alias;
    }
    }
    

    该异常引发在urlConnection.getInputStream();

    这里是捕获服务器和客户端之间的握手。 网络捕获SSL握手

    感谢您的任何建议和提示。


    你永远不会用你的私钥初始化一个KeyManager,所以客户端认证不可能把它拿起来。

    你必须实现X509KeyManager来返回你的PrivateKey和一些硬编码的别名。 这是股票电子邮件应用程序(ICS +)的参考资料。 您可能需要稍微修改它,但应该很容易遵循:基本上它只是将关键字,别名和证书链保存到字段并通过适当的方法返回它们( StubKeyManager仅为未实现和不需要的方法引发异常):

    public static class KeyChainKeyManager extends StubKeyManager {
        private final String mClientAlias;
        private final X509Certificate[] mCertificateChain;
        private final PrivateKey mPrivateKey;
    
        public static KeyChainKeyManager fromAlias(Context context, String alias)
                throws CertificateException {
            X509Certificate[] certificateChain;
            try {
                certificateChain = KeyChain.getCertificateChain(context, alias);
            } catch (KeyChainException e) {
                logError(alias, "certificate chain", e);
                throw new CertificateException(e);
            } catch (InterruptedException e) {
                logError(alias, "certificate chain", e);
                throw new CertificateException(e);
            }
    
            PrivateKey privateKey;
            try {
                privateKey = KeyChain.getPrivateKey(context, alias);
            } catch (KeyChainException e) {
                logError(alias, "private key", e);
                throw new CertificateException(e);
            } catch (InterruptedException e) {
                logError(alias, "private key", e);
                throw new CertificateException(e);
            }
    
            if (certificateChain == null || privateKey == null) {
                throw new CertificateException("Can't access certificate from keystore");
            }
    
            return new KeyChainKeyManager(alias, certificateChain, privateKey);
        }
    
        private KeyChainKeyManager(
                String clientAlias, X509Certificate[] certificateChain, 
                PrivateKey privateKey) {
            mClientAlias = clientAlias;
            mCertificateChain = certificateChain;
            mPrivateKey = privateKey;
        }
    
    
        @Override
        public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
             return mClientAlias;
        }
    
        @Override
        public X509Certificate[] getCertificateChain(String alias) {
              return mCertificateChain;
        }
    
        @Override
        public PrivateKey getPrivateKey(String alias) {
                return mPrivateKey;
        }
    }
    
    链接地址: http://www.djcxy.com/p/66483.html

    上一篇: SSL Client authentication in Android 4.x

    下一篇: python debug tools for multiprocessing