1

我正在尝试调试为什么 javamail 客户端无法成功连接到邮件服务器以转发消息。我安装了 SSLPoke 以查看 SSL 连接发生了什么,因为 Javamail 客户端嵌入在一个实质性的 Web 应用程序 (iDempiere) 中。

这似乎与用于建立连接的 java 密钥库有关。但我不能说它有什么问题。

本地密钥库的内容是:

JAVA_VERSION="11" keytool -list -v -keystore /opt/idempiere/idempiere-server/jettyhome/etc/keystore
Enter keystore password:  
Keystore type: PKCS12
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: accounting-2
Creation date: Dec 14, 2020
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: DC=ca, DC=harte-lyne, C=CA, ST=Ontario, L=Hamilton, O=Harte & Lyne Limited, OU=Networked Data Services, CN=accounting.harte-lyne.ca
Issuer: DC=ca, DC=harte-lyne, C=CA, ST=Ontario, L=Hamilton, O=Harte & Lyne Limited, OU=Networked Data Services, CN=CA_HLL_ISSUER_2016
Serial number: 20160054
Valid from: Fri Jul 31 20:00:00 EDT 2020 until: Sun Aug 31 19:59:59 EDT 2025
Certificate fingerprints:
     SHA1: 20:C4:82:9B:55:08:6C:6B:6D:C3:85:7C:52:5A:87:27:11:48:E9:B6
     SHA256: 98:26:68:02:9D:80:BD:34:B6:FD:93:A1:77:90:C1:5F:1D:75:1C:A7:1D:1B:BF:17:D6:B0:D7:83:78:2E:4E:23
Signature algorithm name: SHA512withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.16.840.1.113730.1.4 Criticality=false
0000: 16 35 68 74 74 70 3A 2F   2F 63 61 2E 68 61 72 74  .5http://ca.hart
0010: 65 2D 6C 79 6E 65 2E 63   61 2F 43 41 5F 48 4C 4C  e-lyne.ca/CA_HLL
0020: 5F 49 53 53 55 45 52 5F   32 30 31 36 2F 63 72 6C  _ISSUER_2016/crl
0030: 2D 76 31 2E 63 72 6C                               -v1.crl


#2: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
  [
   accessMethod: caIssuers
   accessLocation: URIName: http://ca.harte-lyne.ca/CA_HLL_ISSUER_2016/ca.crt
]
]

#3: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: FD C6 20 77 C5 AA E8 34   43 99 C4 3D 5B 65 9A 3C  .. w...4C..=[e.<
0010: 2D 14 8E AF                                        -...
]
[L=Hamilton, DC=ca, DC=harte-lyne, C=CA, OU=Networked Data Services, O=Harte & Lyne Limited, ST=Ontario, CN=CA_HLL_ROOT_2016]
SerialNumber: [    02]
]

#4: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://ca.harte-lyne.ca/CA_HLL_ISSUER_2016/crl-v2.crl]
]]

#5: ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
  [CertificatePolicyId: [1.3.6.1.4.1.44880.100.10.10.3.1]
[PolicyQualifierInfo: [
  qualifierID: 1.3.6.1.5.5.7.2.1
  qualifier: 0000: 16 1B 68 74 74 70 3A 2F   2F 63 61 2E 68 61 72 74  ..http://ca.hart
0010: 65 2D 6C 79 6E 65 2E 63   61 2F 43 50 53           e-lyne.ca/CPS

], PolicyQualifierInfo: [
  qualifierID: 1.3.6.1.5.5.7.2.2
  qualifier: 0000: 30 34 1A 32 4C 69 6D 69   74 65 64 20 4C 69 61 62  04.2Limited Liab
0010: 69 6C 69 74 79 2C 20 73   65 65 20 68 74 74 70 3A  ility, see http:
0020: 2F 2F 63 61 2E 68 61 72   74 65 2D 6C 79 6E 65 2E  //ca.harte-lyne.
0030: 63 61 2F 43 50 53                                  ca/CPS

]]  ]
]

#6: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  serverAuth
  clientAuth
  emailProtection
]

#7: ObjectId: 2.5.29.18 Criticality=false
IssuerAlternativeName [
  RFC822Name: certificates@harte-lyne.ca
  URIName: http://ca.harte-lyne.ca
]

#8: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
  DigitalSignature
  Non_repudiation
  Key_Encipherment
]

#9: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
NetscapeCertType [
   SSL client
   SSL server
   S/MIME
]

