在一个项目开发过程中,需要Java客户端和C++开发的服务端进行 TLS链接,协议是
TLSv1,双向验证,在连调过程中,一开始客户端怎么也连不上服务端,查询服务端日志,发现如下错误:
error:1408F10B:SSL
routines:SSL3_GET_RECORD:wrong version number.
初始代码:
try {
SSLContext sslContext = SSLContext.getInstance("TLSv1");
//
TrustManager
KeyStore kstm =
KeyStore.getInstance("JKS");
kstm.load(new FileInputStream("F:/box/tclient.keystore"),
"123456".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"
);
tmf.init(kstm);
TrustManager[] tm = tmf.getTrustManagers();
//
KeyManager
KeyStore ks_p = KeyStore.getInstance("PKCS12");
FileInputStream fis = new
FileInputStream("F:/box/SMSCERT.p12");
ks_p.load(fis, "666666".toCharArray());
KeyManagerFactory keyFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(ks_p, "666666".toCharArray());
KeyManager[] keyManagers = keyFactory.getKeyManagers();
//
create SSL socket
sslContext.init(keyManagers, tm, new
java.security.SecureRandom());
SSLSocketFactory ssf = sslContext.getSocketFactory();
SSLSocket socket= (SSLSocket
)ssf.createSocket("172.23.159.98", 4001);
//
write message
socket.getOutputStream().write("1111111111111111".getBytes());
socket.getOutputStream().flush();
} catch (Exception e)
{
e.printStackTrace();
}
客户端执行时一直等待在ocket.getOutputStream().write() 直至超时,
服务端提示握手失败,给出如题目的错误信息。
而C++开发的客户端却能够联通正常,
代码如下:
======== C++ =============
vector calist;
BIO *pBio = NULL;
pBio = BIO_new_file("SMrootCAcert.pem",
"r");
X509 *pTLRoot = PEM_read_bio_X509(pBio,
NULL, NULL, NULL);
calist.push_back(pTLRoot);
BIO_free(pBio);
pBio = BIO_new_file("SMsecLevelCAcert.pem",
"r");
X509 *pTLlevel = PEM_read_bio_X509(pBio,
NULL, NULL, NULL);
calist.push_back(pTLlevel);
BIO_free(pBio);
//本地证书
pBio = BIO_new_file("SMStheLeafcert.pem",
"r");
X509 *a_SMSCert = PEM_read_bio_X509(pBio,
NULL, NULL, NULL);
BIO_free(pBio);
//本地私钥
pBio = BIO_new_file("theLeafprikey.pem",
"r");
EVP_PKEY *a_SMSPKey =
PEM_read_bio_PrivateKey(pBio, NULL, NULL, NULL);
BIO_free(pBio);
pTLS = new CTLS_Translate_Client(
a_SMSCert, calist, a_SMSPKey );
startup:
rt =
pTLS->CTLS_Translate_Client_Init(SSL_VERIFY_PEER);
// rt =
pTLS->CTLS_Translate_Client_Init(SSL_VERIFY_NONE);
if((int)rt != PUB_SHARE_OK)
{
printf("[ERROR]
initialize failed! error code %d\n", rt);
delete pTLS;
return -1;
}
rt = pTLS->TLS_StartUp(ServerIP,
ServerPort);
if((int)rt != PUB_SHARE_OK)
{
printf("[ERROR] Sconnect
SM failed! error code %d\n", rt);
printf("[INFO]
try to connect SM 3 seconds later\n\n");
sleep(3);
goto startup;
}
//测试获取服务器方证书
printf("\n---------------------------------------------*\n");
printf("[SM Certificate:]\n");
BIO *bio_f = NULL;
const X509 *peer =
NULL;
pTLS->TLS_Get_Peer_Cert(&peer);
bio_f=BIO_new(BIO_s_file_internal());
BIO_set_fp(bio_f,stdout,BIO_NOCLOSE);
X509_print(bio_f, (X509
*)peer);
BIO_free(bio_f);
printf("---------------------------------------------*\n");
CRYPTO_malloc_init();
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
printf( "TLS Connect Server : %s:%d
SUCCESS\n", ServerIP, ServerPort );
memset(message_buf, 0, 20);
strcpy((char*)message_buf,"1111111111111111");
memset(w_message_buf, 0, 20);
if(PUB_SHARE_OK==pTLS->TLS_Write(message_buf,16,0,&WriteLen))
{
printf("TLS_Write
SUCCESSFULLY!");
}
==========End C++===========
经代码检查 CTLS_Translate_Client 是使用openssl
v0.9.8开发包的包装类,确实是使用了TLSv1协议。
客户端试过多种办法,都没有解决问题:1、试验不同的协议
如:SSL,SSLv2,SSLv3;2、试验不同的证书加载方式,将本地密钥的公开密钥放到可信任列表中;3、调整超时时间,增加延时(因为服务器是嵌入式,速度没有台式机快);4、调整为单线程处理,因为网上有文章怀疑是多线程问题。
以上办法没有解决,继续从网上搜索资料,变换不同的关键字,使用不同的搜索引擎。
最后,在 serverfault.com 和 fixunix.com
网站的两篇文章的启发下解决了问题。(网址参加最后)
论坛文章中分别提到:
“Changing
Courier's setting "TLS_STARTTLS_PROTOCOL" from imapd-ssl
-configuration file to "TLS_STARTTLS_PROTOCOL=SSL3" seemed to fix
this problem for me.”
和
“This
error is returned when SSL version number in peer record can
not be
recognized (not 20, 30, 31).”
由此想到,可能因为是要服务端和客户端要双向验证,服务端需要客户端的协议版本号的原因导致。根据此思路调整代码,果然解决问题。
正确连接服务器的代码如下:
SSLSocket socket= (SSLSocket
)ssf.createSocket("172.23.159.98", 4001);
SSLParameters parameter =new
SSLParameters();
parameter.setProtocols(new
String[]{"TLSv1"});
//parameter.setNeedClientAuth(true);
//parameter.setWantClientAuth(true);
socket.setSSLParameters(parameter);
socket.startHandshake();
关键就是通过setSSLParameters指定互联的协议是 TLSv1.
startHandshake可以不需要,但增加上可以加快连接,今早发现问题。
以上就是问题解决思路和办法,下面是参考文档:
《Re: error:1408F10B:SSL
routines:SSL3_GET_RECORD:wrong version -
Openssl》
加载中,请稍候......