我完全被卡住了。我有一段Java客户端代码需要连接到使用自签名证书的SSL服务器。
问题仅在我在服务器端禁用SSLv2支持时才会出现。
private static DefaultHttpClient createHttpClient(int port) {
try {
java.lang.System.setProperty(
"sun.security.ssl.allowUnsafeRenegotiation", "true");
// First create a trust manager that won't care.
X509TrustManager trustManager = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// Don't do anything.
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// Don't do anything.
}
public X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[0];
}
};
// Now put the trust manager into an SSLContext.
// Supported: SSL, SSLv2, SSLv3, TLS, TLSv1, TLSv1.1
SSLContext sslContext = SSLContext.getInstance("SSLv3");
sslContext.init(null, new TrustManager[] { trustManager },
new SecureRandom());
// Use the above SSLContext to create your socket factory
// (I found trying to extend the factory a bit difficult due to a
// call to createSocket with no arguments, a method which doesn't
// exist anywhere I can find, but hey-ho).
SSLSocketFactory sf = new SSLSocketFactory(sslContext);
// Accept any hostname, so the self-signed certificates don't fail
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
// Register our new socket factory with the typical SSL port and the
// correct protocol name.
//Scheme httpsScheme = new Scheme("https", sf, port);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https", sf, port));
HttpParams params = new BasicHttpParams();
ClientConnectionManager cm = new SingleClientConnManager(params,
schemeRegistry);
return new DefaultHttpClient(cm, params);
} catch (Exception ex) {
Log.error("ERROR Creating SSL Connection: " + ex.getMessage());
return null;
}
}
这些是追踪信息
trigger seeding of SecureRandom
done seeding SecureRandom
keyStore is :
keyStore type is : jks
keyStore provider is :
init keystore
init keymanager of type SunX509
trustStore is: /usr/lib/jvm/java-6-openjdk/jre/lib/security/cacerts
trustStore type is : jks
trustStore provider is :
init truststore
adding as trusted cert:
x
x
x
trigger seeding of SecureRandom
done seeding SecureRandom
2010-12-16 17:25:08,705 [DEBUG][gwt-log][ 5] Connecting: 1
Allow unsafe renegotiation: true
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
%% No cached client session
*** ClientHello, TLSv1
RandomCookie: GMT: 1292516708 bytes = { 205, 187, 238, 65, 164, 126, 107, 173, 51, 124, 60, 146, 4, 127, 165, 246, 216, 181, 106, 72, 9, 214, 243, 64, 34, 117, 141, 76 }
Session ID: {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods: { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
***
[write] MD5 and SHA1 hashes: len = 177
0000: 01 00 00 AD 03 01 4D 0A 3D 64 CD BB EE 41 A4 7E ......M.=d...A..
xxxxxxx
00B0: 00 .
btpool0-0, WRITE: TLSv1 Handshake, length = 177
[write] MD5 and SHA1 hashes: len = 173
0000: 01 03 01 00 84 00 00 00 20 00 00 04 01 00 80 00 ........ .......
xxxxxxx
00A0: F6 D8 B5 6A 48 09 D6 F3 40 22 75 8D 4C ...jH...@"u.L
btpool0-0, WRITE: SSLv2 client hello message, length = 173
[Raw write]: length = 175
0000: 80 AD 01 03 01 00 84 00 00 00 20 00 00 04 01 00 .......... .....
xxxxxxx
00A0: 7F A5 F6 D8 B5 6A 48 09 D6 F3 40 22 75 8D 4C .....jH...@"u.L
btpool0-0, handling exception: java.net.SocketException: Connection reset
btpool0-0, SEND TLSv1 ALERT: fatal, description = unexpected_message
btpool0-0, WRITE: TLSv1 Alert, length = 2
btpool0-0, Exception sending alert: java.net.SocketException: Broken pipe
btpool0-0, called closeSocket()
btpool0-0, IOException in getSession(): java.net.SocketException: Connection reset
2010-12-16 17:25:08,890 [DEBUG][gwt-log][ 6] peer not authenticated
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:371)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:399)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:143)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
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:731)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:709)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:700)
[Fatal Error] :1:1: Premature end of file.
Finalizer, called close()
Finalizer, called closeInternal(true)
在服务器端,我可以看到以下跟踪信息:
info sock48 handshake start {before/accept initialization}
info sock48 accept loop {before/accept initialization}
info sock48 accept exit {SSLv3 read client hello B}
error sock48 {wrong version number}
如果我启用SSL2,那么我就会看到:
info sock47 handshake start {before/accept initialization}
info sock47 accept loop {before/accept initialization}
info sock47 accept loop {SSLv3 read client hello A}
info sock47 accept loop {SSLv3 write server hello A}
info sock47 accept loop {SSLv3 write certificate A}
info sock47 accept loop {SSLv3 write server done A}
info sock47 accept loop {SSLv3 flush data}
info sock47 accept exit {SSLv3 read client certificate A}
info sock47 accept exit {SSLv3 read client certificate A}
info sock47 accept loop {SSLv3 read client key exchange A}
info sock47 accept loop {SSLv3 read finished A}
info sock47 accept loop {SSLv3 write change cipher spec A}
info sock47 accept loop {SSLv3 write finished A}
info sock47 accept loop {SSLv3 flush data}
info sock47 handshake done {SSL negotiation finished successfully}
info sock47 accept exit {SSL negotiation finished successfully}
info sock47 alert write {close notify}
一切都正常工作。
我也知道这不是服务器端的问题,因为使用其他软件连接正常。
你有什么想法我做错了什么吗?
还有,有人知道“读取客户端hello A / B”的含义吗?
谢谢
更新 - 已解决
SSLSocketFactory需要被这个新的TLSSocketFactory替换。
public class TLSSocketFactory extends SSLSocketFactory {
private final javax.net.ssl.SSLSocketFactory socketfactory;
public TLSSocketFactory(SSLContext sslContext) {
super(sslContext);
this.socketfactory = sslContext.getSocketFactory();
}
public Socket createSocket() throws IOException {
SSLSocket socket = (SSLSocket) super.createSocket();
socket.setEnabledProtocols(new String[] {"SSLv3, TLSv1"});
return socket;
}
public Socket createSocket(
final Socket socket,
final String host,
final int port,
final boolean autoClose
) throws IOException, UnknownHostException {
SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
socket,
host,
port,
autoClose
);
sslSocket.setEnabledProtocols(new String[] {"SSLv3", "TLSv1"});
getHostnameVerifier().verify(host, sslSocket);
return sslSocket;
}
}
SSLv2ClientHello
,而不是从头开始定义自己的列表。 - user207421