#10: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  RFC822Name: certificates@example.com
  DNSName: accounting.harte-lyne.ca
  DNSName: accounting
  DNSName: accounting.internal
  DNSName: accounting.harte-lyne.ca
  DNSName: accounting.internal.harte-lyne.ca
  DNSName: accounting-1
  DNSName: accounting-1.internal
  DNSName: accounting-1.harte-lyne.ca
  DNSName: accounting-1.internal.harte-lyne.ca
  DNSName: accounting-2
  DNSName: accounting-2.internal
  DNSName: accounting-2.harte-lyne.ca
  DNSName: accounting-2.internal.harte-lyne.ca
  DNSName: ledgersmb
  DNSName: ledgersmb.internal
  DNSName: ledgersmb.harte-lyne.ca
  DNSName: ledgersmb.internal.harte-lyne.ca
  DNSName: localhost
  DNSName: localhost.harte-lyne.ca
  IPAddress: 216.185.71.87
  IPAddress: 192.168.216.87
  IPAddress: 192.168.216.88
  IPAddress: 216.185.71.87
  IPAddress: 216.185.71.88
  IPAddress: 127.0.87.1
  IPAddress: 127.0.88.1
  IPAddress: 127.0.0.1
]

#11: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 23 12 19 8F 6E CB 1D 21   C2 7F 59 03 C6 69 B6 FB  #...n..!..Y..i..
0010: 41 99 B5 89                                        A...
]
]



*******************************************
*******************************************

这是从包含以下内容的 pkcs12 文件创建的:

openssl pkcs12 -in accounting-2.p12 | grep subject
Enter Import Password:
subject=CN = accounting.harte-lyne.ca, OU = Networked Data Services, O = Harte & Lyne Limited, L = Hamilton, ST = Ontario, C = CA, DC = harte-lyne, DC = ca
subject=CN = CA_ISSUER_2016, OU = Networked Data Services, O = Harte & Lyne Limited, L = Hamilton, ST = Ontario, C = CA, DC = harte-lyne, DC = ca
subject=CN = CA_HLL_ROOT_2016, ST = Ontario, O = Harte & Lyne Limited, OU = Networked Data Services, C = CA, DC = harte-lyne, DC = ca, L = Hamilton
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

使用:

JAVA_VERSION="11" keytool -importkeystore  -srckeystore accounting-2.p12  -destkeystore accounting-2.keystore -srcstoretype pkcs12 -alias accounting-2

cp -p accounting-2.keystore /opt/idempiere/idempiere-server/jettyhome/etc/keystore

我要连接的服务使用 CA_ISSUER_2016 颁发的证书,并引用包含该颁发者及其根证书的 ca_bundle。

但是,当我使用 SSLpoke 连接到该服务器来测试密钥库的有效性时,我得到了这个:

