我正在Android上开发一个使用REST Web服务的应用程序。 Web服务使用HTTPS。我无法提供网络服务详情,因为它是保密的。我按照以下链接中提到的步骤进行操作:
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
该应用程序到目前为止工作正常,并能够下载Web服务内容。突然持续一周它无法连接并抛出“javax.net.ssl.SSLException:不可信服务器证书”。我按照下面提到的步骤来设置:
步骤1:我在我的应用程序中使用了GeoTrust提供的根证书来启用安全通信。所以从地理信任站点收集了根证书“GeoTrust_Global_CA.cer”:http://www.geotrust.com/resources/root-certificates/index.html
它是Base64编码的X.509格式。
步骤2:下载BouncyCastle提供程序并使用此创建的密钥库。我从命令行使用java 6 keytool运行以下命令来生成密钥存储:
keytool -importcert -v -trustcacerts -file“G:\ workspace \ TestHttps \ GeoTrustglobal.cer”-alias IntermediateCA -keystore“G:\ workspace \ TestHttps \ res \ raw \ mykeystore.bks”-provider org.bouncycastle .jce.provider.BouncyCastleProvider -providerpath“G:\ workspace \ TestHttps \ SigningProcess \ bcprov-jdk16-146.jar”-storetype BKS -storepass mysecret
成功后,它会创建myKeyStore.bks并将其复制到我的应用程序的/ res / raw文件夹中。
然后通过运行以下命令验证此密钥库:
keytool -importcert -v -trustcacerts -file“G:\ workspace \ TestHttps \ GeoTrustglobal.cer”-alias IntermediateCA -keystore“G:\ workspace \ TestHttps \ res \ raw \ mykeystore.bks”-provider org.bouncycastle .jce.provider.BouncyCastleProvider -providerpath“G:\ workspace \ TestHttps \ SigningProcess \ bcprov-jdk16-146.jar”-storetype BKS -storepass mysecret
它返回1个中间证书的结果如下:
IntermediateCA,22.10.2010,trustedCertEntry,Thumbprint(MD5):98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
第3步:
现在我编写了以下从DefaultHttpClient扩展的代码
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.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".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:
package com.test.https;
import java.io.IOException;
import java.net.UnknownHostException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.os.Bundle;
public class TestHttps extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
startConnect();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void startConnect() throws UnknownHostException{
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://ssltest15.bbtest.net/");
// Execute the GET call and obtain the response
HttpResponse getResponse = null;
try {
getResponse = client.execute(get);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(UnknownHostException uhe){
uhe.printStackTrace();
throw new UnknownHostException();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String response = null;
if(getResponse != null){
HttpEntity responseEntity = getResponse.getEntity();
try {
response = EntityUtils.toString(responseEntity);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
当我执行此代码时,它会抛出以下异常:
java.security.cert.CertPathValidatorException:找不到CertPath的TrustAnchor。
javax.net.ssl.SSLException:不受信任的服务器证书
所以我尝试使用相同的应用程序连接各种其他Web服务,包括geotrust(https://ssltest15.bbtest.net/)提供的服务。所有抛出相同的异常。我对这个问题的猜测是,
提供REST Web服务的Web服务器可能会有一些更改,导致此问题
我使用的Geo Trust证书已过期
我遵循的步骤有一些问题
与上述代码相同的应用程序在1周之前工作正常,现在突然失败意味着,服务器端发生了一些变化导致此问题。我不清楚确切的问题。
如果有人能帮助我理解这个问题,我们非常感谢。提前谢谢。
答案 0 :(得分:0)
您似乎没有正确填充您的信任存储区。我知道你不能讨论你的网络服务的细节,但是你的服务证书是什么?您需要将 链放在您的客户端应用程序的信任密钥库中。
例如,如果您的Web服务是从中间GeoTrust CA签名的,那么您应该将中间GeoTrust CA的证书以及根GeoTrust CA的证书放入您的商店。如果仍然出现错误,也请将您的Web服务证书放入客户端信任存储区。
查看keytool -list输出,您的信任库中只有一个条目。