如何解决SSLHandshakeException?我为什么要这样做?

时间:2014-04-17 17:09:46

标签: java java-ee tomcat web-applications ssl

我正在使用java ee 6tomcat。其中一个语句抛出以下异常:

sun.security.validator.ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: unable to 
find valid certification path to requested target
.
.
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.
ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: unable to 
find valid certification path to requested target

我的应用程序使用与Twitter API对话的API。在下面的代码片段中,注释语句抛出异常:

try {
        RequestToken rToken = twitter.getOAuthRequestToken(); //THROWS EXCEPTION
        authURL = rToken.getAuthorizationURL();
    }catch(Exception exc) {
        System.out.println("$$$$$$$$Inside exception block$$$$$$$$$$");
        exc.printStackTrace();
    }

这种例外可能是什么原因?

5 个答案:

答案 0 :(得分:4)

听起来您信任库中的证书路径不完整。例如,您可能已安装了您信任服务器的证书,但未安装一个或多个签署该证书的中间证书。确保将完整路径返回到受信任的根目录。

编辑:

  • 要查看服务器使用的完整证书路径,请使用here
  • 所述的命令
  • 要打开JSSE SSL / TLS图层的调试,请设置此系统属性:-Djavax.net.debug = ssl

答案 1 :(得分:2)

最简单快捷的方法是将twitter证书导入jvm的密钥库(由Tomcat使用):

使用浏览器访问Twitter API页面并在本地下载证书。然后将证书导入JVM,如下所示:

keytool -importcert -file /path/to/twitter.crt -keystore /usr/java/jdk1.6.0_16/jre/lib/security/cacerts -alias TwitterCert 

假设您的JVM(JAVA_HOME)位于/usr/java/jdk1.6.0_16 /

它会要求您输入密码,如果您没有更改密码,则为"更改"

重新启动Tomcat,异常将消失: - )

答案 2 :(得分:1)

我认为Rob和Alex指出了问题和答案。以下是答案的详细信息。它向您展示了如何使用具有感兴趣的根CA的SSLSocketFactory来拨打根CA以验证Java中的链。它向您展示了如何使用s_client来检查证书链。

该代码还避免了将其放入密钥库的需要。当您已经知道需要使用的证书并且不希望要求用户修改其密钥库时,跳过密钥库会很有意义。此外,证书是公开的,通常不需要存储保护。最后,它避开了CA Zoo,这总是一件好事(没有必要让Diginotar声称自己是Twitter的CA.)

static String CA_FILE = "twitter-ca.pem";
...

FileInputStream fis = new FileInputStream(CA_FILE);
X509Certificate ca = (X509Certificate) CertificateFactory.getInstance(
        "X.509").generateCertificate(new BufferedInputStream(fis));

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry(Integer.toString(1), ca);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(
        TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);

SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

URL url = new URL("https://example.com:8443");

HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(context.getSocketFactory());
...

在上面的代码中,HttpsURLConnection用于检测自定义SSL / TLS内容。我不知道你在twitter.getOAuthRequestToken()使用了什么对象或者如何探测它。您必须自己展示更多代码或自行解决。

如果您使用 Twitter4J ,则您可能会对以下内容感兴趣:Connect to twitter after use SSLSocketFactory。另请参阅Twitter4J邮件列表上的setSSLSocketFactory support?。在Twitter4J的坏方面(如果你使用它):

$ cd twitter4j-4.0.1
$ grep -R setSSLSocketFactory *
$
$ grep -R SSLSocketFactory *
$

因此,图书馆甚至可能没有你需要安全地做的事情。


您可以从OpenSSL twitter-ca.pem获取s_client。使用您用于twitter.getOAuthRequestToken()的网址(而不仅仅是twitter.com):

$ openssl s_client -connect twitter.com:443 
CONNECTED(00000003)
depth=1 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = Terms of use at https://www.verisign.com/rpa (c)06, CN = VeriSign Class 3 Extended Validation SSL CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/businessCategory=Private Organization/serialNumber=4337446/C=US/postalCode=94103-1307/ST=California/L=San Francisco/street=1355 Market St/O=Twitter, Inc./OU=Twitter Security/CN=twitter.com
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended Validation SSL CA
 1 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended Validation SSL CA
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5

s_client开始,您知道自己需要VeriSign Class 3 Public Primary Certification Authority - G5。你可以从VeriSign Root Certificates获得。文件名为PCA-3G5.pem

请下载VeriSign Class 3 Public Primary Certification Authority - G5,将其另存为twitter-ca.pem,然后在上述程序中使用。

使用适当的CA,您将能够执行s_client并验证链。请注意Verify return code: 0 (ok)。它还会清除您的javax.net.ssl.SSLHandshakeException问题:

$ openssl s_client -connect twitter.com:443 -CAfile twitter-ca.pem 
CONNECTED(00000003)
depth=2 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 2006 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 3 Public Primary Certification Authority - G5
verify return:1
depth=1 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = Terms of use at https://www.verisign.com/rpa (c)06, CN = VeriSign Class 3 Extended Validation SSL CA
verify return:1
depth=0 1.3.6.1.4.1.311.60.2.1.3 = US, 1.3.6.1.4.1.311.60.2.1.2 = Delaware, businessCategory = Private Organization, serialNumber = 4337446, C = US, postalCode = 94103-1307, ST = California, L = San Francisco, street = 1355 Market St, O = "Twitter, Inc.", OU = Twitter Security, CN = twitter.com
verify return:1
---
Certificate chain
 0 s:/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/businessCategory=Private Organization/serialNumber=4337446/C=US/postalCode=94103-1307/ST=California/L=San Francisco/street=1355 Market St/O=Twitter, Inc./OU=Twitter Security/CN=twitter.com
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended Validation SSL CA
 1 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended Validation SSL CA
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
---
...
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: DA2581658CBA4B9B2B5061CCA69166D7...
    Session-ID-ctx: 
    Master-Key: 6CF97D758C953E627015F2EF0EBA9918...
    Key-Arg   : None
    ...
    Start Time: 1398555988
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)

$ cat twitter-ca.pem 
-----BEGIN CERTIFICATE-----
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
-----END CERTIFICATE-----

答案 3 :(得分:0)

您是否可能处于通过代理访问Internet的环境中?如果代理使用自签名证书,则JDK无法对任何Internet主机执行SSL,因为它无法识别代理的CA.出现此问题的原因是JDK不使用操作系统的信任库,您的IT将在其中添加自签名证书。解决方案是将代理的自签名证书导入JDK的信任库(即cacerts文件)。在我的场景中,您将能够从浏览器获取代理的证书(因为它使用操作系统的信任库)。然后,您将使用JDK的keytool将证书导入JDK的信任库(但事先进行备份!)。

答案 4 :(得分:0)

我得到了同样的错误并花时间研究它。尝试了所有选项建议,例如将twitter .crt文件添加到我的java cacerts,通过在twitter4j.properties中提供所有相关的密钥/令牌/秘密来修改代码,而不是通过我的代码中的API等设置它们......但最终找到了问题是由于我的网络中存在防火墙。

我成功地从不同的网络执行相同的代码!看看这个选项,看看这对你有用......干杯!

相关问题