您可以使用之前在Android KeyChain(系统密钥库)中安装的证书,扩展
X509ExtendedKeyManager
来配置由
URLConnection
使用的
SSLContext
。
证书由您需要的别名引用。要提示用户选择类似于Chrome的对话框,请使用:
KeyChain.choosePrivateKeyAlias(this, this,
new String[] {"RSA", "DSA"},
null,
null,
-1,
DEFAULT_ALIAS);
这是配置SSL连接使用自定义KeyManager的代码。它使用默认的TrustManager和HostnameVerifier。如果服务器使用Android默认的信任库中不存在的自签名证书,您需要对它们进行配置(不建议信任所有证书)。
TrustManager[] trustManagers = null;
KeyManager keyManager = KeyChainKeyManager.fromAlias(
context, mClientCertAlias);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[] {keyManager}, trustManagers, null);
URL url = new URL( versionUrl );
HttpsURLConnection urlConnection = ( HttpsURLConnection ) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
urlConnection.setConnectTimeout( 10000 );
InputStream in = urlConnection.getInputStream();
最后在这里,您可以找到来自这里和这里的完整自定义X509ExtendedKeyManager
实现,它负责选择客户端证书。我已经提取了所需的代码。
public static class KeyChainKeyManager extends X509ExtendedKeyManager {
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) {
throw new CertificateException(e);
} catch (InterruptedException e) {
throw new CertificateException(e);
}
PrivateKey privateKey;
try {
privateKey = KeyChain.getPrivateKey(context, alias);
} catch (KeyChainException e) {
throw new CertificateException(e);
} catch (InterruptedException 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;
}
@Override
public final String chooseServerAlias( String keyType, Principal[] issuers, Socket socket) {
throw new UnsupportedOperationException();
}
@Override
public final String[] getClientAliases(String keyType, Principal[] issuers) {
throw new UnsupportedOperationException();
}
@Override
public final String[] getServerAliases(String keyType, Principal[] issuers) {
throw new UnsupportedOperationException();
}
}
}
我没有测试它。请报告任何错误!
HttpsURLConnection
? - pedrofb