我一直在开发一个需要进行相互 ssl 身份验证的 rss 阅读器。我已经设法使用 Keychain API 获取用户证书,并且得到了似乎大部分工作的 SSLSocketFactory。但是每当我尝试与服务器建立连接时,我都会收到 401 Unauthorized 错误,我觉得这可能与我设置 SSL 连接和通用代码的方式有关。如果有人可以帮助指出我做错了什么以及我需要做什么,我将不胜感激。
主要活动:
public class AliasLoader extends AsyncTask<Void, Void, X509Certificate[]>
{
X509Certificate[] chain = null;
@Override protected X509Certificate[] doInBackground(Void... params) {
android.os.Debug.waitForDebugger();
if(!SavedAlias.isEmpty())
{
try {
PrivateKey key2 = KeyChain.getPrivateKey(getApplicationContext(), SavedAlias);
setPrivateKey(key2);
chain = KeyChain.getCertificateChain(getApplicationContext(),SavedAlias);
setCertificate(chain);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
else
{
this.cancel(true);
}
return chain;
}
@Override
protected void onPostExecute(X509Certificate[] chain)
{
if(chain != null)
{
HttpClient client = CustomSSLSocketFactory.getNewHttpClient(context, getAlias(), chain, key);
String formDataServiceUrl = "https://android.diif.r.mil.uk";
WebView wv = (WebView) findViewById(R.id.rssFeedItemView);
HttpPost post = new HttpPost(formDataServiceUrl);
final HttpGet request = new HttpGet(formDataServiceUrl);
HttpResponse result = null;
try {
result = client.execute(post);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
wv.loadUrl(formDataServiceUrl);
}
else
{
Toast.makeText(getApplicationContext(), "Certificate is Empty", Toast.LENGTH_LONG).show();
}
}
}
自定义SSLSocketFactory:
public class CustomSSLSocketFactory extends SSLSocketFactory {
public static KeyStore rootCAtrustStore = null;
public static KeyStore clientKeyStore = null;
SSLContext sslContext = SSLContext.getInstance("TLS");
Context context;
/**
* Constructor.
*/
public CustomSSLSocketFactory(Context context, KeyStore keystore, String keyStorePassword, KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(keystore, keyStorePassword, truststore);
this.context = context;
// custom TrustManager,trusts all servers
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
Log.i("CLIENT CERTIFICATES", "Loaded client certificates: " + keystore.size());
// initialize key manager factory with the client certificate
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore,null);
sslContext.init(keyManagerFactory.getKeyManagers(), new TrustManager[] { tm }, null);
//sslContext.init(null, new TrustManager[]{tm}, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
/**
* Create new HttpClient with CustomSSLSocketFactory.
*/
public static HttpClient getNewHttpClient(Context context, String alias, X509Certificate[] chain, PrivateKey key) {
try {
// This is method from tutorial ----------------------------------------------------
//The root CA Trust Store
rootCAtrustStore = KeyStore.getInstance("BKS");
rootCAtrustStore.load(null);
//InputStream in = context.getResources().openRawResource(com.DII.RSS_Viewer.R.raw.rootca);
//rootCAtrustStore.load(in, "PASSWORD".toCharArray());
//The Keystore with client certificates.
//clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
clientKeyStore = KeyStore.getInstance("pkcs12");
clientKeyStore.load(null);
// client certificate is stored in android's keystore
if((alias != null) && (chain != null))
{
Key pKey = key;
clientKeyStore.setKeyEntry(alias, pKey, "password".toCharArray(), chain);
}
//SSLSocketFactory sf = new CustomSSLSocketFactory(context, clientKeyStore, "password", rootCAtrustStore);
SSLSocketFactory sf = new SSLSocketFactory(clientKeyStore, "password");
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", (SocketFactory) sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
}
catch (Exception e)
{
return new DefaultHttpClient();
}
}
}