JAVA_VERSION="11" java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=/opt/idempiere/idempiere-server/jettyhome/etc/keystore  SSLPoke 192.168.216.32 465
javax.net.ssl|DEBUG|01|main|2020-12-18 09:42:33.441 EST|SSLCipher.java:438|jdk.tls.keyLimits:  entry = AES/GCM/NoPadding KeyUpdate 2^37. AES/GCM/NOPADDING:KEYUPDATE = 137438953472
javax.net.ssl|DEBUG|01|main|2020-12-18 09:42:33.607 EST|SSLCipher.java:1840|KeyLimit read side: algorithm = AES/GCM/NOPADDING:KEYUPDATE
countdown value = 137438953472
javax.net.ssl|DEBUG|01|main|2020-12-18 09:42:33.611 EST|SSLCipher.java:1994|KeyLimit write side: algorithm = AES/GCM/NOPADDING:KEYUPDATE
countdown value = 137438953472
javax.net.ssl|WARNING|01|main|2020-12-18 09:42:33.660 EST|SSLSocketImpl.java:1550|handling exception (
"throwable" : {
  java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

事实证明,该java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty错误是由于密钥库受密码保护且未提供密码这一事实引起的。

提供密码后,获得的错误会发生变化:

导出密码=keystore_password

JAVA_VERSION="11" java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=/opt/idempiere/idempiere-server/jettyhome/etc/keystore  -Djavax.net.ssl.trustStorePassword=$PW  -Djavax.net.ssl.keyStorePassword=$PW SSLPoke google.ca 443
JAVA_VERSION="11" java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=/opt/idempiere/idempiere-server/jettyhome/etc/keystore  -Djavax.net.ssl.trustStorePassword=$PW  -Djavax.net.ssl.keyStorePassword=$PW SSLPoke google.ca 443javax.net.ssl|DEBUG|01|main|2020-12-18 10:13:45.561 EST|SSLCipher.java:438|jdk.tls.keyLimits:  entry = AES/GCM/NoPadding KeyUpdate 2^37. AES/GCM/NOPADDING:KEYUPDATE = 137438953472
javax.net.ssl|ERROR|01|main|2020-12-18 10:13:45.904 EST|TransportContext.java:318|Fatal (CERTIFICATE_UNKNOWN): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target (
"throwable" : {
  sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

我不知道如何解释这一点。该消息是否意味着我正在使用的密钥库中缺少 google 证书链?或者这是否意味着本地密钥库不包含本地主机的证书?

如果我将目标更改为其证书由与客户端相同的颁发者和根 CA 颁发的服务,我会收到相同的错误:

JAVA_VERSION="11" java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=/opt/idempiere/idempiere-server/jettyhome/etc/keystore  -Djavax.net.ssl.trustStorePassword=$PW  -Djavax.net.ssl.keyStorePassword=$PW SSLPoke webmail.harte-lyne.ca 443
javax.net.ssl|DEBUG|01|main|2020-12-18 10:18:23.532 EST|SSLCipher.java:438|jdk.tls.keyLimits:  entry = AES/GCM/NoPadding KeyUpdate 2^37. AES/GCM/NOPADDING:KEYUPDATE = 137438953472
javax.net.ssl|ERROR|01|main|2020-12-18 10:18:23.889 EST|TransportContext.java:318|Fatal (CERTIFICATE_UNKNOWN): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target (
"throwable" : {
  sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

需要在密钥库中提供什么才能使连接正常工作?使用 openssl s_client 和我们自己的证书连接到我们的内部服务没有问题。

进一步的测试改变了一些事情。我决定手动将中间证书和根证书添加到密钥库的副本中。然后错误发生了变化:

JAVA_VERSION="11" keytool -import -trustcacerts -file /usr/local/etc/pki/tls/certs/CA_HLL_ISSUER_2016.crt -alias 'hartelyneissuer2016 [hll]' -keystore /root/ca_certs_accounting-2.keystore 输入密钥库密码:
所有者:DC=ca、DC=harte-lyne、C=CA、ST=Ontario、L=Hamilton、O=Harte & Lyne Limited、OU=Networked Data Services、CN=CA_ISSUER_2016。. . 相信这个证书?[否]:是 证书已添加到密钥库

AVA_VERSION="11" keytool -import -trustcacerts -file /usr/local/etc/pki/tls/certs/CA_HLL_ROOT_2016.crt -alias 'hartelyneroot2016 [hll]' -keystore /root/ca_certs_accounting-2.keystore 输入密钥库密码:
所有者:L=Hamilton, DC=ca, DC=harte-lyne, C=CA, OU=Networked Data Services, O=Harte & Lyne Limited, ST=Ontario, CN=CA_HLL_ROOT_2016。. . 相信这个证书?[否]:是 证书已添加到密钥库

现在 SSLPoke 给出了这个错误:

JAVA_VERSION="11" java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=/root/ca_certs_accounting-2.keystore  -Djavax.net.ssl.trustStorePassword=$PW  -Djavax.net.ssl.keyStorePassword=$PW SSLPoke webmail.harte-lyne.ca 443
javax.net.ssl|DEBUG|01|main|2020-12-18 10:33:08.306 EST|SSLCipher.java:438|jdk.tls.keyLimits:  entry = AES/GCM/NoPadding KeyUpdate 2^37. AES/GCM/NOPADDING:KEYUPDATE = 137438953472
javax.net.ssl|ERROR|01|main|2020-12-18 10:33:08.626 EST|TransportContext.java:318|Fatal (CERTIFICATE_UNKNOWN): PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors (
"throwable" : {

根据SSL Exception on Java: Path does not chain with any trust anchors上一个错误,unable to find valid certification path to requested target是由于 keytool 一次只导入一个证书,而不管 pkcs12 文件中提供的证书链的长度如何. 因此,添加缺少的中间证书和根证书消除了该问题并导致了Path does not chain with any of the trust anchors错误。

现在的问题是:如何建立私有 CA 根证书作为 Java 可接受的信任锚?

我之前已将根证书和中间证书添加到 JAVA_HOME 中的 cacerts 文件的副本中:

keytool -keystore  /usr/local/openjdk11/lib/security/cacerts -storepass changeit -list | grep hll
hartelyneissuer2016 [hll], Dec 14, 2020, trustedCertEntry, 
hartelyneroot2016 [hll], Dec 14, 2020, trustedCertEntry, 

但这并没有,而且仍然没有消除Path does not chain with any of the trust anchors错误。为什么不?

4

0 回答 0