我尝试使用自签名证书连接到服务器。我使用此代码接受所有证书。
public class CertificateAcceptor {
public void initializeTrustManager() {
try {
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, createTrustManager(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
private TrustManager[] createTrustManager() {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// leave blank to trust all clients
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// leave blank to trust all servers
for (X509Certificate c : chain) {
System.out.println(c.toString());
}
}
}
};
return trustAllCerts;
}
}
但是我得到以下错误:
javax.net.ssl.SSLException: hostname in certificate didn't match: <xyz.ch> != <localhost>
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:220)
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:149)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:130)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:339)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:123)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:147)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
我确定我的证书代码已执行,那么可能是什么问题?
答案 0 :(得分:16)
ALLOW_ALL不是正确的答案。您应该使用带有ext
扩展名的键盘工具来设置具有正确名称的证书:
keytool -genkeypair \
-keystore keystore.jks \
-dname "CN=OLEKSIYS-W3T, OU=Sun Java System Application Server, O=Sun Microsystems, L=Santa Clara, ST=California, C=US" \
-keypass changeit \
-storepass changeit \
-keyalg RSA \
-keysize 2048 \
-alias default \
-ext SAN=DNS:localhost,IP:127.0.0.1 \
-validity 9999
有关详细信息,请参阅http://tersesystems.com/2014/03/23/fixing-hostname-verification/。
答案 1 :(得分:7)
您可以使用SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
SSLSocketFactory sf = new SSLSocketFactory(
SSLContext.getInstance("TLS"),
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme sch = new Scheme("https", 443, sf);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
HttpGet httpget = new HttpGet("https://host/");
...
...
答案 2 :(得分:2)
您是否尝试过调用setDefaultHostnameVerifier
的{{1}}。
请参阅此链接以获取示例: Accepting a certificate for HTTPs on Android
答案 3 :(得分:1)
Prashant的答案可能不起作用,因为您还需要初始化SSLContext
。
我会这样做,
SSLSocketFactory sf=null ;
SSLContext sslContext = null;
StringWriter writer;
try {
sslContext = SSLContext.getInstance("TLS") ;
sslContext.init(null,null,null);
} catch (NoSuchAlgorithmException e) {
//<YourErrorHandling>
} catch (KeyManagementException e){
//<YourErrorHandling>
}
try{
sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
} catch(Exception e) {
//<YourErrorHandling>
}
Scheme scheme = new Scheme("https",443,sf);
httpClient.getConnectionManager().getSchemeRegistry().register(scheme);
答案 4 :(得分:0)
我的问题是,Java SE 6或更小版本不支持SNI。这意味着,一个IP只能有一个ssl证书。但在我的服务器上,有3个不同的apis具有不同的ssl证书。 Java SE 7或更高版本支持SNI,一切正常。 (或只在服务器上运行一个api)