打开https URL时出错:未设置keyCertSign位

时间:2012-04-22 12:34:20

标签: java ssl groovy

我使用以下代码调用远程https网址:

   def inputStream = new URL("https://somewebsite.com").openStream()

这在我的本地计算机上运行良好,但是当我部署到服务器时,我得到以下异常:

java.security.cert.CertPathValidatorException: CA key usage check failed: keyCertSign bit is not set

这个错误的原因是什么,以及在一台机器而不是另一台机器上工作的原因是什么?


更新


我正在生产中运行Ubuntu服务器并在本地Mac上进行开发。我正在尝试访问的网站(我们称之为peopleware.com)具有以下证书信息:

  1. AddTrust外部CA根
  2. UTN-USERFirst-硬件
  3. peopleware.com
  4. 我尝试从浏览器保存.cer文件并将它们安装到/ etc / ssl / certs / java / castore的密钥库中

1 个答案:

答案 0 :(得分:5)

我假设你在谈论UTN-USERFirst-Hardware的这个证书:

-----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

基本上,我们这里有一个同时包含X509v3 Key UsageX509v3 Extended Key Usage的CA证书。

然而,RFC 3280 says the following about the extended key usage extension

  

通常,此扩展程序仅出现在最终实体中   证书。

这对于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-Hardware,显然是Comodo)并要求他们解决此问题。我必须说,那些在这些RFC背后赚钱的人看起来并不好看。

当然,这可能需要一段时间,并不能解决您当前的问题。

我想我在其他中间CA证书中看到了这个主题DN(UTN-USERFirst-Hardware),因此上面的那个可能不是您正在使用的那个。

您可以做的事情(假设您能够在不考虑这些问题的情况下手动验证服务器证书本身)是使用SSLContextTrustManager专门限制使用它证书,用于此连接。这可能会阻止证书路径算法尝试查找颁发者证书并陷入此问题。

修改

以下是此解决方法的更多详细信息(应该仍然保证您的连接安全)。

  • 使用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();