在運行Android 2.3但不是4的模擬器中獲取"javax.net.ssl.SSLPeerUnverifiedException: No peer certificate error"
。我正試圖通過https連接到一個活的服務器。它使用有效的Thawte證書,在所有瀏覽器和Android 3和4中均可正常工作。Android 2.3中沒有對等證書錯誤,但不是4
如果任何人有代碼幫助,請致謝。此外,如果有人對安全解決方法有任何建議,我會很感激。我仍然在學習,而且我一直在解決這個問題一個星期。它必須結束,所以我可以繼續工作和學習。 Urgh。
這裏是HttpClient的代碼,禮貌安託萬·豪克(http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/):
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.security.cert.X509Certificate;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import android.content.Context;
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.my_cert);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "my_pass".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
這裏是實例化它的代碼:
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpPost post = new HttpPost(server_login_url);
List <NameValuePair> parameters = new ArrayList <NameValuePair>();
parameters.add(new BasicNameValuePair("username", user));
parameters.add(new BasicNameValuePair("password", pass));
try {
post.setEntity(new UrlEncodedFormEntity(parameters, HTTP.UTF_8));
} catch (UnsupportedEncodingException e2) {
// TODO Auto-generated catch block
Log.d(DEBUG_TAG, "in UnsupportedEncodingException - " + e2.getMessage());
e2.printStackTrace();
}
// Execute the GET call and obtain the response
HttpResponse getResponse = null;
try {
getResponse = client.execute(post);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
// Toast.makeText(getBaseContext(),message,Toast.LENGTH_LONG).show();
Log.d(DEBUG_TAG, "in ClientProtocolException - " + e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
// Toast.makeText(getBaseContext(),message,Toast.LENGTH_LONG).show();
Log.d(DEBUG_TAG, "in client.execute IOException - " + e.getMessage());
e.printStackTrace();
}
錯誤是夾在IOException異常塊。這裏是堆棧:
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:258)
org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93)
org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164)
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
org.ffb.tools.SplashActivity$LoginTask.makeConnection(SplashActivity.java:506)
org.ffb.tools.SplashActivity$LoginTask.doLogin(SplashActivity.java:451)
org.ffb.tools.SplashActivity$LoginTask.doInBackground(SplashActivity.java:439)
org.ffb.tools.SplashActivity$LoginTask.doInBackground(SplashActivity.java:1)
android.os.AsyncTask$2.call(AsyncTask.java:185)
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
java.util.concurrent.FutureTask.run(FutureTask.java:138)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
java.lang.Thread.run(Thread.java:1019)
這裏是鏈順序(從OpenSSL的命令):
鏈看起來不錯,我認爲。
i:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
1 s:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
2 s:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
i:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/[email protected]
謝謝,編輯。向原始文章添加證書鏈。我使用Java keytool將中間和根證書都包含在一個密鑰庫中。這是正確的方式去做事嗎? – user1214401 2012-03-06 18:58:53
如果您使用Thawte,則不需要在應用程序中包含您的證書。 Thawte在Android 2.3 [受信任的CA列表]中(http://www.andreabaccega.com/blog/2010/09/23/android-root-certification-authorities-list/)。另外需要注意的是,Android 2.3不支持[Server Name Indication](服務器名稱指示)(http://en.wikipedia.org/wiki/Server_Name_Indication),所以如果你的服務器依賴於它,Android可能不會獲得你的「重新期待。 – 2012-03-06 19:50:41
從一開始我回顧一年後,這不會很有趣。我花了兩個星期的時間修復一些沒有損壞的東西。是的,埃德,你是對的。密鑰庫是不必要的;解凍證書已被信任。它正在運行我的Android 4手機和仿真器。最初我得到了一個證書錯誤(不記得它是什麼),這是什麼導致我走了這條路,但是......好吧,在過去的兩週裏我學到了很多......埃德,如果你更新你的編輯的原始答案我可以將其標記爲答案。謝謝!! – user1214401 2012-03-07 06:31:12