我正在使用java ee 6
和tomcat
。其中一个语句抛出以下异常:
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();
}
这种例外可能是什么原因?
答案 0 :(得分:4)
听起来您信任库中的证书路径不完整。例如,您可能已安装了您信任服务器的证书,但未安装一个或多个签署该证书的中间证书。确保将完整路径返回到受信任的根目录。
编辑:
答案 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等设置它们......但最终找到了问题是由于我的网络中存在防火墙。
我成功地从不同的网络执行相同的代码!看看这个选项,看看这对你有用......干杯!