Android生成CertPathvalidatorexception(issuername!= objectname)上的Apache httpclient
-
29-09-2019 - |
题
我正在开发一个访问battle.net的android应用程序(https://eu.battle.net)帐户数据(魔兽世界),我正在使用 org.apache.http.client.HttpClient
这样做。
这是我正在使用的代码:
public static final String USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 (.NET CLR 3.5.30729)";
public static class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
super();
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.battlenetkeystore);
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);
}
}
}
private static void maybeCreateHttpClient(Context context) {
if (mHttpClient == null) {
mHttpClient = new MyHttpClient(context);
final HttpParams params = mHttpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT);
ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT);
Log.d(TAG, LEAVE + "maybeCreateHttpClient()");
}
}
public static boolean authenticate(String username, String password, Handler handler,
final Context context) {
final HttpResponse resp;
final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair(PARAM_USERNAME, username));
params.add(new BasicNameValuePair(PARAM_PASSWORD, password));
HttpEntity entity = null;
try {
entity = new UrlEncodedFormEntity(params);
} catch (final UnsupportedEncodingException e) {
// this should never happen.
throw new AssertionError(e);
}
final HttpPost post = new HttpPost(THE_URL);
post.addHeader(entity.getContentType());
post.addHeader("User-Agent", USER_AGENT);
post.setEntity(entity);
maybeCreateHttpClient(context);
if (mHttpClient == null) {
return false;
}
try {
resp = mHttpClient.execute(post);
} catch (final IOException e) {
Log.e(TAG, "IOException while authenticating", e);
return false;
} finally {
}
}
像这样(通过OpenSSL)检索了密钥库:
openssl s_client -connect eu.battle.net:443 -showcerts
我已经比较了命令产生的证书(http://vipsaran.webs.com/openssl_output.txt)我从firefox出口的人(http://vipsaran.webs.com/firefox_output.zip),它们是一样的。
通过以下建议 这个博客, ,我已经设置了上述代码,并将用于HTTPCLIENT的密钥库(battlenetkeystore.bks)导入了(root和Intermediate)证书。
这是我用于将证书导入密钥库的命令:
keytool -importcert -v -file ~/lib/ThawteSSLCA.crt -alias thawtesslca -keystore ~/lib/battlenetkeystore.bks -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ~/lib/bcprov-jdk16-145.jar -storetype BKS -storepass mysecret -keypass mysecret -keyalg "RSA" -sigalg "SHA1withRSA"
keytool -importcert -v -file ~/lib/thawtePrimaryRootCA.crt -alias thawteprimaryrootca -keystore ~/lib/battlenetkeystore.bks -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ~/lib/bcprov-jdk16-145.jar -storetype BKS -storepass mysecret -keypass mysecret -keyalg "RSA" -sigalg "SHA1withRSA"
顺便提一句。我也尝试了 keytool -import
没有 -keyalg "RSA" -sigalg "SHA1withRSA"
, ,但没有改变。
问题 是我遇到了这个错误:
javax.net.ssl.SSLException: Not trusted server certificate
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)
at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities.authenticateWithPass(NetworkUtilities.java:346)
at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities$1.run(NetworkUtilities.java:166)
at org.homedns.saran.android.wowcalendarsync.network.NetworkUtilities$5.run(NetworkUtilities.java:278)
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: IssuerName(CN=thawte Primary Root CA, OU="(c) 2006 thawte, Inc. - For authorized use only", OU=Certification Services Division, O="thawte, Inc.", C=US) does not match SubjectName(CN=Thawte SSL CA, O="Thawte, Inc.", C=US) of signing certificate
at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
... 12 more
Caused by: java.security.cert.CertPathValidatorException: IssuerName(CN=thawte Primary Root CA, OU="(c) 2006 thawte, Inc. - For authorized use only", OU=Certification Services Division, O="thawte, Inc.", C=US) does not match SubjectName(CN=Thawte SSL CA, O="Thawte, Inc.", C=US) of signing certificate
at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:373)
at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
... 13 more
而且我无法找到解决方案的方法。尝试以不同的顺序将证书导入密钥库。但是什么都没有。
请帮忙 (并且请重点关注基于Android的Apache HTTPClient的解决方案 只要).
解决方案
我希望您现在有自己的解决方案,但如果没有:
通过结合见解
- 安托万·哈克(Antoine Hauck)的博客
- http://blog.synyx.de/2010/06/android-and-self-signed-ssl-certificates/
- 上面BDC的出色答案
- 如果我没有阻止我,那么“ EasysslsocketFactory”和“ Easyx509TrustManager”的易于访问的源代码将提供一个链接(首次回答!)
我设法达到了与 https://eu.battle.net/login/en/login.xml 只有以下课程。请注意,由于根CA被Android信任,因此无需构建密钥库 - 问题仅仅是证书以错误的顺序返回。
(免责声明:虽然没有花任何时间清理代码。)
Easyx509TrustManager:
package com.trustit.trustme;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class EasyX509TrustManager implements X509TrustManager
{
private X509TrustManager standardTrustManager = null;
/**
* Constructor for EasyX509TrustManager.
*/
public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException
{
super();
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init(keystore);
TrustManager[] trustmanagers = factory.getTrustManagers();
if (trustmanagers.length == 0)
{
throw new NoSuchAlgorithmException("no trust manager found");
}
this.standardTrustManager = (X509TrustManager) trustmanagers[0];
}
/**
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
*/
public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException
{
standardTrustManager.checkClientTrusted(certificates, authType);
}
/**
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)
*/
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException
{
// Clean up the certificates chain and build a new one.
// Theoretically, we shouldn't have to do this, but various web servers
// in practice are mis-configured to have out-of-order certificates or
// expired self-issued root certificate.
int chainLength = certificates.length;
if (certificates.length > 1)
{
// 1. we clean the received certificates chain.
// We start from the end-entity certificate, tracing down by matching
// the "issuer" field and "subject" field until we can't continue.
// This helps when the certificates are out of order or
// some certificates are not related to the site.
int currIndex;
for (currIndex = 0; currIndex < certificates.length; ++currIndex)
{
boolean foundNext = false;
for (int nextIndex = currIndex + 1;
nextIndex < certificates.length;
++nextIndex)
{
if (certificates[currIndex].getIssuerDN().equals(
certificates[nextIndex].getSubjectDN()))
{
foundNext = true;
// Exchange certificates so that 0 through currIndex + 1 are in proper order
if (nextIndex != currIndex + 1)
{
X509Certificate tempCertificate = certificates[nextIndex];
certificates[nextIndex] = certificates[currIndex + 1];
certificates[currIndex + 1] = tempCertificate;
}
break;
}
}
if (!foundNext) break;
}
// 2. we exam if the last traced certificate is self issued and it is expired.
// If so, we drop it and pass the rest to checkServerTrusted(), hoping we might
// have a similar but unexpired trusted root.
chainLength = currIndex + 1;
X509Certificate lastCertificate = certificates[chainLength - 1];
Date now = new Date();
if (lastCertificate.getSubjectDN().equals(lastCertificate.getIssuerDN())
&& now.after(lastCertificate.getNotAfter()))
{
--chainLength;
}
}
standardTrustManager.checkServerTrusted(certificates, authType);
}
/**
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
public X509Certificate[] getAcceptedIssuers()
{
return this.standardTrustManager.getAcceptedIssuers();
}
}
EasysslsocketFactory
package com.trustit.trustme;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.LayeredSocketFactory;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory
{
private SSLContext sslcontext = null;
private static SSLContext createEasySSLContext() throws IOException
{
try
{
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] { new EasyX509TrustManager(null) }, null);
return context;
}
catch (Exception e)
{
throw new IOException(e.getMessage());
}
}
private SSLContext getSSLContext() throws IOException
{
if (this.sslcontext == null)
{
this.sslcontext = createEasySSLContext();
}
return this.sslcontext;
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, java.lang.String, int,
* java.net.InetAddress, int, org.apache.http.params.HttpParams)
*/
public Socket connectSocket(Socket sock,
String host,
int port,
InetAddress localAddress,
int localPort,
HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException
{
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());
if ((localAddress != null) || (localPort > 0))
{
// we need to bind explicitly
if (localPort < 0)
{
localPort = 0; // indicates "any"
}
InetSocketAddress isa = new InetSocketAddress(localAddress, localPort);
sslsock.bind(isa);
}
sslsock.connect(remoteAddress, connTimeout);
sslsock.setSoTimeout(soTimeout);
return sslsock;
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#createSocket()
*/
public Socket createSocket() throws IOException {
return getSSLContext().getSocketFactory().createSocket();
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket)
*/
public boolean isSecure(Socket socket) throws IllegalArgumentException {
return true;
}
/**
* @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.String, int,
* boolean)
*/
public Socket createSocket(Socket socket,
String host,
int port,
boolean autoClose) throws IOException,
UnknownHostException
{
return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
}
// -------------------------------------------------------------------
// javadoc in org.apache.http.conn.scheme.SocketFactory says :
// Both Object.equals() and Object.hashCode() must be overridden
// for the correct operation of some connection managers
// -------------------------------------------------------------------
public boolean equals(Object obj) {
return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class));
}
public int hashCode() {
return EasySSLSocketFactory.class.hashCode();
}
}
myhttpclient
package com.trustit.trustme;
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.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.HttpParams;
import android.content.Context;
public class MyHttpClient extends DefaultHttpClient
{
final Context context;
public MyHttpClient(HttpParams hparms, Context context)
{
super(hparms);
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", new EasySSLSocketFactory(), 443));
//http://blog.synyx.de/2010/06/android-and-self-signed-ssl-certificates/
return new SingleClientConnManager(getParams(), registry);
}
}
TRESTME(活动)
package com.trustit.trustme;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class TrustMe extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = (TextView)findViewById(R.id.tv1);
HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established.
int timeoutConnection = 10000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 10000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
// Instantiate the custom HttpClient
HttpClient client = new MyHttpClient(httpParameters,
getApplicationContext());
HttpGet request = new HttpGet("https://eu.battle.net/login/en/login.xml");
BufferedReader in = null;
try
{
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null)
{
sb.append(line + NL);
}
in.close();
String page = sb.toString();
//System.out.println(page);
tv.setText(page);
}
catch (ClientProtocolException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (in != null)
{
try
{
in.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
其他提示
查看“ openssl s_client -connect eu.battle.net:443”,我看到以下证书链:
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/emailAddress=premium-server@thawte.com
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
请注意,这是错误的。链中Cert“ N”的发行人应与CERT“ N+1”的主题相匹配。最后一个证书的发行人应自行签名(主题==发行者),并且在技术上不包括。
正确的链条将被订购:
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/emailAddress=premium-server@thawte.com
Android浏览器与Out Out Order链的应对 android.net.http.certificatechainvalidator 代码在将证书链条通过之前重新排序以进行验证。
136 // Clean up the certificates chain and build a new one.
137 // Theoretically, we shouldn't have to do this, but various web servers
138 // in practice are mis-configured to have out-of-order certificates or
139 // expired self-issued root certificate.
140 int chainLength = serverCertificates.length;
141 if (serverCertificates.length > 1) {
142 // 1. we clean the received certificates chain.
143 // We start from the end-entity certificate, tracing down by matching
144 // the "issuer" field and "subject" field until we can't continue.
145 // This helps when the certificates are out of order or
146 // some certificates are not related to the site.
147 int currIndex;
148 for (currIndex = 0; currIndex < serverCertificates.length; ++currIndex) {
149 boolean foundNext = false;
150 for (int nextIndex = currIndex + 1;
151 nextIndex < serverCertificates.length;
152 ++nextIndex) {
153 if (serverCertificates[currIndex].getIssuerDN().equals(
154 serverCertificates[nextIndex].getSubjectDN())) {
155 foundNext = true;
156 // Exchange certificates so that 0 through currIndex + 1 are in proper order
157 if (nextIndex != currIndex + 1) {
158 X509Certificate tempCertificate = serverCertificates[nextIndex];
159 serverCertificates[nextIndex] = serverCertificates[currIndex + 1];
160 serverCertificates[currIndex + 1] = tempCertificate;
161 }
162 break;
163 }
164 }
165 if (!foundNext) break;
166 }
167
168 // 2. we exam if the last traced certificate is self issued and it is expired.
169 // If so, we drop it and pass the rest to checkServerTrusted(), hoping we might
170 // have a similar but unexpired trusted root.
171 chainLength = currIndex + 1;
172 X509Certificate lastCertificate = serverCertificates[chainLength - 1];
173 Date now = new Date();
174 if (lastCertificate.getSubjectDN().equals(lastCertificate.getIssuerDN())
175 && now.after(lastCertificate.getNotAfter())) {
176 --chainLength;
177 }
178 }
要在自己的应用程序中处理此问题,您想从SSLContext中创建自己的Javax.net.ssl.sslsocketFactory,该sslContext用X509TrustManager初始化,该X509TrustManager在调用默认的TrustManagerFactory提供的trustmanager之前将链条重新定位。
我最近还没有查看Apache HTTP客户端代码,以查看如何提供您的自定义javax.net.ssl.sslsocketFactory到其SSLSOcketFactory包装器,但应该可以使用(或者只是不使用Apache HTTP Client,并且只需使用新的url(“ https:// ..”).openconnection(),它允许您在httpsurlConnection上指定自定义Javax.net.ssl.ssl.sslsocketFactory。
最后,请注意,您只需要将自签名的root CA导入到您的密钥库中(并且只有当它尚未在系统商店中,但我只是检查了,并且此CA不存在于Froyo中)。在这种情况下,您想要的CA有主题:
/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
我想您的问题现在已经解决了,但是我有相同的问题,我也挣扎了一些时间来找到正确的解决方案。也许它可以帮助某人。
我也使用了来自 Antoine的博客 但是我更改了用于SSLSocketFactory的构造函数。
所以我用
SSLSocketFactory sf = new SSLSocketFactory(certStore, "some_password", trustStore);
因此,我创建了两个密钥库
KeyStore trustStore = KeyStore.getInstance("BKS");
KeyStore certStore = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.signature_certstore);
try {
certStore.load(in, "some_password".toCharArray());
} finally {
in.close();
}
in = context.getResources().openRawResource(R.raw.signature_truststore);
try {
trustStore.load(in, "some_password".toCharArray());
} finally {
in.close();
}
我用 Portecle. 。在signature_truststore.bks中,我导入了root证书,在signature_certstore.bks中,您必须导入一个或多个中间证书。
该代码的其余部分与博客中的代码完全相同。
我没有解决路径的解决方案。但是我有一个解决方案来忽略证书。我使用这种方法来忽略开发中的自签名证书。看看是否有帮助。
protected final static ClientConnectionManager clientConnectionManager;
protected final static HttpParams params;
// ......
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
params = new BasicHttpParams();
params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(1));
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setUserAgent(params, "android-client-v1.0");
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf8");
clientConnectionManager = new ThreadSafeClientConnManager(params, schemeRegistry);
// and later do this
HttpClient client = new DefaultHttpClient(clientConnectionManager, params);
HttpGet request = new HttpGet(uri);
HttpResponse response = client.execute(request);
这可能会有所帮助: http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/ ,您是否有来自CA的信任证书(例如Versign或Geotrust)?或者您正在使用自签名证书...我面临类似的问题并立即解决了...
顺便说一句,我是上述博客的作者;)我尝试在这里回答您的问题。
我已经查看了Firefox和OpenSSL的证书输出,发现一些有趣的东西。
在OpenSSL输出中查看根CA证书(索引1)。发行人名称为:Thawte Premium Server CA主题名称为:Thawte Primary Root CA主题和发行者名称不同。因此,该证书不被视为根CA,因为它是由另一个实例发行的。因此,Bouncycastle提供商将此证书视为根CA,但由于问题和主题不同而抱怨。
我不知道您是如何获得“错误的”根CA证书的。当我查看Firefox中的Root CA证书时,主题和发行人是相同的。
尝试获取正确的根CA,然后重试。
希望这可以帮助。问候和好运;)
我终于解决了我的“ jeSsuername不符合主题名称”的异常。我已经关注了Antoine的同一个博客,这里有无数次所描述的内容,这是如何使其最终起作用的方法:
1)我们的网站使用Geotrust的两个证书:中间CA由Geotrust SSL CA颁发给我们,并且root CA由Geotrust Global CA发给GeoTrust SSL CA;
2)如果仅使用root ca或root ca或1)中的root和中间cas,则我会得到不匹配的例外,因为Android仅支持 有限数量的可信根CA, ,而Geotrust Global CA不在列表中;
3)在www.geotrust.com的“支持页面”中,有一个名为Geotrust Cross root CA的页面,只需下载它,将其保存到Crossroot.pem之类的名称,然后使用此命令来生成密钥库::
c: program文件 java jdk1.6.0_24 bin> keytool -importcert -v -trustcacerts -file c: ssl ssl crossroot.pem -alias newroot -keystore -keystore -keystore -keystore c: ssl ssl ssl ssl crossrot.bks -provider.bks -provider org.borncycastle org.boncycast. 。
Antonie博客的步骤2具有下载BouncyCastleProvider的链接;
4)将密钥库文件添加到Android项目中,并且它起作用 - 这是有道理的,因为现在Android找到了可信赖的根Equifax安全证书授权(请参阅上面的列表 1)其主题名称GeoTrust Global CA匹配我们网站的root jeadername。
5)博客步骤3中的代码正常运行,为了使其更完整,我在下面复制了测试代码:
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
BufferedReader in = new BufferedReader(new InputStreamReader(entity.getContent()));
String line;
while ((line = in.readLine()) != null)
System.out.println(line);
in.close();
这个问题的困难部分是,如果您的根CA的发行人不在Android的可信赖列表中,您必须从向您发行证书的公司那里获取它 - 要求他们为您提供具有root root的跨根CA发行人是可信赖的Android的根源之一。