我打电话用下面的代码远程HTTPS URL:
def inputStream = new URL("https://somewebsite.com").openStream()
这是我的本地机器上的伟大工程,但是当我部署到服务器,我得到以下异常:
java.security.cert.CertPathValidatorException: CA key usage check failed: keyCertSign bit is not set
这是什么错误的原因,什么可以解释它的工作一台机器上,而不是其他?
UPDATE
我正在生产的Ubuntu的服务器和本地Mac上的发展。 我试图访问该网站(姑且称之为peopleware.com)具有以下证书信息:
- AddTrust外部CA根
- UTN-USERFirst五金
- peopleware.com
我试图从我的浏览器保存的.CER文件,并在在/ etc / SSL /证书/ JAVA / castore将它们安装到密钥库
我假设你在谈论从UTN-USERFirst五金此证书:
-----BEGIN CERTIFICATE-----
MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
-----END CERTIFICATE-----
在人类可读的版本:
Version: 3 (0x2)
Serial Number:
44:be:0c:8b:50:00:24:b4:11:d3:36:2a:fe:65:0a:fd
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware
Validity
Not Before: Jul 9 18:10:42 1999 GMT
Not After : Jul 9 18:19:22 2019 GMT
Subject: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware
Subject Public Key Info:
[...]
X509v3 extensions:
X509v3 Key Usage:
Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
A1:72:5F:26:1B:28:98:43:95:5D:07:37:D5:85:96:9D:4B:D2:C3:45
X509v3 CRL Distribution Points:
Full Name:
URI:http://crl.usertrust.com/UTN-USERFirst-Hardware.crl
X509v3 Extended Key Usage:
TLS Web Server Authentication, IPSec End System, IPSec Tunnel, IPSec User
从本质上讲,我们在这里既具有CA证书X509v3 Key Usage
和X509v3 Extended Key Usage
。
然而, RFC 3280说,有关扩展密钥使用扩展如下 :
一般情况下,这种扩展将在最终实体证书才会出现。
这并不是一个CA证书开始太顺利,但后来,同一节还这样说:
如果证书包含一个密钥用法扩展和一个扩展密钥用法扩展,则两个扩展必须独立地处理,并且该证书必须仅被用于具有两个延伸相一致的目的。 如果没有目的有两个扩展一致的,那么证书不得用于任何目的。
在这个证书是在这个RFC唯一的扩展的密钥使用扩展TLS的Web服务器身份验证 :
id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
-- TLS WWW server authentication
-- Key usage bits that may be consistent: digitalSignature,
-- keyEncipherment or keyAgreement
当然,这是不具有一致keyCertSign
,其中,根据RFC 3280(和RFC 5280)。 (我也怀疑任何IPSec的扩展与兼容keyCertSign
)。 这使得该证书没用颁发证书(不是非常的CA证书有用)。
我将使用此证书,要求他们与他们的CA(UTN-USERFirst五金,显然魔岛),并要求他们解决这个问题联系该网站。 我必须说,它并不好看的人谁赚来的钱对这些RFC的后面来。
当然,这可能需要一段时间,不会解决你眼前的问题。
我想我已经看到了这个主题DN(UTN-USERFirst五金)其他中间CA证书,所以一个以上的可能不是你所使用的一个。
你也许能够做的(前提是你能手动验证服务器证书本身尽管存在这些问题)是使用SSLContext
和TrustManager
特别局限于使用非常证书,此连接。 这可能会妨碍认证路径算法,试图找到颁发者证书,落入了这个问题。
编辑:
以下是此解决办法更多详细资料(这应该仍然保持你的连接安全)。
- 使用Firefox连接到该网站。
- 点击蓝色/绿色条,选择“更多信息...”
- 安全性 - >查看证书 - >详细
- 从列表中选择服务器证书的顶部,然后选择“导出...”
- 同样的PEM文件的某处。
使用keytool
来创建一个新的密钥库(选择信任该证书,并选择一个合理的密码):
keytool -importcert -keystore example.jks -file example.pem
然后,使用这个Java代码,这应该不是太难端口的Groovy:
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("/.../example.jks");
ks.load(fis, null);
// or ks.load(fis, "thepassword".toCharArray());
fis.close();
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
URL url = new URL("https://somewebsite.com");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(sslContext.getSocketFactory());
InputStream is = conn.getInputStream();