Apache HttpClient на Android, производящем CertPathValidatorException (имя_отчета!= Имя_почты)
Я разрабатываю приложение Android для доступа к некоторым файлам battle.net(https://eu.battle.net) (для World of Warcraft) и я ', используя 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), и они одинаковы.
Следуя советам этого блога, я установил вышеуказанный код и импортировал (корневые и промежуточные) сертификаты в хранилище ключей (battlenetkeystore. bks), который используется для HttpClient.
Это команды, которые я использовал для импорта сертификатов в хранилище ключей:
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"
Btw. Я также пробовал 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).
Ответы
Ответ 1
Я ожидаю, что у вас уже есть собственное решение, но если нет:
Объединив идеи из
Мне удалось добиться безопасного подключения к https://eu.battle.net/login/en/login.xml только с помощью следующих классов. Обратите внимание, что нет необходимости создавать хранилище ключей, так как корневому ЦС доверяет андроид - проблема в том, что сертификаты возвращаются в неправильном порядке.
(Отказ от ответственности: не тратить время на очистку кода, хотя.)
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);
}
}
TrustMe (активность)
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();
}
}
}
}
}
Ответ 2
Глядя на "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/[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
Обратите внимание, что вышло из строя. эмитент сертификата "n" в цепочке должен соответствовать типу сертификата "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/[email protected]
Браузер Android справляется с цепочкой из-за порядка с помощью кода 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 }
Чтобы справиться с этим в своем собственном приложении, вы хотите создать свой собственный javax.net.ssl.SSLSocketFactory из SSLContext, который был инициализирован X509TrustManager, который переупорядочивает цепочку перед вызовом TrustManagerFactory по умолчанию, предоставленным TrustManager.
Недавно я не просмотрел код HTTP-клиента Apache, чтобы узнать, как предоставить ваш пользовательский javax.net.ssl.SSLSocketFactory для их оболочки SSLSocketFactory, но он должен быть возможен (или просто не использовать Apache HTTP Client и просто используйте новый URL ( "https://.." ).openConnection(), который позволяет вам указать пользовательский javax.net.ssl.SSLSocketFactory в HttpsURLConnection.
Наконец, обратите внимание, что вам нужно только импортировать самозаверяющий корневой центр сертификации в хранилище ключей (и только если его еще нет в системном хранилище, но я только что проверил, и этот ЦС отсутствует в 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
Ответ 3
Я предполагаю, что ваша проблема решена прямо сейчас, но у меня был такой же, и я также долго пытался найти правильное решение. Может быть, это помогает кому-то.
Я также использовал код из Antoine Blog, но я изменил конструктор, используемый для SSLSocketFactory.
Поэтому я использую
SSLSocketFactory sf = new SSLSocketFactory(certStore, "some_password", trustStore);
поэтому я создал два KeyStores
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();
}
Я создал магазины BKS с Portecle. В файле signature_truststore.bks я импортировал корневой сертификат, а в файле signature_certstore.bks вы должны импортировать один или несколько промежуточных сертификатов.
Остальная часть кода точно такая же, как и в блоге.
Ответ 4
У меня нет решения для исправления пути. Но у меня есть решение игнорировать сертификаты. Я использую этот метод, чтобы игнорировать самоподписанные сертификаты в разработке. Посмотрите, помогает ли это.
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);
Ответ 5
это может помочь: http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/, У вас есть доверенные сертификаты из CA (например, versign или Geotrust)? или вы используете самоподписанный сертификат... я столкнулся с подобной проблемой и решил ее сегодня...
Ответ 6
Btw, я автор из упомянутого выше блога;) Я пытаюсь ответить на ваш вопрос здесь.
Я посмотрел ваши выходы из firefox и openssl и нашел что-то интересное.
Посмотрите сертификат root ca (индекс 1) на свой вывод openssl.
Имя эмитента: Thawte Premium Server CA
Название темы: thawte Primary Root CA
Имена субъектов и эмитентов разные. Поэтому этот сертификат не считается корневым ЦС, поскольку он был выпущен другим экземпляром.
Таким образом, поставщик bouncycastle рассматривает этот сертификат как корневой ЦС, но он жалуется, потому что проблемы и субъект различны.
Я понятия не имею, как вы получили "неправильный" Root CA certificate. Когда я смотрю на сертификат Root CA в firefox, субъект и эмитент совпадают, как и должно быть.
Попробуйте получить правильный корневой ЦС и повторите попытку.
Надеюсь, это поможет.
Приветствия и удачи;)
Ответ 7
Наконец-то я решил, что мое исключение "Имя эмитента не совпадает с именем субъекта". Я следил за тем же блогом Антуаном и тем, что здесь описано много раз, и вот как это сделать, наконец, работать:
1) Наш сайт использует два сертификата от GeoTrust: промежуточный ЦС выдается нам с помощью GeoTrust SSL CA, а корневой ЦС выдается в GeoTrust SSL CA от GeoTrust Global CA;
2) Если используются только корневой ЦС или оба корневых и промежуточных ЦС в 1), я получаю исключение несоответствия, потому что Android поддерживает только a ограниченное количество доверенных корневых CA и GeoTrust Global CA отсутствует в списке;
3) На странице поддержки www.geotrust.com есть страница под названием GeoTrust Cross Root CA, просто загрузите ее, сохраните ее под именем crossroot.pem и используйте эту команду для создания хранилища ключей:
C:\Program Files\Java\jdk1.6.0_24\bin > keytool -importcert -v -trustcacerts -file c:\ssl\crossroot.pem -alias newroot -keystore c:\ssl\crossroot.bks -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "c:\downloads\bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Шаг 2 блога Antonie имеет ссылку для загрузки BouncyCastleProvider;
4) Добавьте файл хранилища ключей в проект Android, и он работает - это имеет смысл, потому что теперь Android находит доверенный корневой центр сертификации Equifax (см. список выше 1), чей SubjectName GeoTrust Global CA соответствует нашему корневому имени пользователя.
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, вам придется получить его от компании, которая выдает вам сертификаты, - попросите их предоставить вам кросс-корневой центр сертификации, который имеет корневой эмитент как один из доверенных корневых центров сертификации Android.