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

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

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

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

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

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


UPDATE


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

  1. AddTrust外部CA根
  2. UTN-USERFirst五金
  3. peopleware.com

我尝试从浏览器保存.cer文件并将它们安装到/ etc / ssl / certs / java / castore的密钥库中

我假设您正在谈论来自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说明了扩展密钥用法扩展的以下内容 :

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

这对于CA证书来说并不是很好,但是稍后,同一部分也说明了这一点:

如果证书包含密钥用法扩展和扩展密钥用法扩展,则两个扩展必须独立处理,并且证书必须仅用于与两个扩展一致的目的。 如果没有与两个扩展一致的目的,则证书不得用于任何目的。

此RFC中此证书中唯一的扩展密钥用法扩展是TLS Web服务器身份validation

  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),因此上面的那个可能不是您正在使用的那个。

您可以做的事情(假设您能够在不考虑这些问题的情况下手动validation服务器证书本身)是使用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();