Android的SSL我有一个例外,没有同行证书

问题描述:

:没有对方的证书Android的SSL我有一个例外,没有同行证书

当我问谷歌,然后我得到的解决方案,在那里我相信所有证书。但这个问题的答案是,它是不安全的。

于是就给类:

HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; 
      HttpClient client = new DefaultHttpClient(); 

      SchemeRegistry registry = new SchemeRegistry(); 
      SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory(); 
      socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier); 
      registry.register(new Scheme("https", socketFactory, 443)); 
      SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry); 
      DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams()); 

      HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); 
      Log.v("URL:", Url[0]); 
      HttpPost post = new HttpPost(Url[0]); 
      post.addHeader("Username", Url[1]); 
      post.addHeader("Passwort", Url[2]); 
      HttpResponse getResponse = httpClient.execute(post); //Wirft Exception 
      HttpEntity responseEntity = getResponse.getEntity(); 
      UserID = Integer.parseInt(responseEntity.getContent().toString()); 

这是我的课:

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", (SocketFactory) 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.mykey); 
     try { 
      // Initialize the keystore with the provided trusted certificates 
      // Also provide the password of the keystore 
      trusted.load(in, "PASSWORT".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 
     // [url=http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506]Chapter2.Connection management[/url] 
     sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); 
     return sf; 
    } catch (Exception e) { 
     throw new AssertionError(e); 
    } 
} 

}

盲目信任所有证书听起来像一个非常糟糕的主意。你真的应该试着找出这个问题的原因。我得到了运行2.3.3较旧的Android设备上同样的错误(较新的Android版本的工作没有任何问题,就像iOS设备):

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 

阅读几种不同的相关问题后,我到了这样的结论这可能发生的原因有两个(或许更多):

在我的情况下,这是证书的不正确排序。作为一个例子,我将从this question发布的证书订单与来自用户bdc的深刻解答贴在一起。您可以通过从终端做以下拿到证书顺序:

openssl s_client -connect eu.battle.net:443 

(用自己的服务器显然替换eu.battle.net)。在eu.battle.net当时的情况下,顺序为:

Certificate chain 
0 s:/C=US/ST=California/L=Irvine/O=Blizzard Entertainment, Inc./CN=*.battle.net 
    i:/C=US/O=Thawte, Inc./CN=Thawte SSL CA 
1 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] 
2 s:/C=US/O=Thawte, Inc./CN=Thawte 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 

虽然它应该是:

Certificate chain 
0 s:/C=US/ST=California/L=Irvine/O=Blizzard Entertainment, Inc./CN=*.battle.net 
    i:/C=US/O=Thawte, Inc./CN=Thawte SSL CA 
1 s:/C=US/O=Thawte, Inc./CN=Thawte 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] 

的规则是,证书的颁发者“N”链条应符合证书“n + 1”的主题。

一旦我发现问题,更改服务器上的证书订单和立即开始在Android 2.3.3设备上工作的事情是微不足道的。我想早期的Android版本对于证书订单有点讨厌是件好事,但它也是一个噩梦,因为更新的Android版本会自动对证书进行重新排序。地狱,即使是一个旧的iPhone 3GS的失败证书工作。

我已经发现了SSLPeerUnverifiedException的另一个可能的原因:没有对等证书

如果你的模拟器与那就是当创建证书你可能会遇到这个异常得比较早的日期运行。

本人的证书已于7月10日通过验证,但仿真器的当前日期为5月7日。

我不知道为什么我的模拟器的日期设置为5月7日,因为它应该是从网络获取时间,但这是另一个时间的问题。

只是觉得我应该分享一下,以免它能帮助别人避免浪费两三天的时间。

+0

这节省了我很多时间。谢谢 – waqaslam 2013-08-23 08:59:19

+0

我在这上面浪费了两个小时。非常感谢! – Arlo 2014-01-22 15:53:28

+0

我面临类似的问题,平板电脑相比真正的月份有+1个月。我有同样的例外。配置正确的日期固定它!谢谢 – Seynorth 2014-07-23 08:50:34