安全地修复:javax.net.ssl.SSLPeerUnverifiedException:没有对等证书

有关于这个问题的几十个post(javax.net.ssl.SSLPeerUnverifiedException:没有同行证书),但我还没有find任何适合我的东西。

许多post(比如这个和这个 )通过允许所有的证书被接受来“解决”这个问题,当然,除了testing之外,这不是一个好的解决scheme。

其他人似乎相当本地化,不为我工作。 我真的希望有人有一些洞察力,我缺乏。

所以,我的问题:我在只能通过本地networking访问的服务器上testing,通过HTTPS连接。 拨打电话,我需要通过浏览器工作正常。 没有抱怨证书,如果你检查证书,这一切看起来不错。

当我尝试在我的Android设备上,我得到javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

这是调用它的代码:

 StringBuilder builder = new StringBuilder(); builder.append( /* stuff goes here*/ ); httpGet.setEntity(new UrlEncodedFormEntity(nameValuePairs)); ResponseHandler<String> responseHandler = new BasicResponseHandler(); // Execute HTTP Post Request. Response body returned as a string HttpClient httpClient = MyActivity.getHttpClient(); HttpGet httpGet = new HttpGet(builder.toString()); String jsonResponse = httpClient.execute(httpGet, responseHandler); //Line causing the Exception 

MyActivity.getHttpClient()我的代码:

 protected synchronized static HttpClient getHttpClient(){ if (httpClient != null) return httpClient; HttpParams httpParameters = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, TIMEOUT_CONNECTION); HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SOCKET); HttpProtocolParams.setVersion(httpParameters, HttpVersion.HTTP_1_1); //Thread safe in case various AsyncTasks try to access it concurrently SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); ClientConnectionManager cm = new ThreadSafeClientConnManager(httpParameters, schemeRegistry); httpClient = new DefaultHttpClient(cm, httpParameters); CookieStore cookieStore = httpClient.getCookieStore(); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); return httpClient; } 

任何帮助将不胜感激。

编辑

也只是提到我已经与另一个应用程序的其他SSL问题,但添加SchemeRegistry部分之前修复了我。

编辑2

到目前为止,我只testing了Android 3.1,但是我需要这个在Android 2.2+上工作。 我刚刚在我的Android选项卡(Android 3.1)的浏览器上进行testing,并且抱怨证书。 在我的电脑浏览器上没问题,但不是在Android浏览器或我的应用程序。

编辑3

事实certificate,iOS浏览器也抱怨。 我开始认为这是这里描述的证书链问题( SSL证书不可信 – 仅在移动设备上 )

事实certificate,我的代码是好的,问题是服务器没有返回完整的证书链。 欲了解更多信息,请看这个SOpost和这个超级用户的post:

SSL证书不受信任 – 仅限移动设备

https://superuser.com/questions/347588/how-do-ssl-chains-work

尝试下面的代码: –

  BasicHttpResponse httpResponse = null; HttpPost httppost = new HttpPost(URL); HttpParams httpParameters = new BasicHttpParams(); // Set the timeout in milliseconds until a connection is // established. int timeoutConnection = ConstantLib.CONNECTION_TIMEOUT; HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); // Set the default socket timeout (SO_TIMEOUT) // in milliseconds which is the timeout for waiting for data. int timeoutSocket = ConstantLib.CONNECTION_TIMEOUT; HttpConnectionParams .setSoTimeout(httpParameters, timeoutSocket); DefaultHttpClient httpClient = new DefaultHttpClient( httpParameters); List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(); nameValuePairs.add(new BasicNameValuePair(ConstantLib.locale, locale)); 

在我的情况下,一切正常工作。 突然在2天后,我的设备没有显示任何https网站或图像链接。

经过一番调查后发现我的时间设置在设备上并不是最新的。

我改变了我的时间设置正确,它的工作。

当我使用自签名证书+ IP地址时,我有这个例外。 只需添加这些行

 HostnameVerifier allHostsValid = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }; HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); 

和你的HttpURLConnection将工作。 这个窍门与CA的validation无关! 所以如果我指定错误的CA并使用这个技巧,我会得到另一个exception。 所以主机仍然是可信的

为了以防万一,我将留下代码来指定您自己的CA:

 String certStr = context.getString(R.string.caApi); X509Certificate ca = SecurityHelper.readCert(certStr); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(null); ks.setCertificateEntry("caCert", ca); tmf.init(ks); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); 

不要忘记使用酷的functionbuildTypes和debugging/释放res文件夹中放置不同的CA。